blob: eb29176ec70118eae4756b10a25c506ed0ad9744 [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
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):
Kevin Benton1d0c1dc2016-02-04 14:30:08 -0800816 ports = self._list_ports(device_id=server['id'], fixed_ip=ip_addr)
Sean M. Collins2e896832015-12-15 13:58:47 -0500817 # A port can have more then one IP address in some cases.
818 # If the network is dual-stack (IPv4 + IPv6), this port is associated
819 # with 2 subnets
Daniel Mellado9e3e1062015-08-06 18:07:05 +0200820 port_map = [(p["id"], fxip["ip_address"])
821 for p in ports
822 for fxip in p["fixed_ips"]
Kevin Benton1d0c1dc2016-02-04 14:30:08 -0800823 if netaddr.valid_ipv4(fxip["ip_address"])
824 and p['status'] == 'ACTIVE']
825 inactive = [p for p in ports if p['status'] != 'ACTIVE']
826 if inactive:
827 LOG.warning("Instance has ports that are not ACTIVE: %s", inactive)
Daniel Mellado9e3e1062015-08-06 18:07:05 +0200828
John L. Villalovosb83286f2015-11-04 14:46:57 -0800829 self.assertNotEqual(0, len(port_map),
830 "No IPv4 addresses found in: %s" % ports)
Daniel Mellado9e3e1062015-08-06 18:07:05 +0200831 self.assertEqual(len(port_map), 1,
832 "Found multiple IPv4 addresses: %s. "
833 "Unable to determine which port to target."
834 % port_map)
835 return port_map[0]
Yair Fried1fc32a12014-08-04 09:11:30 +0300836
David Shrewsbury9bac3662014-08-07 15:07:01 -0400837 def _get_network_by_name(self, network_name):
838 net = self._list_networks(name=network_name)
Adam Gandelman878a5fd2015-03-30 14:33:36 -0700839 self.assertNotEqual(len(net), 0,
840 "Unable to get network by name: %s" % network_name)
Yair Fried8186f812014-09-28 09:39:39 +0300841 return net_resources.AttributeDict(net[0])
David Shrewsbury9bac3662014-08-07 15:07:01 -0400842
Yair Friedae0e73d2014-11-24 11:56:26 +0200843 def create_floating_ip(self, thing, external_network_id=None,
844 port_id=None, client=None):
Ken'ichi Ohmichia112a592015-11-17 08:49:37 +0000845 """Create a floating IP and associates to a resource/port on Neutron"""
Yair Friedae0e73d2014-11-24 11:56:26 +0200846 if not external_network_id:
847 external_network_id = CONF.network.public_network_id
Yair Frieddb6c9e92014-08-06 08:53:13 +0300848 if not client:
John Warrenfbf2a892015-11-17 12:36:14 -0500849 client = self.floating_ips_client
Yair Fried1fc32a12014-08-04 09:11:30 +0300850 if not port_id:
Kirill Shileev14113572014-11-21 16:58:02 +0300851 port_id, ip4 = self._get_server_port_id_and_ip4(thing)
852 else:
853 ip4 = None
David Kranz34e88122014-12-11 15:24:05 -0500854 result = client.create_floatingip(
Yair Fried1fc32a12014-08-04 09:11:30 +0300855 floating_network_id=external_network_id,
856 port_id=port_id,
Kirill Shileev14113572014-11-21 16:58:02 +0300857 tenant_id=thing['tenant_id'],
858 fixed_ip_address=ip4
Yair Fried1fc32a12014-08-04 09:11:30 +0300859 )
860 floating_ip = net_resources.DeletableFloatingIp(
Yair Frieddb6c9e92014-08-06 08:53:13 +0300861 client=client,
Yair Fried1fc32a12014-08-04 09:11:30 +0300862 **result['floatingip'])
863 self.addCleanup(self.delete_wrapper, floating_ip.delete)
864 return floating_ip
865
866 def _associate_floating_ip(self, floating_ip, server):
Kirill Shileev14113572014-11-21 16:58:02 +0300867 port_id, _ = self._get_server_port_id_and_ip4(server)
Yair Fried1fc32a12014-08-04 09:11:30 +0300868 floating_ip.update(port_id=port_id)
869 self.assertEqual(port_id, floating_ip.port_id)
870 return floating_ip
871
872 def _disassociate_floating_ip(self, floating_ip):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000873 """:param floating_ip: type DeletableFloatingIp"""
Yair Fried1fc32a12014-08-04 09:11:30 +0300874 floating_ip.update(port_id=None)
875 self.assertIsNone(floating_ip.port_id)
876 return floating_ip
877
Yair Fried45f92952014-06-26 05:19:19 +0300878 def check_floating_ip_status(self, floating_ip, status):
Carl Baldwina754e2d2014-10-23 22:47:41 +0000879 """Verifies floatingip reaches the given status
Yair Fried45f92952014-06-26 05:19:19 +0300880
881 :param floating_ip: net_resources.DeletableFloatingIp floating IP to
882 to check status
883 :param status: target status
884 :raises: AssertionError if status doesn't match
885 """
Carl Baldwina754e2d2014-10-23 22:47:41 +0000886 def refresh():
887 floating_ip.refresh()
888 return status == floating_ip.status
889
890 tempest.test.call_until_true(refresh,
891 CONF.network.build_timeout,
892 CONF.network.build_interval)
Yair Fried45f92952014-06-26 05:19:19 +0300893 self.assertEqual(status, floating_ip.status,
894 message="FloatingIP: {fp} is at status: {cst}. "
895 "failed to reach status: {st}"
896 .format(fp=floating_ip, cst=floating_ip.status,
897 st=status))
898 LOG.info("FloatingIP: {fp} is at status: {st}"
899 .format(fp=floating_ip, st=status))
900
Yair Fried1fc32a12014-08-04 09:11:30 +0300901 def _check_tenant_network_connectivity(self, server,
902 username,
903 private_key,
904 should_connect=True,
905 servers_for_debug=None):
906 if not CONF.network.tenant_networks_reachable:
907 msg = 'Tenant networks not configured to be reachable.'
908 LOG.info(msg)
909 return
910 # The target login is assumed to have been configured for
911 # key-based authentication by cloud-init.
912 try:
Matthew Treinish71426682015-04-23 11:19:38 -0400913 for net_name, ip_addresses in six.iteritems(server['addresses']):
Yair Fried1fc32a12014-08-04 09:11:30 +0300914 for ip_address in ip_addresses:
ghanshyam807211c2014-12-18 13:21:22 +0900915 self.check_vm_connectivity(ip_address['addr'],
Yair Friedae0e73d2014-11-24 11:56:26 +0200916 username,
917 private_key,
918 should_connect=should_connect)
Yair Fried1fc32a12014-08-04 09:11:30 +0300919 except Exception as e:
920 LOG.exception('Tenant network connectivity check failed')
921 self._log_console_output(servers_for_debug)
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000922 self._log_net_info(e)
Yair Fried1fc32a12014-08-04 09:11:30 +0300923 raise
924
Yair Friedbc46f592015-11-18 16:29:34 +0200925 def _check_remote_connectivity(self, source, dest, should_succeed=True,
926 nic=None):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000927 """check ping server via source ssh connection
Yair Fried1fc32a12014-08-04 09:11:30 +0300928
929 :param source: RemoteClient: an ssh connection from which to ping
930 :param dest: and IP to ping against
931 :param should_succeed: boolean should ping succeed or not
Yair Friedbc46f592015-11-18 16:29:34 +0200932 :param nic: specific network interface to ping from
Yair Fried1fc32a12014-08-04 09:11:30 +0300933 :returns: boolean -- should_succeed == ping
934 :returns: ping is false if ping failed
935 """
936 def ping_remote():
937 try:
Yair Friedbc46f592015-11-18 16:29:34 +0200938 source.ping_host(dest, nic=nic)
Andrey Pavlov64723762015-04-29 06:24:58 +0300939 except lib_exc.SSHExecCommandFailed:
zhangguoqing6c096642016-01-04 06:17:21 +0000940 LOG.warning('Failed to ping IP: %s via a ssh connection '
941 'from: %s.' % (dest, source.ssh_client.host))
Yair Fried1fc32a12014-08-04 09:11:30 +0300942 return not should_succeed
943 return should_succeed
944
945 return tempest.test.call_until_true(ping_remote,
lanoux5fc14522015-09-21 08:17:35 +0000946 CONF.validation.ping_timeout,
Yair Fried1fc32a12014-08-04 09:11:30 +0300947 1)
948
John Warren456d9ae2016-01-12 15:36:33 -0500949 def _create_security_group(self, security_group_rules_client=None,
950 tenant_id=None,
John Warrenf9606e92015-12-10 12:12:42 -0500951 namestart='secgroup-smoke',
952 security_groups_client=None):
John Warren456d9ae2016-01-12 15:36:33 -0500953 if security_group_rules_client is None:
954 security_group_rules_client = self.security_group_rules_client
John Warrenf9606e92015-12-10 12:12:42 -0500955 if security_groups_client is None:
956 security_groups_client = self.security_groups_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300957 if tenant_id is None:
John Warrenf9606e92015-12-10 12:12:42 -0500958 tenant_id = security_groups_client.tenant_id
959 secgroup = self._create_empty_security_group(
960 namestart=namestart, client=security_groups_client,
961 tenant_id=tenant_id)
Yair Fried1fc32a12014-08-04 09:11:30 +0300962
963 # Add rules to the security group
John Warrenf9606e92015-12-10 12:12:42 -0500964 rules = self._create_loginable_secgroup_rule(
John Warren456d9ae2016-01-12 15:36:33 -0500965 security_group_rules_client=security_group_rules_client,
966 secgroup=secgroup,
John Warrenf9606e92015-12-10 12:12:42 -0500967 security_groups_client=security_groups_client)
Yair Fried1fc32a12014-08-04 09:11:30 +0300968 for rule in rules:
969 self.assertEqual(tenant_id, rule.tenant_id)
970 self.assertEqual(secgroup.id, rule.security_group_id)
971 return secgroup
972
Yair Frieddb6c9e92014-08-06 08:53:13 +0300973 def _create_empty_security_group(self, client=None, tenant_id=None,
Yair Fried1fc32a12014-08-04 09:11:30 +0300974 namestart='secgroup-smoke'):
975 """Create a security group without rules.
976
977 Default rules will be created:
978 - IPv4 egress to any
979 - IPv6 egress to any
980
981 :param tenant_id: secgroup will be created in this tenant
982 :returns: DeletableSecurityGroup -- containing the secgroup created
983 """
984 if client is None:
John Warrenf9606e92015-12-10 12:12:42 -0500985 client = self.security_groups_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300986 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000987 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300988 sg_name = data_utils.rand_name(namestart)
989 sg_desc = sg_name + " description"
990 sg_dict = dict(name=sg_name,
991 description=sg_desc)
992 sg_dict['tenant_id'] = tenant_id
David Kranz34e88122014-12-11 15:24:05 -0500993 result = client.create_security_group(**sg_dict)
Yair Fried1fc32a12014-08-04 09:11:30 +0300994 secgroup = net_resources.DeletableSecurityGroup(
995 client=client,
996 **result['security_group']
997 )
998 self.assertEqual(secgroup.name, sg_name)
999 self.assertEqual(tenant_id, secgroup.tenant_id)
1000 self.assertEqual(secgroup.description, sg_desc)
1001 self.addCleanup(self.delete_wrapper, secgroup.delete)
1002 return secgroup
1003
Yair Frieddb6c9e92014-08-06 08:53:13 +03001004 def _default_security_group(self, client=None, tenant_id=None):
Yair Fried1fc32a12014-08-04 09:11:30 +03001005 """Get default secgroup for given tenant_id.
1006
1007 :returns: DeletableSecurityGroup -- default secgroup for given tenant
1008 """
1009 if client is None:
John Warrenf9606e92015-12-10 12:12:42 -05001010 client = self.security_groups_client
Yair Frieddb6c9e92014-08-06 08:53:13 +03001011 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +00001012 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001013 sgs = [
1014 sg for sg in client.list_security_groups().values()[0]
1015 if sg['tenant_id'] == tenant_id and sg['name'] == 'default'
1016 ]
1017 msg = "No default security group for tenant %s." % (tenant_id)
1018 self.assertTrue(len(sgs) > 0, msg)
Yair Fried1fc32a12014-08-04 09:11:30 +03001019 return net_resources.DeletableSecurityGroup(client=client,
1020 **sgs[0])
1021
John Warren456d9ae2016-01-12 15:36:33 -05001022 def _create_security_group_rule(self, secgroup=None,
1023 sec_group_rules_client=None,
John Warrenf9606e92015-12-10 12:12:42 -05001024 tenant_id=None,
1025 security_groups_client=None, **kwargs):
Yair Fried1fc32a12014-08-04 09:11:30 +03001026 """Create a rule from a dictionary of rule parameters.
1027
1028 Create a rule in a secgroup. if secgroup not defined will search for
1029 default secgroup in tenant_id.
1030
1031 :param secgroup: type DeletableSecurityGroup.
Yair Fried1fc32a12014-08-04 09:11:30 +03001032 :param tenant_id: if secgroup not passed -- the tenant in which to
1033 search for default secgroup
1034 :param kwargs: a dictionary containing rule parameters:
1035 for example, to allow incoming ssh:
1036 rule = {
1037 direction: 'ingress'
1038 protocol:'tcp',
1039 port_range_min: 22,
1040 port_range_max: 22
1041 }
1042 """
John Warren456d9ae2016-01-12 15:36:33 -05001043 if sec_group_rules_client is None:
1044 sec_group_rules_client = self.security_group_rules_client
John Warrenf9606e92015-12-10 12:12:42 -05001045 if security_groups_client is None:
1046 security_groups_client = self.security_groups_client
Yair Frieddb6c9e92014-08-06 08:53:13 +03001047 if not tenant_id:
John Warrenf9606e92015-12-10 12:12:42 -05001048 tenant_id = security_groups_client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001049 if secgroup is None:
John Warrenf9606e92015-12-10 12:12:42 -05001050 secgroup = self._default_security_group(
1051 client=security_groups_client, tenant_id=tenant_id)
Yair Fried1fc32a12014-08-04 09:11:30 +03001052
1053 ruleset = dict(security_group_id=secgroup.id,
1054 tenant_id=secgroup.tenant_id)
1055 ruleset.update(kwargs)
1056
John Warren456d9ae2016-01-12 15:36:33 -05001057 sg_rule = sec_group_rules_client.create_security_group_rule(**ruleset)
Yair Fried1fc32a12014-08-04 09:11:30 +03001058 sg_rule = net_resources.DeletableSecurityGroupRule(
John Warren456d9ae2016-01-12 15:36:33 -05001059 client=sec_group_rules_client,
Yair Fried1fc32a12014-08-04 09:11:30 +03001060 **sg_rule['security_group_rule']
1061 )
Yair Fried1fc32a12014-08-04 09:11:30 +03001062 self.assertEqual(secgroup.tenant_id, sg_rule.tenant_id)
1063 self.assertEqual(secgroup.id, sg_rule.security_group_id)
1064
1065 return sg_rule
1066
John Warren456d9ae2016-01-12 15:36:33 -05001067 def _create_loginable_secgroup_rule(self, security_group_rules_client=None,
1068 secgroup=None,
John Warrenf9606e92015-12-10 12:12:42 -05001069 security_groups_client=None):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001070 """Create loginable security group rule
1071
1072 These rules are intended to permit inbound ssh and icmp
Yair Fried1fc32a12014-08-04 09:11:30 +03001073 traffic from all sources, so no group_id is provided.
1074 Setting a group_id would only permit traffic from ports
1075 belonging to the same security group.
1076 """
1077
John Warren456d9ae2016-01-12 15:36:33 -05001078 if security_group_rules_client is None:
1079 security_group_rules_client = self.security_group_rules_client
John Warrenf9606e92015-12-10 12:12:42 -05001080 if security_groups_client is None:
1081 security_groups_client = self.security_groups_client
Yair Fried1fc32a12014-08-04 09:11:30 +03001082 rules = []
1083 rulesets = [
1084 dict(
1085 # ssh
1086 protocol='tcp',
1087 port_range_min=22,
1088 port_range_max=22,
1089 ),
1090 dict(
1091 # ping
1092 protocol='icmp',
Andreas Scheuring887ca8e2015-02-03 17:56:12 +01001093 ),
1094 dict(
1095 # ipv6-icmp for ping6
1096 protocol='icmp',
1097 ethertype='IPv6',
Yair Fried1fc32a12014-08-04 09:11:30 +03001098 )
1099 ]
John Warren456d9ae2016-01-12 15:36:33 -05001100 sec_group_rules_client = security_group_rules_client
Yair Fried1fc32a12014-08-04 09:11:30 +03001101 for ruleset in rulesets:
1102 for r_direction in ['ingress', 'egress']:
1103 ruleset['direction'] = r_direction
1104 try:
1105 sg_rule = self._create_security_group_rule(
John Warren456d9ae2016-01-12 15:36:33 -05001106 sec_group_rules_client=sec_group_rules_client,
1107 secgroup=secgroup,
John Warrenf9606e92015-12-10 12:12:42 -05001108 security_groups_client=security_groups_client,
1109 **ruleset)
Masayuki Igawad9388762015-01-20 14:56:42 +09001110 except lib_exc.Conflict as ex:
Yair Fried1fc32a12014-08-04 09:11:30 +03001111 # if rule already exist - skip rule and continue
1112 msg = 'Security group rule already exists'
1113 if msg not in ex._error_string:
1114 raise ex
1115 else:
1116 self.assertEqual(r_direction, sg_rule.direction)
1117 rules.append(sg_rule)
1118
1119 return rules
1120
Yair Frieddb6c9e92014-08-06 08:53:13 +03001121 def _get_router(self, client=None, tenant_id=None):
Yair Fried1fc32a12014-08-04 09:11:30 +03001122 """Retrieve a router for the given tenant id.
1123
1124 If a public router has been configured, it will be returned.
1125
1126 If a public router has not been configured, but a public
1127 network has, a tenant router will be created and returned that
1128 routes traffic to the public network.
1129 """
Yair Frieddb6c9e92014-08-06 08:53:13 +03001130 if not client:
1131 client = self.network_client
1132 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +00001133 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001134 router_id = CONF.network.public_router_id
1135 network_id = CONF.network.public_network_id
1136 if router_id:
David Kranzca4c7e72015-05-27 11:39:19 -04001137 body = client.show_router(router_id)
Sergey Shnaidman5e9c8fd2014-09-30 18:31:43 +04001138 return net_resources.AttributeDict(**body['router'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001139 elif network_id:
Yair Frieddb6c9e92014-08-06 08:53:13 +03001140 router = self._create_router(client, tenant_id)
Yair Fried1fc32a12014-08-04 09:11:30 +03001141 router.set_gateway(network_id)
1142 return router
1143 else:
1144 raise Exception("Neither of 'public_router_id' or "
1145 "'public_network_id' has been defined.")
1146
Yair Frieddb6c9e92014-08-06 08:53:13 +03001147 def _create_router(self, client=None, tenant_id=None,
1148 namestart='router-smoke'):
1149 if not client:
1150 client = self.network_client
1151 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +00001152 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001153 name = data_utils.rand_name(namestart)
David Kranz34e88122014-12-11 15:24:05 -05001154 result = client.create_router(name=name,
1155 admin_state_up=True,
1156 tenant_id=tenant_id)
Yair Frieddb6c9e92014-08-06 08:53:13 +03001157 router = net_resources.DeletableRouter(client=client,
Yair Fried1fc32a12014-08-04 09:11:30 +03001158 **result['router'])
1159 self.assertEqual(router.name, name)
1160 self.addCleanup(self.delete_wrapper, router.delete)
1161 return router
1162
Alok Maurya6384bbb2014-07-13 06:44:29 -07001163 def _update_router_admin_state(self, router, admin_state_up):
1164 router.update(admin_state_up=admin_state_up)
1165 self.assertEqual(admin_state_up, router.admin_state_up)
1166
John Warren94d8faf2015-09-15 12:22:24 -04001167 def create_networks(self, client=None, networks_client=None,
John Warren3961acd2015-10-02 14:38:53 -04001168 subnets_client=None, tenant_id=None,
1169 dns_nameservers=None):
Yair Fried1fc32a12014-08-04 09:11:30 +03001170 """Create a network with a subnet connected to a router.
1171
David Shrewsbury9bac3662014-08-07 15:07:01 -04001172 The baremetal driver is a special case since all nodes are
1173 on the same shared network.
1174
Yair Fried413bf2d2014-11-19 17:07:11 +02001175 :param client: network client to create resources with.
1176 :param tenant_id: id of tenant to create resources in.
1177 :param dns_nameservers: list of dns servers to send to subnet.
Yair Fried1fc32a12014-08-04 09:11:30 +03001178 :returns: network, subnet, router
1179 """
David Shrewsbury9bac3662014-08-07 15:07:01 -04001180 if CONF.baremetal.driver_enabled:
1181 # NOTE(Shrews): This exception is for environments where tenant
1182 # credential isolation is available, but network separation is
1183 # not (the current baremetal case). Likely can be removed when
1184 # test account mgmt is reworked:
1185 # https://blueprints.launchpad.net/tempest/+spec/test-accounts
Adam Gandelman878a5fd2015-03-30 14:33:36 -07001186 if not CONF.compute.fixed_network_name:
1187 m = 'fixed_network_name must be specified in config'
1188 raise exceptions.InvalidConfiguration(m)
David Shrewsbury9bac3662014-08-07 15:07:01 -04001189 network = self._get_network_by_name(
1190 CONF.compute.fixed_network_name)
1191 router = None
1192 subnet = None
1193 else:
John Warren94d8faf2015-09-15 12:22:24 -04001194 network = self._create_network(
1195 client=client, networks_client=networks_client,
1196 tenant_id=tenant_id)
Yair Frieddb6c9e92014-08-06 08:53:13 +03001197 router = self._get_router(client=client, tenant_id=tenant_id)
Yair Fried413bf2d2014-11-19 17:07:11 +02001198
John Warren3961acd2015-10-02 14:38:53 -04001199 subnet_kwargs = dict(network=network, client=client,
1200 subnets_client=subnets_client)
Yair Fried413bf2d2014-11-19 17:07:11 +02001201 # use explicit check because empty list is a valid option
1202 if dns_nameservers is not None:
1203 subnet_kwargs['dns_nameservers'] = dns_nameservers
1204 subnet = self._create_subnet(**subnet_kwargs)
David Shrewsbury9bac3662014-08-07 15:07:01 -04001205 subnet.add_to_router(router.id)
Yair Fried1fc32a12014-08-04 09:11:30 +03001206 return network, subnet, router
1207
1208
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001209# power/provision states as of icehouse
1210class BaremetalPowerStates(object):
1211 """Possible power states of an Ironic node."""
1212 POWER_ON = 'power on'
1213 POWER_OFF = 'power off'
1214 REBOOT = 'rebooting'
1215 SUSPEND = 'suspended'
1216
1217
1218class BaremetalProvisionStates(object):
1219 """Possible provision states of an Ironic node."""
1220 NOSTATE = None
1221 INIT = 'initializing'
1222 ACTIVE = 'active'
1223 BUILDING = 'building'
1224 DEPLOYWAIT = 'wait call-back'
1225 DEPLOYING = 'deploying'
1226 DEPLOYFAIL = 'deploy failed'
1227 DEPLOYDONE = 'deploy complete'
1228 DELETING = 'deleting'
1229 DELETED = 'deleted'
1230 ERROR = 'error'
1231
1232
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001233class BaremetalScenarioTest(ScenarioTest):
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001234
1235 credentials = ['primary', 'admin']
1236
Adam Gandelman4a48a602014-03-20 18:23:18 -07001237 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001238 def skip_checks(cls):
1239 super(BaremetalScenarioTest, cls).skip_checks()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001240 if (not CONF.service_available.ironic or
1241 not CONF.baremetal.driver_enabled):
1242 msg = 'Ironic not available or Ironic compute driver not enabled'
1243 raise cls.skipException(msg)
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001244
1245 @classmethod
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001246 def setup_clients(cls):
1247 super(BaremetalScenarioTest, cls).setup_clients()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001248
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001249 cls.baremetal_client = cls.admin_manager.baremetal_client
Adam Gandelman4a48a602014-03-20 18:23:18 -07001250
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001251 @classmethod
1252 def resource_setup(cls):
1253 super(BaremetalScenarioTest, cls).resource_setup()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001254 # allow any issues obtaining the node list to raise early
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001255 cls.baremetal_client.list_nodes()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001256
1257 def _node_state_timeout(self, node_id, state_attr,
1258 target_states, timeout=10, interval=1):
1259 if not isinstance(target_states, list):
1260 target_states = [target_states]
1261
1262 def check_state():
1263 node = self.get_node(node_id=node_id)
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001264 if node.get(state_attr) in target_states:
Adam Gandelman4a48a602014-03-20 18:23:18 -07001265 return True
1266 return False
1267
1268 if not tempest.test.call_until_true(
1269 check_state, timeout, interval):
1270 msg = ("Timed out waiting for node %s to reach %s state(s) %s" %
1271 (node_id, state_attr, target_states))
1272 raise exceptions.TimeoutException(msg)
1273
1274 def wait_provisioning_state(self, node_id, state, timeout):
1275 self._node_state_timeout(
1276 node_id=node_id, state_attr='provision_state',
1277 target_states=state, timeout=timeout)
1278
1279 def wait_power_state(self, node_id, state):
1280 self._node_state_timeout(
1281 node_id=node_id, state_attr='power_state',
1282 target_states=state, timeout=CONF.baremetal.power_timeout)
1283
1284 def wait_node(self, instance_id):
1285 """Waits for a node to be associated with instance_id."""
Zhi Kun Liu4a8d1ea2014-04-15 22:08:21 -05001286
Adam Gandelman4a48a602014-03-20 18:23:18 -07001287 def _get_node():
1288 node = None
1289 try:
1290 node = self.get_node(instance_id=instance_id)
Masayuki Igawabfa07602015-01-20 18:47:17 +09001291 except lib_exc.NotFound:
Adam Gandelman4a48a602014-03-20 18:23:18 -07001292 pass
1293 return node is not None
1294
1295 if not tempest.test.call_until_true(
1296 _get_node, CONF.baremetal.association_timeout, 1):
1297 msg = ('Timed out waiting to get Ironic node by instance id %s'
1298 % instance_id)
1299 raise exceptions.TimeoutException(msg)
1300
1301 def get_node(self, node_id=None, instance_id=None):
1302 if node_id:
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001303 _, body = self.baremetal_client.show_node(node_id)
1304 return body
Adam Gandelman4a48a602014-03-20 18:23:18 -07001305 elif instance_id:
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001306 _, body = self.baremetal_client.show_node_by_instance_uuid(
1307 instance_id)
1308 if body['nodes']:
1309 return body['nodes'][0]
Adam Gandelman4a48a602014-03-20 18:23:18 -07001310
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001311 def get_ports(self, node_uuid):
Adam Gandelman4a48a602014-03-20 18:23:18 -07001312 ports = []
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001313 _, body = self.baremetal_client.list_node_ports(node_uuid)
1314 for port in body['ports']:
1315 _, p = self.baremetal_client.show_port(port['uuid'])
1316 ports.append(p)
Adam Gandelman4a48a602014-03-20 18:23:18 -07001317 return ports
1318
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001319 def add_keypair(self):
1320 self.keypair = self.create_keypair()
1321
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001322 def boot_instance(self):
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001323 self.instance = self.create_server(
lanoux5fc14522015-09-21 08:17:35 +00001324 key_name=self.keypair['name'])
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001325
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001326 self.wait_node(self.instance['id'])
1327 self.node = self.get_node(instance_id=self.instance['id'])
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001328
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001329 self.wait_power_state(self.node['uuid'], BaremetalPowerStates.POWER_ON)
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001330
1331 self.wait_provisioning_state(
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001332 self.node['uuid'],
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001333 [BaremetalProvisionStates.DEPLOYWAIT,
1334 BaremetalProvisionStates.ACTIVE],
1335 timeout=15)
1336
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001337 self.wait_provisioning_state(self.node['uuid'],
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001338 BaremetalProvisionStates.ACTIVE,
1339 timeout=CONF.baremetal.active_timeout)
1340
Ken'ichi Ohmichi0eb153c2015-07-13 02:18:25 +00001341 waiters.wait_for_server_status(self.servers_client,
1342 self.instance['id'], 'ACTIVE')
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001343 self.node = self.get_node(instance_id=self.instance['id'])
ghanshyam0f825252015-08-25 16:02:50 +09001344 self.instance = (self.servers_client.show_server(self.instance['id'])
1345 ['server'])
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001346
1347 def terminate_instance(self):
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001348 self.servers_client.delete_server(self.instance['id'])
1349 self.wait_power_state(self.node['uuid'],
1350 BaremetalPowerStates.POWER_OFF)
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001351 self.wait_provisioning_state(
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001352 self.node['uuid'],
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001353 BaremetalProvisionStates.NOSTATE,
1354 timeout=CONF.baremetal.unprovision_timeout)
1355
Adam Gandelman4a48a602014-03-20 18:23:18 -07001356
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001357class EncryptionScenarioTest(ScenarioTest):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001358 """Base class for encryption scenario tests"""
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001359
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001360 credentials = ['primary', 'admin']
David Kranz4cc852b2015-03-09 14:57:11 -04001361
1362 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001363 def setup_clients(cls):
1364 super(EncryptionScenarioTest, cls).setup_clients()
Ivan Kolodyazhnybcfc32e2015-08-06 13:31:36 +03001365 if CONF.volume_feature_enabled.api_v1:
1366 cls.admin_volume_types_client = cls.os_adm.volume_types_client
1367 else:
1368 cls.admin_volume_types_client = cls.os_adm.volume_types_v2_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001369
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001370 def create_volume_type(self, client=None, name=None):
1371 if not client:
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001372 client = self.admin_volume_types_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001373 if not name:
1374 name = 'generic'
Ken'ichi Ohmichi6ded8df2015-03-23 02:00:19 +00001375 randomized_name = data_utils.rand_name('scenario-type-' + name)
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001376 LOG.debug("Creating a volume type: %s", randomized_name)
Joseph Lanoux6809bab2014-12-18 14:57:18 +00001377 body = client.create_volume_type(
lei zhang83c4bbd2015-11-27 00:35:21 +08001378 name=randomized_name)['volume_type']
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001379 self.assertIn('id', body)
1380 self.addCleanup(client.delete_volume_type, body['id'])
1381 return body
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001382
1383 def create_encryption_type(self, client=None, type_id=None, provider=None,
1384 key_size=None, cipher=None,
1385 control_location=None):
1386 if not client:
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001387 client = self.admin_volume_types_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001388 if not type_id:
1389 volume_type = self.create_volume_type()
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001390 type_id = volume_type['id']
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001391 LOG.debug("Creating an encryption type for volume type: %s", type_id)
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001392 client.create_encryption_type(
1393 type_id, provider=provider, key_size=key_size, cipher=cipher,
John Warrend053ded2015-08-13 15:22:48 +00001394 control_location=control_location)['encryption']
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001395
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001396
Masayuki Igawa0870db52015-09-18 21:08:36 +09001397class ObjectStorageScenarioTest(ScenarioTest):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001398 """Provide harness to do Object Storage scenario tests.
Chris Dent0d494112014-08-26 13:48:30 +01001399
1400 Subclasses implement the tests that use the methods provided by this
1401 class.
1402 """
1403
1404 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001405 def skip_checks(cls):
Masayuki Igawa0870db52015-09-18 21:08:36 +09001406 super(ObjectStorageScenarioTest, cls).skip_checks()
Chris Dent0d494112014-08-26 13:48:30 +01001407 if not CONF.service_available.swift:
1408 skip_msg = ("%s skipped as swift is not available" %
1409 cls.__name__)
1410 raise cls.skipException(skip_msg)
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001411
1412 @classmethod
1413 def setup_credentials(cls):
Masayuki Igawa60ea6c52014-10-15 17:32:14 +09001414 cls.set_network_resources()
Masayuki Igawa0870db52015-09-18 21:08:36 +09001415 super(ObjectStorageScenarioTest, cls).setup_credentials()
Matthew Treinish4a596932015-03-06 20:37:01 -05001416 operator_role = CONF.object_storage.operator_role
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +01001417 cls.os_operator = cls.get_client_manager(roles=[operator_role])
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001418
1419 @classmethod
1420 def setup_clients(cls):
Masayuki Igawa0870db52015-09-18 21:08:36 +09001421 super(ObjectStorageScenarioTest, cls).setup_clients()
Chris Dent0d494112014-08-26 13:48:30 +01001422 # Clients for Swift
Matthew Treinish8f268292015-02-24 20:01:36 -05001423 cls.account_client = cls.os_operator.account_client
1424 cls.container_client = cls.os_operator.container_client
1425 cls.object_client = cls.os_operator.object_client
Chris Dent0d494112014-08-26 13:48:30 +01001426
Chris Dentde456a12014-09-10 12:41:15 +01001427 def get_swift_stat(self):
Chris Dent0d494112014-08-26 13:48:30 +01001428 """get swift status for our user account."""
1429 self.account_client.list_account_containers()
1430 LOG.debug('Swift status information obtained successfully')
1431
Chris Dentde456a12014-09-10 12:41:15 +01001432 def create_container(self, container_name=None):
Chris Dent0d494112014-08-26 13:48:30 +01001433 name = container_name or data_utils.rand_name(
1434 'swift-scenario-container')
1435 self.container_client.create_container(name)
1436 # look for the container to assure it is created
Chris Dentde456a12014-09-10 12:41:15 +01001437 self.list_and_check_container_objects(name)
Chris Dent0d494112014-08-26 13:48:30 +01001438 LOG.debug('Container %s created' % (name))
Chris Dent1d4313a2014-10-28 12:16:48 +00001439 self.addCleanup(self.delete_wrapper,
1440 self.container_client.delete_container,
1441 name)
Chris Dent0d494112014-08-26 13:48:30 +01001442 return name
1443
Chris Dentde456a12014-09-10 12:41:15 +01001444 def delete_container(self, container_name):
Chris Dent0d494112014-08-26 13:48:30 +01001445 self.container_client.delete_container(container_name)
1446 LOG.debug('Container %s deleted' % (container_name))
1447
Chris Dentde456a12014-09-10 12:41:15 +01001448 def upload_object_to_container(self, container_name, obj_name=None):
Chris Dent0d494112014-08-26 13:48:30 +01001449 obj_name = obj_name or data_utils.rand_name('swift-scenario-object')
1450 obj_data = data_utils.arbitrary_string()
1451 self.object_client.create_object(container_name, obj_name, obj_data)
Chris Dent1d4313a2014-10-28 12:16:48 +00001452 self.addCleanup(self.delete_wrapper,
1453 self.object_client.delete_object,
1454 container_name,
1455 obj_name)
Chris Dent0d494112014-08-26 13:48:30 +01001456 return obj_name, obj_data
1457
Chris Dentde456a12014-09-10 12:41:15 +01001458 def delete_object(self, container_name, filename):
Chris Dent0d494112014-08-26 13:48:30 +01001459 self.object_client.delete_object(container_name, filename)
Chris Dentde456a12014-09-10 12:41:15 +01001460 self.list_and_check_container_objects(container_name,
1461 not_present_obj=[filename])
Chris Dent0d494112014-08-26 13:48:30 +01001462
Chris Dentde456a12014-09-10 12:41:15 +01001463 def list_and_check_container_objects(self, container_name,
1464 present_obj=None,
1465 not_present_obj=None):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001466 # List objects for a given container and assert which are present and
1467 # which are not.
Ghanshyam2a180b82014-06-16 13:54:22 +09001468 if present_obj is None:
1469 present_obj = []
1470 if not_present_obj is None:
1471 not_present_obj = []
Chris Dent0d494112014-08-26 13:48:30 +01001472 _, object_list = self.container_client.list_container_contents(
1473 container_name)
1474 if present_obj:
1475 for obj in present_obj:
1476 self.assertIn(obj, object_list)
1477 if not_present_obj:
1478 for obj in not_present_obj:
1479 self.assertNotIn(obj, object_list)
1480
Chris Dentde456a12014-09-10 12:41:15 +01001481 def change_container_acl(self, container_name, acl):
Chris Dent0d494112014-08-26 13:48:30 +01001482 metadata_param = {'metadata_prefix': 'x-container-',
1483 'metadata': {'read': acl}}
1484 self.container_client.update_container_metadata(container_name,
1485 **metadata_param)
1486 resp, _ = self.container_client.list_container_metadata(container_name)
1487 self.assertEqual(resp['x-container-read'], acl)
1488
Chris Dentde456a12014-09-10 12:41:15 +01001489 def download_and_verify(self, container_name, obj_name, expected_data):
Chris Dent0d494112014-08-26 13:48:30 +01001490 _, obj = self.object_client.get_object(container_name, obj_name)
1491 self.assertEqual(obj, expected_data)