blob: 1962286d16efb4bda7924322dc4789942076f032 [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
Anusha Ramineni9aaef8b2016-01-19 10:56:40 +0530165 def create_server(self, name=None, image_id=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,
Anusha Ramineni9aaef8b2016-01-19 10:56:40 +0530245 name=name, flavor=flavor,
246 image_id=image_id, **kwargs)
lanoux5fc14522015-09-21 08:17:35 +0000247
248 # TODO(jlanoux) Move wait_on_delete in compute.py
Andrea Frittoli247058f2014-07-16 16:09:22 +0100249 if wait_on_delete:
Ken'ichi Ohmichie91a0c62015-08-13 02:09:16 +0000250 self.addCleanup(waiters.wait_for_server_termination,
lanoux5fc14522015-09-21 08:17:35 +0000251 clients.servers_client,
252 body['id'])
253
Andrea Frittoli247058f2014-07-16 16:09:22 +0100254 self.addCleanup_with_wait(
Ken'ichi Ohmichie91a0c62015-08-13 02:09:16 +0000255 waiter_callable=waiters.wait_for_server_termination,
lanoux5fc14522015-09-21 08:17:35 +0000256 thing_id=body['id'], thing_id_param='server_id',
Andrea Frittoli247058f2014-07-16 16:09:22 +0100257 cleanup_callable=self.delete_wrapper,
lanoux5fc14522015-09-21 08:17:35 +0000258 cleanup_args=[clients.servers_client.delete_server, body['id']],
259 waiter_client=clients.servers_client)
260 server = clients.servers_client.show_server(body['id'])['server']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100261 return server
262
Markus Zoeller3d2a21c2015-02-27 12:04:22 +0100263 def create_volume(self, size=None, name=None, snapshot_id=None,
Andrea Frittoli247058f2014-07-16 16:09:22 +0100264 imageRef=None, volume_type=None, wait_on_delete=True):
265 if name is None:
266 name = data_utils.rand_name(self.__class__.__name__)
Ghanshyam8fc0ed22015-12-18 10:25:14 +0900267 kwargs = {'display_name': name,
268 'snapshot_id': snapshot_id,
269 'imageRef': imageRef,
270 'volume_type': volume_type}
271 if size is not None:
272 kwargs.update({'size': size})
273 volume = self.volumes_client.create_volume(**kwargs)['volume']
Matt Riedemanne85c2702014-09-10 11:50:13 -0700274
Andrea Frittoli247058f2014-07-16 16:09:22 +0100275 if wait_on_delete:
276 self.addCleanup(self.volumes_client.wait_for_resource_deletion,
277 volume['id'])
Matt Riedemanne85c2702014-09-10 11:50:13 -0700278 self.addCleanup(self.delete_wrapper,
279 self.volumes_client.delete_volume, volume['id'])
280 else:
281 self.addCleanup_with_wait(
282 waiter_callable=self.volumes_client.wait_for_resource_deletion,
283 thing_id=volume['id'], thing_id_param='id',
284 cleanup_callable=self.delete_wrapper,
285 cleanup_args=[self.volumes_client.delete_volume, volume['id']])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100286
Ivan Kolodyazhnybcfc32e2015-08-06 13:31:36 +0300287 # NOTE(e0ne): Cinder API v2 uses name instead of display_name
288 if 'display_name' in volume:
289 self.assertEqual(name, volume['display_name'])
290 else:
291 self.assertEqual(name, volume['name'])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100292 self.volumes_client.wait_for_volume_status(volume['id'], 'available')
293 # The volume retrieved on creation has a non-up-to-date status.
294 # Retrieval after it becomes active ensures correct details.
John Warren6177c9e2015-08-19 20:00:17 +0000295 volume = self.volumes_client.show_volume(volume['id'])['volume']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100296 return volume
297
Yair Fried1fc32a12014-08-04 09:11:30 +0300298 def _create_loginable_secgroup_rule(self, secgroup_id=None):
John Warrenf2345512015-12-10 13:39:30 -0500299 _client = self.compute_security_groups_client
John Warren5cdbf422016-01-05 12:42:43 -0500300 _client_rules = self.compute_security_group_rules_client
Andrea Frittoli247058f2014-07-16 16:09:22 +0100301 if secgroup_id is None:
ghanshyamb610b772015-08-24 17:29:38 +0900302 sgs = _client.list_security_groups()['security_groups']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100303 for sg in sgs:
304 if sg['name'] == 'default':
305 secgroup_id = sg['id']
306
307 # These rules are intended to permit inbound ssh and icmp
308 # traffic from all sources, so no group_id is provided.
309 # Setting a group_id would only permit traffic from ports
310 # belonging to the same security group.
311 rulesets = [
312 {
313 # ssh
Ken'ichi Ohmichieb7eeec2015-07-21 01:00:06 +0000314 'ip_protocol': 'tcp',
Andrea Frittoli247058f2014-07-16 16:09:22 +0100315 'from_port': 22,
316 'to_port': 22,
317 'cidr': '0.0.0.0/0',
318 },
319 {
320 # ping
Ken'ichi Ohmichieb7eeec2015-07-21 01:00:06 +0000321 'ip_protocol': 'icmp',
Andrea Frittoli247058f2014-07-16 16:09:22 +0100322 'from_port': -1,
323 'to_port': -1,
324 'cidr': '0.0.0.0/0',
325 }
326 ]
327 rules = list()
328 for ruleset in rulesets:
Ken'ichi Ohmichieb7eeec2015-07-21 01:00:06 +0000329 sg_rule = _client_rules.create_security_group_rule(
ghanshyam0a5e1232015-08-24 16:59:59 +0900330 parent_group_id=secgroup_id, **ruleset)['security_group_rule']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100331 rules.append(sg_rule)
332 return rules
333
Yair Fried1fc32a12014-08-04 09:11:30 +0300334 def _create_security_group(self):
Andrea Frittoli247058f2014-07-16 16:09:22 +0100335 # Create security group
336 sg_name = data_utils.rand_name(self.__class__.__name__)
337 sg_desc = sg_name + " description"
John Warrenf2345512015-12-10 13:39:30 -0500338 secgroup = self.compute_security_groups_client.create_security_group(
ghanshyamb610b772015-08-24 17:29:38 +0900339 name=sg_name, description=sg_desc)['security_group']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100340 self.assertEqual(secgroup['name'], sg_name)
341 self.assertEqual(secgroup['description'], sg_desc)
John Warrenf2345512015-12-10 13:39:30 -0500342 self.addCleanup(
343 self.delete_wrapper,
344 self.compute_security_groups_client.delete_security_group,
345 secgroup['id'])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100346
347 # Add rules to the security group
Yair Fried1fc32a12014-08-04 09:11:30 +0300348 self._create_loginable_secgroup_rule(secgroup['id'])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100349
350 return secgroup
351
Sean Dague20e98612016-01-06 14:33:28 -0500352 def get_remote_client(self, ip_address, username=None, private_key=None):
JordanP3fe2dc32014-11-17 13:06:01 +0100353 """Get a SSH client to a remote server
354
Sean Dague20e98612016-01-06 14:33:28 -0500355 @param ip_address the server floating or fixed IP address to use
356 for ssh validation
JordanP3fe2dc32014-11-17 13:06:01 +0100357 @param username name of the Linux account on the remote server
358 @param private_key the SSH private key to use
JordanP3fe2dc32014-11-17 13:06:01 +0100359 @return a RemoteClient object
360 """
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700361
Andrea Frittoli247058f2014-07-16 16:09:22 +0100362 if username is None:
lanoux283273b2015-12-04 03:01:54 -0800363 username = CONF.validation.image_ssh_user
wantwatering896300c2015-03-27 15:17:42 +0800364 # Set this with 'keypair' or others to log in with keypair or
365 # username/password.
lanoux5fc14522015-09-21 08:17:35 +0000366 if CONF.validation.auth_method == 'keypair':
wantwatering896300c2015-03-27 15:17:42 +0800367 password = None
368 if private_key is None:
369 private_key = self.keypair['private_key']
370 else:
lanoux283273b2015-12-04 03:01:54 -0800371 password = CONF.validation.image_ssh_password
wantwatering896300c2015-03-27 15:17:42 +0800372 private_key = None
Sean Dague20e98612016-01-06 14:33:28 -0500373 linux_client = remote_client.RemoteClient(ip_address, username,
wantwatering896300c2015-03-27 15:17:42 +0800374 pkey=private_key,
375 password=password)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100376 try:
377 linux_client.validate_authentication()
Matt Riedemann5f0ac522015-05-21 09:16:24 -0700378 except Exception as e:
379 message = ('Initializing SSH connection to %(ip)s failed. '
Eric Brown0911af62016-02-08 17:15:40 -0800380 'Error: %(error)s' % {'ip': ip_address,
Sean Dague20e98612016-01-06 14:33:28 -0500381 'error': e})
Matt Riedemann5f0ac522015-05-21 09:16:24 -0700382 caller = misc_utils.find_test_caller()
383 if caller:
384 message = '(%s) %s' % (caller, message)
385 LOG.exception(message)
Sean Dague2c98a162016-01-06 14:11:13 -0500386 self._log_console_output()
Andrea Frittoli247058f2014-07-16 16:09:22 +0100387 raise
388
389 return linux_client
390
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000391 def _image_create(self, name, fmt, path,
392 disk_format=None, properties=None):
Ghanshyam2a180b82014-06-16 13:54:22 +0900393 if properties is None:
394 properties = {}
Andrea Frittoli247058f2014-07-16 16:09:22 +0100395 name = data_utils.rand_name('%s-' % name)
396 image_file = open(path, 'rb')
397 self.addCleanup(image_file.close)
398 params = {
399 'name': name,
400 'container_format': fmt,
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000401 'disk_format': disk_format or fmt,
Andrea Frittoli247058f2014-07-16 16:09:22 +0100402 'is_public': 'False',
403 }
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000404 params['properties'] = properties
John Warren66207252015-07-31 15:51:02 -0400405 image = self.image_client.create_image(**params)['image']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100406 self.addCleanup(self.image_client.delete_image, image['id'])
407 self.assertEqual("queued", image['status'])
408 self.image_client.update_image(image['id'], data=image_file)
409 return image['id']
410
411 def glance_image_create(self):
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300412 img_path = CONF.scenario.img_dir + "/" + CONF.scenario.img_file
Andrea Frittoli247058f2014-07-16 16:09:22 +0100413 aki_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.aki_img_file
414 ari_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.ari_img_file
415 ami_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.ami_img_file
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300416 img_container_format = CONF.scenario.img_container_format
417 img_disk_format = CONF.scenario.img_disk_format
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000418 img_properties = CONF.scenario.img_properties
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300419 LOG.debug("paths: img: %s, container_fomat: %s, disk_format: %s, "
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000420 "properties: %s, ami: %s, ari: %s, aki: %s" %
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300421 (img_path, img_container_format, img_disk_format,
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000422 img_properties, ami_img_path, ari_img_path, aki_img_path))
Andrea Frittoli247058f2014-07-16 16:09:22 +0100423 try:
Jordan Pittier1e443ec2015-11-20 16:15:58 +0100424 image = self._image_create('scenario-img',
425 img_container_format,
426 img_path,
427 disk_format=img_disk_format,
428 properties=img_properties)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100429 except IOError:
430 LOG.debug("A qcow2 image was not found. Try to get a uec image.")
431 kernel = self._image_create('scenario-aki', 'aki', aki_img_path)
432 ramdisk = self._image_create('scenario-ari', 'ari', ari_img_path)
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000433 properties = {'kernel_id': kernel, 'ramdisk_id': ramdisk}
Jordan Pittier1e443ec2015-11-20 16:15:58 +0100434 image = self._image_create('scenario-ami', 'ami',
435 path=ami_img_path,
436 properties=properties)
437 LOG.debug("image:%s" % image)
438
439 return image
Andrea Frittoli247058f2014-07-16 16:09:22 +0100440
441 def _log_console_output(self, servers=None):
Matthew Treinish42a3f3a2014-09-04 15:04:53 -0400442 if not CONF.compute_feature_enabled.console_output:
443 LOG.debug('Console output not supported, cannot log')
444 return
Andrea Frittoli247058f2014-07-16 16:09:22 +0100445 if not servers:
David Kranzae99b9a2015-02-16 13:37:01 -0500446 servers = self.servers_client.list_servers()
Andrea Frittoli247058f2014-07-16 16:09:22 +0100447 servers = servers['servers']
448 for server in servers:
Brant Knudson566c5712014-09-24 20:04:50 -0500449 console_output = self.servers_client.get_console_output(
Ken'ichi Ohmichibf4766a2015-12-09 07:48:43 +0000450 server['id'])['output']
David Kranzae99b9a2015-02-16 13:37:01 -0500451 LOG.debug('Console output for %s\nbody=\n%s',
452 server['id'], console_output)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100453
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000454 def _log_net_info(self, exc):
455 # network debug is called as part of ssh init
Andrey Pavlov64723762015-04-29 06:24:58 +0300456 if not isinstance(exc, lib_exc.SSHTimeout):
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000457 LOG.debug('Network information on a devstack host')
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000458
nithya-ganesan882595e2014-07-29 18:51:07 +0000459 def create_server_snapshot(self, server, name=None):
460 # Glance client
461 _image_client = self.image_client
462 # Compute client
Ghanshyamae76c122015-12-22 13:41:35 +0900463 _images_client = self.compute_images_client
nithya-ganesan882595e2014-07-29 18:51:07 +0000464 if name is None:
Ken'ichi Ohmichi6ded8df2015-03-23 02:00:19 +0000465 name = data_utils.rand_name('scenario-snapshot')
nithya-ganesan882595e2014-07-29 18:51:07 +0000466 LOG.debug("Creating a snapshot image for server: %s", server['name'])
Ken'ichi Ohmichi28f18672015-07-17 10:00:38 +0000467 image = _images_client.create_image(server['id'], name=name)
David Kranza5299eb2015-01-15 17:24:05 -0500468 image_id = image.response['location'].split('images/')[1]
nithya-ganesan882595e2014-07-29 18:51:07 +0000469 _image_client.wait_for_image_status(image_id, 'active')
470 self.addCleanup_with_wait(
471 waiter_callable=_image_client.wait_for_resource_deletion,
472 thing_id=image_id, thing_id_param='id',
473 cleanup_callable=self.delete_wrapper,
474 cleanup_args=[_image_client.delete_image, image_id])
David Kranz34f18782015-01-06 13:43:55 -0500475 snapshot_image = _image_client.get_image_meta(image_id)
Andrey Pavlovc8bd4b12015-08-17 10:20:17 +0300476
477 bdm = snapshot_image.get('properties', {}).get('block_device_mapping')
478 if bdm:
479 bdm = json.loads(bdm)
480 if bdm and 'snapshot_id' in bdm[0]:
481 snapshot_id = bdm[0]['snapshot_id']
482 self.addCleanup(
483 self.snapshots_client.wait_for_resource_deletion,
484 snapshot_id)
485 self.addCleanup(
486 self.delete_wrapper, self.snapshots_client.delete_snapshot,
487 snapshot_id)
Andrey Pavlovd35957b2015-08-27 20:12:15 +0300488 self.snapshots_client.wait_for_snapshot_status(snapshot_id,
489 'available')
Andrey Pavlovc8bd4b12015-08-17 10:20:17 +0300490
nithya-ganesan882595e2014-07-29 18:51:07 +0000491 image_name = snapshot_image['name']
492 self.assertEqual(name, image_name)
493 LOG.debug("Created snapshot image %s for server %s",
494 image_name, server['name'])
495 return snapshot_image
496
Jordan Pittier7cf64762015-10-14 15:01:12 +0200497 def nova_volume_attach(self, server, volume_to_attach):
Joseph Lanoux6809bab2014-12-18 14:57:18 +0000498 volume = self.servers_client.attach_volume(
Jordan Pittier7cf64762015-10-14 15:01:12 +0200499 server['id'], volumeId=volume_to_attach['id'], device='/dev/%s'
ghanshyam0f825252015-08-25 16:02:50 +0900500 % CONF.compute.volume_device_name)['volumeAttachment']
Jordan Pittier7cf64762015-10-14 15:01:12 +0200501 self.assertEqual(volume_to_attach['id'], volume['id'])
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900502 self.volumes_client.wait_for_volume_status(volume['id'], 'in-use')
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900503
Jordan Pittier7cf64762015-10-14 15:01:12 +0200504 # Return the updated volume after the attachment
505 return self.volumes_client.show_volume(volume['id'])['volume']
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900506
Jordan Pittier7cf64762015-10-14 15:01:12 +0200507 def nova_volume_detach(self, server, volume):
508 self.servers_client.detach_volume(server['id'], volume['id'])
509 self.volumes_client.wait_for_volume_status(volume['id'], 'available')
510
511 volume = self.volumes_client.show_volume(volume['id'])['volume']
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900512 self.assertEqual('available', volume['status'])
513
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700514 def rebuild_server(self, server_id, image=None,
515 preserve_ephemeral=False, wait=True,
516 rebuild_kwargs=None):
517 if image is None:
518 image = CONF.compute.image_ref
519
520 rebuild_kwargs = rebuild_kwargs or {}
521
522 LOG.debug("Rebuilding server (id: %s, image: %s, preserve eph: %s)",
523 server_id, image, preserve_ephemeral)
Ken'ichi Ohmichi5271b0f2015-08-10 07:53:27 +0000524 self.servers_client.rebuild_server(
525 server_id=server_id, image_ref=image,
526 preserve_ephemeral=preserve_ephemeral,
527 **rebuild_kwargs)
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700528 if wait:
Ken'ichi Ohmichi0eb153c2015-07-13 02:18:25 +0000529 waiters.wait_for_server_status(self.servers_client,
530 server_id, 'ACTIVE')
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700531
Steven Hardyda2a8352014-10-02 12:52:20 +0100532 def ping_ip_address(self, ip_address, should_succeed=True,
533 ping_timeout=None):
lanoux5fc14522015-09-21 08:17:35 +0000534 timeout = ping_timeout or CONF.validation.ping_timeout
Aaron Rosena7df13b2014-09-23 09:45:45 -0700535 cmd = ['ping', '-c1', '-w1', ip_address]
536
537 def ping():
538 proc = subprocess.Popen(cmd,
539 stdout=subprocess.PIPE,
540 stderr=subprocess.PIPE)
541 proc.communicate()
Shuquan Huang753629e2015-07-20 08:52:29 +0000542
Aaron Rosena7df13b2014-09-23 09:45:45 -0700543 return (proc.returncode == 0) == should_succeed
544
Shuquan Huang753629e2015-07-20 08:52:29 +0000545 caller = misc_utils.find_test_caller()
546 LOG.debug('%(caller)s begins to ping %(ip)s in %(timeout)s sec and the'
547 ' expected result is %(should_succeed)s' % {
548 'caller': caller, 'ip': ip_address, 'timeout': timeout,
549 'should_succeed':
550 'reachable' if should_succeed else 'unreachable'
551 })
552 result = tempest.test.call_until_true(ping, timeout, 1)
553 LOG.debug('%(caller)s finishes ping %(ip)s in %(timeout)s sec and the '
554 'ping result is %(result)s' % {
555 'caller': caller, 'ip': ip_address, 'timeout': timeout,
556 'result': 'expected' if result else 'unexpected'
557 })
558 return result
Aaron Rosena7df13b2014-09-23 09:45:45 -0700559
Yair Friedae0e73d2014-11-24 11:56:26 +0200560 def check_vm_connectivity(self, ip_address,
561 username=None,
562 private_key=None,
563 should_connect=True):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000564 """Check server connectivity
565
Yair Friedae0e73d2014-11-24 11:56:26 +0200566 :param ip_address: server to test against
567 :param username: server's ssh username
568 :param private_key: server's ssh private key to be used
569 :param should_connect: True/False indicates positive/negative test
570 positive - attempt ping and ssh
571 negative - attempt ping and fail if succeed
572
573 :raises: AssertError if the result of the connectivity check does
574 not match the value of the should_connect param
575 """
576 if should_connect:
577 msg = "Timed out waiting for %s to become reachable" % ip_address
578 else:
579 msg = "ip address %s is reachable" % ip_address
580 self.assertTrue(self.ping_ip_address(ip_address,
581 should_succeed=should_connect),
582 msg=msg)
583 if should_connect:
584 # no need to check ssh for negative connectivity
585 self.get_remote_client(ip_address, username, private_key)
586
587 def check_public_network_connectivity(self, ip_address, username,
588 private_key, should_connect=True,
589 msg=None, servers=None):
590 # The target login is assumed to have been configured for
591 # key-based authentication by cloud-init.
592 LOG.debug('checking network connections to IP %s with user: %s' %
593 (ip_address, username))
594 try:
595 self.check_vm_connectivity(ip_address,
596 username,
597 private_key,
598 should_connect=should_connect)
Matthew Treinish53483132014-12-09 18:50:06 -0500599 except Exception:
Yair Friedae0e73d2014-11-24 11:56:26 +0200600 ex_msg = 'Public network connectivity check failed'
601 if msg:
602 ex_msg += ": " + msg
603 LOG.exception(ex_msg)
604 self._log_console_output(servers)
Yair Friedae0e73d2014-11-24 11:56:26 +0200605 raise
606
607 def create_floating_ip(self, thing, pool_name=None):
Ken'ichi Ohmichia112a592015-11-17 08:49:37 +0000608 """Create a floating IP and associates to a server on Nova"""
Yair Friedae0e73d2014-11-24 11:56:26 +0200609
John Warrene74890a2015-11-11 15:18:01 -0500610 floating_ip = (self.compute_floating_ips_client.
Ken'ichi Ohmichie037a6f2015-12-03 06:41:49 +0000611 create_floating_ip(pool=pool_name)['floating_ip'])
Yair Friedae0e73d2014-11-24 11:56:26 +0200612 self.addCleanup(self.delete_wrapper,
John Warrene74890a2015-11-11 15:18:01 -0500613 self.compute_floating_ips_client.delete_floating_ip,
Yair Friedae0e73d2014-11-24 11:56:26 +0200614 floating_ip['id'])
John Warrene74890a2015-11-11 15:18:01 -0500615 self.compute_floating_ips_client.associate_floating_ip_to_server(
Yair Friedae0e73d2014-11-24 11:56:26 +0200616 floating_ip['ip'], thing['id'])
617 return floating_ip
618
Sean Dague20e98612016-01-06 14:33:28 -0500619 def create_timestamp(self, ip_address, dev_name=None, mount_path='/mnt',
Matt Riedemannfd5657d2015-09-30 14:47:07 -0700620 private_key=None):
Sean Dague20e98612016-01-06 14:33:28 -0500621 ssh_client = self.get_remote_client(ip_address,
Matt Riedemannfd5657d2015-09-30 14:47:07 -0700622 private_key=private_key)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300623 if dev_name is not None:
624 ssh_client.make_fs(dev_name)
Matt Riedemann076685a2015-09-30 14:38:16 -0700625 ssh_client.mount(dev_name, mount_path)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300626 cmd_timestamp = 'sudo sh -c "date > %s/timestamp; sync"' % mount_path
627 ssh_client.exec_command(cmd_timestamp)
628 timestamp = ssh_client.exec_command('sudo cat %s/timestamp'
629 % mount_path)
630 if dev_name is not None:
631 ssh_client.umount(mount_path)
632 return timestamp
633
Sean Dague20e98612016-01-06 14:33:28 -0500634 def get_timestamp(self, ip_address, dev_name=None, mount_path='/mnt',
Matt Riedemannfd5657d2015-09-30 14:47:07 -0700635 private_key=None):
Sean Dague20e98612016-01-06 14:33:28 -0500636 ssh_client = self.get_remote_client(ip_address,
Matt Riedemannfd5657d2015-09-30 14:47:07 -0700637 private_key=private_key)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300638 if dev_name is not None:
Matt Riedemann076685a2015-09-30 14:38:16 -0700639 ssh_client.mount(dev_name, mount_path)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300640 timestamp = ssh_client.exec_command('sudo cat %s/timestamp'
641 % mount_path)
642 if dev_name is not None:
643 ssh_client.umount(mount_path)
644 return timestamp
645
Sean Dague20e98612016-01-06 14:33:28 -0500646 def get_server_ip(self, server):
647 """Get the server fixed or floating IP.
648
649 Based on the configuration we're in, return a correct ip
650 address for validating that a guest is up.
651 """
Alexander Gubanovc8829f82015-11-12 10:35:13 +0200652 if CONF.validation.connect_method == 'floating':
Sean Dague20e98612016-01-06 14:33:28 -0500653 # The tests calling this method don't have a floating IP
654 # and can't make use of the validattion resources. So the
655 # method is creating the floating IP there.
656 return self.create_floating_ip(server)['ip']
657 elif CONF.validation.connect_method == 'fixed':
658 addresses = server['addresses'][CONF.validation.network_for_ssh]
659 for address in addresses:
660 if address['version'] == CONF.validation.ip_version_for_ssh:
661 return address['addr']
662 raise exceptions.ServerUnreachable()
Alexander Gubanovc8829f82015-11-12 10:35:13 +0200663 else:
Sean Dague20e98612016-01-06 14:33:28 -0500664 raise exceptions.InvalidConfiguration()
Alexander Gubanovc8829f82015-11-12 10:35:13 +0200665
Andrea Frittoli2e733b52014-07-16 14:12:11 +0100666
Andrea Frittoli4971fc82014-09-25 10:22:20 +0100667class NetworkScenarioTest(ScenarioTest):
Yair Fried1fc32a12014-08-04 09:11:30 +0300668 """Base class for network scenario tests.
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000669
Yair Fried1fc32a12014-08-04 09:11:30 +0300670 This class provide helpers for network scenario tests, using the neutron
671 API. Helpers from ancestor which use the nova network API are overridden
672 with the neutron API.
673
674 This Class also enforces using Neutron instead of novanetwork.
675 Subclassed tests will be skipped if Neutron is not enabled
676
677 """
678
Andrea Frittolib21de6c2015-02-06 20:12:38 +0000679 credentials = ['primary', 'admin']
680
Yair Fried1fc32a12014-08-04 09:11:30 +0300681 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +0000682 def skip_checks(cls):
683 super(NetworkScenarioTest, cls).skip_checks()
Andrea Frittoli2ddc2632014-09-25 11:03:00 +0100684 if not CONF.service_available.neutron:
685 raise cls.skipException('Neutron not available')
Yair Fried1fc32a12014-08-04 09:11:30 +0300686
687 @classmethod
Andrea Frittoliac20b5e2014-09-15 13:31:14 +0100688 def resource_setup(cls):
689 super(NetworkScenarioTest, cls).resource_setup()
Yair Fried1fc32a12014-08-04 09:11:30 +0300690 cls.tenant_id = cls.manager.identity_client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300691
John Warren94d8faf2015-09-15 12:22:24 -0400692 def _create_network(self, client=None, networks_client=None,
693 tenant_id=None, namestart='network-smoke-'):
Yair Frieddb6c9e92014-08-06 08:53:13 +0300694 if not client:
695 client = self.network_client
John Warren94d8faf2015-09-15 12:22:24 -0400696 if not networks_client:
697 networks_client = self.networks_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300698 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000699 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300700 name = data_utils.rand_name(namestart)
John Warren94d8faf2015-09-15 12:22:24 -0400701 result = networks_client.create_network(name=name, tenant_id=tenant_id)
702 network = net_resources.DeletableNetwork(
703 networks_client=networks_client, **result['network'])
Yair Fried1fc32a12014-08-04 09:11:30 +0300704 self.assertEqual(network.name, name)
705 self.addCleanup(self.delete_wrapper, network.delete)
706 return network
707
708 def _list_networks(self, *args, **kwargs):
709 """List networks using admin creds """
John Warren94d8faf2015-09-15 12:22:24 -0400710 networks_list = self.admin_manager.networks_client.list_networks(
ghanshyam2f7cc022015-06-26 18:18:11 +0900711 *args, **kwargs)
712 return networks_list['networks']
Yair Fried1fc32a12014-08-04 09:11:30 +0300713
714 def _list_subnets(self, *args, **kwargs):
715 """List subnets using admin creds """
John Warren3961acd2015-10-02 14:38:53 -0400716 subnets_list = self.admin_manager.subnets_client.list_subnets(
ghanshyam2f7cc022015-06-26 18:18:11 +0900717 *args, **kwargs)
718 return subnets_list['subnets']
Yair Fried1fc32a12014-08-04 09:11:30 +0300719
720 def _list_routers(self, *args, **kwargs):
721 """List routers using admin creds """
ghanshyam2f7cc022015-06-26 18:18:11 +0900722 routers_list = self.admin_manager.network_client.list_routers(
723 *args, **kwargs)
724 return routers_list['routers']
Yair Fried1fc32a12014-08-04 09:11:30 +0300725
726 def _list_ports(self, *args, **kwargs):
727 """List ports using admin creds """
John Warren49c0fe52015-10-22 12:35:54 -0400728 ports_list = self.admin_manager.ports_client.list_ports(
ghanshyam2f7cc022015-06-26 18:18:11 +0900729 *args, **kwargs)
730 return ports_list['ports']
Yair Fried1fc32a12014-08-04 09:11:30 +0300731
Yair Fried564d89d2015-08-06 17:02:12 +0300732 def _list_agents(self, *args, **kwargs):
733 """List agents using admin creds """
Ken'ichi Ohmichi71860062015-12-15 08:20:13 +0000734 agents_list = self.admin_manager.network_agents_client.list_agents(
Yair Fried564d89d2015-08-06 17:02:12 +0300735 *args, **kwargs)
736 return agents_list['agents']
737
John Warren3961acd2015-10-02 14:38:53 -0400738 def _create_subnet(self, network, client=None, subnets_client=None,
739 namestart='subnet-smoke', **kwargs):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000740 """Create a subnet for the given network
741
742 within the cidr block configured for tenant networks.
Yair Fried1fc32a12014-08-04 09:11:30 +0300743 """
Yair Frieddb6c9e92014-08-06 08:53:13 +0300744 if not client:
745 client = self.network_client
John Warren3961acd2015-10-02 14:38:53 -0400746 if not subnets_client:
747 subnets_client = self.subnets_client
Yair Fried1fc32a12014-08-04 09:11:30 +0300748
749 def cidr_in_use(cidr, tenant_id):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000750 """Check cidr existence
751
lei zhangdd552b22015-11-25 20:41:48 +0800752 :returns: True if subnet with cidr already exist in tenant
753 False else
Yair Fried1fc32a12014-08-04 09:11:30 +0300754 """
755 cidr_in_use = self._list_subnets(tenant_id=tenant_id, cidr=cidr)
756 return len(cidr_in_use) != 0
757
Kirill Shileev14113572014-11-21 16:58:02 +0300758 ip_version = kwargs.pop('ip_version', 4)
759
760 if ip_version == 6:
761 tenant_cidr = netaddr.IPNetwork(
762 CONF.network.tenant_network_v6_cidr)
763 num_bits = CONF.network.tenant_network_v6_mask_bits
764 else:
765 tenant_cidr = netaddr.IPNetwork(CONF.network.tenant_network_cidr)
766 num_bits = CONF.network.tenant_network_mask_bits
767
Yair Fried1fc32a12014-08-04 09:11:30 +0300768 result = None
Kirill Shileev14113572014-11-21 16:58:02 +0300769 str_cidr = None
Yair Fried1fc32a12014-08-04 09:11:30 +0300770 # Repeatedly attempt subnet creation with sequential cidr
771 # blocks until an unallocated block is found.
Kirill Shileev14113572014-11-21 16:58:02 +0300772 for subnet_cidr in tenant_cidr.subnet(num_bits):
Yair Fried1fc32a12014-08-04 09:11:30 +0300773 str_cidr = str(subnet_cidr)
774 if cidr_in_use(str_cidr, tenant_id=network.tenant_id):
775 continue
776
777 subnet = dict(
778 name=data_utils.rand_name(namestart),
Yair Fried1fc32a12014-08-04 09:11:30 +0300779 network_id=network.id,
780 tenant_id=network.tenant_id,
781 cidr=str_cidr,
Kirill Shileev14113572014-11-21 16:58:02 +0300782 ip_version=ip_version,
Yair Fried1fc32a12014-08-04 09:11:30 +0300783 **kwargs
784 )
785 try:
John Warren3961acd2015-10-02 14:38:53 -0400786 result = subnets_client.create_subnet(**subnet)
Yair Fried1fc32a12014-08-04 09:11:30 +0300787 break
Masayuki Igawad9388762015-01-20 14:56:42 +0900788 except lib_exc.Conflict as e:
Yair Fried1fc32a12014-08-04 09:11:30 +0300789 is_overlapping_cidr = 'overlaps with another subnet' in str(e)
790 if not is_overlapping_cidr:
791 raise
792 self.assertIsNotNone(result, 'Unable to allocate tenant network')
John Warren3961acd2015-10-02 14:38:53 -0400793 subnet = net_resources.DeletableSubnet(
794 network_client=client, subnets_client=subnets_client,
795 **result['subnet'])
Yair Fried1fc32a12014-08-04 09:11:30 +0300796 self.assertEqual(subnet.cidr, str_cidr)
797 self.addCleanup(self.delete_wrapper, subnet.delete)
798 return subnet
799
Itzik Brown2ca01cd2014-12-08 12:58:20 +0200800 def _create_port(self, network_id, client=None, namestart='port-quotatest',
801 **kwargs):
Yair Frieddb6c9e92014-08-06 08:53:13 +0300802 if not client:
John Warren49c0fe52015-10-22 12:35:54 -0400803 client = self.ports_client
Yair Fried1fc32a12014-08-04 09:11:30 +0300804 name = data_utils.rand_name(namestart)
David Kranz34e88122014-12-11 15:24:05 -0500805 result = client.create_port(
Yair Fried1fc32a12014-08-04 09:11:30 +0300806 name=name,
Itzik Brown2ca01cd2014-12-08 12:58:20 +0200807 network_id=network_id,
808 **kwargs)
Yair Fried1fc32a12014-08-04 09:11:30 +0300809 self.assertIsNotNone(result, 'Unable to allocate port')
John Warren49c0fe52015-10-22 12:35:54 -0400810 port = net_resources.DeletablePort(ports_client=client,
Yair Fried1fc32a12014-08-04 09:11:30 +0300811 **result['port'])
812 self.addCleanup(self.delete_wrapper, port.delete)
813 return port
814
Kirill Shileev14113572014-11-21 16:58:02 +0300815 def _get_server_port_id_and_ip4(self, server, ip_addr=None):
Ken'ichi Ohmichi30b769e2015-10-14 09:47:22 +0000816 ports = self._list_ports(device_id=server['id'], status='ACTIVE',
Yair Fried1fc32a12014-08-04 09:11:30 +0300817 fixed_ip=ip_addr)
Sean M. Collins2e896832015-12-15 13:58:47 -0500818 # A port can have more then one IP address in some cases.
819 # If the network is dual-stack (IPv4 + IPv6), this port is associated
820 # with 2 subnets
Daniel Mellado9e3e1062015-08-06 18:07:05 +0200821 port_map = [(p["id"], fxip["ip_address"])
822 for p in ports
823 for fxip in p["fixed_ips"]
824 if netaddr.valid_ipv4(fxip["ip_address"])]
825
John L. Villalovosb83286f2015-11-04 14:46:57 -0800826 self.assertNotEqual(0, len(port_map),
827 "No IPv4 addresses found in: %s" % ports)
Daniel Mellado9e3e1062015-08-06 18:07:05 +0200828 self.assertEqual(len(port_map), 1,
829 "Found multiple IPv4 addresses: %s. "
830 "Unable to determine which port to target."
831 % port_map)
832 return port_map[0]
Yair Fried1fc32a12014-08-04 09:11:30 +0300833
David Shrewsbury9bac3662014-08-07 15:07:01 -0400834 def _get_network_by_name(self, network_name):
835 net = self._list_networks(name=network_name)
Adam Gandelman878a5fd2015-03-30 14:33:36 -0700836 self.assertNotEqual(len(net), 0,
837 "Unable to get network by name: %s" % network_name)
Yair Fried8186f812014-09-28 09:39:39 +0300838 return net_resources.AttributeDict(net[0])
David Shrewsbury9bac3662014-08-07 15:07:01 -0400839
Yair Friedae0e73d2014-11-24 11:56:26 +0200840 def create_floating_ip(self, thing, external_network_id=None,
841 port_id=None, client=None):
Ken'ichi Ohmichia112a592015-11-17 08:49:37 +0000842 """Create a floating IP and associates to a resource/port on Neutron"""
Yair Friedae0e73d2014-11-24 11:56:26 +0200843 if not external_network_id:
844 external_network_id = CONF.network.public_network_id
Yair Frieddb6c9e92014-08-06 08:53:13 +0300845 if not client:
John Warrenfbf2a892015-11-17 12:36:14 -0500846 client = self.floating_ips_client
Yair Fried1fc32a12014-08-04 09:11:30 +0300847 if not port_id:
Kirill Shileev14113572014-11-21 16:58:02 +0300848 port_id, ip4 = self._get_server_port_id_and_ip4(thing)
849 else:
850 ip4 = None
David Kranz34e88122014-12-11 15:24:05 -0500851 result = client.create_floatingip(
Yair Fried1fc32a12014-08-04 09:11:30 +0300852 floating_network_id=external_network_id,
853 port_id=port_id,
Kirill Shileev14113572014-11-21 16:58:02 +0300854 tenant_id=thing['tenant_id'],
855 fixed_ip_address=ip4
Yair Fried1fc32a12014-08-04 09:11:30 +0300856 )
857 floating_ip = net_resources.DeletableFloatingIp(
Yair Frieddb6c9e92014-08-06 08:53:13 +0300858 client=client,
Yair Fried1fc32a12014-08-04 09:11:30 +0300859 **result['floatingip'])
860 self.addCleanup(self.delete_wrapper, floating_ip.delete)
861 return floating_ip
862
863 def _associate_floating_ip(self, floating_ip, server):
Kirill Shileev14113572014-11-21 16:58:02 +0300864 port_id, _ = self._get_server_port_id_and_ip4(server)
Yair Fried1fc32a12014-08-04 09:11:30 +0300865 floating_ip.update(port_id=port_id)
866 self.assertEqual(port_id, floating_ip.port_id)
867 return floating_ip
868
869 def _disassociate_floating_ip(self, floating_ip):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000870 """:param floating_ip: type DeletableFloatingIp"""
Yair Fried1fc32a12014-08-04 09:11:30 +0300871 floating_ip.update(port_id=None)
872 self.assertIsNone(floating_ip.port_id)
873 return floating_ip
874
Yair Fried45f92952014-06-26 05:19:19 +0300875 def check_floating_ip_status(self, floating_ip, status):
Carl Baldwina754e2d2014-10-23 22:47:41 +0000876 """Verifies floatingip reaches the given status
Yair Fried45f92952014-06-26 05:19:19 +0300877
878 :param floating_ip: net_resources.DeletableFloatingIp floating IP to
879 to check status
880 :param status: target status
881 :raises: AssertionError if status doesn't match
882 """
Carl Baldwina754e2d2014-10-23 22:47:41 +0000883 def refresh():
884 floating_ip.refresh()
885 return status == floating_ip.status
886
887 tempest.test.call_until_true(refresh,
888 CONF.network.build_timeout,
889 CONF.network.build_interval)
Yair Fried45f92952014-06-26 05:19:19 +0300890 self.assertEqual(status, floating_ip.status,
891 message="FloatingIP: {fp} is at status: {cst}. "
892 "failed to reach status: {st}"
893 .format(fp=floating_ip, cst=floating_ip.status,
894 st=status))
895 LOG.info("FloatingIP: {fp} is at status: {st}"
896 .format(fp=floating_ip, st=status))
897
Yair Fried1fc32a12014-08-04 09:11:30 +0300898 def _check_tenant_network_connectivity(self, server,
899 username,
900 private_key,
901 should_connect=True,
902 servers_for_debug=None):
903 if not CONF.network.tenant_networks_reachable:
904 msg = 'Tenant networks not configured to be reachable.'
905 LOG.info(msg)
906 return
907 # The target login is assumed to have been configured for
908 # key-based authentication by cloud-init.
909 try:
Matthew Treinish71426682015-04-23 11:19:38 -0400910 for net_name, ip_addresses in six.iteritems(server['addresses']):
Yair Fried1fc32a12014-08-04 09:11:30 +0300911 for ip_address in ip_addresses:
ghanshyam807211c2014-12-18 13:21:22 +0900912 self.check_vm_connectivity(ip_address['addr'],
Yair Friedae0e73d2014-11-24 11:56:26 +0200913 username,
914 private_key,
915 should_connect=should_connect)
Yair Fried1fc32a12014-08-04 09:11:30 +0300916 except Exception as e:
917 LOG.exception('Tenant network connectivity check failed')
918 self._log_console_output(servers_for_debug)
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000919 self._log_net_info(e)
Yair Fried1fc32a12014-08-04 09:11:30 +0300920 raise
921
Yair Friedbc46f592015-11-18 16:29:34 +0200922 def _check_remote_connectivity(self, source, dest, should_succeed=True,
923 nic=None):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000924 """check ping server via source ssh connection
Yair Fried1fc32a12014-08-04 09:11:30 +0300925
926 :param source: RemoteClient: an ssh connection from which to ping
927 :param dest: and IP to ping against
928 :param should_succeed: boolean should ping succeed or not
Yair Friedbc46f592015-11-18 16:29:34 +0200929 :param nic: specific network interface to ping from
Yair Fried1fc32a12014-08-04 09:11:30 +0300930 :returns: boolean -- should_succeed == ping
931 :returns: ping is false if ping failed
932 """
933 def ping_remote():
934 try:
Yair Friedbc46f592015-11-18 16:29:34 +0200935 source.ping_host(dest, nic=nic)
Andrey Pavlov64723762015-04-29 06:24:58 +0300936 except lib_exc.SSHExecCommandFailed:
zhangguoqing6c096642016-01-04 06:17:21 +0000937 LOG.warning('Failed to ping IP: %s via a ssh connection '
938 'from: %s.' % (dest, source.ssh_client.host))
Yair Fried1fc32a12014-08-04 09:11:30 +0300939 return not should_succeed
940 return should_succeed
941
942 return tempest.test.call_until_true(ping_remote,
lanoux5fc14522015-09-21 08:17:35 +0000943 CONF.validation.ping_timeout,
Yair Fried1fc32a12014-08-04 09:11:30 +0300944 1)
945
John Warren456d9ae2016-01-12 15:36:33 -0500946 def _create_security_group(self, security_group_rules_client=None,
947 tenant_id=None,
John Warrenf9606e92015-12-10 12:12:42 -0500948 namestart='secgroup-smoke',
949 security_groups_client=None):
John Warren456d9ae2016-01-12 15:36:33 -0500950 if security_group_rules_client is None:
951 security_group_rules_client = self.security_group_rules_client
John Warrenf9606e92015-12-10 12:12:42 -0500952 if security_groups_client is None:
953 security_groups_client = self.security_groups_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300954 if tenant_id is None:
John Warrenf9606e92015-12-10 12:12:42 -0500955 tenant_id = security_groups_client.tenant_id
956 secgroup = self._create_empty_security_group(
957 namestart=namestart, client=security_groups_client,
958 tenant_id=tenant_id)
Yair Fried1fc32a12014-08-04 09:11:30 +0300959
960 # Add rules to the security group
John Warrenf9606e92015-12-10 12:12:42 -0500961 rules = self._create_loginable_secgroup_rule(
John Warren456d9ae2016-01-12 15:36:33 -0500962 security_group_rules_client=security_group_rules_client,
963 secgroup=secgroup,
John Warrenf9606e92015-12-10 12:12:42 -0500964 security_groups_client=security_groups_client)
Yair Fried1fc32a12014-08-04 09:11:30 +0300965 for rule in rules:
966 self.assertEqual(tenant_id, rule.tenant_id)
967 self.assertEqual(secgroup.id, rule.security_group_id)
968 return secgroup
969
Yair Frieddb6c9e92014-08-06 08:53:13 +0300970 def _create_empty_security_group(self, client=None, tenant_id=None,
Yair Fried1fc32a12014-08-04 09:11:30 +0300971 namestart='secgroup-smoke'):
972 """Create a security group without rules.
973
974 Default rules will be created:
975 - IPv4 egress to any
976 - IPv6 egress to any
977
978 :param tenant_id: secgroup will be created in this tenant
979 :returns: DeletableSecurityGroup -- containing the secgroup created
980 """
981 if client is None:
John Warrenf9606e92015-12-10 12:12:42 -0500982 client = self.security_groups_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300983 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000984 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300985 sg_name = data_utils.rand_name(namestart)
986 sg_desc = sg_name + " description"
987 sg_dict = dict(name=sg_name,
988 description=sg_desc)
989 sg_dict['tenant_id'] = tenant_id
David Kranz34e88122014-12-11 15:24:05 -0500990 result = client.create_security_group(**sg_dict)
Yair Fried1fc32a12014-08-04 09:11:30 +0300991 secgroup = net_resources.DeletableSecurityGroup(
992 client=client,
993 **result['security_group']
994 )
995 self.assertEqual(secgroup.name, sg_name)
996 self.assertEqual(tenant_id, secgroup.tenant_id)
997 self.assertEqual(secgroup.description, sg_desc)
998 self.addCleanup(self.delete_wrapper, secgroup.delete)
999 return secgroup
1000
Yair Frieddb6c9e92014-08-06 08:53:13 +03001001 def _default_security_group(self, client=None, tenant_id=None):
Yair Fried1fc32a12014-08-04 09:11:30 +03001002 """Get default secgroup for given tenant_id.
1003
1004 :returns: DeletableSecurityGroup -- default secgroup for given tenant
1005 """
1006 if client is None:
John Warrenf9606e92015-12-10 12:12:42 -05001007 client = self.security_groups_client
Yair Frieddb6c9e92014-08-06 08:53:13 +03001008 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +00001009 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001010 sgs = [
1011 sg for sg in client.list_security_groups().values()[0]
1012 if sg['tenant_id'] == tenant_id and sg['name'] == 'default'
1013 ]
1014 msg = "No default security group for tenant %s." % (tenant_id)
1015 self.assertTrue(len(sgs) > 0, msg)
Yair Fried1fc32a12014-08-04 09:11:30 +03001016 return net_resources.DeletableSecurityGroup(client=client,
1017 **sgs[0])
1018
John Warren456d9ae2016-01-12 15:36:33 -05001019 def _create_security_group_rule(self, secgroup=None,
1020 sec_group_rules_client=None,
John Warrenf9606e92015-12-10 12:12:42 -05001021 tenant_id=None,
1022 security_groups_client=None, **kwargs):
Yair Fried1fc32a12014-08-04 09:11:30 +03001023 """Create a rule from a dictionary of rule parameters.
1024
1025 Create a rule in a secgroup. if secgroup not defined will search for
1026 default secgroup in tenant_id.
1027
1028 :param secgroup: type DeletableSecurityGroup.
Yair Fried1fc32a12014-08-04 09:11:30 +03001029 :param tenant_id: if secgroup not passed -- the tenant in which to
1030 search for default secgroup
1031 :param kwargs: a dictionary containing rule parameters:
1032 for example, to allow incoming ssh:
1033 rule = {
1034 direction: 'ingress'
1035 protocol:'tcp',
1036 port_range_min: 22,
1037 port_range_max: 22
1038 }
1039 """
John Warren456d9ae2016-01-12 15:36:33 -05001040 if sec_group_rules_client is None:
1041 sec_group_rules_client = self.security_group_rules_client
John Warrenf9606e92015-12-10 12:12:42 -05001042 if security_groups_client is None:
1043 security_groups_client = self.security_groups_client
Yair Frieddb6c9e92014-08-06 08:53:13 +03001044 if not tenant_id:
John Warrenf9606e92015-12-10 12:12:42 -05001045 tenant_id = security_groups_client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001046 if secgroup is None:
John Warrenf9606e92015-12-10 12:12:42 -05001047 secgroup = self._default_security_group(
1048 client=security_groups_client, tenant_id=tenant_id)
Yair Fried1fc32a12014-08-04 09:11:30 +03001049
1050 ruleset = dict(security_group_id=secgroup.id,
1051 tenant_id=secgroup.tenant_id)
1052 ruleset.update(kwargs)
1053
John Warren456d9ae2016-01-12 15:36:33 -05001054 sg_rule = sec_group_rules_client.create_security_group_rule(**ruleset)
Yair Fried1fc32a12014-08-04 09:11:30 +03001055 sg_rule = net_resources.DeletableSecurityGroupRule(
John Warren456d9ae2016-01-12 15:36:33 -05001056 client=sec_group_rules_client,
Yair Fried1fc32a12014-08-04 09:11:30 +03001057 **sg_rule['security_group_rule']
1058 )
Yair Fried1fc32a12014-08-04 09:11:30 +03001059 self.assertEqual(secgroup.tenant_id, sg_rule.tenant_id)
1060 self.assertEqual(secgroup.id, sg_rule.security_group_id)
1061
1062 return sg_rule
1063
John Warren456d9ae2016-01-12 15:36:33 -05001064 def _create_loginable_secgroup_rule(self, security_group_rules_client=None,
1065 secgroup=None,
John Warrenf9606e92015-12-10 12:12:42 -05001066 security_groups_client=None):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001067 """Create loginable security group rule
1068
1069 These rules are intended to permit inbound ssh and icmp
Yair Fried1fc32a12014-08-04 09:11:30 +03001070 traffic from all sources, so no group_id is provided.
1071 Setting a group_id would only permit traffic from ports
1072 belonging to the same security group.
1073 """
1074
John Warren456d9ae2016-01-12 15:36:33 -05001075 if security_group_rules_client is None:
1076 security_group_rules_client = self.security_group_rules_client
John Warrenf9606e92015-12-10 12:12:42 -05001077 if security_groups_client is None:
1078 security_groups_client = self.security_groups_client
Yair Fried1fc32a12014-08-04 09:11:30 +03001079 rules = []
1080 rulesets = [
1081 dict(
1082 # ssh
1083 protocol='tcp',
1084 port_range_min=22,
1085 port_range_max=22,
1086 ),
1087 dict(
1088 # ping
1089 protocol='icmp',
Andreas Scheuring887ca8e2015-02-03 17:56:12 +01001090 ),
1091 dict(
1092 # ipv6-icmp for ping6
1093 protocol='icmp',
1094 ethertype='IPv6',
Yair Fried1fc32a12014-08-04 09:11:30 +03001095 )
1096 ]
John Warren456d9ae2016-01-12 15:36:33 -05001097 sec_group_rules_client = security_group_rules_client
Yair Fried1fc32a12014-08-04 09:11:30 +03001098 for ruleset in rulesets:
1099 for r_direction in ['ingress', 'egress']:
1100 ruleset['direction'] = r_direction
1101 try:
1102 sg_rule = self._create_security_group_rule(
John Warren456d9ae2016-01-12 15:36:33 -05001103 sec_group_rules_client=sec_group_rules_client,
1104 secgroup=secgroup,
John Warrenf9606e92015-12-10 12:12:42 -05001105 security_groups_client=security_groups_client,
1106 **ruleset)
Masayuki Igawad9388762015-01-20 14:56:42 +09001107 except lib_exc.Conflict as ex:
Yair Fried1fc32a12014-08-04 09:11:30 +03001108 # if rule already exist - skip rule and continue
1109 msg = 'Security group rule already exists'
1110 if msg not in ex._error_string:
1111 raise ex
1112 else:
1113 self.assertEqual(r_direction, sg_rule.direction)
1114 rules.append(sg_rule)
1115
1116 return rules
1117
Yair Frieddb6c9e92014-08-06 08:53:13 +03001118 def _get_router(self, client=None, tenant_id=None):
Yair Fried1fc32a12014-08-04 09:11:30 +03001119 """Retrieve a router for the given tenant id.
1120
1121 If a public router has been configured, it will be returned.
1122
1123 If a public router has not been configured, but a public
1124 network has, a tenant router will be created and returned that
1125 routes traffic to the public network.
1126 """
Yair Frieddb6c9e92014-08-06 08:53:13 +03001127 if not client:
1128 client = self.network_client
1129 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +00001130 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001131 router_id = CONF.network.public_router_id
1132 network_id = CONF.network.public_network_id
1133 if router_id:
David Kranzca4c7e72015-05-27 11:39:19 -04001134 body = client.show_router(router_id)
Sergey Shnaidman5e9c8fd2014-09-30 18:31:43 +04001135 return net_resources.AttributeDict(**body['router'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001136 elif network_id:
Yair Frieddb6c9e92014-08-06 08:53:13 +03001137 router = self._create_router(client, tenant_id)
Yair Fried1fc32a12014-08-04 09:11:30 +03001138 router.set_gateway(network_id)
1139 return router
1140 else:
1141 raise Exception("Neither of 'public_router_id' or "
1142 "'public_network_id' has been defined.")
1143
Yair Frieddb6c9e92014-08-06 08:53:13 +03001144 def _create_router(self, client=None, tenant_id=None,
1145 namestart='router-smoke'):
1146 if not client:
1147 client = self.network_client
1148 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +00001149 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001150 name = data_utils.rand_name(namestart)
David Kranz34e88122014-12-11 15:24:05 -05001151 result = client.create_router(name=name,
1152 admin_state_up=True,
1153 tenant_id=tenant_id)
Yair Frieddb6c9e92014-08-06 08:53:13 +03001154 router = net_resources.DeletableRouter(client=client,
Yair Fried1fc32a12014-08-04 09:11:30 +03001155 **result['router'])
1156 self.assertEqual(router.name, name)
1157 self.addCleanup(self.delete_wrapper, router.delete)
1158 return router
1159
Alok Maurya6384bbb2014-07-13 06:44:29 -07001160 def _update_router_admin_state(self, router, admin_state_up):
1161 router.update(admin_state_up=admin_state_up)
1162 self.assertEqual(admin_state_up, router.admin_state_up)
1163
John Warren94d8faf2015-09-15 12:22:24 -04001164 def create_networks(self, client=None, networks_client=None,
John Warren3961acd2015-10-02 14:38:53 -04001165 subnets_client=None, tenant_id=None,
1166 dns_nameservers=None):
Yair Fried1fc32a12014-08-04 09:11:30 +03001167 """Create a network with a subnet connected to a router.
1168
David Shrewsbury9bac3662014-08-07 15:07:01 -04001169 The baremetal driver is a special case since all nodes are
1170 on the same shared network.
1171
Yair Fried413bf2d2014-11-19 17:07:11 +02001172 :param client: network client to create resources with.
1173 :param tenant_id: id of tenant to create resources in.
1174 :param dns_nameservers: list of dns servers to send to subnet.
Yair Fried1fc32a12014-08-04 09:11:30 +03001175 :returns: network, subnet, router
1176 """
David Shrewsbury9bac3662014-08-07 15:07:01 -04001177 if CONF.baremetal.driver_enabled:
1178 # NOTE(Shrews): This exception is for environments where tenant
1179 # credential isolation is available, but network separation is
1180 # not (the current baremetal case). Likely can be removed when
1181 # test account mgmt is reworked:
1182 # https://blueprints.launchpad.net/tempest/+spec/test-accounts
Adam Gandelman878a5fd2015-03-30 14:33:36 -07001183 if not CONF.compute.fixed_network_name:
1184 m = 'fixed_network_name must be specified in config'
1185 raise exceptions.InvalidConfiguration(m)
David Shrewsbury9bac3662014-08-07 15:07:01 -04001186 network = self._get_network_by_name(
1187 CONF.compute.fixed_network_name)
1188 router = None
1189 subnet = None
1190 else:
John Warren94d8faf2015-09-15 12:22:24 -04001191 network = self._create_network(
1192 client=client, networks_client=networks_client,
1193 tenant_id=tenant_id)
Yair Frieddb6c9e92014-08-06 08:53:13 +03001194 router = self._get_router(client=client, tenant_id=tenant_id)
Yair Fried413bf2d2014-11-19 17:07:11 +02001195
John Warren3961acd2015-10-02 14:38:53 -04001196 subnet_kwargs = dict(network=network, client=client,
1197 subnets_client=subnets_client)
Yair Fried413bf2d2014-11-19 17:07:11 +02001198 # use explicit check because empty list is a valid option
1199 if dns_nameservers is not None:
1200 subnet_kwargs['dns_nameservers'] = dns_nameservers
1201 subnet = self._create_subnet(**subnet_kwargs)
David Shrewsbury9bac3662014-08-07 15:07:01 -04001202 subnet.add_to_router(router.id)
Yair Fried1fc32a12014-08-04 09:11:30 +03001203 return network, subnet, router
1204
1205
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001206# power/provision states as of icehouse
1207class BaremetalPowerStates(object):
1208 """Possible power states of an Ironic node."""
1209 POWER_ON = 'power on'
1210 POWER_OFF = 'power off'
1211 REBOOT = 'rebooting'
1212 SUSPEND = 'suspended'
1213
1214
1215class BaremetalProvisionStates(object):
1216 """Possible provision states of an Ironic node."""
1217 NOSTATE = None
1218 INIT = 'initializing'
1219 ACTIVE = 'active'
1220 BUILDING = 'building'
1221 DEPLOYWAIT = 'wait call-back'
1222 DEPLOYING = 'deploying'
1223 DEPLOYFAIL = 'deploy failed'
1224 DEPLOYDONE = 'deploy complete'
1225 DELETING = 'deleting'
1226 DELETED = 'deleted'
1227 ERROR = 'error'
1228
1229
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001230class BaremetalScenarioTest(ScenarioTest):
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001231
1232 credentials = ['primary', 'admin']
1233
Adam Gandelman4a48a602014-03-20 18:23:18 -07001234 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001235 def skip_checks(cls):
1236 super(BaremetalScenarioTest, cls).skip_checks()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001237 if (not CONF.service_available.ironic or
1238 not CONF.baremetal.driver_enabled):
1239 msg = 'Ironic not available or Ironic compute driver not enabled'
1240 raise cls.skipException(msg)
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001241
1242 @classmethod
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001243 def setup_clients(cls):
1244 super(BaremetalScenarioTest, cls).setup_clients()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001245
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001246 cls.baremetal_client = cls.admin_manager.baremetal_client
Adam Gandelman4a48a602014-03-20 18:23:18 -07001247
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001248 @classmethod
1249 def resource_setup(cls):
1250 super(BaremetalScenarioTest, cls).resource_setup()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001251 # allow any issues obtaining the node list to raise early
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001252 cls.baremetal_client.list_nodes()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001253
1254 def _node_state_timeout(self, node_id, state_attr,
1255 target_states, timeout=10, interval=1):
1256 if not isinstance(target_states, list):
1257 target_states = [target_states]
1258
1259 def check_state():
1260 node = self.get_node(node_id=node_id)
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001261 if node.get(state_attr) in target_states:
Adam Gandelman4a48a602014-03-20 18:23:18 -07001262 return True
1263 return False
1264
1265 if not tempest.test.call_until_true(
1266 check_state, timeout, interval):
1267 msg = ("Timed out waiting for node %s to reach %s state(s) %s" %
1268 (node_id, state_attr, target_states))
1269 raise exceptions.TimeoutException(msg)
1270
1271 def wait_provisioning_state(self, node_id, state, timeout):
1272 self._node_state_timeout(
1273 node_id=node_id, state_attr='provision_state',
1274 target_states=state, timeout=timeout)
1275
1276 def wait_power_state(self, node_id, state):
1277 self._node_state_timeout(
1278 node_id=node_id, state_attr='power_state',
1279 target_states=state, timeout=CONF.baremetal.power_timeout)
1280
1281 def wait_node(self, instance_id):
1282 """Waits for a node to be associated with instance_id."""
Zhi Kun Liu4a8d1ea2014-04-15 22:08:21 -05001283
Adam Gandelman4a48a602014-03-20 18:23:18 -07001284 def _get_node():
1285 node = None
1286 try:
1287 node = self.get_node(instance_id=instance_id)
Masayuki Igawabfa07602015-01-20 18:47:17 +09001288 except lib_exc.NotFound:
Adam Gandelman4a48a602014-03-20 18:23:18 -07001289 pass
1290 return node is not None
1291
1292 if not tempest.test.call_until_true(
1293 _get_node, CONF.baremetal.association_timeout, 1):
1294 msg = ('Timed out waiting to get Ironic node by instance id %s'
1295 % instance_id)
1296 raise exceptions.TimeoutException(msg)
1297
1298 def get_node(self, node_id=None, instance_id=None):
1299 if node_id:
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001300 _, body = self.baremetal_client.show_node(node_id)
1301 return body
Adam Gandelman4a48a602014-03-20 18:23:18 -07001302 elif instance_id:
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001303 _, body = self.baremetal_client.show_node_by_instance_uuid(
1304 instance_id)
1305 if body['nodes']:
1306 return body['nodes'][0]
Adam Gandelman4a48a602014-03-20 18:23:18 -07001307
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001308 def get_ports(self, node_uuid):
Adam Gandelman4a48a602014-03-20 18:23:18 -07001309 ports = []
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001310 _, body = self.baremetal_client.list_node_ports(node_uuid)
1311 for port in body['ports']:
1312 _, p = self.baremetal_client.show_port(port['uuid'])
1313 ports.append(p)
Adam Gandelman4a48a602014-03-20 18:23:18 -07001314 return ports
1315
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001316 def add_keypair(self):
1317 self.keypair = self.create_keypair()
1318
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001319 def boot_instance(self):
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001320 self.instance = self.create_server(
lanoux5fc14522015-09-21 08:17:35 +00001321 key_name=self.keypair['name'])
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001322
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001323 self.wait_node(self.instance['id'])
1324 self.node = self.get_node(instance_id=self.instance['id'])
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001325
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001326 self.wait_power_state(self.node['uuid'], BaremetalPowerStates.POWER_ON)
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001327
1328 self.wait_provisioning_state(
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001329 self.node['uuid'],
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001330 [BaremetalProvisionStates.DEPLOYWAIT,
1331 BaremetalProvisionStates.ACTIVE],
1332 timeout=15)
1333
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001334 self.wait_provisioning_state(self.node['uuid'],
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001335 BaremetalProvisionStates.ACTIVE,
1336 timeout=CONF.baremetal.active_timeout)
1337
Ken'ichi Ohmichi0eb153c2015-07-13 02:18:25 +00001338 waiters.wait_for_server_status(self.servers_client,
1339 self.instance['id'], 'ACTIVE')
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001340 self.node = self.get_node(instance_id=self.instance['id'])
ghanshyam0f825252015-08-25 16:02:50 +09001341 self.instance = (self.servers_client.show_server(self.instance['id'])
1342 ['server'])
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001343
1344 def terminate_instance(self):
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001345 self.servers_client.delete_server(self.instance['id'])
1346 self.wait_power_state(self.node['uuid'],
1347 BaremetalPowerStates.POWER_OFF)
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001348 self.wait_provisioning_state(
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001349 self.node['uuid'],
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001350 BaremetalProvisionStates.NOSTATE,
1351 timeout=CONF.baremetal.unprovision_timeout)
1352
Adam Gandelman4a48a602014-03-20 18:23:18 -07001353
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001354class EncryptionScenarioTest(ScenarioTest):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001355 """Base class for encryption scenario tests"""
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001356
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001357 credentials = ['primary', 'admin']
David Kranz4cc852b2015-03-09 14:57:11 -04001358
1359 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001360 def setup_clients(cls):
1361 super(EncryptionScenarioTest, cls).setup_clients()
Ivan Kolodyazhnybcfc32e2015-08-06 13:31:36 +03001362 if CONF.volume_feature_enabled.api_v1:
1363 cls.admin_volume_types_client = cls.os_adm.volume_types_client
1364 else:
1365 cls.admin_volume_types_client = cls.os_adm.volume_types_v2_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001366
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001367 def create_volume_type(self, client=None, name=None):
1368 if not client:
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001369 client = self.admin_volume_types_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001370 if not name:
1371 name = 'generic'
Ken'ichi Ohmichi6ded8df2015-03-23 02:00:19 +00001372 randomized_name = data_utils.rand_name('scenario-type-' + name)
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001373 LOG.debug("Creating a volume type: %s", randomized_name)
Joseph Lanoux6809bab2014-12-18 14:57:18 +00001374 body = client.create_volume_type(
lei zhang83c4bbd2015-11-27 00:35:21 +08001375 name=randomized_name)['volume_type']
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001376 self.assertIn('id', body)
1377 self.addCleanup(client.delete_volume_type, body['id'])
1378 return body
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001379
1380 def create_encryption_type(self, client=None, type_id=None, provider=None,
1381 key_size=None, cipher=None,
1382 control_location=None):
1383 if not client:
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001384 client = self.admin_volume_types_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001385 if not type_id:
1386 volume_type = self.create_volume_type()
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001387 type_id = volume_type['id']
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001388 LOG.debug("Creating an encryption type for volume type: %s", type_id)
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001389 client.create_encryption_type(
1390 type_id, provider=provider, key_size=key_size, cipher=cipher,
John Warrend053ded2015-08-13 15:22:48 +00001391 control_location=control_location)['encryption']
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001392
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001393
Masayuki Igawa0870db52015-09-18 21:08:36 +09001394class ObjectStorageScenarioTest(ScenarioTest):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001395 """Provide harness to do Object Storage scenario tests.
Chris Dent0d494112014-08-26 13:48:30 +01001396
1397 Subclasses implement the tests that use the methods provided by this
1398 class.
1399 """
1400
1401 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001402 def skip_checks(cls):
Masayuki Igawa0870db52015-09-18 21:08:36 +09001403 super(ObjectStorageScenarioTest, cls).skip_checks()
Chris Dent0d494112014-08-26 13:48:30 +01001404 if not CONF.service_available.swift:
1405 skip_msg = ("%s skipped as swift is not available" %
1406 cls.__name__)
1407 raise cls.skipException(skip_msg)
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001408
1409 @classmethod
1410 def setup_credentials(cls):
Masayuki Igawa60ea6c52014-10-15 17:32:14 +09001411 cls.set_network_resources()
Masayuki Igawa0870db52015-09-18 21:08:36 +09001412 super(ObjectStorageScenarioTest, cls).setup_credentials()
Matthew Treinish4a596932015-03-06 20:37:01 -05001413 operator_role = CONF.object_storage.operator_role
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +01001414 cls.os_operator = cls.get_client_manager(roles=[operator_role])
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001415
1416 @classmethod
1417 def setup_clients(cls):
Masayuki Igawa0870db52015-09-18 21:08:36 +09001418 super(ObjectStorageScenarioTest, cls).setup_clients()
Chris Dent0d494112014-08-26 13:48:30 +01001419 # Clients for Swift
Matthew Treinish8f268292015-02-24 20:01:36 -05001420 cls.account_client = cls.os_operator.account_client
1421 cls.container_client = cls.os_operator.container_client
1422 cls.object_client = cls.os_operator.object_client
Chris Dent0d494112014-08-26 13:48:30 +01001423
Chris Dentde456a12014-09-10 12:41:15 +01001424 def get_swift_stat(self):
Chris Dent0d494112014-08-26 13:48:30 +01001425 """get swift status for our user account."""
1426 self.account_client.list_account_containers()
1427 LOG.debug('Swift status information obtained successfully')
1428
Chris Dentde456a12014-09-10 12:41:15 +01001429 def create_container(self, container_name=None):
Chris Dent0d494112014-08-26 13:48:30 +01001430 name = container_name or data_utils.rand_name(
1431 'swift-scenario-container')
1432 self.container_client.create_container(name)
1433 # look for the container to assure it is created
Chris Dentde456a12014-09-10 12:41:15 +01001434 self.list_and_check_container_objects(name)
Chris Dent0d494112014-08-26 13:48:30 +01001435 LOG.debug('Container %s created' % (name))
Chris Dent1d4313a2014-10-28 12:16:48 +00001436 self.addCleanup(self.delete_wrapper,
1437 self.container_client.delete_container,
1438 name)
Chris Dent0d494112014-08-26 13:48:30 +01001439 return name
1440
Chris Dentde456a12014-09-10 12:41:15 +01001441 def delete_container(self, container_name):
Chris Dent0d494112014-08-26 13:48:30 +01001442 self.container_client.delete_container(container_name)
1443 LOG.debug('Container %s deleted' % (container_name))
1444
Chris Dentde456a12014-09-10 12:41:15 +01001445 def upload_object_to_container(self, container_name, obj_name=None):
Chris Dent0d494112014-08-26 13:48:30 +01001446 obj_name = obj_name or data_utils.rand_name('swift-scenario-object')
1447 obj_data = data_utils.arbitrary_string()
1448 self.object_client.create_object(container_name, obj_name, obj_data)
Chris Dent1d4313a2014-10-28 12:16:48 +00001449 self.addCleanup(self.delete_wrapper,
1450 self.object_client.delete_object,
1451 container_name,
1452 obj_name)
Chris Dent0d494112014-08-26 13:48:30 +01001453 return obj_name, obj_data
1454
Chris Dentde456a12014-09-10 12:41:15 +01001455 def delete_object(self, container_name, filename):
Chris Dent0d494112014-08-26 13:48:30 +01001456 self.object_client.delete_object(container_name, filename)
Chris Dentde456a12014-09-10 12:41:15 +01001457 self.list_and_check_container_objects(container_name,
1458 not_present_obj=[filename])
Chris Dent0d494112014-08-26 13:48:30 +01001459
Chris Dentde456a12014-09-10 12:41:15 +01001460 def list_and_check_container_objects(self, container_name,
1461 present_obj=None,
1462 not_present_obj=None):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001463 # List objects for a given container and assert which are present and
1464 # which are not.
Ghanshyam2a180b82014-06-16 13:54:22 +09001465 if present_obj is None:
1466 present_obj = []
1467 if not_present_obj is None:
1468 not_present_obj = []
Chris Dent0d494112014-08-26 13:48:30 +01001469 _, object_list = self.container_client.list_container_contents(
1470 container_name)
1471 if present_obj:
1472 for obj in present_obj:
1473 self.assertIn(obj, object_list)
1474 if not_present_obj:
1475 for obj in not_present_obj:
1476 self.assertNotIn(obj, object_list)
1477
Chris Dentde456a12014-09-10 12:41:15 +01001478 def change_container_acl(self, container_name, acl):
Chris Dent0d494112014-08-26 13:48:30 +01001479 metadata_param = {'metadata_prefix': 'x-container-',
1480 'metadata': {'read': acl}}
1481 self.container_client.update_container_metadata(container_name,
1482 **metadata_param)
1483 resp, _ = self.container_client.list_container_metadata(container_name)
1484 self.assertEqual(resp['x-container-read'], acl)
1485
Chris Dentde456a12014-09-10 12:41:15 +01001486 def download_and_verify(self, container_name, obj_name, expected_data):
Chris Dent0d494112014-08-26 13:48:30 +01001487 _, obj = self.object_client.get_object(container_name, obj_name)
1488 self.assertEqual(obj, expected_data)