blob: 0c160567067232eddc33d2156103cf385517816d [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
Sean Dague6dbc6da2013-05-08 17:49:46 -040023
lanoux5fc14522015-09-21 08:17:35 +000024from tempest.common import compute
Fei Long Wangd39431f2015-05-14 11:30:48 +120025from tempest.common.utils import data_utils
Masayuki Igawa4ded9f02014-02-17 15:05:59 +090026from tempest.common.utils.linux import remote_client
Ken'ichi Ohmichi0eb153c2015-07-13 02:18:25 +000027from tempest.common import waiters
Matthew Treinish6c072292014-01-29 19:15:52 +000028from tempest import config
Giulio Fidente92f77192013-08-26 17:13:28 +020029from tempest import exceptions
Andrea Frittoli (andreaf)db9672e2016-02-23 14:07:24 -050030from tempest.lib.common.utils import misc as misc_utils
31from tempest.lib import exceptions as lib_exc
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
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +000069 cls.routers_client = cls.manager.routers_client
John Warren3961acd2015-10-02 14:38:53 -040070 cls.subnets_client = cls.manager.subnets_client
John Warrenfbf2a892015-11-17 12:36:14 -050071 cls.floating_ips_client = cls.manager.floating_ips_client
John Warrenf9606e92015-12-10 12:12:42 -050072 cls.security_groups_client = cls.manager.security_groups_client
John Warren456d9ae2016-01-12 15:36:33 -050073 cls.security_group_rules_client = (
74 cls.manager.security_group_rules_client)
Masayuki Igawabc6fe8d2014-08-29 16:50:01 +090075 # Heat client
76 cls.orchestration_client = cls.manager.orchestration_client
Andrea Frittoli2e733b52014-07-16 14:12:11 +010077
Ivan Kolodyazhnybcfc32e2015-08-06 13:31:36 +030078 if CONF.volume_feature_enabled.api_v1:
79 cls.volumes_client = cls.manager.volumes_client
80 cls.snapshots_client = cls.manager.snapshots_client
81 else:
82 cls.volumes_client = cls.manager.volumes_v2_client
83 cls.snapshots_client = cls.manager.snapshots_v2_client
84
Andrea Frittoli247058f2014-07-16 16:09:22 +010085 # ## Methods to handle sync and async deletes
86
87 def setUp(self):
88 super(ScenarioTest, self).setUp()
89 self.cleanup_waits = []
90 # NOTE(mtreinish) This is safe to do in setUp instead of setUp class
91 # because scenario tests in the same test class should not share
92 # resources. If resources were shared between test cases then it
93 # should be a single scenario test instead of multiples.
94
95 # NOTE(yfried): this list is cleaned at the end of test_methods and
96 # not at the end of the class
97 self.addCleanup(self._wait_for_cleanups)
98
Yair Fried1fc32a12014-08-04 09:11:30 +030099 def delete_wrapper(self, delete_thing, *args, **kwargs):
Andrea Frittoli247058f2014-07-16 16:09:22 +0100100 """Ignores NotFound exceptions for delete operations.
101
Yair Fried1fc32a12014-08-04 09:11:30 +0300102 @param delete_thing: delete method of a resource. method will be
103 executed as delete_thing(*args, **kwargs)
104
Andrea Frittoli247058f2014-07-16 16:09:22 +0100105 """
106 try:
107 # Tempest clients return dicts, so there is no common delete
108 # method available. Using a callable instead
Yair Fried1fc32a12014-08-04 09:11:30 +0300109 delete_thing(*args, **kwargs)
Masayuki Igawabfa07602015-01-20 18:47:17 +0900110 except lib_exc.NotFound:
Andrea Frittoli247058f2014-07-16 16:09:22 +0100111 # If the resource is already missing, mission accomplished.
112 pass
113
114 def addCleanup_with_wait(self, waiter_callable, thing_id, thing_id_param,
Ghanshyam2a180b82014-06-16 13:54:22 +0900115 cleanup_callable, cleanup_args=None,
Ken'ichi Ohmichie91a0c62015-08-13 02:09:16 +0000116 cleanup_kwargs=None, waiter_client=None):
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700117 """Adds wait for async resource deletion at the end of cleanups
Andrea Frittoli247058f2014-07-16 16:09:22 +0100118
119 @param waiter_callable: callable to wait for the resource to delete
Ken'ichi Ohmichie91a0c62015-08-13 02:09:16 +0000120 with the following waiter_client if specified.
Andrea Frittoli247058f2014-07-16 16:09:22 +0100121 @param thing_id: the id of the resource to be cleaned-up
122 @param thing_id_param: the name of the id param in the waiter
123 @param cleanup_callable: method to load pass to self.addCleanup with
124 the following *cleanup_args, **cleanup_kwargs.
125 usually a delete method.
126 """
Ghanshyam2a180b82014-06-16 13:54:22 +0900127 if cleanup_args is None:
128 cleanup_args = []
129 if cleanup_kwargs is None:
130 cleanup_kwargs = {}
Andrea Frittoli247058f2014-07-16 16:09:22 +0100131 self.addCleanup(cleanup_callable, *cleanup_args, **cleanup_kwargs)
132 wait_dict = {
133 'waiter_callable': waiter_callable,
134 thing_id_param: thing_id
135 }
Ken'ichi Ohmichie91a0c62015-08-13 02:09:16 +0000136 if waiter_client:
137 wait_dict['client'] = waiter_client
Andrea Frittoli247058f2014-07-16 16:09:22 +0100138 self.cleanup_waits.append(wait_dict)
139
140 def _wait_for_cleanups(self):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000141 # To handle async delete actions, a list of waits is added
142 # which will be iterated over as the last step of clearing the
143 # cleanup queue. That way all the delete calls are made up front
144 # and the tests won't succeed unless the deletes are eventually
145 # successful. This is the same basic approach used in the api tests to
146 # limit cleanup execution time except here it is multi-resource,
147 # because of the nature of the scenario tests.
Andrea Frittoli247058f2014-07-16 16:09:22 +0100148 for wait in self.cleanup_waits:
149 waiter_callable = wait.pop('waiter_callable')
150 waiter_callable(**wait)
151
152 # ## Test functions library
153 #
154 # The create_[resource] functions only return body and discard the
155 # resp part which is not used in scenario tests
156
Yair Frieddb6c9e92014-08-06 08:53:13 +0300157 def create_keypair(self, client=None):
158 if not client:
159 client = self.keypairs_client
Andrea Frittoli247058f2014-07-16 16:09:22 +0100160 name = data_utils.rand_name(self.__class__.__name__)
161 # We don't need to create a keypair by pubkey in scenario
Ken'ichi Ohmichie364bce2015-07-17 10:27:59 +0000162 body = client.create_keypair(name=name)
Yair Frieddb6c9e92014-08-06 08:53:13 +0300163 self.addCleanup(client.delete_keypair, name)
ghanshyamdee01f22015-08-17 11:41:47 +0900164 return body['keypair']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100165
Anusha Ramineni9aaef8b2016-01-19 10:56:40 +0530166 def create_server(self, name=None, image_id=None, flavor=None,
lanoux5fc14522015-09-21 08:17:35 +0000167 validatable=False, wait_until=None,
168 wait_on_delete=True, clients=None, **kwargs):
169 """Wrapper utility that returns a test server.
Andrea Frittoli247058f2014-07-16 16:09:22 +0100170
lanoux5fc14522015-09-21 08:17:35 +0000171 This wrapper utility calls the common create test server and
172 returns a test server. The purpose of this wrapper is to minimize
173 the impact on the code of the tests already using this
174 function.
Andrea Frittoli247058f2014-07-16 16:09:22 +0100175 """
Andrea Frittoli247058f2014-07-16 16:09:22 +0100176
lanoux5fc14522015-09-21 08:17:35 +0000177 # NOTE(jlanoux): As a first step, ssh checks in the scenario
178 # tests need to be run regardless of the run_validation and
179 # validatable parameters and thus until the ssh validation job
180 # becomes voting in CI. The test resources management and IP
181 # association are taken care of in the scenario tests.
182 # Therefore, the validatable parameter is set to false in all
183 # those tests. In this way create_server just return a standard
184 # server and the scenario tests always perform ssh checks.
185
186 # Needed for the cross_tenant_traffic test:
187 if clients is None:
188 clients = self.manager
189
190 vnic_type = CONF.network.port_vnic_type
191
192 # If vnic_type is configured create port for
193 # every network
194 if vnic_type:
195 ports = []
196 networks = []
197 create_port_body = {'binding:vnic_type': vnic_type,
198 'namestart': 'port-smoke'}
199 if kwargs:
200 # Convert security group names to security group ids
201 # to pass to create_port
202 if 'security_groups' in kwargs:
203 security_groups =\
John Warrenf9606e92015-12-10 12:12:42 -0500204 clients.security_groups_client.list_security_groups(
lanoux5fc14522015-09-21 08:17:35 +0000205 ).get('security_groups')
206 sec_dict = dict([(s['name'], s['id'])
207 for s in security_groups])
208
209 sec_groups_names = [s['name'] for s in kwargs.pop(
210 'security_groups')]
211 security_groups_ids = [sec_dict[s]
212 for s in sec_groups_names]
213
214 if security_groups_ids:
215 create_port_body[
216 'security_groups'] = security_groups_ids
217 networks = kwargs.pop('networks')
218
219 # If there are no networks passed to us we look up
220 # for the tenant's private networks and create a port
221 # if there is only one private network. The same behaviour
222 # as we would expect when passing the call to the clients
223 # with no networks
224 if not networks:
225 networks = clients.networks_client.list_networks(
226 filters={'router:external': False})
227 self.assertEqual(1, len(networks),
228 "There is more than one"
229 " network for the tenant")
230 for net in networks:
231 net_id = net['uuid']
232 port = self._create_port(network_id=net_id,
233 client=clients.ports_client,
234 **create_port_body)
235 ports.append({'port': port.id})
236 if ports:
237 kwargs['networks'] = ports
238 self.ports = ports
239
240 tenant_network = self.get_tenant_network()
241
242 body, servers = compute.create_test_server(
243 clients,
244 tenant_network=tenant_network,
245 wait_until=wait_until,
Anusha Ramineni9aaef8b2016-01-19 10:56:40 +0530246 name=name, flavor=flavor,
247 image_id=image_id, **kwargs)
lanoux5fc14522015-09-21 08:17:35 +0000248
249 # TODO(jlanoux) Move wait_on_delete in compute.py
Andrea Frittoli247058f2014-07-16 16:09:22 +0100250 if wait_on_delete:
Ken'ichi Ohmichie91a0c62015-08-13 02:09:16 +0000251 self.addCleanup(waiters.wait_for_server_termination,
lanoux5fc14522015-09-21 08:17:35 +0000252 clients.servers_client,
253 body['id'])
254
Andrea Frittoli247058f2014-07-16 16:09:22 +0100255 self.addCleanup_with_wait(
Ken'ichi Ohmichie91a0c62015-08-13 02:09:16 +0000256 waiter_callable=waiters.wait_for_server_termination,
lanoux5fc14522015-09-21 08:17:35 +0000257 thing_id=body['id'], thing_id_param='server_id',
Andrea Frittoli247058f2014-07-16 16:09:22 +0100258 cleanup_callable=self.delete_wrapper,
lanoux5fc14522015-09-21 08:17:35 +0000259 cleanup_args=[clients.servers_client.delete_server, body['id']],
260 waiter_client=clients.servers_client)
261 server = clients.servers_client.show_server(body['id'])['server']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100262 return server
263
Markus Zoeller3d2a21c2015-02-27 12:04:22 +0100264 def create_volume(self, size=None, name=None, snapshot_id=None,
Andrea Frittoli247058f2014-07-16 16:09:22 +0100265 imageRef=None, volume_type=None, wait_on_delete=True):
266 if name is None:
267 name = data_utils.rand_name(self.__class__.__name__)
Ghanshyam8fc0ed22015-12-18 10:25:14 +0900268 kwargs = {'display_name': name,
269 'snapshot_id': snapshot_id,
270 'imageRef': imageRef,
271 'volume_type': volume_type}
272 if size is not None:
273 kwargs.update({'size': size})
274 volume = self.volumes_client.create_volume(**kwargs)['volume']
Matt Riedemanne85c2702014-09-10 11:50:13 -0700275
Andrea Frittoli247058f2014-07-16 16:09:22 +0100276 if wait_on_delete:
277 self.addCleanup(self.volumes_client.wait_for_resource_deletion,
278 volume['id'])
Matt Riedemanne85c2702014-09-10 11:50:13 -0700279 self.addCleanup(self.delete_wrapper,
280 self.volumes_client.delete_volume, volume['id'])
281 else:
282 self.addCleanup_with_wait(
283 waiter_callable=self.volumes_client.wait_for_resource_deletion,
284 thing_id=volume['id'], thing_id_param='id',
285 cleanup_callable=self.delete_wrapper,
286 cleanup_args=[self.volumes_client.delete_volume, volume['id']])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100287
Ivan Kolodyazhnybcfc32e2015-08-06 13:31:36 +0300288 # NOTE(e0ne): Cinder API v2 uses name instead of display_name
289 if 'display_name' in volume:
290 self.assertEqual(name, volume['display_name'])
291 else:
292 self.assertEqual(name, volume['name'])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100293 self.volumes_client.wait_for_volume_status(volume['id'], 'available')
294 # The volume retrieved on creation has a non-up-to-date status.
295 # Retrieval after it becomes active ensures correct details.
John Warren6177c9e2015-08-19 20:00:17 +0000296 volume = self.volumes_client.show_volume(volume['id'])['volume']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100297 return volume
298
Yair Fried1fc32a12014-08-04 09:11:30 +0300299 def _create_loginable_secgroup_rule(self, secgroup_id=None):
John Warrenf2345512015-12-10 13:39:30 -0500300 _client = self.compute_security_groups_client
John Warren5cdbf422016-01-05 12:42:43 -0500301 _client_rules = self.compute_security_group_rules_client
Andrea Frittoli247058f2014-07-16 16:09:22 +0100302 if secgroup_id is None:
ghanshyamb610b772015-08-24 17:29:38 +0900303 sgs = _client.list_security_groups()['security_groups']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100304 for sg in sgs:
305 if sg['name'] == 'default':
306 secgroup_id = sg['id']
307
308 # These rules are intended to permit inbound ssh and icmp
309 # traffic from all sources, so no group_id is provided.
310 # Setting a group_id would only permit traffic from ports
311 # belonging to the same security group.
312 rulesets = [
313 {
314 # ssh
Ken'ichi Ohmichieb7eeec2015-07-21 01:00:06 +0000315 'ip_protocol': 'tcp',
Andrea Frittoli247058f2014-07-16 16:09:22 +0100316 'from_port': 22,
317 'to_port': 22,
318 'cidr': '0.0.0.0/0',
319 },
320 {
321 # ping
Ken'ichi Ohmichieb7eeec2015-07-21 01:00:06 +0000322 'ip_protocol': 'icmp',
Andrea Frittoli247058f2014-07-16 16:09:22 +0100323 'from_port': -1,
324 'to_port': -1,
325 'cidr': '0.0.0.0/0',
326 }
327 ]
328 rules = list()
329 for ruleset in rulesets:
Ken'ichi Ohmichieb7eeec2015-07-21 01:00:06 +0000330 sg_rule = _client_rules.create_security_group_rule(
ghanshyam0a5e1232015-08-24 16:59:59 +0900331 parent_group_id=secgroup_id, **ruleset)['security_group_rule']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100332 rules.append(sg_rule)
333 return rules
334
Yair Fried1fc32a12014-08-04 09:11:30 +0300335 def _create_security_group(self):
Andrea Frittoli247058f2014-07-16 16:09:22 +0100336 # Create security group
337 sg_name = data_utils.rand_name(self.__class__.__name__)
338 sg_desc = sg_name + " description"
John Warrenf2345512015-12-10 13:39:30 -0500339 secgroup = self.compute_security_groups_client.create_security_group(
ghanshyamb610b772015-08-24 17:29:38 +0900340 name=sg_name, description=sg_desc)['security_group']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100341 self.assertEqual(secgroup['name'], sg_name)
342 self.assertEqual(secgroup['description'], sg_desc)
John Warrenf2345512015-12-10 13:39:30 -0500343 self.addCleanup(
344 self.delete_wrapper,
345 self.compute_security_groups_client.delete_security_group,
346 secgroup['id'])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100347
348 # Add rules to the security group
Yair Fried1fc32a12014-08-04 09:11:30 +0300349 self._create_loginable_secgroup_rule(secgroup['id'])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100350
351 return secgroup
352
Sean Dague20e98612016-01-06 14:33:28 -0500353 def get_remote_client(self, ip_address, username=None, private_key=None):
JordanP3fe2dc32014-11-17 13:06:01 +0100354 """Get a SSH client to a remote server
355
Sean Dague20e98612016-01-06 14:33:28 -0500356 @param ip_address the server floating or fixed IP address to use
357 for ssh validation
JordanP3fe2dc32014-11-17 13:06:01 +0100358 @param username name of the Linux account on the remote server
359 @param private_key the SSH private key to use
JordanP3fe2dc32014-11-17 13:06:01 +0100360 @return a RemoteClient object
361 """
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700362
Andrea Frittoli247058f2014-07-16 16:09:22 +0100363 if username is None:
lanoux283273b2015-12-04 03:01:54 -0800364 username = CONF.validation.image_ssh_user
wantwatering896300c2015-03-27 15:17:42 +0800365 # Set this with 'keypair' or others to log in with keypair or
366 # username/password.
lanoux5fc14522015-09-21 08:17:35 +0000367 if CONF.validation.auth_method == 'keypair':
wantwatering896300c2015-03-27 15:17:42 +0800368 password = None
369 if private_key is None:
370 private_key = self.keypair['private_key']
371 else:
lanoux283273b2015-12-04 03:01:54 -0800372 password = CONF.validation.image_ssh_password
wantwatering896300c2015-03-27 15:17:42 +0800373 private_key = None
Sean Dague20e98612016-01-06 14:33:28 -0500374 linux_client = remote_client.RemoteClient(ip_address, username,
wantwatering896300c2015-03-27 15:17:42 +0800375 pkey=private_key,
376 password=password)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100377 try:
378 linux_client.validate_authentication()
Matt Riedemann5f0ac522015-05-21 09:16:24 -0700379 except Exception as e:
380 message = ('Initializing SSH connection to %(ip)s failed. '
Eric Brown0911af62016-02-08 17:15:40 -0800381 'Error: %(error)s' % {'ip': ip_address,
Sean Dague20e98612016-01-06 14:33:28 -0500382 'error': e})
Matt Riedemann5f0ac522015-05-21 09:16:24 -0700383 caller = misc_utils.find_test_caller()
384 if caller:
385 message = '(%s) %s' % (caller, message)
386 LOG.exception(message)
Sean Dague2c98a162016-01-06 14:11:13 -0500387 self._log_console_output()
Andrea Frittoli247058f2014-07-16 16:09:22 +0100388 raise
389
390 return linux_client
391
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000392 def _image_create(self, name, fmt, path,
393 disk_format=None, properties=None):
Ghanshyam2a180b82014-06-16 13:54:22 +0900394 if properties is None:
395 properties = {}
Andrea Frittoli247058f2014-07-16 16:09:22 +0100396 name = data_utils.rand_name('%s-' % name)
397 image_file = open(path, 'rb')
398 self.addCleanup(image_file.close)
399 params = {
400 'name': name,
401 'container_format': fmt,
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000402 'disk_format': disk_format or fmt,
Andrea Frittoli247058f2014-07-16 16:09:22 +0100403 'is_public': 'False',
404 }
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000405 params['properties'] = properties
John Warren66207252015-07-31 15:51:02 -0400406 image = self.image_client.create_image(**params)['image']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100407 self.addCleanup(self.image_client.delete_image, image['id'])
408 self.assertEqual("queued", image['status'])
409 self.image_client.update_image(image['id'], data=image_file)
410 return image['id']
411
412 def glance_image_create(self):
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300413 img_path = CONF.scenario.img_dir + "/" + CONF.scenario.img_file
Andrea Frittoli247058f2014-07-16 16:09:22 +0100414 aki_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.aki_img_file
415 ari_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.ari_img_file
416 ami_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.ami_img_file
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300417 img_container_format = CONF.scenario.img_container_format
418 img_disk_format = CONF.scenario.img_disk_format
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000419 img_properties = CONF.scenario.img_properties
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300420 LOG.debug("paths: img: %s, container_fomat: %s, disk_format: %s, "
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000421 "properties: %s, ami: %s, ari: %s, aki: %s" %
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300422 (img_path, img_container_format, img_disk_format,
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000423 img_properties, ami_img_path, ari_img_path, aki_img_path))
Andrea Frittoli247058f2014-07-16 16:09:22 +0100424 try:
Jordan Pittier1e443ec2015-11-20 16:15:58 +0100425 image = self._image_create('scenario-img',
426 img_container_format,
427 img_path,
428 disk_format=img_disk_format,
429 properties=img_properties)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100430 except IOError:
431 LOG.debug("A qcow2 image was not found. Try to get a uec image.")
432 kernel = self._image_create('scenario-aki', 'aki', aki_img_path)
433 ramdisk = self._image_create('scenario-ari', 'ari', ari_img_path)
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000434 properties = {'kernel_id': kernel, 'ramdisk_id': ramdisk}
Jordan Pittier1e443ec2015-11-20 16:15:58 +0100435 image = self._image_create('scenario-ami', 'ami',
436 path=ami_img_path,
437 properties=properties)
438 LOG.debug("image:%s" % image)
439
440 return image
Andrea Frittoli247058f2014-07-16 16:09:22 +0100441
442 def _log_console_output(self, servers=None):
Matthew Treinish42a3f3a2014-09-04 15:04:53 -0400443 if not CONF.compute_feature_enabled.console_output:
444 LOG.debug('Console output not supported, cannot log')
445 return
Andrea Frittoli247058f2014-07-16 16:09:22 +0100446 if not servers:
David Kranzae99b9a2015-02-16 13:37:01 -0500447 servers = self.servers_client.list_servers()
Andrea Frittoli247058f2014-07-16 16:09:22 +0100448 servers = servers['servers']
449 for server in servers:
Brant Knudson566c5712014-09-24 20:04:50 -0500450 console_output = self.servers_client.get_console_output(
Ken'ichi Ohmichibf4766a2015-12-09 07:48:43 +0000451 server['id'])['output']
David Kranzae99b9a2015-02-16 13:37:01 -0500452 LOG.debug('Console output for %s\nbody=\n%s',
453 server['id'], console_output)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100454
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000455 def _log_net_info(self, exc):
456 # network debug is called as part of ssh init
Andrey Pavlov64723762015-04-29 06:24:58 +0300457 if not isinstance(exc, lib_exc.SSHTimeout):
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000458 LOG.debug('Network information on a devstack host')
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000459
nithya-ganesan882595e2014-07-29 18:51:07 +0000460 def create_server_snapshot(self, server, name=None):
461 # Glance client
462 _image_client = self.image_client
463 # Compute client
Ghanshyamae76c122015-12-22 13:41:35 +0900464 _images_client = self.compute_images_client
nithya-ganesan882595e2014-07-29 18:51:07 +0000465 if name is None:
Ken'ichi Ohmichi6ded8df2015-03-23 02:00:19 +0000466 name = data_utils.rand_name('scenario-snapshot')
nithya-ganesan882595e2014-07-29 18:51:07 +0000467 LOG.debug("Creating a snapshot image for server: %s", server['name'])
Ken'ichi Ohmichi28f18672015-07-17 10:00:38 +0000468 image = _images_client.create_image(server['id'], name=name)
David Kranza5299eb2015-01-15 17:24:05 -0500469 image_id = image.response['location'].split('images/')[1]
nithya-ganesan882595e2014-07-29 18:51:07 +0000470 _image_client.wait_for_image_status(image_id, 'active')
471 self.addCleanup_with_wait(
472 waiter_callable=_image_client.wait_for_resource_deletion,
473 thing_id=image_id, thing_id_param='id',
474 cleanup_callable=self.delete_wrapper,
475 cleanup_args=[_image_client.delete_image, image_id])
David Kranz34f18782015-01-06 13:43:55 -0500476 snapshot_image = _image_client.get_image_meta(image_id)
Andrey Pavlovc8bd4b12015-08-17 10:20:17 +0300477
478 bdm = snapshot_image.get('properties', {}).get('block_device_mapping')
479 if bdm:
480 bdm = json.loads(bdm)
481 if bdm and 'snapshot_id' in bdm[0]:
482 snapshot_id = bdm[0]['snapshot_id']
483 self.addCleanup(
484 self.snapshots_client.wait_for_resource_deletion,
485 snapshot_id)
486 self.addCleanup(
487 self.delete_wrapper, self.snapshots_client.delete_snapshot,
488 snapshot_id)
Andrey Pavlovd35957b2015-08-27 20:12:15 +0300489 self.snapshots_client.wait_for_snapshot_status(snapshot_id,
490 'available')
Andrey Pavlovc8bd4b12015-08-17 10:20:17 +0300491
nithya-ganesan882595e2014-07-29 18:51:07 +0000492 image_name = snapshot_image['name']
493 self.assertEqual(name, image_name)
494 LOG.debug("Created snapshot image %s for server %s",
495 image_name, server['name'])
496 return snapshot_image
497
Jordan Pittier7cf64762015-10-14 15:01:12 +0200498 def nova_volume_attach(self, server, volume_to_attach):
Joseph Lanoux6809bab2014-12-18 14:57:18 +0000499 volume = self.servers_client.attach_volume(
Jordan Pittier7cf64762015-10-14 15:01:12 +0200500 server['id'], volumeId=volume_to_attach['id'], device='/dev/%s'
ghanshyam0f825252015-08-25 16:02:50 +0900501 % CONF.compute.volume_device_name)['volumeAttachment']
Jordan Pittier7cf64762015-10-14 15:01:12 +0200502 self.assertEqual(volume_to_attach['id'], volume['id'])
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900503 self.volumes_client.wait_for_volume_status(volume['id'], 'in-use')
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900504
Jordan Pittier7cf64762015-10-14 15:01:12 +0200505 # Return the updated volume after the attachment
506 return self.volumes_client.show_volume(volume['id'])['volume']
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900507
Jordan Pittier7cf64762015-10-14 15:01:12 +0200508 def nova_volume_detach(self, server, volume):
509 self.servers_client.detach_volume(server['id'], volume['id'])
510 self.volumes_client.wait_for_volume_status(volume['id'], 'available')
511
512 volume = self.volumes_client.show_volume(volume['id'])['volume']
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900513 self.assertEqual('available', volume['status'])
514
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700515 def rebuild_server(self, server_id, image=None,
516 preserve_ephemeral=False, wait=True,
517 rebuild_kwargs=None):
518 if image is None:
519 image = CONF.compute.image_ref
520
521 rebuild_kwargs = rebuild_kwargs or {}
522
523 LOG.debug("Rebuilding server (id: %s, image: %s, preserve eph: %s)",
524 server_id, image, preserve_ephemeral)
Ken'ichi Ohmichi5271b0f2015-08-10 07:53:27 +0000525 self.servers_client.rebuild_server(
526 server_id=server_id, image_ref=image,
527 preserve_ephemeral=preserve_ephemeral,
528 **rebuild_kwargs)
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700529 if wait:
Ken'ichi Ohmichi0eb153c2015-07-13 02:18:25 +0000530 waiters.wait_for_server_status(self.servers_client,
531 server_id, 'ACTIVE')
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700532
Steven Hardyda2a8352014-10-02 12:52:20 +0100533 def ping_ip_address(self, ip_address, should_succeed=True,
534 ping_timeout=None):
lanoux5fc14522015-09-21 08:17:35 +0000535 timeout = ping_timeout or CONF.validation.ping_timeout
Aaron Rosena7df13b2014-09-23 09:45:45 -0700536 cmd = ['ping', '-c1', '-w1', ip_address]
537
538 def ping():
539 proc = subprocess.Popen(cmd,
540 stdout=subprocess.PIPE,
541 stderr=subprocess.PIPE)
542 proc.communicate()
Shuquan Huang753629e2015-07-20 08:52:29 +0000543
Aaron Rosena7df13b2014-09-23 09:45:45 -0700544 return (proc.returncode == 0) == should_succeed
545
Shuquan Huang753629e2015-07-20 08:52:29 +0000546 caller = misc_utils.find_test_caller()
547 LOG.debug('%(caller)s begins to ping %(ip)s in %(timeout)s sec and the'
548 ' expected result is %(should_succeed)s' % {
549 'caller': caller, 'ip': ip_address, 'timeout': timeout,
550 'should_succeed':
551 'reachable' if should_succeed else 'unreachable'
552 })
553 result = tempest.test.call_until_true(ping, timeout, 1)
554 LOG.debug('%(caller)s finishes ping %(ip)s in %(timeout)s sec and the '
555 'ping result is %(result)s' % {
556 'caller': caller, 'ip': ip_address, 'timeout': timeout,
557 'result': 'expected' if result else 'unexpected'
558 })
559 return result
Aaron Rosena7df13b2014-09-23 09:45:45 -0700560
Yair Friedae0e73d2014-11-24 11:56:26 +0200561 def check_vm_connectivity(self, ip_address,
562 username=None,
563 private_key=None,
564 should_connect=True):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000565 """Check server connectivity
566
Yair Friedae0e73d2014-11-24 11:56:26 +0200567 :param ip_address: server to test against
568 :param username: server's ssh username
569 :param private_key: server's ssh private key to be used
570 :param should_connect: True/False indicates positive/negative test
571 positive - attempt ping and ssh
572 negative - attempt ping and fail if succeed
573
574 :raises: AssertError if the result of the connectivity check does
575 not match the value of the should_connect param
576 """
577 if should_connect:
578 msg = "Timed out waiting for %s to become reachable" % ip_address
579 else:
580 msg = "ip address %s is reachable" % ip_address
581 self.assertTrue(self.ping_ip_address(ip_address,
582 should_succeed=should_connect),
583 msg=msg)
584 if should_connect:
585 # no need to check ssh for negative connectivity
586 self.get_remote_client(ip_address, username, private_key)
587
588 def check_public_network_connectivity(self, ip_address, username,
589 private_key, should_connect=True,
590 msg=None, servers=None):
591 # The target login is assumed to have been configured for
592 # key-based authentication by cloud-init.
593 LOG.debug('checking network connections to IP %s with user: %s' %
594 (ip_address, username))
595 try:
596 self.check_vm_connectivity(ip_address,
597 username,
598 private_key,
599 should_connect=should_connect)
Matthew Treinish53483132014-12-09 18:50:06 -0500600 except Exception:
Yair Friedae0e73d2014-11-24 11:56:26 +0200601 ex_msg = 'Public network connectivity check failed'
602 if msg:
603 ex_msg += ": " + msg
604 LOG.exception(ex_msg)
605 self._log_console_output(servers)
Yair Friedae0e73d2014-11-24 11:56:26 +0200606 raise
607
608 def create_floating_ip(self, thing, pool_name=None):
Ken'ichi Ohmichia112a592015-11-17 08:49:37 +0000609 """Create a floating IP and associates to a server on Nova"""
Yair Friedae0e73d2014-11-24 11:56:26 +0200610
John Warrene74890a2015-11-11 15:18:01 -0500611 floating_ip = (self.compute_floating_ips_client.
Ken'ichi Ohmichie037a6f2015-12-03 06:41:49 +0000612 create_floating_ip(pool=pool_name)['floating_ip'])
Yair Friedae0e73d2014-11-24 11:56:26 +0200613 self.addCleanup(self.delete_wrapper,
John Warrene74890a2015-11-11 15:18:01 -0500614 self.compute_floating_ips_client.delete_floating_ip,
Yair Friedae0e73d2014-11-24 11:56:26 +0200615 floating_ip['id'])
John Warrene74890a2015-11-11 15:18:01 -0500616 self.compute_floating_ips_client.associate_floating_ip_to_server(
Yair Friedae0e73d2014-11-24 11:56:26 +0200617 floating_ip['ip'], thing['id'])
618 return floating_ip
619
Sean Dague20e98612016-01-06 14:33:28 -0500620 def create_timestamp(self, ip_address, dev_name=None, mount_path='/mnt',
Matt Riedemannfd5657d2015-09-30 14:47:07 -0700621 private_key=None):
Sean Dague20e98612016-01-06 14:33:28 -0500622 ssh_client = self.get_remote_client(ip_address,
Matt Riedemannfd5657d2015-09-30 14:47:07 -0700623 private_key=private_key)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300624 if dev_name is not None:
625 ssh_client.make_fs(dev_name)
Matt Riedemann076685a2015-09-30 14:38:16 -0700626 ssh_client.mount(dev_name, mount_path)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300627 cmd_timestamp = 'sudo sh -c "date > %s/timestamp; sync"' % mount_path
628 ssh_client.exec_command(cmd_timestamp)
629 timestamp = ssh_client.exec_command('sudo cat %s/timestamp'
630 % mount_path)
631 if dev_name is not None:
632 ssh_client.umount(mount_path)
633 return timestamp
634
Sean Dague20e98612016-01-06 14:33:28 -0500635 def get_timestamp(self, ip_address, dev_name=None, mount_path='/mnt',
Matt Riedemannfd5657d2015-09-30 14:47:07 -0700636 private_key=None):
Sean Dague20e98612016-01-06 14:33:28 -0500637 ssh_client = self.get_remote_client(ip_address,
Matt Riedemannfd5657d2015-09-30 14:47:07 -0700638 private_key=private_key)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300639 if dev_name is not None:
Matt Riedemann076685a2015-09-30 14:38:16 -0700640 ssh_client.mount(dev_name, mount_path)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300641 timestamp = ssh_client.exec_command('sudo cat %s/timestamp'
642 % mount_path)
643 if dev_name is not None:
644 ssh_client.umount(mount_path)
645 return timestamp
646
Sean Dague20e98612016-01-06 14:33:28 -0500647 def get_server_ip(self, server):
648 """Get the server fixed or floating IP.
649
650 Based on the configuration we're in, return a correct ip
651 address for validating that a guest is up.
652 """
Alexander Gubanovc8829f82015-11-12 10:35:13 +0200653 if CONF.validation.connect_method == 'floating':
Sean Dague20e98612016-01-06 14:33:28 -0500654 # The tests calling this method don't have a floating IP
655 # and can't make use of the validattion resources. So the
656 # method is creating the floating IP there.
657 return self.create_floating_ip(server)['ip']
658 elif CONF.validation.connect_method == 'fixed':
659 addresses = server['addresses'][CONF.validation.network_for_ssh]
660 for address in addresses:
661 if address['version'] == CONF.validation.ip_version_for_ssh:
662 return address['addr']
663 raise exceptions.ServerUnreachable()
Alexander Gubanovc8829f82015-11-12 10:35:13 +0200664 else:
Sean Dague20e98612016-01-06 14:33:28 -0500665 raise exceptions.InvalidConfiguration()
Alexander Gubanovc8829f82015-11-12 10:35:13 +0200666
Andrea Frittoli2e733b52014-07-16 14:12:11 +0100667
Andrea Frittoli4971fc82014-09-25 10:22:20 +0100668class NetworkScenarioTest(ScenarioTest):
Yair Fried1fc32a12014-08-04 09:11:30 +0300669 """Base class for network scenario tests.
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000670
Yair Fried1fc32a12014-08-04 09:11:30 +0300671 This class provide helpers for network scenario tests, using the neutron
672 API. Helpers from ancestor which use the nova network API are overridden
673 with the neutron API.
674
675 This Class also enforces using Neutron instead of novanetwork.
676 Subclassed tests will be skipped if Neutron is not enabled
677
678 """
679
Andrea Frittolib21de6c2015-02-06 20:12:38 +0000680 credentials = ['primary', 'admin']
681
Yair Fried1fc32a12014-08-04 09:11:30 +0300682 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +0000683 def skip_checks(cls):
684 super(NetworkScenarioTest, cls).skip_checks()
Andrea Frittoli2ddc2632014-09-25 11:03:00 +0100685 if not CONF.service_available.neutron:
686 raise cls.skipException('Neutron not available')
Yair Fried1fc32a12014-08-04 09:11:30 +0300687
688 @classmethod
Andrea Frittoliac20b5e2014-09-15 13:31:14 +0100689 def resource_setup(cls):
690 super(NetworkScenarioTest, cls).resource_setup()
Yair Fried1fc32a12014-08-04 09:11:30 +0300691 cls.tenant_id = cls.manager.identity_client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300692
John Warren94d8faf2015-09-15 12:22:24 -0400693 def _create_network(self, client=None, networks_client=None,
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000694 routers_client=None, tenant_id=None,
695 namestart='network-smoke-'):
Yair Frieddb6c9e92014-08-06 08:53:13 +0300696 if not client:
697 client = self.network_client
John Warren94d8faf2015-09-15 12:22:24 -0400698 if not networks_client:
699 networks_client = self.networks_client
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000700 if not routers_client:
701 routers_client = self.routers_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300702 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000703 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300704 name = data_utils.rand_name(namestart)
John Warren94d8faf2015-09-15 12:22:24 -0400705 result = networks_client.create_network(name=name, tenant_id=tenant_id)
706 network = net_resources.DeletableNetwork(
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000707 networks_client=networks_client, routers_client=routers_client,
708 **result['network'])
Yair Fried1fc32a12014-08-04 09:11:30 +0300709 self.assertEqual(network.name, name)
710 self.addCleanup(self.delete_wrapper, network.delete)
711 return network
712
713 def _list_networks(self, *args, **kwargs):
714 """List networks using admin creds """
John Warren94d8faf2015-09-15 12:22:24 -0400715 networks_list = self.admin_manager.networks_client.list_networks(
ghanshyam2f7cc022015-06-26 18:18:11 +0900716 *args, **kwargs)
717 return networks_list['networks']
Yair Fried1fc32a12014-08-04 09:11:30 +0300718
719 def _list_subnets(self, *args, **kwargs):
720 """List subnets using admin creds """
John Warren3961acd2015-10-02 14:38:53 -0400721 subnets_list = self.admin_manager.subnets_client.list_subnets(
ghanshyam2f7cc022015-06-26 18:18:11 +0900722 *args, **kwargs)
723 return subnets_list['subnets']
Yair Fried1fc32a12014-08-04 09:11:30 +0300724
725 def _list_routers(self, *args, **kwargs):
726 """List routers using admin creds """
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000727 routers_list = self.admin_manager.routers_client.list_routers(
ghanshyam2f7cc022015-06-26 18:18:11 +0900728 *args, **kwargs)
729 return routers_list['routers']
Yair Fried1fc32a12014-08-04 09:11:30 +0300730
731 def _list_ports(self, *args, **kwargs):
732 """List ports using admin creds """
John Warren49c0fe52015-10-22 12:35:54 -0400733 ports_list = self.admin_manager.ports_client.list_ports(
ghanshyam2f7cc022015-06-26 18:18:11 +0900734 *args, **kwargs)
735 return ports_list['ports']
Yair Fried1fc32a12014-08-04 09:11:30 +0300736
Yair Fried564d89d2015-08-06 17:02:12 +0300737 def _list_agents(self, *args, **kwargs):
738 """List agents using admin creds """
Ken'ichi Ohmichi71860062015-12-15 08:20:13 +0000739 agents_list = self.admin_manager.network_agents_client.list_agents(
Yair Fried564d89d2015-08-06 17:02:12 +0300740 *args, **kwargs)
741 return agents_list['agents']
742
John Warren3961acd2015-10-02 14:38:53 -0400743 def _create_subnet(self, network, client=None, subnets_client=None,
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000744 routers_client=None, namestart='subnet-smoke',
745 **kwargs):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000746 """Create a subnet for the given network
747
748 within the cidr block configured for tenant networks.
Yair Fried1fc32a12014-08-04 09:11:30 +0300749 """
Yair Frieddb6c9e92014-08-06 08:53:13 +0300750 if not client:
751 client = self.network_client
John Warren3961acd2015-10-02 14:38:53 -0400752 if not subnets_client:
753 subnets_client = self.subnets_client
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000754 if not routers_client:
755 routers_client = self.routers_client
Yair Fried1fc32a12014-08-04 09:11:30 +0300756
757 def cidr_in_use(cidr, tenant_id):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000758 """Check cidr existence
759
lei zhangdd552b22015-11-25 20:41:48 +0800760 :returns: True if subnet with cidr already exist in tenant
761 False else
Yair Fried1fc32a12014-08-04 09:11:30 +0300762 """
763 cidr_in_use = self._list_subnets(tenant_id=tenant_id, cidr=cidr)
764 return len(cidr_in_use) != 0
765
Kirill Shileev14113572014-11-21 16:58:02 +0300766 ip_version = kwargs.pop('ip_version', 4)
767
768 if ip_version == 6:
769 tenant_cidr = netaddr.IPNetwork(
770 CONF.network.tenant_network_v6_cidr)
771 num_bits = CONF.network.tenant_network_v6_mask_bits
772 else:
773 tenant_cidr = netaddr.IPNetwork(CONF.network.tenant_network_cidr)
774 num_bits = CONF.network.tenant_network_mask_bits
775
Yair Fried1fc32a12014-08-04 09:11:30 +0300776 result = None
Kirill Shileev14113572014-11-21 16:58:02 +0300777 str_cidr = None
Yair Fried1fc32a12014-08-04 09:11:30 +0300778 # Repeatedly attempt subnet creation with sequential cidr
779 # blocks until an unallocated block is found.
Kirill Shileev14113572014-11-21 16:58:02 +0300780 for subnet_cidr in tenant_cidr.subnet(num_bits):
Yair Fried1fc32a12014-08-04 09:11:30 +0300781 str_cidr = str(subnet_cidr)
782 if cidr_in_use(str_cidr, tenant_id=network.tenant_id):
783 continue
784
785 subnet = dict(
786 name=data_utils.rand_name(namestart),
Yair Fried1fc32a12014-08-04 09:11:30 +0300787 network_id=network.id,
788 tenant_id=network.tenant_id,
789 cidr=str_cidr,
Kirill Shileev14113572014-11-21 16:58:02 +0300790 ip_version=ip_version,
Yair Fried1fc32a12014-08-04 09:11:30 +0300791 **kwargs
792 )
793 try:
John Warren3961acd2015-10-02 14:38:53 -0400794 result = subnets_client.create_subnet(**subnet)
Yair Fried1fc32a12014-08-04 09:11:30 +0300795 break
Masayuki Igawad9388762015-01-20 14:56:42 +0900796 except lib_exc.Conflict as e:
Yair Fried1fc32a12014-08-04 09:11:30 +0300797 is_overlapping_cidr = 'overlaps with another subnet' in str(e)
798 if not is_overlapping_cidr:
799 raise
800 self.assertIsNotNone(result, 'Unable to allocate tenant network')
John Warren3961acd2015-10-02 14:38:53 -0400801 subnet = net_resources.DeletableSubnet(
802 network_client=client, subnets_client=subnets_client,
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000803 routers_client=routers_client, **result['subnet'])
Yair Fried1fc32a12014-08-04 09:11:30 +0300804 self.assertEqual(subnet.cidr, str_cidr)
805 self.addCleanup(self.delete_wrapper, subnet.delete)
806 return subnet
807
Itzik Brown2ca01cd2014-12-08 12:58:20 +0200808 def _create_port(self, network_id, client=None, namestart='port-quotatest',
809 **kwargs):
Yair Frieddb6c9e92014-08-06 08:53:13 +0300810 if not client:
John Warren49c0fe52015-10-22 12:35:54 -0400811 client = self.ports_client
Yair Fried1fc32a12014-08-04 09:11:30 +0300812 name = data_utils.rand_name(namestart)
David Kranz34e88122014-12-11 15:24:05 -0500813 result = client.create_port(
Yair Fried1fc32a12014-08-04 09:11:30 +0300814 name=name,
Itzik Brown2ca01cd2014-12-08 12:58:20 +0200815 network_id=network_id,
816 **kwargs)
Yair Fried1fc32a12014-08-04 09:11:30 +0300817 self.assertIsNotNone(result, 'Unable to allocate port')
John Warren49c0fe52015-10-22 12:35:54 -0400818 port = net_resources.DeletablePort(ports_client=client,
Yair Fried1fc32a12014-08-04 09:11:30 +0300819 **result['port'])
820 self.addCleanup(self.delete_wrapper, port.delete)
821 return port
822
Kirill Shileev14113572014-11-21 16:58:02 +0300823 def _get_server_port_id_and_ip4(self, server, ip_addr=None):
Kevin Benton1d0c1dc2016-02-04 14:30:08 -0800824 ports = self._list_ports(device_id=server['id'], fixed_ip=ip_addr)
Sean M. Collins2e896832015-12-15 13:58:47 -0500825 # A port can have more then one IP address in some cases.
826 # If the network is dual-stack (IPv4 + IPv6), this port is associated
827 # with 2 subnets
Daniel Mellado9e3e1062015-08-06 18:07:05 +0200828 port_map = [(p["id"], fxip["ip_address"])
829 for p in ports
830 for fxip in p["fixed_ips"]
Kevin Benton1d0c1dc2016-02-04 14:30:08 -0800831 if netaddr.valid_ipv4(fxip["ip_address"])
832 and p['status'] == 'ACTIVE']
833 inactive = [p for p in ports if p['status'] != 'ACTIVE']
834 if inactive:
835 LOG.warning("Instance has ports that are not ACTIVE: %s", inactive)
Daniel Mellado9e3e1062015-08-06 18:07:05 +0200836
John L. Villalovosb83286f2015-11-04 14:46:57 -0800837 self.assertNotEqual(0, len(port_map),
838 "No IPv4 addresses found in: %s" % ports)
Daniel Mellado9e3e1062015-08-06 18:07:05 +0200839 self.assertEqual(len(port_map), 1,
840 "Found multiple IPv4 addresses: %s. "
841 "Unable to determine which port to target."
842 % port_map)
843 return port_map[0]
Yair Fried1fc32a12014-08-04 09:11:30 +0300844
David Shrewsbury9bac3662014-08-07 15:07:01 -0400845 def _get_network_by_name(self, network_name):
846 net = self._list_networks(name=network_name)
Adam Gandelman878a5fd2015-03-30 14:33:36 -0700847 self.assertNotEqual(len(net), 0,
848 "Unable to get network by name: %s" % network_name)
Yair Fried8186f812014-09-28 09:39:39 +0300849 return net_resources.AttributeDict(net[0])
David Shrewsbury9bac3662014-08-07 15:07:01 -0400850
Yair Friedae0e73d2014-11-24 11:56:26 +0200851 def create_floating_ip(self, thing, external_network_id=None,
852 port_id=None, client=None):
Ken'ichi Ohmichia112a592015-11-17 08:49:37 +0000853 """Create a floating IP and associates to a resource/port on Neutron"""
Yair Friedae0e73d2014-11-24 11:56:26 +0200854 if not external_network_id:
855 external_network_id = CONF.network.public_network_id
Yair Frieddb6c9e92014-08-06 08:53:13 +0300856 if not client:
John Warrenfbf2a892015-11-17 12:36:14 -0500857 client = self.floating_ips_client
Yair Fried1fc32a12014-08-04 09:11:30 +0300858 if not port_id:
Kirill Shileev14113572014-11-21 16:58:02 +0300859 port_id, ip4 = self._get_server_port_id_and_ip4(thing)
860 else:
861 ip4 = None
David Kranz34e88122014-12-11 15:24:05 -0500862 result = client.create_floatingip(
Yair Fried1fc32a12014-08-04 09:11:30 +0300863 floating_network_id=external_network_id,
864 port_id=port_id,
Kirill Shileev14113572014-11-21 16:58:02 +0300865 tenant_id=thing['tenant_id'],
866 fixed_ip_address=ip4
Yair Fried1fc32a12014-08-04 09:11:30 +0300867 )
868 floating_ip = net_resources.DeletableFloatingIp(
Yair Frieddb6c9e92014-08-06 08:53:13 +0300869 client=client,
Yair Fried1fc32a12014-08-04 09:11:30 +0300870 **result['floatingip'])
871 self.addCleanup(self.delete_wrapper, floating_ip.delete)
872 return floating_ip
873
874 def _associate_floating_ip(self, floating_ip, server):
Kirill Shileev14113572014-11-21 16:58:02 +0300875 port_id, _ = self._get_server_port_id_and_ip4(server)
Yair Fried1fc32a12014-08-04 09:11:30 +0300876 floating_ip.update(port_id=port_id)
877 self.assertEqual(port_id, floating_ip.port_id)
878 return floating_ip
879
880 def _disassociate_floating_ip(self, floating_ip):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000881 """:param floating_ip: type DeletableFloatingIp"""
Yair Fried1fc32a12014-08-04 09:11:30 +0300882 floating_ip.update(port_id=None)
883 self.assertIsNone(floating_ip.port_id)
884 return floating_ip
885
Yair Fried45f92952014-06-26 05:19:19 +0300886 def check_floating_ip_status(self, floating_ip, status):
Carl Baldwina754e2d2014-10-23 22:47:41 +0000887 """Verifies floatingip reaches the given status
Yair Fried45f92952014-06-26 05:19:19 +0300888
889 :param floating_ip: net_resources.DeletableFloatingIp floating IP to
890 to check status
891 :param status: target status
892 :raises: AssertionError if status doesn't match
893 """
Carl Baldwina754e2d2014-10-23 22:47:41 +0000894 def refresh():
895 floating_ip.refresh()
896 return status == floating_ip.status
897
898 tempest.test.call_until_true(refresh,
899 CONF.network.build_timeout,
900 CONF.network.build_interval)
Yair Fried45f92952014-06-26 05:19:19 +0300901 self.assertEqual(status, floating_ip.status,
902 message="FloatingIP: {fp} is at status: {cst}. "
903 "failed to reach status: {st}"
904 .format(fp=floating_ip, cst=floating_ip.status,
905 st=status))
906 LOG.info("FloatingIP: {fp} is at status: {st}"
907 .format(fp=floating_ip, st=status))
908
Yair Fried1fc32a12014-08-04 09:11:30 +0300909 def _check_tenant_network_connectivity(self, server,
910 username,
911 private_key,
912 should_connect=True,
913 servers_for_debug=None):
914 if not CONF.network.tenant_networks_reachable:
915 msg = 'Tenant networks not configured to be reachable.'
916 LOG.info(msg)
917 return
918 # The target login is assumed to have been configured for
919 # key-based authentication by cloud-init.
920 try:
Matthew Treinish71426682015-04-23 11:19:38 -0400921 for net_name, ip_addresses in six.iteritems(server['addresses']):
Yair Fried1fc32a12014-08-04 09:11:30 +0300922 for ip_address in ip_addresses:
ghanshyam807211c2014-12-18 13:21:22 +0900923 self.check_vm_connectivity(ip_address['addr'],
Yair Friedae0e73d2014-11-24 11:56:26 +0200924 username,
925 private_key,
926 should_connect=should_connect)
Yair Fried1fc32a12014-08-04 09:11:30 +0300927 except Exception as e:
928 LOG.exception('Tenant network connectivity check failed')
929 self._log_console_output(servers_for_debug)
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000930 self._log_net_info(e)
Yair Fried1fc32a12014-08-04 09:11:30 +0300931 raise
932
Yair Friedbc46f592015-11-18 16:29:34 +0200933 def _check_remote_connectivity(self, source, dest, should_succeed=True,
934 nic=None):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000935 """check ping server via source ssh connection
Yair Fried1fc32a12014-08-04 09:11:30 +0300936
937 :param source: RemoteClient: an ssh connection from which to ping
938 :param dest: and IP to ping against
939 :param should_succeed: boolean should ping succeed or not
Yair Friedbc46f592015-11-18 16:29:34 +0200940 :param nic: specific network interface to ping from
Yair Fried1fc32a12014-08-04 09:11:30 +0300941 :returns: boolean -- should_succeed == ping
942 :returns: ping is false if ping failed
943 """
944 def ping_remote():
945 try:
Yair Friedbc46f592015-11-18 16:29:34 +0200946 source.ping_host(dest, nic=nic)
Andrey Pavlov64723762015-04-29 06:24:58 +0300947 except lib_exc.SSHExecCommandFailed:
zhangguoqing6c096642016-01-04 06:17:21 +0000948 LOG.warning('Failed to ping IP: %s via a ssh connection '
949 'from: %s.' % (dest, source.ssh_client.host))
Yair Fried1fc32a12014-08-04 09:11:30 +0300950 return not should_succeed
951 return should_succeed
952
953 return tempest.test.call_until_true(ping_remote,
lanoux5fc14522015-09-21 08:17:35 +0000954 CONF.validation.ping_timeout,
Yair Fried1fc32a12014-08-04 09:11:30 +0300955 1)
956
John Warren456d9ae2016-01-12 15:36:33 -0500957 def _create_security_group(self, security_group_rules_client=None,
958 tenant_id=None,
John Warrenf9606e92015-12-10 12:12:42 -0500959 namestart='secgroup-smoke',
960 security_groups_client=None):
John Warren456d9ae2016-01-12 15:36:33 -0500961 if security_group_rules_client is None:
962 security_group_rules_client = self.security_group_rules_client
John Warrenf9606e92015-12-10 12:12:42 -0500963 if security_groups_client is None:
964 security_groups_client = self.security_groups_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300965 if tenant_id is None:
John Warrenf9606e92015-12-10 12:12:42 -0500966 tenant_id = security_groups_client.tenant_id
967 secgroup = self._create_empty_security_group(
968 namestart=namestart, client=security_groups_client,
969 tenant_id=tenant_id)
Yair Fried1fc32a12014-08-04 09:11:30 +0300970
971 # Add rules to the security group
John Warrenf9606e92015-12-10 12:12:42 -0500972 rules = self._create_loginable_secgroup_rule(
John Warren456d9ae2016-01-12 15:36:33 -0500973 security_group_rules_client=security_group_rules_client,
974 secgroup=secgroup,
John Warrenf9606e92015-12-10 12:12:42 -0500975 security_groups_client=security_groups_client)
Yair Fried1fc32a12014-08-04 09:11:30 +0300976 for rule in rules:
977 self.assertEqual(tenant_id, rule.tenant_id)
978 self.assertEqual(secgroup.id, rule.security_group_id)
979 return secgroup
980
Yair Frieddb6c9e92014-08-06 08:53:13 +0300981 def _create_empty_security_group(self, client=None, tenant_id=None,
Yair Fried1fc32a12014-08-04 09:11:30 +0300982 namestart='secgroup-smoke'):
983 """Create a security group without rules.
984
985 Default rules will be created:
986 - IPv4 egress to any
987 - IPv6 egress to any
988
989 :param tenant_id: secgroup will be created in this tenant
990 :returns: DeletableSecurityGroup -- containing the secgroup created
991 """
992 if client is None:
John Warrenf9606e92015-12-10 12:12:42 -0500993 client = self.security_groups_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300994 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000995 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300996 sg_name = data_utils.rand_name(namestart)
997 sg_desc = sg_name + " description"
998 sg_dict = dict(name=sg_name,
999 description=sg_desc)
1000 sg_dict['tenant_id'] = tenant_id
David Kranz34e88122014-12-11 15:24:05 -05001001 result = client.create_security_group(**sg_dict)
Yair Fried1fc32a12014-08-04 09:11:30 +03001002 secgroup = net_resources.DeletableSecurityGroup(
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +00001003 client=client, routers_client=self.routers_client,
Yair Fried1fc32a12014-08-04 09:11:30 +03001004 **result['security_group']
1005 )
1006 self.assertEqual(secgroup.name, sg_name)
1007 self.assertEqual(tenant_id, secgroup.tenant_id)
1008 self.assertEqual(secgroup.description, sg_desc)
1009 self.addCleanup(self.delete_wrapper, secgroup.delete)
1010 return secgroup
1011
Yair Frieddb6c9e92014-08-06 08:53:13 +03001012 def _default_security_group(self, client=None, tenant_id=None):
Yair Fried1fc32a12014-08-04 09:11:30 +03001013 """Get default secgroup for given tenant_id.
1014
1015 :returns: DeletableSecurityGroup -- default secgroup for given tenant
1016 """
1017 if client is None:
John Warrenf9606e92015-12-10 12:12:42 -05001018 client = self.security_groups_client
Yair Frieddb6c9e92014-08-06 08:53:13 +03001019 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +00001020 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001021 sgs = [
1022 sg for sg in client.list_security_groups().values()[0]
1023 if sg['tenant_id'] == tenant_id and sg['name'] == 'default'
1024 ]
1025 msg = "No default security group for tenant %s." % (tenant_id)
1026 self.assertTrue(len(sgs) > 0, msg)
Yair Fried1fc32a12014-08-04 09:11:30 +03001027 return net_resources.DeletableSecurityGroup(client=client,
1028 **sgs[0])
1029
John Warren456d9ae2016-01-12 15:36:33 -05001030 def _create_security_group_rule(self, secgroup=None,
1031 sec_group_rules_client=None,
John Warrenf9606e92015-12-10 12:12:42 -05001032 tenant_id=None,
1033 security_groups_client=None, **kwargs):
Yair Fried1fc32a12014-08-04 09:11:30 +03001034 """Create a rule from a dictionary of rule parameters.
1035
1036 Create a rule in a secgroup. if secgroup not defined will search for
1037 default secgroup in tenant_id.
1038
1039 :param secgroup: type DeletableSecurityGroup.
Yair Fried1fc32a12014-08-04 09:11:30 +03001040 :param tenant_id: if secgroup not passed -- the tenant in which to
1041 search for default secgroup
1042 :param kwargs: a dictionary containing rule parameters:
1043 for example, to allow incoming ssh:
1044 rule = {
1045 direction: 'ingress'
1046 protocol:'tcp',
1047 port_range_min: 22,
1048 port_range_max: 22
1049 }
1050 """
John Warren456d9ae2016-01-12 15:36:33 -05001051 if sec_group_rules_client is None:
1052 sec_group_rules_client = self.security_group_rules_client
John Warrenf9606e92015-12-10 12:12:42 -05001053 if security_groups_client is None:
1054 security_groups_client = self.security_groups_client
Yair Frieddb6c9e92014-08-06 08:53:13 +03001055 if not tenant_id:
John Warrenf9606e92015-12-10 12:12:42 -05001056 tenant_id = security_groups_client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001057 if secgroup is None:
John Warrenf9606e92015-12-10 12:12:42 -05001058 secgroup = self._default_security_group(
1059 client=security_groups_client, tenant_id=tenant_id)
Yair Fried1fc32a12014-08-04 09:11:30 +03001060
1061 ruleset = dict(security_group_id=secgroup.id,
1062 tenant_id=secgroup.tenant_id)
1063 ruleset.update(kwargs)
1064
John Warren456d9ae2016-01-12 15:36:33 -05001065 sg_rule = sec_group_rules_client.create_security_group_rule(**ruleset)
Yair Fried1fc32a12014-08-04 09:11:30 +03001066 sg_rule = net_resources.DeletableSecurityGroupRule(
John Warren456d9ae2016-01-12 15:36:33 -05001067 client=sec_group_rules_client,
Yair Fried1fc32a12014-08-04 09:11:30 +03001068 **sg_rule['security_group_rule']
1069 )
Yair Fried1fc32a12014-08-04 09:11:30 +03001070 self.assertEqual(secgroup.tenant_id, sg_rule.tenant_id)
1071 self.assertEqual(secgroup.id, sg_rule.security_group_id)
1072
1073 return sg_rule
1074
John Warren456d9ae2016-01-12 15:36:33 -05001075 def _create_loginable_secgroup_rule(self, security_group_rules_client=None,
1076 secgroup=None,
John Warrenf9606e92015-12-10 12:12:42 -05001077 security_groups_client=None):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001078 """Create loginable security group rule
1079
1080 These rules are intended to permit inbound ssh and icmp
Yair Fried1fc32a12014-08-04 09:11:30 +03001081 traffic from all sources, so no group_id is provided.
1082 Setting a group_id would only permit traffic from ports
1083 belonging to the same security group.
1084 """
1085
John Warren456d9ae2016-01-12 15:36:33 -05001086 if security_group_rules_client is None:
1087 security_group_rules_client = self.security_group_rules_client
John Warrenf9606e92015-12-10 12:12:42 -05001088 if security_groups_client is None:
1089 security_groups_client = self.security_groups_client
Yair Fried1fc32a12014-08-04 09:11:30 +03001090 rules = []
1091 rulesets = [
1092 dict(
1093 # ssh
1094 protocol='tcp',
1095 port_range_min=22,
1096 port_range_max=22,
1097 ),
1098 dict(
1099 # ping
1100 protocol='icmp',
Andreas Scheuring887ca8e2015-02-03 17:56:12 +01001101 ),
1102 dict(
1103 # ipv6-icmp for ping6
1104 protocol='icmp',
1105 ethertype='IPv6',
Yair Fried1fc32a12014-08-04 09:11:30 +03001106 )
1107 ]
John Warren456d9ae2016-01-12 15:36:33 -05001108 sec_group_rules_client = security_group_rules_client
Yair Fried1fc32a12014-08-04 09:11:30 +03001109 for ruleset in rulesets:
1110 for r_direction in ['ingress', 'egress']:
1111 ruleset['direction'] = r_direction
1112 try:
1113 sg_rule = self._create_security_group_rule(
John Warren456d9ae2016-01-12 15:36:33 -05001114 sec_group_rules_client=sec_group_rules_client,
1115 secgroup=secgroup,
John Warrenf9606e92015-12-10 12:12:42 -05001116 security_groups_client=security_groups_client,
1117 **ruleset)
Masayuki Igawad9388762015-01-20 14:56:42 +09001118 except lib_exc.Conflict as ex:
Yair Fried1fc32a12014-08-04 09:11:30 +03001119 # if rule already exist - skip rule and continue
1120 msg = 'Security group rule already exists'
1121 if msg not in ex._error_string:
1122 raise ex
1123 else:
1124 self.assertEqual(r_direction, sg_rule.direction)
1125 rules.append(sg_rule)
1126
1127 return rules
1128
Yair Frieddb6c9e92014-08-06 08:53:13 +03001129 def _get_router(self, client=None, tenant_id=None):
Yair Fried1fc32a12014-08-04 09:11:30 +03001130 """Retrieve a router for the given tenant id.
1131
1132 If a public router has been configured, it will be returned.
1133
1134 If a public router has not been configured, but a public
1135 network has, a tenant router will be created and returned that
1136 routes traffic to the public network.
1137 """
Yair Frieddb6c9e92014-08-06 08:53:13 +03001138 if not client:
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +00001139 client = self.routers_client
Yair Frieddb6c9e92014-08-06 08:53:13 +03001140 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +00001141 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001142 router_id = CONF.network.public_router_id
1143 network_id = CONF.network.public_network_id
1144 if router_id:
David Kranzca4c7e72015-05-27 11:39:19 -04001145 body = client.show_router(router_id)
Sergey Shnaidman5e9c8fd2014-09-30 18:31:43 +04001146 return net_resources.AttributeDict(**body['router'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001147 elif network_id:
Yair Frieddb6c9e92014-08-06 08:53:13 +03001148 router = self._create_router(client, tenant_id)
Yair Fried1fc32a12014-08-04 09:11:30 +03001149 router.set_gateway(network_id)
1150 return router
1151 else:
1152 raise Exception("Neither of 'public_router_id' or "
1153 "'public_network_id' has been defined.")
1154
Yair Frieddb6c9e92014-08-06 08:53:13 +03001155 def _create_router(self, client=None, tenant_id=None,
1156 namestart='router-smoke'):
1157 if not client:
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +00001158 client = self.routers_client
Yair Frieddb6c9e92014-08-06 08:53:13 +03001159 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +00001160 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001161 name = data_utils.rand_name(namestart)
David Kranz34e88122014-12-11 15:24:05 -05001162 result = client.create_router(name=name,
1163 admin_state_up=True,
1164 tenant_id=tenant_id)
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +00001165 router = net_resources.DeletableRouter(routers_client=client,
Yair Fried1fc32a12014-08-04 09:11:30 +03001166 **result['router'])
1167 self.assertEqual(router.name, name)
1168 self.addCleanup(self.delete_wrapper, router.delete)
1169 return router
1170
Alok Maurya6384bbb2014-07-13 06:44:29 -07001171 def _update_router_admin_state(self, router, admin_state_up):
1172 router.update(admin_state_up=admin_state_up)
1173 self.assertEqual(admin_state_up, router.admin_state_up)
1174
John Warren94d8faf2015-09-15 12:22:24 -04001175 def create_networks(self, client=None, networks_client=None,
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +00001176 routers_client=None, subnets_client=None,
1177 tenant_id=None, dns_nameservers=None):
Yair Fried1fc32a12014-08-04 09:11:30 +03001178 """Create a network with a subnet connected to a router.
1179
David Shrewsbury9bac3662014-08-07 15:07:01 -04001180 The baremetal driver is a special case since all nodes are
1181 on the same shared network.
1182
Yair Fried413bf2d2014-11-19 17:07:11 +02001183 :param client: network client to create resources with.
1184 :param tenant_id: id of tenant to create resources in.
1185 :param dns_nameservers: list of dns servers to send to subnet.
Yair Fried1fc32a12014-08-04 09:11:30 +03001186 :returns: network, subnet, router
1187 """
David Shrewsbury9bac3662014-08-07 15:07:01 -04001188 if CONF.baremetal.driver_enabled:
1189 # NOTE(Shrews): This exception is for environments where tenant
1190 # credential isolation is available, but network separation is
1191 # not (the current baremetal case). Likely can be removed when
1192 # test account mgmt is reworked:
1193 # https://blueprints.launchpad.net/tempest/+spec/test-accounts
Adam Gandelman878a5fd2015-03-30 14:33:36 -07001194 if not CONF.compute.fixed_network_name:
1195 m = 'fixed_network_name must be specified in config'
1196 raise exceptions.InvalidConfiguration(m)
David Shrewsbury9bac3662014-08-07 15:07:01 -04001197 network = self._get_network_by_name(
1198 CONF.compute.fixed_network_name)
1199 router = None
1200 subnet = None
1201 else:
John Warren94d8faf2015-09-15 12:22:24 -04001202 network = self._create_network(
1203 client=client, networks_client=networks_client,
1204 tenant_id=tenant_id)
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +00001205 router = self._get_router(client=routers_client,
1206 tenant_id=tenant_id)
Yair Fried413bf2d2014-11-19 17:07:11 +02001207
John Warren3961acd2015-10-02 14:38:53 -04001208 subnet_kwargs = dict(network=network, client=client,
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +00001209 subnets_client=subnets_client,
1210 routers_client=routers_client)
Yair Fried413bf2d2014-11-19 17:07:11 +02001211 # use explicit check because empty list is a valid option
1212 if dns_nameservers is not None:
1213 subnet_kwargs['dns_nameservers'] = dns_nameservers
1214 subnet = self._create_subnet(**subnet_kwargs)
David Shrewsbury9bac3662014-08-07 15:07:01 -04001215 subnet.add_to_router(router.id)
Yair Fried1fc32a12014-08-04 09:11:30 +03001216 return network, subnet, router
1217
1218
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001219# power/provision states as of icehouse
1220class BaremetalPowerStates(object):
1221 """Possible power states of an Ironic node."""
1222 POWER_ON = 'power on'
1223 POWER_OFF = 'power off'
1224 REBOOT = 'rebooting'
1225 SUSPEND = 'suspended'
1226
1227
1228class BaremetalProvisionStates(object):
1229 """Possible provision states of an Ironic node."""
1230 NOSTATE = None
1231 INIT = 'initializing'
1232 ACTIVE = 'active'
1233 BUILDING = 'building'
1234 DEPLOYWAIT = 'wait call-back'
1235 DEPLOYING = 'deploying'
1236 DEPLOYFAIL = 'deploy failed'
1237 DEPLOYDONE = 'deploy complete'
1238 DELETING = 'deleting'
1239 DELETED = 'deleted'
1240 ERROR = 'error'
1241
1242
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001243class BaremetalScenarioTest(ScenarioTest):
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001244
1245 credentials = ['primary', 'admin']
1246
Adam Gandelman4a48a602014-03-20 18:23:18 -07001247 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001248 def skip_checks(cls):
1249 super(BaremetalScenarioTest, cls).skip_checks()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001250 if (not CONF.service_available.ironic or
1251 not CONF.baremetal.driver_enabled):
1252 msg = 'Ironic not available or Ironic compute driver not enabled'
1253 raise cls.skipException(msg)
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001254
1255 @classmethod
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001256 def setup_clients(cls):
1257 super(BaremetalScenarioTest, cls).setup_clients()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001258
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001259 cls.baremetal_client = cls.admin_manager.baremetal_client
Adam Gandelman4a48a602014-03-20 18:23:18 -07001260
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001261 @classmethod
1262 def resource_setup(cls):
1263 super(BaremetalScenarioTest, cls).resource_setup()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001264 # allow any issues obtaining the node list to raise early
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001265 cls.baremetal_client.list_nodes()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001266
1267 def _node_state_timeout(self, node_id, state_attr,
1268 target_states, timeout=10, interval=1):
1269 if not isinstance(target_states, list):
1270 target_states = [target_states]
1271
1272 def check_state():
1273 node = self.get_node(node_id=node_id)
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001274 if node.get(state_attr) in target_states:
Adam Gandelman4a48a602014-03-20 18:23:18 -07001275 return True
1276 return False
1277
1278 if not tempest.test.call_until_true(
1279 check_state, timeout, interval):
1280 msg = ("Timed out waiting for node %s to reach %s state(s) %s" %
1281 (node_id, state_attr, target_states))
1282 raise exceptions.TimeoutException(msg)
1283
1284 def wait_provisioning_state(self, node_id, state, timeout):
1285 self._node_state_timeout(
1286 node_id=node_id, state_attr='provision_state',
1287 target_states=state, timeout=timeout)
1288
1289 def wait_power_state(self, node_id, state):
1290 self._node_state_timeout(
1291 node_id=node_id, state_attr='power_state',
1292 target_states=state, timeout=CONF.baremetal.power_timeout)
1293
1294 def wait_node(self, instance_id):
1295 """Waits for a node to be associated with instance_id."""
Zhi Kun Liu4a8d1ea2014-04-15 22:08:21 -05001296
Adam Gandelman4a48a602014-03-20 18:23:18 -07001297 def _get_node():
1298 node = None
1299 try:
1300 node = self.get_node(instance_id=instance_id)
Masayuki Igawabfa07602015-01-20 18:47:17 +09001301 except lib_exc.NotFound:
Adam Gandelman4a48a602014-03-20 18:23:18 -07001302 pass
1303 return node is not None
1304
1305 if not tempest.test.call_until_true(
1306 _get_node, CONF.baremetal.association_timeout, 1):
1307 msg = ('Timed out waiting to get Ironic node by instance id %s'
1308 % instance_id)
1309 raise exceptions.TimeoutException(msg)
1310
1311 def get_node(self, node_id=None, instance_id=None):
1312 if node_id:
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001313 _, body = self.baremetal_client.show_node(node_id)
1314 return body
Adam Gandelman4a48a602014-03-20 18:23:18 -07001315 elif instance_id:
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001316 _, body = self.baremetal_client.show_node_by_instance_uuid(
1317 instance_id)
1318 if body['nodes']:
1319 return body['nodes'][0]
Adam Gandelman4a48a602014-03-20 18:23:18 -07001320
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001321 def get_ports(self, node_uuid):
Adam Gandelman4a48a602014-03-20 18:23:18 -07001322 ports = []
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001323 _, body = self.baremetal_client.list_node_ports(node_uuid)
1324 for port in body['ports']:
1325 _, p = self.baremetal_client.show_port(port['uuid'])
1326 ports.append(p)
Adam Gandelman4a48a602014-03-20 18:23:18 -07001327 return ports
1328
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001329 def add_keypair(self):
1330 self.keypair = self.create_keypair()
1331
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001332 def boot_instance(self):
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001333 self.instance = self.create_server(
lanoux5fc14522015-09-21 08:17:35 +00001334 key_name=self.keypair['name'])
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001335
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001336 self.wait_node(self.instance['id'])
1337 self.node = self.get_node(instance_id=self.instance['id'])
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001338
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001339 self.wait_power_state(self.node['uuid'], BaremetalPowerStates.POWER_ON)
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001340
1341 self.wait_provisioning_state(
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001342 self.node['uuid'],
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001343 [BaremetalProvisionStates.DEPLOYWAIT,
1344 BaremetalProvisionStates.ACTIVE],
1345 timeout=15)
1346
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001347 self.wait_provisioning_state(self.node['uuid'],
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001348 BaremetalProvisionStates.ACTIVE,
1349 timeout=CONF.baremetal.active_timeout)
1350
Ken'ichi Ohmichi0eb153c2015-07-13 02:18:25 +00001351 waiters.wait_for_server_status(self.servers_client,
1352 self.instance['id'], 'ACTIVE')
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001353 self.node = self.get_node(instance_id=self.instance['id'])
ghanshyam0f825252015-08-25 16:02:50 +09001354 self.instance = (self.servers_client.show_server(self.instance['id'])
1355 ['server'])
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001356
1357 def terminate_instance(self):
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001358 self.servers_client.delete_server(self.instance['id'])
1359 self.wait_power_state(self.node['uuid'],
1360 BaremetalPowerStates.POWER_OFF)
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001361 self.wait_provisioning_state(
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001362 self.node['uuid'],
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001363 BaremetalProvisionStates.NOSTATE,
1364 timeout=CONF.baremetal.unprovision_timeout)
1365
Adam Gandelman4a48a602014-03-20 18:23:18 -07001366
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001367class EncryptionScenarioTest(ScenarioTest):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001368 """Base class for encryption scenario tests"""
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001369
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001370 credentials = ['primary', 'admin']
David Kranz4cc852b2015-03-09 14:57:11 -04001371
1372 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001373 def setup_clients(cls):
1374 super(EncryptionScenarioTest, cls).setup_clients()
Ivan Kolodyazhnybcfc32e2015-08-06 13:31:36 +03001375 if CONF.volume_feature_enabled.api_v1:
1376 cls.admin_volume_types_client = cls.os_adm.volume_types_client
1377 else:
1378 cls.admin_volume_types_client = cls.os_adm.volume_types_v2_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001379
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001380 def create_volume_type(self, client=None, name=None):
1381 if not client:
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001382 client = self.admin_volume_types_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001383 if not name:
1384 name = 'generic'
Ken'ichi Ohmichi6ded8df2015-03-23 02:00:19 +00001385 randomized_name = data_utils.rand_name('scenario-type-' + name)
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001386 LOG.debug("Creating a volume type: %s", randomized_name)
Joseph Lanoux6809bab2014-12-18 14:57:18 +00001387 body = client.create_volume_type(
lei zhang83c4bbd2015-11-27 00:35:21 +08001388 name=randomized_name)['volume_type']
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001389 self.assertIn('id', body)
1390 self.addCleanup(client.delete_volume_type, body['id'])
1391 return body
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001392
1393 def create_encryption_type(self, client=None, type_id=None, provider=None,
1394 key_size=None, cipher=None,
1395 control_location=None):
1396 if not client:
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001397 client = self.admin_volume_types_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001398 if not type_id:
1399 volume_type = self.create_volume_type()
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001400 type_id = volume_type['id']
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001401 LOG.debug("Creating an encryption type for volume type: %s", type_id)
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001402 client.create_encryption_type(
1403 type_id, provider=provider, key_size=key_size, cipher=cipher,
John Warrend053ded2015-08-13 15:22:48 +00001404 control_location=control_location)['encryption']
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001405
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001406
Masayuki Igawa0870db52015-09-18 21:08:36 +09001407class ObjectStorageScenarioTest(ScenarioTest):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001408 """Provide harness to do Object Storage scenario tests.
Chris Dent0d494112014-08-26 13:48:30 +01001409
1410 Subclasses implement the tests that use the methods provided by this
1411 class.
1412 """
1413
1414 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001415 def skip_checks(cls):
Masayuki Igawa0870db52015-09-18 21:08:36 +09001416 super(ObjectStorageScenarioTest, cls).skip_checks()
Chris Dent0d494112014-08-26 13:48:30 +01001417 if not CONF.service_available.swift:
1418 skip_msg = ("%s skipped as swift is not available" %
1419 cls.__name__)
1420 raise cls.skipException(skip_msg)
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001421
1422 @classmethod
1423 def setup_credentials(cls):
Masayuki Igawa60ea6c52014-10-15 17:32:14 +09001424 cls.set_network_resources()
Masayuki Igawa0870db52015-09-18 21:08:36 +09001425 super(ObjectStorageScenarioTest, cls).setup_credentials()
Matthew Treinish4a596932015-03-06 20:37:01 -05001426 operator_role = CONF.object_storage.operator_role
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +01001427 cls.os_operator = cls.get_client_manager(roles=[operator_role])
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001428
1429 @classmethod
1430 def setup_clients(cls):
Masayuki Igawa0870db52015-09-18 21:08:36 +09001431 super(ObjectStorageScenarioTest, cls).setup_clients()
Chris Dent0d494112014-08-26 13:48:30 +01001432 # Clients for Swift
Matthew Treinish8f268292015-02-24 20:01:36 -05001433 cls.account_client = cls.os_operator.account_client
1434 cls.container_client = cls.os_operator.container_client
1435 cls.object_client = cls.os_operator.object_client
Chris Dent0d494112014-08-26 13:48:30 +01001436
Chris Dentde456a12014-09-10 12:41:15 +01001437 def get_swift_stat(self):
Chris Dent0d494112014-08-26 13:48:30 +01001438 """get swift status for our user account."""
1439 self.account_client.list_account_containers()
1440 LOG.debug('Swift status information obtained successfully')
1441
Chris Dentde456a12014-09-10 12:41:15 +01001442 def create_container(self, container_name=None):
Chris Dent0d494112014-08-26 13:48:30 +01001443 name = container_name or data_utils.rand_name(
1444 'swift-scenario-container')
1445 self.container_client.create_container(name)
1446 # look for the container to assure it is created
Chris Dentde456a12014-09-10 12:41:15 +01001447 self.list_and_check_container_objects(name)
Chris Dent0d494112014-08-26 13:48:30 +01001448 LOG.debug('Container %s created' % (name))
Chris Dent1d4313a2014-10-28 12:16:48 +00001449 self.addCleanup(self.delete_wrapper,
1450 self.container_client.delete_container,
1451 name)
Chris Dent0d494112014-08-26 13:48:30 +01001452 return name
1453
Chris Dentde456a12014-09-10 12:41:15 +01001454 def delete_container(self, container_name):
Chris Dent0d494112014-08-26 13:48:30 +01001455 self.container_client.delete_container(container_name)
1456 LOG.debug('Container %s deleted' % (container_name))
1457
Chris Dentde456a12014-09-10 12:41:15 +01001458 def upload_object_to_container(self, container_name, obj_name=None):
Chris Dent0d494112014-08-26 13:48:30 +01001459 obj_name = obj_name or data_utils.rand_name('swift-scenario-object')
1460 obj_data = data_utils.arbitrary_string()
1461 self.object_client.create_object(container_name, obj_name, obj_data)
Chris Dent1d4313a2014-10-28 12:16:48 +00001462 self.addCleanup(self.delete_wrapper,
1463 self.object_client.delete_object,
1464 container_name,
1465 obj_name)
Chris Dent0d494112014-08-26 13:48:30 +01001466 return obj_name, obj_data
1467
Chris Dentde456a12014-09-10 12:41:15 +01001468 def delete_object(self, container_name, filename):
Chris Dent0d494112014-08-26 13:48:30 +01001469 self.object_client.delete_object(container_name, filename)
Chris Dentde456a12014-09-10 12:41:15 +01001470 self.list_and_check_container_objects(container_name,
1471 not_present_obj=[filename])
Chris Dent0d494112014-08-26 13:48:30 +01001472
Chris Dentde456a12014-09-10 12:41:15 +01001473 def list_and_check_container_objects(self, container_name,
1474 present_obj=None,
1475 not_present_obj=None):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001476 # List objects for a given container and assert which are present and
1477 # which are not.
Ghanshyam2a180b82014-06-16 13:54:22 +09001478 if present_obj is None:
1479 present_obj = []
1480 if not_present_obj is None:
1481 not_present_obj = []
Chris Dent0d494112014-08-26 13:48:30 +01001482 _, object_list = self.container_client.list_container_contents(
1483 container_name)
1484 if present_obj:
1485 for obj in present_obj:
1486 self.assertIn(obj, object_list)
1487 if not_present_obj:
1488 for obj in not_present_obj:
1489 self.assertNotIn(obj, object_list)
1490
Chris Dentde456a12014-09-10 12:41:15 +01001491 def change_container_acl(self, container_name, acl):
Chris Dent0d494112014-08-26 13:48:30 +01001492 metadata_param = {'metadata_prefix': 'x-container-',
1493 'metadata': {'read': acl}}
1494 self.container_client.update_container_metadata(container_name,
1495 **metadata_param)
1496 resp, _ = self.container_client.list_container_metadata(container_name)
1497 self.assertEqual(resp['x-container-read'], acl)
1498
Chris Dentde456a12014-09-10 12:41:15 +01001499 def download_and_verify(self, container_name, obj_name, expected_data):
Chris Dent0d494112014-08-26 13:48:30 +01001500 _, obj = self.object_client.get_object(container_name, obj_name)
1501 self.assertEqual(obj, expected_data)