blob: 53b24810fbc2caadad1731f169e4bdcdf8a106e2 [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
lanoux5fc14522015-09-21 08:17:35 +000026from tempest.common import compute
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)
Jordan Pittier1d2e40f2016-01-05 18:49:14 +010052 if CONF.service_available.glance:
53 # Glance image client v1
54 cls.image_client = cls.manager.image_client
nithya-ganesan882595e2014-07-29 18:51:07 +000055 # Compute image client
Ghanshyamae76c122015-12-22 13:41:35 +090056 cls.compute_images_client = cls.manager.compute_images_client
Andrea Frittoli247058f2014-07-16 16:09:22 +010057 cls.keypairs_client = cls.manager.keypairs_client
Andrea Frittoli247058f2014-07-16 16:09:22 +010058 # Nova security groups client
John Warrenf2345512015-12-10 13:39:30 -050059 cls.compute_security_groups_client = (
60 cls.manager.compute_security_groups_client)
John Warren5cdbf422016-01-05 12:42:43 -050061 cls.compute_security_group_rules_client = (
62 cls.manager.compute_security_group_rules_client)
Andrea Frittoli247058f2014-07-16 16:09:22 +010063 cls.servers_client = cls.manager.servers_client
Yair Fried1fc32a12014-08-04 09:11:30 +030064 cls.interface_client = cls.manager.interfaces_client
65 # Neutron network client
66 cls.network_client = cls.manager.network_client
John Warren94d8faf2015-09-15 12:22:24 -040067 cls.networks_client = cls.manager.networks_client
John Warren49c0fe52015-10-22 12:35:54 -040068 cls.ports_client = cls.manager.ports_client
John Warren3961acd2015-10-02 14:38:53 -040069 cls.subnets_client = cls.manager.subnets_client
John Warrenfbf2a892015-11-17 12:36:14 -050070 cls.floating_ips_client = cls.manager.floating_ips_client
John Warrenf9606e92015-12-10 12:12:42 -050071 cls.security_groups_client = cls.manager.security_groups_client
John Warren456d9ae2016-01-12 15:36:33 -050072 cls.security_group_rules_client = (
73 cls.manager.security_group_rules_client)
Masayuki Igawabc6fe8d2014-08-29 16:50:01 +090074 # Heat client
75 cls.orchestration_client = cls.manager.orchestration_client
Andrea Frittoli2e733b52014-07-16 14:12:11 +010076
Ivan Kolodyazhnybcfc32e2015-08-06 13:31:36 +030077 if CONF.volume_feature_enabled.api_v1:
78 cls.volumes_client = cls.manager.volumes_client
79 cls.snapshots_client = cls.manager.snapshots_client
80 else:
81 cls.volumes_client = cls.manager.volumes_v2_client
82 cls.snapshots_client = cls.manager.snapshots_v2_client
83
Andrea Frittoli247058f2014-07-16 16:09:22 +010084 # ## Methods to handle sync and async deletes
85
86 def setUp(self):
87 super(ScenarioTest, self).setUp()
88 self.cleanup_waits = []
89 # NOTE(mtreinish) This is safe to do in setUp instead of setUp class
90 # because scenario tests in the same test class should not share
91 # resources. If resources were shared between test cases then it
92 # should be a single scenario test instead of multiples.
93
94 # NOTE(yfried): this list is cleaned at the end of test_methods and
95 # not at the end of the class
96 self.addCleanup(self._wait_for_cleanups)
97
Yair Fried1fc32a12014-08-04 09:11:30 +030098 def delete_wrapper(self, delete_thing, *args, **kwargs):
Andrea Frittoli247058f2014-07-16 16:09:22 +010099 """Ignores NotFound exceptions for delete operations.
100
Yair Fried1fc32a12014-08-04 09:11:30 +0300101 @param delete_thing: delete method of a resource. method will be
102 executed as delete_thing(*args, **kwargs)
103
Andrea Frittoli247058f2014-07-16 16:09:22 +0100104 """
105 try:
106 # Tempest clients return dicts, so there is no common delete
107 # method available. Using a callable instead
Yair Fried1fc32a12014-08-04 09:11:30 +0300108 delete_thing(*args, **kwargs)
Masayuki Igawabfa07602015-01-20 18:47:17 +0900109 except lib_exc.NotFound:
Andrea Frittoli247058f2014-07-16 16:09:22 +0100110 # If the resource is already missing, mission accomplished.
111 pass
112
113 def addCleanup_with_wait(self, waiter_callable, thing_id, thing_id_param,
Ghanshyam2a180b82014-06-16 13:54:22 +0900114 cleanup_callable, cleanup_args=None,
Ken'ichi Ohmichie91a0c62015-08-13 02:09:16 +0000115 cleanup_kwargs=None, waiter_client=None):
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700116 """Adds wait for async resource deletion at the end of cleanups
Andrea Frittoli247058f2014-07-16 16:09:22 +0100117
118 @param waiter_callable: callable to wait for the resource to delete
Ken'ichi Ohmichie91a0c62015-08-13 02:09:16 +0000119 with the following waiter_client if specified.
Andrea Frittoli247058f2014-07-16 16:09:22 +0100120 @param thing_id: the id of the resource to be cleaned-up
121 @param thing_id_param: the name of the id param in the waiter
122 @param cleanup_callable: method to load pass to self.addCleanup with
123 the following *cleanup_args, **cleanup_kwargs.
124 usually a delete method.
125 """
Ghanshyam2a180b82014-06-16 13:54:22 +0900126 if cleanup_args is None:
127 cleanup_args = []
128 if cleanup_kwargs is None:
129 cleanup_kwargs = {}
Andrea Frittoli247058f2014-07-16 16:09:22 +0100130 self.addCleanup(cleanup_callable, *cleanup_args, **cleanup_kwargs)
131 wait_dict = {
132 'waiter_callable': waiter_callable,
133 thing_id_param: thing_id
134 }
Ken'ichi Ohmichie91a0c62015-08-13 02:09:16 +0000135 if waiter_client:
136 wait_dict['client'] = waiter_client
Andrea Frittoli247058f2014-07-16 16:09:22 +0100137 self.cleanup_waits.append(wait_dict)
138
139 def _wait_for_cleanups(self):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000140 # To handle async delete actions, a list of waits is added
141 # which will be iterated over as the last step of clearing the
142 # cleanup queue. That way all the delete calls are made up front
143 # and the tests won't succeed unless the deletes are eventually
144 # successful. This is the same basic approach used in the api tests to
145 # limit cleanup execution time except here it is multi-resource,
146 # because of the nature of the scenario tests.
Andrea Frittoli247058f2014-07-16 16:09:22 +0100147 for wait in self.cleanup_waits:
148 waiter_callable = wait.pop('waiter_callable')
149 waiter_callable(**wait)
150
151 # ## Test functions library
152 #
153 # The create_[resource] functions only return body and discard the
154 # resp part which is not used in scenario tests
155
Yair Frieddb6c9e92014-08-06 08:53:13 +0300156 def create_keypair(self, client=None):
157 if not client:
158 client = self.keypairs_client
Andrea Frittoli247058f2014-07-16 16:09:22 +0100159 name = data_utils.rand_name(self.__class__.__name__)
160 # We don't need to create a keypair by pubkey in scenario
Ken'ichi Ohmichie364bce2015-07-17 10:27:59 +0000161 body = client.create_keypair(name=name)
Yair Frieddb6c9e92014-08-06 08:53:13 +0300162 self.addCleanup(client.delete_keypair, name)
ghanshyamdee01f22015-08-17 11:41:47 +0900163 return body['keypair']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100164
165 def create_server(self, name=None, image=None, flavor=None,
lanoux5fc14522015-09-21 08:17:35 +0000166 validatable=False, wait_until=None,
167 wait_on_delete=True, clients=None, **kwargs):
168 """Wrapper utility that returns a test server.
Andrea Frittoli247058f2014-07-16 16:09:22 +0100169
lanoux5fc14522015-09-21 08:17:35 +0000170 This wrapper utility calls the common create test server and
171 returns a test server. The purpose of this wrapper is to minimize
172 the impact on the code of the tests already using this
173 function.
Andrea Frittoli247058f2014-07-16 16:09:22 +0100174 """
Andrea Frittoli247058f2014-07-16 16:09:22 +0100175
lanoux5fc14522015-09-21 08:17:35 +0000176 # NOTE(jlanoux): As a first step, ssh checks in the scenario
177 # tests need to be run regardless of the run_validation and
178 # validatable parameters and thus until the ssh validation job
179 # becomes voting in CI. The test resources management and IP
180 # association are taken care of in the scenario tests.
181 # Therefore, the validatable parameter is set to false in all
182 # those tests. In this way create_server just return a standard
183 # server and the scenario tests always perform ssh checks.
184
185 # Needed for the cross_tenant_traffic test:
186 if clients is None:
187 clients = self.manager
188
189 vnic_type = CONF.network.port_vnic_type
190
191 # If vnic_type is configured create port for
192 # every network
193 if vnic_type:
194 ports = []
195 networks = []
196 create_port_body = {'binding:vnic_type': vnic_type,
197 'namestart': 'port-smoke'}
198 if kwargs:
199 # Convert security group names to security group ids
200 # to pass to create_port
201 if 'security_groups' in kwargs:
202 security_groups =\
John Warrenf9606e92015-12-10 12:12:42 -0500203 clients.security_groups_client.list_security_groups(
lanoux5fc14522015-09-21 08:17:35 +0000204 ).get('security_groups')
205 sec_dict = dict([(s['name'], s['id'])
206 for s in security_groups])
207
208 sec_groups_names = [s['name'] for s in kwargs.pop(
209 'security_groups')]
210 security_groups_ids = [sec_dict[s]
211 for s in sec_groups_names]
212
213 if security_groups_ids:
214 create_port_body[
215 'security_groups'] = security_groups_ids
216 networks = kwargs.pop('networks')
217
218 # If there are no networks passed to us we look up
219 # for the tenant's private networks and create a port
220 # if there is only one private network. The same behaviour
221 # as we would expect when passing the call to the clients
222 # with no networks
223 if not networks:
224 networks = clients.networks_client.list_networks(
225 filters={'router:external': False})
226 self.assertEqual(1, len(networks),
227 "There is more than one"
228 " network for the tenant")
229 for net in networks:
230 net_id = net['uuid']
231 port = self._create_port(network_id=net_id,
232 client=clients.ports_client,
233 **create_port_body)
234 ports.append({'port': port.id})
235 if ports:
236 kwargs['networks'] = ports
237 self.ports = ports
238
239 tenant_network = self.get_tenant_network()
240
241 body, servers = compute.create_test_server(
242 clients,
243 tenant_network=tenant_network,
244 wait_until=wait_until,
245 **kwargs)
246
247 # TODO(jlanoux) Move wait_on_delete in compute.py
Andrea Frittoli247058f2014-07-16 16:09:22 +0100248 if wait_on_delete:
Ken'ichi Ohmichie91a0c62015-08-13 02:09:16 +0000249 self.addCleanup(waiters.wait_for_server_termination,
lanoux5fc14522015-09-21 08:17:35 +0000250 clients.servers_client,
251 body['id'])
252
Andrea Frittoli247058f2014-07-16 16:09:22 +0100253 self.addCleanup_with_wait(
Ken'ichi Ohmichie91a0c62015-08-13 02:09:16 +0000254 waiter_callable=waiters.wait_for_server_termination,
lanoux5fc14522015-09-21 08:17:35 +0000255 thing_id=body['id'], thing_id_param='server_id',
Andrea Frittoli247058f2014-07-16 16:09:22 +0100256 cleanup_callable=self.delete_wrapper,
lanoux5fc14522015-09-21 08:17:35 +0000257 cleanup_args=[clients.servers_client.delete_server, body['id']],
258 waiter_client=clients.servers_client)
259 server = clients.servers_client.show_server(body['id'])['server']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100260 return server
261
Markus Zoeller3d2a21c2015-02-27 12:04:22 +0100262 def create_volume(self, size=None, name=None, snapshot_id=None,
Andrea Frittoli247058f2014-07-16 16:09:22 +0100263 imageRef=None, volume_type=None, wait_on_delete=True):
264 if name is None:
265 name = data_utils.rand_name(self.__class__.__name__)
Ghanshyam8fc0ed22015-12-18 10:25:14 +0900266 kwargs = {'display_name': name,
267 'snapshot_id': snapshot_id,
268 'imageRef': imageRef,
269 'volume_type': volume_type}
270 if size is not None:
271 kwargs.update({'size': size})
272 volume = self.volumes_client.create_volume(**kwargs)['volume']
Matt Riedemanne85c2702014-09-10 11:50:13 -0700273
Andrea Frittoli247058f2014-07-16 16:09:22 +0100274 if wait_on_delete:
275 self.addCleanup(self.volumes_client.wait_for_resource_deletion,
276 volume['id'])
Matt Riedemanne85c2702014-09-10 11:50:13 -0700277 self.addCleanup(self.delete_wrapper,
278 self.volumes_client.delete_volume, volume['id'])
279 else:
280 self.addCleanup_with_wait(
281 waiter_callable=self.volumes_client.wait_for_resource_deletion,
282 thing_id=volume['id'], thing_id_param='id',
283 cleanup_callable=self.delete_wrapper,
284 cleanup_args=[self.volumes_client.delete_volume, volume['id']])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100285
Ivan Kolodyazhnybcfc32e2015-08-06 13:31:36 +0300286 # NOTE(e0ne): Cinder API v2 uses name instead of display_name
287 if 'display_name' in volume:
288 self.assertEqual(name, volume['display_name'])
289 else:
290 self.assertEqual(name, volume['name'])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100291 self.volumes_client.wait_for_volume_status(volume['id'], 'available')
292 # The volume retrieved on creation has a non-up-to-date status.
293 # Retrieval after it becomes active ensures correct details.
John Warren6177c9e2015-08-19 20:00:17 +0000294 volume = self.volumes_client.show_volume(volume['id'])['volume']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100295 return volume
296
Yair Fried1fc32a12014-08-04 09:11:30 +0300297 def _create_loginable_secgroup_rule(self, secgroup_id=None):
John Warrenf2345512015-12-10 13:39:30 -0500298 _client = self.compute_security_groups_client
John Warren5cdbf422016-01-05 12:42:43 -0500299 _client_rules = self.compute_security_group_rules_client
Andrea Frittoli247058f2014-07-16 16:09:22 +0100300 if secgroup_id is None:
ghanshyamb610b772015-08-24 17:29:38 +0900301 sgs = _client.list_security_groups()['security_groups']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100302 for sg in sgs:
303 if sg['name'] == 'default':
304 secgroup_id = sg['id']
305
306 # These rules are intended to permit inbound ssh and icmp
307 # traffic from all sources, so no group_id is provided.
308 # Setting a group_id would only permit traffic from ports
309 # belonging to the same security group.
310 rulesets = [
311 {
312 # ssh
Ken'ichi Ohmichieb7eeec2015-07-21 01:00:06 +0000313 'ip_protocol': 'tcp',
Andrea Frittoli247058f2014-07-16 16:09:22 +0100314 'from_port': 22,
315 'to_port': 22,
316 'cidr': '0.0.0.0/0',
317 },
318 {
319 # ping
Ken'ichi Ohmichieb7eeec2015-07-21 01:00:06 +0000320 'ip_protocol': 'icmp',
Andrea Frittoli247058f2014-07-16 16:09:22 +0100321 'from_port': -1,
322 'to_port': -1,
323 'cidr': '0.0.0.0/0',
324 }
325 ]
326 rules = list()
327 for ruleset in rulesets:
Ken'ichi Ohmichieb7eeec2015-07-21 01:00:06 +0000328 sg_rule = _client_rules.create_security_group_rule(
ghanshyam0a5e1232015-08-24 16:59:59 +0900329 parent_group_id=secgroup_id, **ruleset)['security_group_rule']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100330 self.addCleanup(self.delete_wrapper,
Ken'ichi Ohmichi685cd172015-07-13 01:29:57 +0000331 _client_rules.delete_security_group_rule,
Andrea Frittoli247058f2014-07-16 16:09:22 +0100332 sg_rule['id'])
333 rules.append(sg_rule)
334 return rules
335
Yair Fried1fc32a12014-08-04 09:11:30 +0300336 def _create_security_group(self):
Andrea Frittoli247058f2014-07-16 16:09:22 +0100337 # Create security group
338 sg_name = data_utils.rand_name(self.__class__.__name__)
339 sg_desc = sg_name + " description"
John Warrenf2345512015-12-10 13:39:30 -0500340 secgroup = self.compute_security_groups_client.create_security_group(
ghanshyamb610b772015-08-24 17:29:38 +0900341 name=sg_name, description=sg_desc)['security_group']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100342 self.assertEqual(secgroup['name'], sg_name)
343 self.assertEqual(secgroup['description'], sg_desc)
John Warrenf2345512015-12-10 13:39:30 -0500344 self.addCleanup(
345 self.delete_wrapper,
346 self.compute_security_groups_client.delete_security_group,
347 secgroup['id'])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100348
349 # Add rules to the security group
Yair Fried1fc32a12014-08-04 09:11:30 +0300350 self._create_loginable_secgroup_rule(secgroup['id'])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100351
352 return secgroup
353
Sean Dague2c98a162016-01-06 14:11:13 -0500354 def get_remote_client(self, server_or_ip, username=None, private_key=None):
JordanP3fe2dc32014-11-17 13:06:01 +0100355 """Get a SSH client to a remote server
356
357 @param server_or_ip a server object as returned by Tempest compute
358 client or an IP address to connect to
359 @param username name of the Linux account on the remote server
360 @param private_key the SSH private key to use
JordanP3fe2dc32014-11-17 13:06:01 +0100361 @return a RemoteClient object
362 """
Andrea Frittoli247058f2014-07-16 16:09:22 +0100363 if isinstance(server_or_ip, six.string_types):
364 ip = server_or_ip
365 else:
lanoux283273b2015-12-04 03:01:54 -0800366 addrs = server_or_ip['addresses'][CONF.validation.network_for_ssh]
Andrew Boik4a3daf12015-03-27 01:59:31 -0400367 try:
368 ip = (addr['addr'] for addr in addrs if
369 netaddr.valid_ipv4(addr['addr'])).next()
370 except StopIteration:
371 raise lib_exc.NotFound("No IPv4 addresses to use for SSH to "
372 "remote server.")
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700373
Andrea Frittoli247058f2014-07-16 16:09:22 +0100374 if username is None:
lanoux283273b2015-12-04 03:01:54 -0800375 username = CONF.validation.image_ssh_user
wantwatering896300c2015-03-27 15:17:42 +0800376 # Set this with 'keypair' or others to log in with keypair or
377 # username/password.
lanoux5fc14522015-09-21 08:17:35 +0000378 if CONF.validation.auth_method == 'keypair':
wantwatering896300c2015-03-27 15:17:42 +0800379 password = None
380 if private_key is None:
381 private_key = self.keypair['private_key']
382 else:
lanoux283273b2015-12-04 03:01:54 -0800383 password = CONF.validation.image_ssh_password
wantwatering896300c2015-03-27 15:17:42 +0800384 private_key = None
Andrea Frittoli247058f2014-07-16 16:09:22 +0100385 linux_client = remote_client.RemoteClient(ip, username,
wantwatering896300c2015-03-27 15:17:42 +0800386 pkey=private_key,
387 password=password)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100388 try:
389 linux_client.validate_authentication()
Matt Riedemann5f0ac522015-05-21 09:16:24 -0700390 except Exception as e:
391 message = ('Initializing SSH connection to %(ip)s failed. '
392 'Error: %(error)s' % {'ip': ip, 'error': e})
393 caller = misc_utils.find_test_caller()
394 if caller:
395 message = '(%s) %s' % (caller, message)
396 LOG.exception(message)
Sean Dague2c98a162016-01-06 14:11:13 -0500397 self._log_console_output()
Andrea Frittoli247058f2014-07-16 16:09:22 +0100398 raise
399
400 return linux_client
401
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000402 def _image_create(self, name, fmt, path,
403 disk_format=None, properties=None):
Ghanshyam2a180b82014-06-16 13:54:22 +0900404 if properties is None:
405 properties = {}
Andrea Frittoli247058f2014-07-16 16:09:22 +0100406 name = data_utils.rand_name('%s-' % name)
407 image_file = open(path, 'rb')
408 self.addCleanup(image_file.close)
409 params = {
410 'name': name,
411 'container_format': fmt,
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000412 'disk_format': disk_format or fmt,
Andrea Frittoli247058f2014-07-16 16:09:22 +0100413 'is_public': 'False',
414 }
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000415 params['properties'] = properties
John Warren66207252015-07-31 15:51:02 -0400416 image = self.image_client.create_image(**params)['image']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100417 self.addCleanup(self.image_client.delete_image, image['id'])
418 self.assertEqual("queued", image['status'])
419 self.image_client.update_image(image['id'], data=image_file)
420 return image['id']
421
422 def glance_image_create(self):
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300423 img_path = CONF.scenario.img_dir + "/" + CONF.scenario.img_file
Andrea Frittoli247058f2014-07-16 16:09:22 +0100424 aki_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.aki_img_file
425 ari_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.ari_img_file
426 ami_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.ami_img_file
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300427 img_container_format = CONF.scenario.img_container_format
428 img_disk_format = CONF.scenario.img_disk_format
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000429 img_properties = CONF.scenario.img_properties
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300430 LOG.debug("paths: img: %s, container_fomat: %s, disk_format: %s, "
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000431 "properties: %s, ami: %s, ari: %s, aki: %s" %
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300432 (img_path, img_container_format, img_disk_format,
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000433 img_properties, ami_img_path, ari_img_path, aki_img_path))
Andrea Frittoli247058f2014-07-16 16:09:22 +0100434 try:
Jordan Pittier1e443ec2015-11-20 16:15:58 +0100435 image = self._image_create('scenario-img',
436 img_container_format,
437 img_path,
438 disk_format=img_disk_format,
439 properties=img_properties)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100440 except IOError:
441 LOG.debug("A qcow2 image was not found. Try to get a uec image.")
442 kernel = self._image_create('scenario-aki', 'aki', aki_img_path)
443 ramdisk = self._image_create('scenario-ari', 'ari', ari_img_path)
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000444 properties = {'kernel_id': kernel, 'ramdisk_id': ramdisk}
Jordan Pittier1e443ec2015-11-20 16:15:58 +0100445 image = self._image_create('scenario-ami', 'ami',
446 path=ami_img_path,
447 properties=properties)
448 LOG.debug("image:%s" % image)
449
450 return image
Andrea Frittoli247058f2014-07-16 16:09:22 +0100451
452 def _log_console_output(self, servers=None):
Matthew Treinish42a3f3a2014-09-04 15:04:53 -0400453 if not CONF.compute_feature_enabled.console_output:
454 LOG.debug('Console output not supported, cannot log')
455 return
Andrea Frittoli247058f2014-07-16 16:09:22 +0100456 if not servers:
David Kranzae99b9a2015-02-16 13:37:01 -0500457 servers = self.servers_client.list_servers()
Andrea Frittoli247058f2014-07-16 16:09:22 +0100458 servers = servers['servers']
459 for server in servers:
Brant Knudson566c5712014-09-24 20:04:50 -0500460 console_output = self.servers_client.get_console_output(
Ken'ichi Ohmichibf4766a2015-12-09 07:48:43 +0000461 server['id'])['output']
David Kranzae99b9a2015-02-16 13:37:01 -0500462 LOG.debug('Console output for %s\nbody=\n%s',
463 server['id'], console_output)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100464
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000465 def _log_net_info(self, exc):
466 # network debug is called as part of ssh init
Andrey Pavlov64723762015-04-29 06:24:58 +0300467 if not isinstance(exc, lib_exc.SSHTimeout):
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000468 LOG.debug('Network information on a devstack host')
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000469
nithya-ganesan882595e2014-07-29 18:51:07 +0000470 def create_server_snapshot(self, server, name=None):
471 # Glance client
472 _image_client = self.image_client
473 # Compute client
Ghanshyamae76c122015-12-22 13:41:35 +0900474 _images_client = self.compute_images_client
nithya-ganesan882595e2014-07-29 18:51:07 +0000475 if name is None:
Ken'ichi Ohmichi6ded8df2015-03-23 02:00:19 +0000476 name = data_utils.rand_name('scenario-snapshot')
nithya-ganesan882595e2014-07-29 18:51:07 +0000477 LOG.debug("Creating a snapshot image for server: %s", server['name'])
Ken'ichi Ohmichi28f18672015-07-17 10:00:38 +0000478 image = _images_client.create_image(server['id'], name=name)
David Kranza5299eb2015-01-15 17:24:05 -0500479 image_id = image.response['location'].split('images/')[1]
nithya-ganesan882595e2014-07-29 18:51:07 +0000480 _image_client.wait_for_image_status(image_id, 'active')
481 self.addCleanup_with_wait(
482 waiter_callable=_image_client.wait_for_resource_deletion,
483 thing_id=image_id, thing_id_param='id',
484 cleanup_callable=self.delete_wrapper,
485 cleanup_args=[_image_client.delete_image, image_id])
David Kranz34f18782015-01-06 13:43:55 -0500486 snapshot_image = _image_client.get_image_meta(image_id)
Andrey Pavlovc8bd4b12015-08-17 10:20:17 +0300487
488 bdm = snapshot_image.get('properties', {}).get('block_device_mapping')
489 if bdm:
490 bdm = json.loads(bdm)
491 if bdm and 'snapshot_id' in bdm[0]:
492 snapshot_id = bdm[0]['snapshot_id']
493 self.addCleanup(
494 self.snapshots_client.wait_for_resource_deletion,
495 snapshot_id)
496 self.addCleanup(
497 self.delete_wrapper, self.snapshots_client.delete_snapshot,
498 snapshot_id)
Andrey Pavlovd35957b2015-08-27 20:12:15 +0300499 self.snapshots_client.wait_for_snapshot_status(snapshot_id,
500 'available')
Andrey Pavlovc8bd4b12015-08-17 10:20:17 +0300501
nithya-ganesan882595e2014-07-29 18:51:07 +0000502 image_name = snapshot_image['name']
503 self.assertEqual(name, image_name)
504 LOG.debug("Created snapshot image %s for server %s",
505 image_name, server['name'])
506 return snapshot_image
507
Jordan Pittier7cf64762015-10-14 15:01:12 +0200508 def nova_volume_attach(self, server, volume_to_attach):
Joseph Lanoux6809bab2014-12-18 14:57:18 +0000509 volume = self.servers_client.attach_volume(
Jordan Pittier7cf64762015-10-14 15:01:12 +0200510 server['id'], volumeId=volume_to_attach['id'], device='/dev/%s'
ghanshyam0f825252015-08-25 16:02:50 +0900511 % CONF.compute.volume_device_name)['volumeAttachment']
Jordan Pittier7cf64762015-10-14 15:01:12 +0200512 self.assertEqual(volume_to_attach['id'], volume['id'])
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900513 self.volumes_client.wait_for_volume_status(volume['id'], 'in-use')
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900514
Jordan Pittier7cf64762015-10-14 15:01:12 +0200515 # Return the updated volume after the attachment
516 return self.volumes_client.show_volume(volume['id'])['volume']
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900517
Jordan Pittier7cf64762015-10-14 15:01:12 +0200518 def nova_volume_detach(self, server, volume):
519 self.servers_client.detach_volume(server['id'], volume['id'])
520 self.volumes_client.wait_for_volume_status(volume['id'], 'available')
521
522 volume = self.volumes_client.show_volume(volume['id'])['volume']
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900523 self.assertEqual('available', volume['status'])
524
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700525 def rebuild_server(self, server_id, image=None,
526 preserve_ephemeral=False, wait=True,
527 rebuild_kwargs=None):
528 if image is None:
529 image = CONF.compute.image_ref
530
531 rebuild_kwargs = rebuild_kwargs or {}
532
533 LOG.debug("Rebuilding server (id: %s, image: %s, preserve eph: %s)",
534 server_id, image, preserve_ephemeral)
Ken'ichi Ohmichi5271b0f2015-08-10 07:53:27 +0000535 self.servers_client.rebuild_server(
536 server_id=server_id, image_ref=image,
537 preserve_ephemeral=preserve_ephemeral,
538 **rebuild_kwargs)
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700539 if wait:
Ken'ichi Ohmichi0eb153c2015-07-13 02:18:25 +0000540 waiters.wait_for_server_status(self.servers_client,
541 server_id, 'ACTIVE')
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700542
Steven Hardyda2a8352014-10-02 12:52:20 +0100543 def ping_ip_address(self, ip_address, should_succeed=True,
544 ping_timeout=None):
lanoux5fc14522015-09-21 08:17:35 +0000545 timeout = ping_timeout or CONF.validation.ping_timeout
Aaron Rosena7df13b2014-09-23 09:45:45 -0700546 cmd = ['ping', '-c1', '-w1', ip_address]
547
548 def ping():
549 proc = subprocess.Popen(cmd,
550 stdout=subprocess.PIPE,
551 stderr=subprocess.PIPE)
552 proc.communicate()
Shuquan Huang753629e2015-07-20 08:52:29 +0000553
Aaron Rosena7df13b2014-09-23 09:45:45 -0700554 return (proc.returncode == 0) == should_succeed
555
Shuquan Huang753629e2015-07-20 08:52:29 +0000556 caller = misc_utils.find_test_caller()
557 LOG.debug('%(caller)s begins to ping %(ip)s in %(timeout)s sec and the'
558 ' expected result is %(should_succeed)s' % {
559 'caller': caller, 'ip': ip_address, 'timeout': timeout,
560 'should_succeed':
561 'reachable' if should_succeed else 'unreachable'
562 })
563 result = tempest.test.call_until_true(ping, timeout, 1)
564 LOG.debug('%(caller)s finishes ping %(ip)s in %(timeout)s sec and the '
565 'ping result is %(result)s' % {
566 'caller': caller, 'ip': ip_address, 'timeout': timeout,
567 'result': 'expected' if result else 'unexpected'
568 })
569 return result
Aaron Rosena7df13b2014-09-23 09:45:45 -0700570
Yair Friedae0e73d2014-11-24 11:56:26 +0200571 def check_vm_connectivity(self, ip_address,
572 username=None,
573 private_key=None,
574 should_connect=True):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000575 """Check server connectivity
576
Yair Friedae0e73d2014-11-24 11:56:26 +0200577 :param ip_address: server to test against
578 :param username: server's ssh username
579 :param private_key: server's ssh private key to be used
580 :param should_connect: True/False indicates positive/negative test
581 positive - attempt ping and ssh
582 negative - attempt ping and fail if succeed
583
584 :raises: AssertError if the result of the connectivity check does
585 not match the value of the should_connect param
586 """
587 if should_connect:
588 msg = "Timed out waiting for %s to become reachable" % ip_address
589 else:
590 msg = "ip address %s is reachable" % ip_address
591 self.assertTrue(self.ping_ip_address(ip_address,
592 should_succeed=should_connect),
593 msg=msg)
594 if should_connect:
595 # no need to check ssh for negative connectivity
596 self.get_remote_client(ip_address, username, private_key)
597
598 def check_public_network_connectivity(self, ip_address, username,
599 private_key, should_connect=True,
600 msg=None, servers=None):
601 # The target login is assumed to have been configured for
602 # key-based authentication by cloud-init.
603 LOG.debug('checking network connections to IP %s with user: %s' %
604 (ip_address, username))
605 try:
606 self.check_vm_connectivity(ip_address,
607 username,
608 private_key,
609 should_connect=should_connect)
Matthew Treinish53483132014-12-09 18:50:06 -0500610 except Exception:
Yair Friedae0e73d2014-11-24 11:56:26 +0200611 ex_msg = 'Public network connectivity check failed'
612 if msg:
613 ex_msg += ": " + msg
614 LOG.exception(ex_msg)
615 self._log_console_output(servers)
Yair Friedae0e73d2014-11-24 11:56:26 +0200616 raise
617
618 def create_floating_ip(self, thing, pool_name=None):
Ken'ichi Ohmichia112a592015-11-17 08:49:37 +0000619 """Create a floating IP and associates to a server on Nova"""
Yair Friedae0e73d2014-11-24 11:56:26 +0200620
John Warrene74890a2015-11-11 15:18:01 -0500621 floating_ip = (self.compute_floating_ips_client.
Ken'ichi Ohmichie037a6f2015-12-03 06:41:49 +0000622 create_floating_ip(pool=pool_name)['floating_ip'])
Yair Friedae0e73d2014-11-24 11:56:26 +0200623 self.addCleanup(self.delete_wrapper,
John Warrene74890a2015-11-11 15:18:01 -0500624 self.compute_floating_ips_client.delete_floating_ip,
Yair Friedae0e73d2014-11-24 11:56:26 +0200625 floating_ip['id'])
John Warrene74890a2015-11-11 15:18:01 -0500626 self.compute_floating_ips_client.associate_floating_ip_to_server(
Yair Friedae0e73d2014-11-24 11:56:26 +0200627 floating_ip['ip'], thing['id'])
628 return floating_ip
629
Matt Riedemannfd5657d2015-09-30 14:47:07 -0700630 def create_timestamp(self, server_or_ip, dev_name=None, mount_path='/mnt',
631 private_key=None):
632 ssh_client = self.get_remote_client(server_or_ip,
633 private_key=private_key)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300634 if dev_name is not None:
635 ssh_client.make_fs(dev_name)
Matt Riedemann076685a2015-09-30 14:38:16 -0700636 ssh_client.mount(dev_name, mount_path)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300637 cmd_timestamp = 'sudo sh -c "date > %s/timestamp; sync"' % mount_path
638 ssh_client.exec_command(cmd_timestamp)
639 timestamp = ssh_client.exec_command('sudo cat %s/timestamp'
640 % mount_path)
641 if dev_name is not None:
642 ssh_client.umount(mount_path)
643 return timestamp
644
Matt Riedemannfd5657d2015-09-30 14:47:07 -0700645 def get_timestamp(self, server_or_ip, dev_name=None, mount_path='/mnt',
646 private_key=None):
647 ssh_client = self.get_remote_client(server_or_ip,
648 private_key=private_key)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300649 if dev_name is not None:
Matt Riedemann076685a2015-09-30 14:38:16 -0700650 ssh_client.mount(dev_name, mount_path)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300651 timestamp = ssh_client.exec_command('sudo cat %s/timestamp'
652 % mount_path)
653 if dev_name is not None:
654 ssh_client.umount(mount_path)
655 return timestamp
656
Alexander Gubanovc8829f82015-11-12 10:35:13 +0200657 def get_server_or_ip(self, server):
658 if CONF.validation.connect_method == 'floating':
659 ip = self.create_floating_ip(server)['ip']
660 else:
661 ip = server
662 return ip
663
Andrea Frittoli2e733b52014-07-16 14:12:11 +0100664
Andrea Frittoli4971fc82014-09-25 10:22:20 +0100665class NetworkScenarioTest(ScenarioTest):
Yair Fried1fc32a12014-08-04 09:11:30 +0300666 """Base class for network scenario tests.
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000667
Yair Fried1fc32a12014-08-04 09:11:30 +0300668 This class provide helpers for network scenario tests, using the neutron
669 API. Helpers from ancestor which use the nova network API are overridden
670 with the neutron API.
671
672 This Class also enforces using Neutron instead of novanetwork.
673 Subclassed tests will be skipped if Neutron is not enabled
674
675 """
676
Andrea Frittolib21de6c2015-02-06 20:12:38 +0000677 credentials = ['primary', 'admin']
678
Yair Fried1fc32a12014-08-04 09:11:30 +0300679 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +0000680 def skip_checks(cls):
681 super(NetworkScenarioTest, cls).skip_checks()
Andrea Frittoli2ddc2632014-09-25 11:03:00 +0100682 if not CONF.service_available.neutron:
683 raise cls.skipException('Neutron not available')
Yair Fried1fc32a12014-08-04 09:11:30 +0300684
685 @classmethod
Andrea Frittoliac20b5e2014-09-15 13:31:14 +0100686 def resource_setup(cls):
687 super(NetworkScenarioTest, cls).resource_setup()
Yair Fried1fc32a12014-08-04 09:11:30 +0300688 cls.tenant_id = cls.manager.identity_client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300689
John Warren94d8faf2015-09-15 12:22:24 -0400690 def _create_network(self, client=None, networks_client=None,
691 tenant_id=None, namestart='network-smoke-'):
Yair Frieddb6c9e92014-08-06 08:53:13 +0300692 if not client:
693 client = self.network_client
John Warren94d8faf2015-09-15 12:22:24 -0400694 if not networks_client:
695 networks_client = self.networks_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300696 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000697 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300698 name = data_utils.rand_name(namestart)
John Warren94d8faf2015-09-15 12:22:24 -0400699 result = networks_client.create_network(name=name, tenant_id=tenant_id)
700 network = net_resources.DeletableNetwork(
701 networks_client=networks_client, **result['network'])
Yair Fried1fc32a12014-08-04 09:11:30 +0300702 self.assertEqual(network.name, name)
703 self.addCleanup(self.delete_wrapper, network.delete)
704 return network
705
706 def _list_networks(self, *args, **kwargs):
707 """List networks using admin creds """
John Warren94d8faf2015-09-15 12:22:24 -0400708 networks_list = self.admin_manager.networks_client.list_networks(
ghanshyam2f7cc022015-06-26 18:18:11 +0900709 *args, **kwargs)
710 return networks_list['networks']
Yair Fried1fc32a12014-08-04 09:11:30 +0300711
712 def _list_subnets(self, *args, **kwargs):
713 """List subnets using admin creds """
John Warren3961acd2015-10-02 14:38:53 -0400714 subnets_list = self.admin_manager.subnets_client.list_subnets(
ghanshyam2f7cc022015-06-26 18:18:11 +0900715 *args, **kwargs)
716 return subnets_list['subnets']
Yair Fried1fc32a12014-08-04 09:11:30 +0300717
718 def _list_routers(self, *args, **kwargs):
719 """List routers using admin creds """
ghanshyam2f7cc022015-06-26 18:18:11 +0900720 routers_list = self.admin_manager.network_client.list_routers(
721 *args, **kwargs)
722 return routers_list['routers']
Yair Fried1fc32a12014-08-04 09:11:30 +0300723
724 def _list_ports(self, *args, **kwargs):
725 """List ports using admin creds """
John Warren49c0fe52015-10-22 12:35:54 -0400726 ports_list = self.admin_manager.ports_client.list_ports(
ghanshyam2f7cc022015-06-26 18:18:11 +0900727 *args, **kwargs)
728 return ports_list['ports']
Yair Fried1fc32a12014-08-04 09:11:30 +0300729
Yair Fried564d89d2015-08-06 17:02:12 +0300730 def _list_agents(self, *args, **kwargs):
731 """List agents using admin creds """
Ken'ichi Ohmichi71860062015-12-15 08:20:13 +0000732 agents_list = self.admin_manager.network_agents_client.list_agents(
Yair Fried564d89d2015-08-06 17:02:12 +0300733 *args, **kwargs)
734 return agents_list['agents']
735
John Warren3961acd2015-10-02 14:38:53 -0400736 def _create_subnet(self, network, client=None, subnets_client=None,
737 namestart='subnet-smoke', **kwargs):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000738 """Create a subnet for the given network
739
740 within the cidr block configured for tenant networks.
Yair Fried1fc32a12014-08-04 09:11:30 +0300741 """
Yair Frieddb6c9e92014-08-06 08:53:13 +0300742 if not client:
743 client = self.network_client
John Warren3961acd2015-10-02 14:38:53 -0400744 if not subnets_client:
745 subnets_client = self.subnets_client
Yair Fried1fc32a12014-08-04 09:11:30 +0300746
747 def cidr_in_use(cidr, tenant_id):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000748 """Check cidr existence
749
lei zhangdd552b22015-11-25 20:41:48 +0800750 :returns: True if subnet with cidr already exist in tenant
751 False else
Yair Fried1fc32a12014-08-04 09:11:30 +0300752 """
753 cidr_in_use = self._list_subnets(tenant_id=tenant_id, cidr=cidr)
754 return len(cidr_in_use) != 0
755
Kirill Shileev14113572014-11-21 16:58:02 +0300756 ip_version = kwargs.pop('ip_version', 4)
757
758 if ip_version == 6:
759 tenant_cidr = netaddr.IPNetwork(
760 CONF.network.tenant_network_v6_cidr)
761 num_bits = CONF.network.tenant_network_v6_mask_bits
762 else:
763 tenant_cidr = netaddr.IPNetwork(CONF.network.tenant_network_cidr)
764 num_bits = CONF.network.tenant_network_mask_bits
765
Yair Fried1fc32a12014-08-04 09:11:30 +0300766 result = None
Kirill Shileev14113572014-11-21 16:58:02 +0300767 str_cidr = None
Yair Fried1fc32a12014-08-04 09:11:30 +0300768 # Repeatedly attempt subnet creation with sequential cidr
769 # blocks until an unallocated block is found.
Kirill Shileev14113572014-11-21 16:58:02 +0300770 for subnet_cidr in tenant_cidr.subnet(num_bits):
Yair Fried1fc32a12014-08-04 09:11:30 +0300771 str_cidr = str(subnet_cidr)
772 if cidr_in_use(str_cidr, tenant_id=network.tenant_id):
773 continue
774
775 subnet = dict(
776 name=data_utils.rand_name(namestart),
Yair Fried1fc32a12014-08-04 09:11:30 +0300777 network_id=network.id,
778 tenant_id=network.tenant_id,
779 cidr=str_cidr,
Kirill Shileev14113572014-11-21 16:58:02 +0300780 ip_version=ip_version,
Yair Fried1fc32a12014-08-04 09:11:30 +0300781 **kwargs
782 )
783 try:
John Warren3961acd2015-10-02 14:38:53 -0400784 result = subnets_client.create_subnet(**subnet)
Yair Fried1fc32a12014-08-04 09:11:30 +0300785 break
Masayuki Igawad9388762015-01-20 14:56:42 +0900786 except lib_exc.Conflict as e:
Yair Fried1fc32a12014-08-04 09:11:30 +0300787 is_overlapping_cidr = 'overlaps with another subnet' in str(e)
788 if not is_overlapping_cidr:
789 raise
790 self.assertIsNotNone(result, 'Unable to allocate tenant network')
John Warren3961acd2015-10-02 14:38:53 -0400791 subnet = net_resources.DeletableSubnet(
792 network_client=client, subnets_client=subnets_client,
793 **result['subnet'])
Yair Fried1fc32a12014-08-04 09:11:30 +0300794 self.assertEqual(subnet.cidr, str_cidr)
795 self.addCleanup(self.delete_wrapper, subnet.delete)
796 return subnet
797
Itzik Brown2ca01cd2014-12-08 12:58:20 +0200798 def _create_port(self, network_id, client=None, namestart='port-quotatest',
799 **kwargs):
Yair Frieddb6c9e92014-08-06 08:53:13 +0300800 if not client:
John Warren49c0fe52015-10-22 12:35:54 -0400801 client = self.ports_client
Yair Fried1fc32a12014-08-04 09:11:30 +0300802 name = data_utils.rand_name(namestart)
David Kranz34e88122014-12-11 15:24:05 -0500803 result = client.create_port(
Yair Fried1fc32a12014-08-04 09:11:30 +0300804 name=name,
Itzik Brown2ca01cd2014-12-08 12:58:20 +0200805 network_id=network_id,
806 **kwargs)
Yair Fried1fc32a12014-08-04 09:11:30 +0300807 self.assertIsNotNone(result, 'Unable to allocate port')
John Warren49c0fe52015-10-22 12:35:54 -0400808 port = net_resources.DeletablePort(ports_client=client,
Yair Fried1fc32a12014-08-04 09:11:30 +0300809 **result['port'])
810 self.addCleanup(self.delete_wrapper, port.delete)
811 return port
812
Kirill Shileev14113572014-11-21 16:58:02 +0300813 def _get_server_port_id_and_ip4(self, server, ip_addr=None):
Ken'ichi Ohmichi30b769e2015-10-14 09:47:22 +0000814 ports = self._list_ports(device_id=server['id'], status='ACTIVE',
Yair Fried1fc32a12014-08-04 09:11:30 +0300815 fixed_ip=ip_addr)
Sean M. Collins2e896832015-12-15 13:58:47 -0500816 # A port can have more then one IP address in some cases.
817 # If the network is dual-stack (IPv4 + IPv6), this port is associated
818 # with 2 subnets
Daniel Mellado9e3e1062015-08-06 18:07:05 +0200819 port_map = [(p["id"], fxip["ip_address"])
820 for p in ports
821 for fxip in p["fixed_ips"]
822 if netaddr.valid_ipv4(fxip["ip_address"])]
823
John L. Villalovosb83286f2015-11-04 14:46:57 -0800824 self.assertNotEqual(0, len(port_map),
825 "No IPv4 addresses found in: %s" % ports)
Daniel Mellado9e3e1062015-08-06 18:07:05 +0200826 self.assertEqual(len(port_map), 1,
827 "Found multiple IPv4 addresses: %s. "
828 "Unable to determine which port to target."
829 % port_map)
830 return port_map[0]
Yair Fried1fc32a12014-08-04 09:11:30 +0300831
David Shrewsbury9bac3662014-08-07 15:07:01 -0400832 def _get_network_by_name(self, network_name):
833 net = self._list_networks(name=network_name)
Adam Gandelman878a5fd2015-03-30 14:33:36 -0700834 self.assertNotEqual(len(net), 0,
835 "Unable to get network by name: %s" % network_name)
Yair Fried8186f812014-09-28 09:39:39 +0300836 return net_resources.AttributeDict(net[0])
David Shrewsbury9bac3662014-08-07 15:07:01 -0400837
Yair Friedae0e73d2014-11-24 11:56:26 +0200838 def create_floating_ip(self, thing, external_network_id=None,
839 port_id=None, client=None):
Ken'ichi Ohmichia112a592015-11-17 08:49:37 +0000840 """Create a floating IP and associates to a resource/port on Neutron"""
Yair Friedae0e73d2014-11-24 11:56:26 +0200841 if not external_network_id:
842 external_network_id = CONF.network.public_network_id
Yair Frieddb6c9e92014-08-06 08:53:13 +0300843 if not client:
John Warrenfbf2a892015-11-17 12:36:14 -0500844 client = self.floating_ips_client
Yair Fried1fc32a12014-08-04 09:11:30 +0300845 if not port_id:
Kirill Shileev14113572014-11-21 16:58:02 +0300846 port_id, ip4 = self._get_server_port_id_and_ip4(thing)
847 else:
848 ip4 = None
David Kranz34e88122014-12-11 15:24:05 -0500849 result = client.create_floatingip(
Yair Fried1fc32a12014-08-04 09:11:30 +0300850 floating_network_id=external_network_id,
851 port_id=port_id,
Kirill Shileev14113572014-11-21 16:58:02 +0300852 tenant_id=thing['tenant_id'],
853 fixed_ip_address=ip4
Yair Fried1fc32a12014-08-04 09:11:30 +0300854 )
855 floating_ip = net_resources.DeletableFloatingIp(
Yair Frieddb6c9e92014-08-06 08:53:13 +0300856 client=client,
Yair Fried1fc32a12014-08-04 09:11:30 +0300857 **result['floatingip'])
858 self.addCleanup(self.delete_wrapper, floating_ip.delete)
859 return floating_ip
860
861 def _associate_floating_ip(self, floating_ip, server):
Kirill Shileev14113572014-11-21 16:58:02 +0300862 port_id, _ = self._get_server_port_id_and_ip4(server)
Yair Fried1fc32a12014-08-04 09:11:30 +0300863 floating_ip.update(port_id=port_id)
864 self.assertEqual(port_id, floating_ip.port_id)
865 return floating_ip
866
867 def _disassociate_floating_ip(self, floating_ip):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000868 """:param floating_ip: type DeletableFloatingIp"""
Yair Fried1fc32a12014-08-04 09:11:30 +0300869 floating_ip.update(port_id=None)
870 self.assertIsNone(floating_ip.port_id)
871 return floating_ip
872
Yair Fried45f92952014-06-26 05:19:19 +0300873 def check_floating_ip_status(self, floating_ip, status):
Carl Baldwina754e2d2014-10-23 22:47:41 +0000874 """Verifies floatingip reaches the given status
Yair Fried45f92952014-06-26 05:19:19 +0300875
876 :param floating_ip: net_resources.DeletableFloatingIp floating IP to
877 to check status
878 :param status: target status
879 :raises: AssertionError if status doesn't match
880 """
Carl Baldwina754e2d2014-10-23 22:47:41 +0000881 def refresh():
882 floating_ip.refresh()
883 return status == floating_ip.status
884
885 tempest.test.call_until_true(refresh,
886 CONF.network.build_timeout,
887 CONF.network.build_interval)
Yair Fried45f92952014-06-26 05:19:19 +0300888 self.assertEqual(status, floating_ip.status,
889 message="FloatingIP: {fp} is at status: {cst}. "
890 "failed to reach status: {st}"
891 .format(fp=floating_ip, cst=floating_ip.status,
892 st=status))
893 LOG.info("FloatingIP: {fp} is at status: {st}"
894 .format(fp=floating_ip, st=status))
895
Yair Fried1fc32a12014-08-04 09:11:30 +0300896 def _check_tenant_network_connectivity(self, server,
897 username,
898 private_key,
899 should_connect=True,
900 servers_for_debug=None):
901 if not CONF.network.tenant_networks_reachable:
902 msg = 'Tenant networks not configured to be reachable.'
903 LOG.info(msg)
904 return
905 # The target login is assumed to have been configured for
906 # key-based authentication by cloud-init.
907 try:
Matthew Treinish71426682015-04-23 11:19:38 -0400908 for net_name, ip_addresses in six.iteritems(server['addresses']):
Yair Fried1fc32a12014-08-04 09:11:30 +0300909 for ip_address in ip_addresses:
ghanshyam807211c2014-12-18 13:21:22 +0900910 self.check_vm_connectivity(ip_address['addr'],
Yair Friedae0e73d2014-11-24 11:56:26 +0200911 username,
912 private_key,
913 should_connect=should_connect)
Yair Fried1fc32a12014-08-04 09:11:30 +0300914 except Exception as e:
915 LOG.exception('Tenant network connectivity check failed')
916 self._log_console_output(servers_for_debug)
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000917 self._log_net_info(e)
Yair Fried1fc32a12014-08-04 09:11:30 +0300918 raise
919
Yair Friedbc46f592015-11-18 16:29:34 +0200920 def _check_remote_connectivity(self, source, dest, should_succeed=True,
921 nic=None):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000922 """check ping server via source ssh connection
Yair Fried1fc32a12014-08-04 09:11:30 +0300923
924 :param source: RemoteClient: an ssh connection from which to ping
925 :param dest: and IP to ping against
926 :param should_succeed: boolean should ping succeed or not
Yair Friedbc46f592015-11-18 16:29:34 +0200927 :param nic: specific network interface to ping from
Yair Fried1fc32a12014-08-04 09:11:30 +0300928 :returns: boolean -- should_succeed == ping
929 :returns: ping is false if ping failed
930 """
931 def ping_remote():
932 try:
Yair Friedbc46f592015-11-18 16:29:34 +0200933 source.ping_host(dest, nic=nic)
Andrey Pavlov64723762015-04-29 06:24:58 +0300934 except lib_exc.SSHExecCommandFailed:
zhangguoqing6c096642016-01-04 06:17:21 +0000935 LOG.warning('Failed to ping IP: %s via a ssh connection '
936 'from: %s.' % (dest, source.ssh_client.host))
Yair Fried1fc32a12014-08-04 09:11:30 +0300937 return not should_succeed
938 return should_succeed
939
940 return tempest.test.call_until_true(ping_remote,
lanoux5fc14522015-09-21 08:17:35 +0000941 CONF.validation.ping_timeout,
Yair Fried1fc32a12014-08-04 09:11:30 +0300942 1)
943
John Warren456d9ae2016-01-12 15:36:33 -0500944 def _create_security_group(self, security_group_rules_client=None,
945 tenant_id=None,
John Warrenf9606e92015-12-10 12:12:42 -0500946 namestart='secgroup-smoke',
947 security_groups_client=None):
John Warren456d9ae2016-01-12 15:36:33 -0500948 if security_group_rules_client is None:
949 security_group_rules_client = self.security_group_rules_client
John Warrenf9606e92015-12-10 12:12:42 -0500950 if security_groups_client is None:
951 security_groups_client = self.security_groups_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300952 if tenant_id is None:
John Warrenf9606e92015-12-10 12:12:42 -0500953 tenant_id = security_groups_client.tenant_id
954 secgroup = self._create_empty_security_group(
955 namestart=namestart, client=security_groups_client,
956 tenant_id=tenant_id)
Yair Fried1fc32a12014-08-04 09:11:30 +0300957
958 # Add rules to the security group
John Warrenf9606e92015-12-10 12:12:42 -0500959 rules = self._create_loginable_secgroup_rule(
John Warren456d9ae2016-01-12 15:36:33 -0500960 security_group_rules_client=security_group_rules_client,
961 secgroup=secgroup,
John Warrenf9606e92015-12-10 12:12:42 -0500962 security_groups_client=security_groups_client)
Yair Fried1fc32a12014-08-04 09:11:30 +0300963 for rule in rules:
964 self.assertEqual(tenant_id, rule.tenant_id)
965 self.assertEqual(secgroup.id, rule.security_group_id)
966 return secgroup
967
Yair Frieddb6c9e92014-08-06 08:53:13 +0300968 def _create_empty_security_group(self, client=None, tenant_id=None,
Yair Fried1fc32a12014-08-04 09:11:30 +0300969 namestart='secgroup-smoke'):
970 """Create a security group without rules.
971
972 Default rules will be created:
973 - IPv4 egress to any
974 - IPv6 egress to any
975
976 :param tenant_id: secgroup will be created in this tenant
977 :returns: DeletableSecurityGroup -- containing the secgroup created
978 """
979 if client is None:
John Warrenf9606e92015-12-10 12:12:42 -0500980 client = self.security_groups_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300981 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000982 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300983 sg_name = data_utils.rand_name(namestart)
984 sg_desc = sg_name + " description"
985 sg_dict = dict(name=sg_name,
986 description=sg_desc)
987 sg_dict['tenant_id'] = tenant_id
David Kranz34e88122014-12-11 15:24:05 -0500988 result = client.create_security_group(**sg_dict)
Yair Fried1fc32a12014-08-04 09:11:30 +0300989 secgroup = net_resources.DeletableSecurityGroup(
990 client=client,
991 **result['security_group']
992 )
993 self.assertEqual(secgroup.name, sg_name)
994 self.assertEqual(tenant_id, secgroup.tenant_id)
995 self.assertEqual(secgroup.description, sg_desc)
996 self.addCleanup(self.delete_wrapper, secgroup.delete)
997 return secgroup
998
Yair Frieddb6c9e92014-08-06 08:53:13 +0300999 def _default_security_group(self, client=None, tenant_id=None):
Yair Fried1fc32a12014-08-04 09:11:30 +03001000 """Get default secgroup for given tenant_id.
1001
1002 :returns: DeletableSecurityGroup -- default secgroup for given tenant
1003 """
1004 if client is None:
John Warrenf9606e92015-12-10 12:12:42 -05001005 client = self.security_groups_client
Yair Frieddb6c9e92014-08-06 08:53:13 +03001006 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +00001007 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001008 sgs = [
1009 sg for sg in client.list_security_groups().values()[0]
1010 if sg['tenant_id'] == tenant_id and sg['name'] == 'default'
1011 ]
1012 msg = "No default security group for tenant %s." % (tenant_id)
1013 self.assertTrue(len(sgs) > 0, msg)
Yair Fried1fc32a12014-08-04 09:11:30 +03001014 return net_resources.DeletableSecurityGroup(client=client,
1015 **sgs[0])
1016
John Warren456d9ae2016-01-12 15:36:33 -05001017 def _create_security_group_rule(self, secgroup=None,
1018 sec_group_rules_client=None,
John Warrenf9606e92015-12-10 12:12:42 -05001019 tenant_id=None,
1020 security_groups_client=None, **kwargs):
Yair Fried1fc32a12014-08-04 09:11:30 +03001021 """Create a rule from a dictionary of rule parameters.
1022
1023 Create a rule in a secgroup. if secgroup not defined will search for
1024 default secgroup in tenant_id.
1025
1026 :param secgroup: type DeletableSecurityGroup.
Yair Fried1fc32a12014-08-04 09:11:30 +03001027 :param tenant_id: if secgroup not passed -- the tenant in which to
1028 search for default secgroup
1029 :param kwargs: a dictionary containing rule parameters:
1030 for example, to allow incoming ssh:
1031 rule = {
1032 direction: 'ingress'
1033 protocol:'tcp',
1034 port_range_min: 22,
1035 port_range_max: 22
1036 }
1037 """
John Warren456d9ae2016-01-12 15:36:33 -05001038 if sec_group_rules_client is None:
1039 sec_group_rules_client = self.security_group_rules_client
John Warrenf9606e92015-12-10 12:12:42 -05001040 if security_groups_client is None:
1041 security_groups_client = self.security_groups_client
Yair Frieddb6c9e92014-08-06 08:53:13 +03001042 if not tenant_id:
John Warrenf9606e92015-12-10 12:12:42 -05001043 tenant_id = security_groups_client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001044 if secgroup is None:
John Warrenf9606e92015-12-10 12:12:42 -05001045 secgroup = self._default_security_group(
1046 client=security_groups_client, tenant_id=tenant_id)
Yair Fried1fc32a12014-08-04 09:11:30 +03001047
1048 ruleset = dict(security_group_id=secgroup.id,
1049 tenant_id=secgroup.tenant_id)
1050 ruleset.update(kwargs)
1051
John Warren456d9ae2016-01-12 15:36:33 -05001052 sg_rule = sec_group_rules_client.create_security_group_rule(**ruleset)
Yair Fried1fc32a12014-08-04 09:11:30 +03001053 sg_rule = net_resources.DeletableSecurityGroupRule(
John Warren456d9ae2016-01-12 15:36:33 -05001054 client=sec_group_rules_client,
Yair Fried1fc32a12014-08-04 09:11:30 +03001055 **sg_rule['security_group_rule']
1056 )
1057 self.addCleanup(self.delete_wrapper, sg_rule.delete)
1058 self.assertEqual(secgroup.tenant_id, sg_rule.tenant_id)
1059 self.assertEqual(secgroup.id, sg_rule.security_group_id)
1060
1061 return sg_rule
1062
John Warren456d9ae2016-01-12 15:36:33 -05001063 def _create_loginable_secgroup_rule(self, security_group_rules_client=None,
1064 secgroup=None,
John Warrenf9606e92015-12-10 12:12:42 -05001065 security_groups_client=None):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001066 """Create loginable security group rule
1067
1068 These rules are intended to permit inbound ssh and icmp
Yair Fried1fc32a12014-08-04 09:11:30 +03001069 traffic from all sources, so no group_id is provided.
1070 Setting a group_id would only permit traffic from ports
1071 belonging to the same security group.
1072 """
1073
John Warren456d9ae2016-01-12 15:36:33 -05001074 if security_group_rules_client is None:
1075 security_group_rules_client = self.security_group_rules_client
John Warrenf9606e92015-12-10 12:12:42 -05001076 if security_groups_client is None:
1077 security_groups_client = self.security_groups_client
Yair Fried1fc32a12014-08-04 09:11:30 +03001078 rules = []
1079 rulesets = [
1080 dict(
1081 # ssh
1082 protocol='tcp',
1083 port_range_min=22,
1084 port_range_max=22,
1085 ),
1086 dict(
1087 # ping
1088 protocol='icmp',
Andreas Scheuring887ca8e2015-02-03 17:56:12 +01001089 ),
1090 dict(
1091 # ipv6-icmp for ping6
1092 protocol='icmp',
1093 ethertype='IPv6',
Yair Fried1fc32a12014-08-04 09:11:30 +03001094 )
1095 ]
John Warren456d9ae2016-01-12 15:36:33 -05001096 sec_group_rules_client = security_group_rules_client
Yair Fried1fc32a12014-08-04 09:11:30 +03001097 for ruleset in rulesets:
1098 for r_direction in ['ingress', 'egress']:
1099 ruleset['direction'] = r_direction
1100 try:
1101 sg_rule = self._create_security_group_rule(
John Warren456d9ae2016-01-12 15:36:33 -05001102 sec_group_rules_client=sec_group_rules_client,
1103 secgroup=secgroup,
John Warrenf9606e92015-12-10 12:12:42 -05001104 security_groups_client=security_groups_client,
1105 **ruleset)
Masayuki Igawad9388762015-01-20 14:56:42 +09001106 except lib_exc.Conflict as ex:
Yair Fried1fc32a12014-08-04 09:11:30 +03001107 # if rule already exist - skip rule and continue
1108 msg = 'Security group rule already exists'
1109 if msg not in ex._error_string:
1110 raise ex
1111 else:
1112 self.assertEqual(r_direction, sg_rule.direction)
1113 rules.append(sg_rule)
1114
1115 return rules
1116
1117 def _ssh_to_server(self, server, private_key):
lanoux283273b2015-12-04 03:01:54 -08001118 ssh_login = CONF.validation.image_ssh_user
Yair Fried1fc32a12014-08-04 09:11:30 +03001119 return self.get_remote_client(server,
1120 username=ssh_login,
1121 private_key=private_key)
1122
Yair Frieddb6c9e92014-08-06 08:53:13 +03001123 def _get_router(self, client=None, tenant_id=None):
Yair Fried1fc32a12014-08-04 09:11:30 +03001124 """Retrieve a router for the given tenant id.
1125
1126 If a public router has been configured, it will be returned.
1127
1128 If a public router has not been configured, but a public
1129 network has, a tenant router will be created and returned that
1130 routes traffic to the public network.
1131 """
Yair Frieddb6c9e92014-08-06 08:53:13 +03001132 if not client:
1133 client = self.network_client
1134 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +00001135 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001136 router_id = CONF.network.public_router_id
1137 network_id = CONF.network.public_network_id
1138 if router_id:
David Kranzca4c7e72015-05-27 11:39:19 -04001139 body = client.show_router(router_id)
Sergey Shnaidman5e9c8fd2014-09-30 18:31:43 +04001140 return net_resources.AttributeDict(**body['router'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001141 elif network_id:
Yair Frieddb6c9e92014-08-06 08:53:13 +03001142 router = self._create_router(client, tenant_id)
Yair Fried1fc32a12014-08-04 09:11:30 +03001143 router.set_gateway(network_id)
1144 return router
1145 else:
1146 raise Exception("Neither of 'public_router_id' or "
1147 "'public_network_id' has been defined.")
1148
Yair Frieddb6c9e92014-08-06 08:53:13 +03001149 def _create_router(self, client=None, tenant_id=None,
1150 namestart='router-smoke'):
1151 if not client:
1152 client = self.network_client
1153 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +00001154 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001155 name = data_utils.rand_name(namestart)
David Kranz34e88122014-12-11 15:24:05 -05001156 result = client.create_router(name=name,
1157 admin_state_up=True,
1158 tenant_id=tenant_id)
Yair Frieddb6c9e92014-08-06 08:53:13 +03001159 router = net_resources.DeletableRouter(client=client,
Yair Fried1fc32a12014-08-04 09:11:30 +03001160 **result['router'])
1161 self.assertEqual(router.name, name)
1162 self.addCleanup(self.delete_wrapper, router.delete)
1163 return router
1164
Alok Maurya6384bbb2014-07-13 06:44:29 -07001165 def _update_router_admin_state(self, router, admin_state_up):
1166 router.update(admin_state_up=admin_state_up)
1167 self.assertEqual(admin_state_up, router.admin_state_up)
1168
John Warren94d8faf2015-09-15 12:22:24 -04001169 def create_networks(self, client=None, networks_client=None,
John Warren3961acd2015-10-02 14:38:53 -04001170 subnets_client=None, tenant_id=None,
1171 dns_nameservers=None):
Yair Fried1fc32a12014-08-04 09:11:30 +03001172 """Create a network with a subnet connected to a router.
1173
David Shrewsbury9bac3662014-08-07 15:07:01 -04001174 The baremetal driver is a special case since all nodes are
1175 on the same shared network.
1176
Yair Fried413bf2d2014-11-19 17:07:11 +02001177 :param client: network client to create resources with.
1178 :param tenant_id: id of tenant to create resources in.
1179 :param dns_nameservers: list of dns servers to send to subnet.
Yair Fried1fc32a12014-08-04 09:11:30 +03001180 :returns: network, subnet, router
1181 """
David Shrewsbury9bac3662014-08-07 15:07:01 -04001182 if CONF.baremetal.driver_enabled:
1183 # NOTE(Shrews): This exception is for environments where tenant
1184 # credential isolation is available, but network separation is
1185 # not (the current baremetal case). Likely can be removed when
1186 # test account mgmt is reworked:
1187 # https://blueprints.launchpad.net/tempest/+spec/test-accounts
Adam Gandelman878a5fd2015-03-30 14:33:36 -07001188 if not CONF.compute.fixed_network_name:
1189 m = 'fixed_network_name must be specified in config'
1190 raise exceptions.InvalidConfiguration(m)
David Shrewsbury9bac3662014-08-07 15:07:01 -04001191 network = self._get_network_by_name(
1192 CONF.compute.fixed_network_name)
1193 router = None
1194 subnet = None
1195 else:
John Warren94d8faf2015-09-15 12:22:24 -04001196 network = self._create_network(
1197 client=client, networks_client=networks_client,
1198 tenant_id=tenant_id)
Yair Frieddb6c9e92014-08-06 08:53:13 +03001199 router = self._get_router(client=client, tenant_id=tenant_id)
Yair Fried413bf2d2014-11-19 17:07:11 +02001200
John Warren3961acd2015-10-02 14:38:53 -04001201 subnet_kwargs = dict(network=network, client=client,
1202 subnets_client=subnets_client)
Yair Fried413bf2d2014-11-19 17:07:11 +02001203 # use explicit check because empty list is a valid option
1204 if dns_nameservers is not None:
1205 subnet_kwargs['dns_nameservers'] = dns_nameservers
1206 subnet = self._create_subnet(**subnet_kwargs)
David Shrewsbury9bac3662014-08-07 15:07:01 -04001207 subnet.add_to_router(router.id)
Yair Fried1fc32a12014-08-04 09:11:30 +03001208 return network, subnet, router
1209
1210
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001211# power/provision states as of icehouse
1212class BaremetalPowerStates(object):
1213 """Possible power states of an Ironic node."""
1214 POWER_ON = 'power on'
1215 POWER_OFF = 'power off'
1216 REBOOT = 'rebooting'
1217 SUSPEND = 'suspended'
1218
1219
1220class BaremetalProvisionStates(object):
1221 """Possible provision states of an Ironic node."""
1222 NOSTATE = None
1223 INIT = 'initializing'
1224 ACTIVE = 'active'
1225 BUILDING = 'building'
1226 DEPLOYWAIT = 'wait call-back'
1227 DEPLOYING = 'deploying'
1228 DEPLOYFAIL = 'deploy failed'
1229 DEPLOYDONE = 'deploy complete'
1230 DELETING = 'deleting'
1231 DELETED = 'deleted'
1232 ERROR = 'error'
1233
1234
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001235class BaremetalScenarioTest(ScenarioTest):
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001236
1237 credentials = ['primary', 'admin']
1238
Adam Gandelman4a48a602014-03-20 18:23:18 -07001239 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001240 def skip_checks(cls):
1241 super(BaremetalScenarioTest, cls).skip_checks()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001242 if (not CONF.service_available.ironic or
1243 not CONF.baremetal.driver_enabled):
1244 msg = 'Ironic not available or Ironic compute driver not enabled'
1245 raise cls.skipException(msg)
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001246
1247 @classmethod
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001248 def setup_clients(cls):
1249 super(BaremetalScenarioTest, cls).setup_clients()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001250
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001251 cls.baremetal_client = cls.admin_manager.baremetal_client
Adam Gandelman4a48a602014-03-20 18:23:18 -07001252
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001253 @classmethod
1254 def resource_setup(cls):
1255 super(BaremetalScenarioTest, cls).resource_setup()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001256 # allow any issues obtaining the node list to raise early
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001257 cls.baremetal_client.list_nodes()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001258
1259 def _node_state_timeout(self, node_id, state_attr,
1260 target_states, timeout=10, interval=1):
1261 if not isinstance(target_states, list):
1262 target_states = [target_states]
1263
1264 def check_state():
1265 node = self.get_node(node_id=node_id)
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001266 if node.get(state_attr) in target_states:
Adam Gandelman4a48a602014-03-20 18:23:18 -07001267 return True
1268 return False
1269
1270 if not tempest.test.call_until_true(
1271 check_state, timeout, interval):
1272 msg = ("Timed out waiting for node %s to reach %s state(s) %s" %
1273 (node_id, state_attr, target_states))
1274 raise exceptions.TimeoutException(msg)
1275
1276 def wait_provisioning_state(self, node_id, state, timeout):
1277 self._node_state_timeout(
1278 node_id=node_id, state_attr='provision_state',
1279 target_states=state, timeout=timeout)
1280
1281 def wait_power_state(self, node_id, state):
1282 self._node_state_timeout(
1283 node_id=node_id, state_attr='power_state',
1284 target_states=state, timeout=CONF.baremetal.power_timeout)
1285
1286 def wait_node(self, instance_id):
1287 """Waits for a node to be associated with instance_id."""
Zhi Kun Liu4a8d1ea2014-04-15 22:08:21 -05001288
Adam Gandelman4a48a602014-03-20 18:23:18 -07001289 def _get_node():
1290 node = None
1291 try:
1292 node = self.get_node(instance_id=instance_id)
Masayuki Igawabfa07602015-01-20 18:47:17 +09001293 except lib_exc.NotFound:
Adam Gandelman4a48a602014-03-20 18:23:18 -07001294 pass
1295 return node is not None
1296
1297 if not tempest.test.call_until_true(
1298 _get_node, CONF.baremetal.association_timeout, 1):
1299 msg = ('Timed out waiting to get Ironic node by instance id %s'
1300 % instance_id)
1301 raise exceptions.TimeoutException(msg)
1302
1303 def get_node(self, node_id=None, instance_id=None):
1304 if node_id:
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001305 _, body = self.baremetal_client.show_node(node_id)
1306 return body
Adam Gandelman4a48a602014-03-20 18:23:18 -07001307 elif instance_id:
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001308 _, body = self.baremetal_client.show_node_by_instance_uuid(
1309 instance_id)
1310 if body['nodes']:
1311 return body['nodes'][0]
Adam Gandelman4a48a602014-03-20 18:23:18 -07001312
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001313 def get_ports(self, node_uuid):
Adam Gandelman4a48a602014-03-20 18:23:18 -07001314 ports = []
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001315 _, body = self.baremetal_client.list_node_ports(node_uuid)
1316 for port in body['ports']:
1317 _, p = self.baremetal_client.show_port(port['uuid'])
1318 ports.append(p)
Adam Gandelman4a48a602014-03-20 18:23:18 -07001319 return ports
1320
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001321 def add_keypair(self):
1322 self.keypair = self.create_keypair()
1323
1324 def verify_connectivity(self, ip=None):
1325 if ip:
1326 dest = self.get_remote_client(ip)
1327 else:
1328 dest = self.get_remote_client(self.instance)
1329 dest.validate_authentication()
1330
1331 def boot_instance(self):
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001332 self.instance = self.create_server(
lanoux5fc14522015-09-21 08:17:35 +00001333 key_name=self.keypair['name'])
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001334
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001335 self.wait_node(self.instance['id'])
1336 self.node = self.get_node(instance_id=self.instance['id'])
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001337
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001338 self.wait_power_state(self.node['uuid'], BaremetalPowerStates.POWER_ON)
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001339
1340 self.wait_provisioning_state(
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001341 self.node['uuid'],
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001342 [BaremetalProvisionStates.DEPLOYWAIT,
1343 BaremetalProvisionStates.ACTIVE],
1344 timeout=15)
1345
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001346 self.wait_provisioning_state(self.node['uuid'],
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001347 BaremetalProvisionStates.ACTIVE,
1348 timeout=CONF.baremetal.active_timeout)
1349
Ken'ichi Ohmichi0eb153c2015-07-13 02:18:25 +00001350 waiters.wait_for_server_status(self.servers_client,
1351 self.instance['id'], 'ACTIVE')
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001352 self.node = self.get_node(instance_id=self.instance['id'])
ghanshyam0f825252015-08-25 16:02:50 +09001353 self.instance = (self.servers_client.show_server(self.instance['id'])
1354 ['server'])
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001355
1356 def terminate_instance(self):
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001357 self.servers_client.delete_server(self.instance['id'])
1358 self.wait_power_state(self.node['uuid'],
1359 BaremetalPowerStates.POWER_OFF)
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001360 self.wait_provisioning_state(
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001361 self.node['uuid'],
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001362 BaremetalProvisionStates.NOSTATE,
1363 timeout=CONF.baremetal.unprovision_timeout)
1364
Adam Gandelman4a48a602014-03-20 18:23:18 -07001365
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001366class EncryptionScenarioTest(ScenarioTest):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001367 """Base class for encryption scenario tests"""
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001368
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001369 credentials = ['primary', 'admin']
David Kranz4cc852b2015-03-09 14:57:11 -04001370
1371 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001372 def setup_clients(cls):
1373 super(EncryptionScenarioTest, cls).setup_clients()
Ivan Kolodyazhnybcfc32e2015-08-06 13:31:36 +03001374 if CONF.volume_feature_enabled.api_v1:
1375 cls.admin_volume_types_client = cls.os_adm.volume_types_client
1376 else:
1377 cls.admin_volume_types_client = cls.os_adm.volume_types_v2_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001378
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001379 def create_volume_type(self, client=None, name=None):
1380 if not client:
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001381 client = self.admin_volume_types_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001382 if not name:
1383 name = 'generic'
Ken'ichi Ohmichi6ded8df2015-03-23 02:00:19 +00001384 randomized_name = data_utils.rand_name('scenario-type-' + name)
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001385 LOG.debug("Creating a volume type: %s", randomized_name)
Joseph Lanoux6809bab2014-12-18 14:57:18 +00001386 body = client.create_volume_type(
lei zhang83c4bbd2015-11-27 00:35:21 +08001387 name=randomized_name)['volume_type']
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001388 self.assertIn('id', body)
1389 self.addCleanup(client.delete_volume_type, body['id'])
1390 return body
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001391
1392 def create_encryption_type(self, client=None, type_id=None, provider=None,
1393 key_size=None, cipher=None,
1394 control_location=None):
1395 if not client:
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001396 client = self.admin_volume_types_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001397 if not type_id:
1398 volume_type = self.create_volume_type()
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001399 type_id = volume_type['id']
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001400 LOG.debug("Creating an encryption type for volume type: %s", type_id)
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001401 client.create_encryption_type(
1402 type_id, provider=provider, key_size=key_size, cipher=cipher,
John Warrend053ded2015-08-13 15:22:48 +00001403 control_location=control_location)['encryption']
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001404
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001405
Masayuki Igawa0870db52015-09-18 21:08:36 +09001406class ObjectStorageScenarioTest(ScenarioTest):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001407 """Provide harness to do Object Storage scenario tests.
Chris Dent0d494112014-08-26 13:48:30 +01001408
1409 Subclasses implement the tests that use the methods provided by this
1410 class.
1411 """
1412
1413 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001414 def skip_checks(cls):
Masayuki Igawa0870db52015-09-18 21:08:36 +09001415 super(ObjectStorageScenarioTest, cls).skip_checks()
Chris Dent0d494112014-08-26 13:48:30 +01001416 if not CONF.service_available.swift:
1417 skip_msg = ("%s skipped as swift is not available" %
1418 cls.__name__)
1419 raise cls.skipException(skip_msg)
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001420
1421 @classmethod
1422 def setup_credentials(cls):
Masayuki Igawa60ea6c52014-10-15 17:32:14 +09001423 cls.set_network_resources()
Masayuki Igawa0870db52015-09-18 21:08:36 +09001424 super(ObjectStorageScenarioTest, cls).setup_credentials()
Matthew Treinish4a596932015-03-06 20:37:01 -05001425 operator_role = CONF.object_storage.operator_role
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +01001426 cls.os_operator = cls.get_client_manager(roles=[operator_role])
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001427
1428 @classmethod
1429 def setup_clients(cls):
Masayuki Igawa0870db52015-09-18 21:08:36 +09001430 super(ObjectStorageScenarioTest, cls).setup_clients()
Chris Dent0d494112014-08-26 13:48:30 +01001431 # Clients for Swift
Matthew Treinish8f268292015-02-24 20:01:36 -05001432 cls.account_client = cls.os_operator.account_client
1433 cls.container_client = cls.os_operator.container_client
1434 cls.object_client = cls.os_operator.object_client
Chris Dent0d494112014-08-26 13:48:30 +01001435
Chris Dentde456a12014-09-10 12:41:15 +01001436 def get_swift_stat(self):
Chris Dent0d494112014-08-26 13:48:30 +01001437 """get swift status for our user account."""
1438 self.account_client.list_account_containers()
1439 LOG.debug('Swift status information obtained successfully')
1440
Chris Dentde456a12014-09-10 12:41:15 +01001441 def create_container(self, container_name=None):
Chris Dent0d494112014-08-26 13:48:30 +01001442 name = container_name or data_utils.rand_name(
1443 'swift-scenario-container')
1444 self.container_client.create_container(name)
1445 # look for the container to assure it is created
Chris Dentde456a12014-09-10 12:41:15 +01001446 self.list_and_check_container_objects(name)
Chris Dent0d494112014-08-26 13:48:30 +01001447 LOG.debug('Container %s created' % (name))
Chris Dent1d4313a2014-10-28 12:16:48 +00001448 self.addCleanup(self.delete_wrapper,
1449 self.container_client.delete_container,
1450 name)
Chris Dent0d494112014-08-26 13:48:30 +01001451 return name
1452
Chris Dentde456a12014-09-10 12:41:15 +01001453 def delete_container(self, container_name):
Chris Dent0d494112014-08-26 13:48:30 +01001454 self.container_client.delete_container(container_name)
1455 LOG.debug('Container %s deleted' % (container_name))
1456
Chris Dentde456a12014-09-10 12:41:15 +01001457 def upload_object_to_container(self, container_name, obj_name=None):
Chris Dent0d494112014-08-26 13:48:30 +01001458 obj_name = obj_name or data_utils.rand_name('swift-scenario-object')
1459 obj_data = data_utils.arbitrary_string()
1460 self.object_client.create_object(container_name, obj_name, obj_data)
Chris Dent1d4313a2014-10-28 12:16:48 +00001461 self.addCleanup(self.delete_wrapper,
1462 self.object_client.delete_object,
1463 container_name,
1464 obj_name)
Chris Dent0d494112014-08-26 13:48:30 +01001465 return obj_name, obj_data
1466
Chris Dentde456a12014-09-10 12:41:15 +01001467 def delete_object(self, container_name, filename):
Chris Dent0d494112014-08-26 13:48:30 +01001468 self.object_client.delete_object(container_name, filename)
Chris Dentde456a12014-09-10 12:41:15 +01001469 self.list_and_check_container_objects(container_name,
1470 not_present_obj=[filename])
Chris Dent0d494112014-08-26 13:48:30 +01001471
Chris Dentde456a12014-09-10 12:41:15 +01001472 def list_and_check_container_objects(self, container_name,
1473 present_obj=None,
1474 not_present_obj=None):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001475 # List objects for a given container and assert which are present and
1476 # which are not.
Ghanshyam2a180b82014-06-16 13:54:22 +09001477 if present_obj is None:
1478 present_obj = []
1479 if not_present_obj is None:
1480 not_present_obj = []
Chris Dent0d494112014-08-26 13:48:30 +01001481 _, object_list = self.container_client.list_container_contents(
1482 container_name)
1483 if present_obj:
1484 for obj in present_obj:
1485 self.assertIn(obj, object_list)
1486 if not_present_obj:
1487 for obj in not_present_obj:
1488 self.assertNotIn(obj, object_list)
1489
Chris Dentde456a12014-09-10 12:41:15 +01001490 def change_container_acl(self, container_name, acl):
Chris Dent0d494112014-08-26 13:48:30 +01001491 metadata_param = {'metadata_prefix': 'x-container-',
1492 'metadata': {'read': acl}}
1493 self.container_client.update_container_metadata(container_name,
1494 **metadata_param)
1495 resp, _ = self.container_client.list_container_metadata(container_name)
1496 self.assertEqual(resp['x-container-read'], acl)
1497
Chris Dentde456a12014-09-10 12:41:15 +01001498 def download_and_verify(self, container_name, obj_name, expected_data):
Chris Dent0d494112014-08-26 13:48:30 +01001499 _, obj = self.object_client.get_object(container_name, obj_name)
1500 self.assertEqual(obj, expected_data)