blob: bebba0f5bc566b7c1b088e6a68808ca66ed141b8 [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
Jordan Pittier9e227c52016-02-09 14:35:18 +010030from tempest.lib.common.utils import test_utils
Andrea Frittoli (andreaf)db9672e2016-02-23 14:07:24 -050031from tempest.lib import exceptions as lib_exc
Ken'ichi Ohmichi69a182a2016-04-29 10:56:27 -070032from tempest.scenario import network_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
John Warren94d8faf2015-09-15 12:22:24 -040066 cls.networks_client = cls.manager.networks_client
John Warren49c0fe52015-10-22 12:35:54 -040067 cls.ports_client = cls.manager.ports_client
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +000068 cls.routers_client = cls.manager.routers_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
Andrea Frittoli247058f2014-07-16 16:09:22 +010098 def addCleanup_with_wait(self, waiter_callable, thing_id, thing_id_param,
Ghanshyam2a180b82014-06-16 13:54:22 +090099 cleanup_callable, cleanup_args=None,
Ken'ichi Ohmichie91a0c62015-08-13 02:09:16 +0000100 cleanup_kwargs=None, waiter_client=None):
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700101 """Adds wait for async resource deletion at the end of cleanups
Andrea Frittoli247058f2014-07-16 16:09:22 +0100102
103 @param waiter_callable: callable to wait for the resource to delete
Ken'ichi Ohmichie91a0c62015-08-13 02:09:16 +0000104 with the following waiter_client if specified.
Andrea Frittoli247058f2014-07-16 16:09:22 +0100105 @param thing_id: the id of the resource to be cleaned-up
106 @param thing_id_param: the name of the id param in the waiter
107 @param cleanup_callable: method to load pass to self.addCleanup with
108 the following *cleanup_args, **cleanup_kwargs.
109 usually a delete method.
110 """
Ghanshyam2a180b82014-06-16 13:54:22 +0900111 if cleanup_args is None:
112 cleanup_args = []
113 if cleanup_kwargs is None:
114 cleanup_kwargs = {}
Andrea Frittoli247058f2014-07-16 16:09:22 +0100115 self.addCleanup(cleanup_callable, *cleanup_args, **cleanup_kwargs)
116 wait_dict = {
117 'waiter_callable': waiter_callable,
118 thing_id_param: thing_id
119 }
Ken'ichi Ohmichie91a0c62015-08-13 02:09:16 +0000120 if waiter_client:
121 wait_dict['client'] = waiter_client
Andrea Frittoli247058f2014-07-16 16:09:22 +0100122 self.cleanup_waits.append(wait_dict)
123
124 def _wait_for_cleanups(self):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000125 # To handle async delete actions, a list of waits is added
126 # which will be iterated over as the last step of clearing the
127 # cleanup queue. That way all the delete calls are made up front
128 # and the tests won't succeed unless the deletes are eventually
129 # successful. This is the same basic approach used in the api tests to
130 # limit cleanup execution time except here it is multi-resource,
131 # because of the nature of the scenario tests.
Andrea Frittoli247058f2014-07-16 16:09:22 +0100132 for wait in self.cleanup_waits:
133 waiter_callable = wait.pop('waiter_callable')
134 waiter_callable(**wait)
135
136 # ## Test functions library
137 #
138 # The create_[resource] functions only return body and discard the
139 # resp part which is not used in scenario tests
140
Yair Frieddb6c9e92014-08-06 08:53:13 +0300141 def create_keypair(self, client=None):
142 if not client:
143 client = self.keypairs_client
Andrea Frittoli247058f2014-07-16 16:09:22 +0100144 name = data_utils.rand_name(self.__class__.__name__)
145 # We don't need to create a keypair by pubkey in scenario
Ken'ichi Ohmichie364bce2015-07-17 10:27:59 +0000146 body = client.create_keypair(name=name)
Yair Frieddb6c9e92014-08-06 08:53:13 +0300147 self.addCleanup(client.delete_keypair, name)
ghanshyamdee01f22015-08-17 11:41:47 +0900148 return body['keypair']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100149
Anusha Ramineni9aaef8b2016-01-19 10:56:40 +0530150 def create_server(self, name=None, image_id=None, flavor=None,
lanoux5fc14522015-09-21 08:17:35 +0000151 validatable=False, wait_until=None,
152 wait_on_delete=True, clients=None, **kwargs):
153 """Wrapper utility that returns a test server.
Andrea Frittoli247058f2014-07-16 16:09:22 +0100154
lanoux5fc14522015-09-21 08:17:35 +0000155 This wrapper utility calls the common create test server and
156 returns a test server. The purpose of this wrapper is to minimize
157 the impact on the code of the tests already using this
158 function.
Andrea Frittoli247058f2014-07-16 16:09:22 +0100159 """
Andrea Frittoli247058f2014-07-16 16:09:22 +0100160
lanoux5fc14522015-09-21 08:17:35 +0000161 # NOTE(jlanoux): As a first step, ssh checks in the scenario
162 # tests need to be run regardless of the run_validation and
163 # validatable parameters and thus until the ssh validation job
164 # becomes voting in CI. The test resources management and IP
165 # association are taken care of in the scenario tests.
166 # Therefore, the validatable parameter is set to false in all
167 # those tests. In this way create_server just return a standard
168 # server and the scenario tests always perform ssh checks.
169
170 # Needed for the cross_tenant_traffic test:
171 if clients is None:
172 clients = self.manager
173
174 vnic_type = CONF.network.port_vnic_type
175
176 # If vnic_type is configured create port for
177 # every network
178 if vnic_type:
179 ports = []
180 networks = []
181 create_port_body = {'binding:vnic_type': vnic_type,
182 'namestart': 'port-smoke'}
183 if kwargs:
184 # Convert security group names to security group ids
185 # to pass to create_port
186 if 'security_groups' in kwargs:
187 security_groups =\
John Warrenf9606e92015-12-10 12:12:42 -0500188 clients.security_groups_client.list_security_groups(
lanoux5fc14522015-09-21 08:17:35 +0000189 ).get('security_groups')
190 sec_dict = dict([(s['name'], s['id'])
191 for s in security_groups])
192
193 sec_groups_names = [s['name'] for s in kwargs.pop(
194 'security_groups')]
195 security_groups_ids = [sec_dict[s]
196 for s in sec_groups_names]
197
198 if security_groups_ids:
199 create_port_body[
200 'security_groups'] = security_groups_ids
201 networks = kwargs.pop('networks')
202
203 # If there are no networks passed to us we look up
Sean Dagueed6e5862016-04-04 10:49:13 -0400204 # for the project's private networks and create a port
lanoux5fc14522015-09-21 08:17:35 +0000205 # if there is only one private network. The same behaviour
206 # as we would expect when passing the call to the clients
207 # with no networks
208 if not networks:
209 networks = clients.networks_client.list_networks(
210 filters={'router:external': False})
211 self.assertEqual(1, len(networks),
212 "There is more than one"
213 " network for the tenant")
214 for net in networks:
215 net_id = net['uuid']
216 port = self._create_port(network_id=net_id,
217 client=clients.ports_client,
218 **create_port_body)
219 ports.append({'port': port.id})
220 if ports:
221 kwargs['networks'] = ports
222 self.ports = ports
223
224 tenant_network = self.get_tenant_network()
225
226 body, servers = compute.create_test_server(
227 clients,
228 tenant_network=tenant_network,
229 wait_until=wait_until,
Anusha Ramineni9aaef8b2016-01-19 10:56:40 +0530230 name=name, flavor=flavor,
231 image_id=image_id, **kwargs)
lanoux5fc14522015-09-21 08:17:35 +0000232
233 # TODO(jlanoux) Move wait_on_delete in compute.py
Andrea Frittoli247058f2014-07-16 16:09:22 +0100234 if wait_on_delete:
Ken'ichi Ohmichie91a0c62015-08-13 02:09:16 +0000235 self.addCleanup(waiters.wait_for_server_termination,
lanoux5fc14522015-09-21 08:17:35 +0000236 clients.servers_client,
237 body['id'])
238
Andrea Frittoli247058f2014-07-16 16:09:22 +0100239 self.addCleanup_with_wait(
Ken'ichi Ohmichie91a0c62015-08-13 02:09:16 +0000240 waiter_callable=waiters.wait_for_server_termination,
lanoux5fc14522015-09-21 08:17:35 +0000241 thing_id=body['id'], thing_id_param='server_id',
Jordan Pittier9e227c52016-02-09 14:35:18 +0100242 cleanup_callable=test_utils.call_and_ignore_notfound_exc,
lanoux5fc14522015-09-21 08:17:35 +0000243 cleanup_args=[clients.servers_client.delete_server, body['id']],
244 waiter_client=clients.servers_client)
245 server = clients.servers_client.show_server(body['id'])['server']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100246 return server
247
Markus Zoeller3d2a21c2015-02-27 12:04:22 +0100248 def create_volume(self, size=None, name=None, snapshot_id=None,
Jordan Pittier5e1741c2016-03-02 18:25:51 +0100249 imageRef=None, volume_type=None):
Andrea Frittoli247058f2014-07-16 16:09:22 +0100250 if name is None:
251 name = data_utils.rand_name(self.__class__.__name__)
Ghanshyam8fc0ed22015-12-18 10:25:14 +0900252 kwargs = {'display_name': name,
253 'snapshot_id': snapshot_id,
254 'imageRef': imageRef,
255 'volume_type': volume_type}
256 if size is not None:
257 kwargs.update({'size': size})
258 volume = self.volumes_client.create_volume(**kwargs)['volume']
Matt Riedemanne85c2702014-09-10 11:50:13 -0700259
Jordan Pittier5e1741c2016-03-02 18:25:51 +0100260 self.addCleanup(self.volumes_client.wait_for_resource_deletion,
261 volume['id'])
Jordan Pittier9e227c52016-02-09 14:35:18 +0100262 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
Jordan Pittier5e1741c2016-03-02 18:25:51 +0100263 self.volumes_client.delete_volume, volume['id'])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100264
Ivan Kolodyazhnybcfc32e2015-08-06 13:31:36 +0300265 # NOTE(e0ne): Cinder API v2 uses name instead of display_name
266 if 'display_name' in volume:
267 self.assertEqual(name, volume['display_name'])
268 else:
269 self.assertEqual(name, volume['name'])
Yaroslav Lobankoved3a35b2016-03-24 22:41:30 -0500270 waiters.wait_for_volume_status(self.volumes_client,
271 volume['id'], 'available')
Andrea Frittoli247058f2014-07-16 16:09:22 +0100272 # The volume retrieved on creation has a non-up-to-date status.
273 # Retrieval after it becomes active ensures correct details.
John Warren6177c9e2015-08-19 20:00:17 +0000274 volume = self.volumes_client.show_volume(volume['id'])['volume']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100275 return volume
276
Yair Fried1fc32a12014-08-04 09:11:30 +0300277 def _create_loginable_secgroup_rule(self, secgroup_id=None):
John Warrenf2345512015-12-10 13:39:30 -0500278 _client = self.compute_security_groups_client
John Warren5cdbf422016-01-05 12:42:43 -0500279 _client_rules = self.compute_security_group_rules_client
Andrea Frittoli247058f2014-07-16 16:09:22 +0100280 if secgroup_id is None:
ghanshyamb610b772015-08-24 17:29:38 +0900281 sgs = _client.list_security_groups()['security_groups']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100282 for sg in sgs:
283 if sg['name'] == 'default':
284 secgroup_id = sg['id']
285
286 # These rules are intended to permit inbound ssh and icmp
287 # traffic from all sources, so no group_id is provided.
288 # Setting a group_id would only permit traffic from ports
289 # belonging to the same security group.
290 rulesets = [
291 {
292 # ssh
Ken'ichi Ohmichieb7eeec2015-07-21 01:00:06 +0000293 'ip_protocol': 'tcp',
Andrea Frittoli247058f2014-07-16 16:09:22 +0100294 'from_port': 22,
295 'to_port': 22,
296 'cidr': '0.0.0.0/0',
297 },
298 {
299 # ping
Ken'ichi Ohmichieb7eeec2015-07-21 01:00:06 +0000300 'ip_protocol': 'icmp',
Andrea Frittoli247058f2014-07-16 16:09:22 +0100301 'from_port': -1,
302 'to_port': -1,
303 'cidr': '0.0.0.0/0',
304 }
305 ]
306 rules = list()
307 for ruleset in rulesets:
Ken'ichi Ohmichieb7eeec2015-07-21 01:00:06 +0000308 sg_rule = _client_rules.create_security_group_rule(
ghanshyam0a5e1232015-08-24 16:59:59 +0900309 parent_group_id=secgroup_id, **ruleset)['security_group_rule']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100310 rules.append(sg_rule)
311 return rules
312
Yair Fried1fc32a12014-08-04 09:11:30 +0300313 def _create_security_group(self):
Andrea Frittoli247058f2014-07-16 16:09:22 +0100314 # Create security group
315 sg_name = data_utils.rand_name(self.__class__.__name__)
316 sg_desc = sg_name + " description"
John Warrenf2345512015-12-10 13:39:30 -0500317 secgroup = self.compute_security_groups_client.create_security_group(
ghanshyamb610b772015-08-24 17:29:38 +0900318 name=sg_name, description=sg_desc)['security_group']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100319 self.assertEqual(secgroup['name'], sg_name)
320 self.assertEqual(secgroup['description'], sg_desc)
John Warrenf2345512015-12-10 13:39:30 -0500321 self.addCleanup(
Jordan Pittier9e227c52016-02-09 14:35:18 +0100322 test_utils.call_and_ignore_notfound_exc,
John Warrenf2345512015-12-10 13:39:30 -0500323 self.compute_security_groups_client.delete_security_group,
324 secgroup['id'])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100325
326 # Add rules to the security group
Yair Fried1fc32a12014-08-04 09:11:30 +0300327 self._create_loginable_secgroup_rule(secgroup['id'])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100328
329 return secgroup
330
Sean Dague20e98612016-01-06 14:33:28 -0500331 def get_remote_client(self, ip_address, username=None, private_key=None):
JordanP3fe2dc32014-11-17 13:06:01 +0100332 """Get a SSH client to a remote server
333
Sean Dague20e98612016-01-06 14:33:28 -0500334 @param ip_address the server floating or fixed IP address to use
335 for ssh validation
JordanP3fe2dc32014-11-17 13:06:01 +0100336 @param username name of the Linux account on the remote server
337 @param private_key the SSH private key to use
JordanP3fe2dc32014-11-17 13:06:01 +0100338 @return a RemoteClient object
339 """
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700340
Andrea Frittoli247058f2014-07-16 16:09:22 +0100341 if username is None:
lanoux283273b2015-12-04 03:01:54 -0800342 username = CONF.validation.image_ssh_user
wantwatering896300c2015-03-27 15:17:42 +0800343 # Set this with 'keypair' or others to log in with keypair or
344 # username/password.
lanoux5fc14522015-09-21 08:17:35 +0000345 if CONF.validation.auth_method == 'keypair':
wantwatering896300c2015-03-27 15:17:42 +0800346 password = None
347 if private_key is None:
348 private_key = self.keypair['private_key']
349 else:
lanoux283273b2015-12-04 03:01:54 -0800350 password = CONF.validation.image_ssh_password
wantwatering896300c2015-03-27 15:17:42 +0800351 private_key = None
Sean Dague20e98612016-01-06 14:33:28 -0500352 linux_client = remote_client.RemoteClient(ip_address, username,
wantwatering896300c2015-03-27 15:17:42 +0800353 pkey=private_key,
354 password=password)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100355 try:
356 linux_client.validate_authentication()
Matt Riedemann5f0ac522015-05-21 09:16:24 -0700357 except Exception as e:
358 message = ('Initializing SSH connection to %(ip)s failed. '
Eric Brown0911af62016-02-08 17:15:40 -0800359 'Error: %(error)s' % {'ip': ip_address,
Sean Dague20e98612016-01-06 14:33:28 -0500360 'error': e})
Jordan Pittier9e227c52016-02-09 14:35:18 +0100361 caller = test_utils.find_test_caller()
Matt Riedemann5f0ac522015-05-21 09:16:24 -0700362 if caller:
363 message = '(%s) %s' % (caller, message)
364 LOG.exception(message)
Sean Dague2c98a162016-01-06 14:11:13 -0500365 self._log_console_output()
Andrea Frittoli247058f2014-07-16 16:09:22 +0100366 raise
367
368 return linux_client
369
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000370 def _image_create(self, name, fmt, path,
371 disk_format=None, properties=None):
Ghanshyam2a180b82014-06-16 13:54:22 +0900372 if properties is None:
373 properties = {}
Andrea Frittoli247058f2014-07-16 16:09:22 +0100374 name = data_utils.rand_name('%s-' % name)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100375 params = {
376 'name': name,
377 'container_format': fmt,
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000378 'disk_format': disk_format or fmt,
Andrea Frittoli247058f2014-07-16 16:09:22 +0100379 'is_public': 'False',
380 }
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000381 params['properties'] = properties
John Warren66207252015-07-31 15:51:02 -0400382 image = self.image_client.create_image(**params)['image']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100383 self.addCleanup(self.image_client.delete_image, image['id'])
384 self.assertEqual("queued", image['status'])
zhang.leia4b1cef2016-03-01 10:50:01 +0800385 with open(path, 'rb') as image_file:
386 self.image_client.update_image(image['id'], data=image_file)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100387 return image['id']
388
389 def glance_image_create(self):
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300390 img_path = CONF.scenario.img_dir + "/" + CONF.scenario.img_file
Andrea Frittoli247058f2014-07-16 16:09:22 +0100391 aki_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.aki_img_file
392 ari_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.ari_img_file
393 ami_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.ami_img_file
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300394 img_container_format = CONF.scenario.img_container_format
395 img_disk_format = CONF.scenario.img_disk_format
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000396 img_properties = CONF.scenario.img_properties
PranaliD2aa523c2016-06-07 03:54:34 -0400397 LOG.debug("paths: img: %s, container_format: %s, disk_format: %s, "
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000398 "properties: %s, ami: %s, ari: %s, aki: %s" %
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300399 (img_path, img_container_format, img_disk_format,
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000400 img_properties, ami_img_path, ari_img_path, aki_img_path))
Andrea Frittoli247058f2014-07-16 16:09:22 +0100401 try:
Jordan Pittier1e443ec2015-11-20 16:15:58 +0100402 image = self._image_create('scenario-img',
403 img_container_format,
404 img_path,
405 disk_format=img_disk_format,
406 properties=img_properties)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100407 except IOError:
408 LOG.debug("A qcow2 image was not found. Try to get a uec image.")
409 kernel = self._image_create('scenario-aki', 'aki', aki_img_path)
410 ramdisk = self._image_create('scenario-ari', 'ari', ari_img_path)
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000411 properties = {'kernel_id': kernel, 'ramdisk_id': ramdisk}
Jordan Pittier1e443ec2015-11-20 16:15:58 +0100412 image = self._image_create('scenario-ami', 'ami',
413 path=ami_img_path,
414 properties=properties)
415 LOG.debug("image:%s" % image)
416
417 return image
Andrea Frittoli247058f2014-07-16 16:09:22 +0100418
419 def _log_console_output(self, servers=None):
Matthew Treinish42a3f3a2014-09-04 15:04:53 -0400420 if not CONF.compute_feature_enabled.console_output:
421 LOG.debug('Console output not supported, cannot log')
422 return
Andrea Frittoli247058f2014-07-16 16:09:22 +0100423 if not servers:
David Kranzae99b9a2015-02-16 13:37:01 -0500424 servers = self.servers_client.list_servers()
Andrea Frittoli247058f2014-07-16 16:09:22 +0100425 servers = servers['servers']
426 for server in servers:
Brant Knudson566c5712014-09-24 20:04:50 -0500427 console_output = self.servers_client.get_console_output(
Ken'ichi Ohmichibf4766a2015-12-09 07:48:43 +0000428 server['id'])['output']
David Kranzae99b9a2015-02-16 13:37:01 -0500429 LOG.debug('Console output for %s\nbody=\n%s',
430 server['id'], console_output)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100431
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000432 def _log_net_info(self, exc):
433 # network debug is called as part of ssh init
Andrey Pavlov64723762015-04-29 06:24:58 +0300434 if not isinstance(exc, lib_exc.SSHTimeout):
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000435 LOG.debug('Network information on a devstack host')
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000436
nithya-ganesan882595e2014-07-29 18:51:07 +0000437 def create_server_snapshot(self, server, name=None):
438 # Glance client
439 _image_client = self.image_client
440 # Compute client
Ghanshyamae76c122015-12-22 13:41:35 +0900441 _images_client = self.compute_images_client
nithya-ganesan882595e2014-07-29 18:51:07 +0000442 if name is None:
Ken'ichi Ohmichi6ded8df2015-03-23 02:00:19 +0000443 name = data_utils.rand_name('scenario-snapshot')
nithya-ganesan882595e2014-07-29 18:51:07 +0000444 LOG.debug("Creating a snapshot image for server: %s", server['name'])
Ken'ichi Ohmichi28f18672015-07-17 10:00:38 +0000445 image = _images_client.create_image(server['id'], name=name)
David Kranza5299eb2015-01-15 17:24:05 -0500446 image_id = image.response['location'].split('images/')[1]
Yaroslav Lobankov2fea4052016-04-19 15:05:57 +0300447 waiters.wait_for_image_status(_image_client, image_id, 'active')
nithya-ganesan882595e2014-07-29 18:51:07 +0000448 self.addCleanup_with_wait(
449 waiter_callable=_image_client.wait_for_resource_deletion,
450 thing_id=image_id, thing_id_param='id',
Jordan Pittier9e227c52016-02-09 14:35:18 +0100451 cleanup_callable=test_utils.call_and_ignore_notfound_exc,
nithya-ganesan882595e2014-07-29 18:51:07 +0000452 cleanup_args=[_image_client.delete_image, image_id])
Yaroslav Lobankov9d28a0f2016-04-19 15:05:57 +0300453 snapshot_image = _image_client.check_image(image_id)
Andrey Pavlovc8bd4b12015-08-17 10:20:17 +0300454
455 bdm = snapshot_image.get('properties', {}).get('block_device_mapping')
456 if bdm:
457 bdm = json.loads(bdm)
458 if bdm and 'snapshot_id' in bdm[0]:
459 snapshot_id = bdm[0]['snapshot_id']
460 self.addCleanup(
461 self.snapshots_client.wait_for_resource_deletion,
462 snapshot_id)
Jordan Pittier9e227c52016-02-09 14:35:18 +0100463 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
464 self.snapshots_client.delete_snapshot,
465 snapshot_id)
Yaroslav Lobankov667aaa22016-03-24 23:13:28 -0500466 waiters.wait_for_snapshot_status(self.snapshots_client,
467 snapshot_id, 'available')
nithya-ganesan882595e2014-07-29 18:51:07 +0000468 image_name = snapshot_image['name']
469 self.assertEqual(name, image_name)
470 LOG.debug("Created snapshot image %s for server %s",
471 image_name, server['name'])
472 return snapshot_image
473
Jordan Pittier7cf64762015-10-14 15:01:12 +0200474 def nova_volume_attach(self, server, volume_to_attach):
Joseph Lanoux6809bab2014-12-18 14:57:18 +0000475 volume = self.servers_client.attach_volume(
Jordan Pittier7cf64762015-10-14 15:01:12 +0200476 server['id'], volumeId=volume_to_attach['id'], device='/dev/%s'
ghanshyam0f825252015-08-25 16:02:50 +0900477 % CONF.compute.volume_device_name)['volumeAttachment']
Jordan Pittier7cf64762015-10-14 15:01:12 +0200478 self.assertEqual(volume_to_attach['id'], volume['id'])
Yaroslav Lobankoved3a35b2016-03-24 22:41:30 -0500479 waiters.wait_for_volume_status(self.volumes_client,
480 volume['id'], 'in-use')
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900481
Jordan Pittier7cf64762015-10-14 15:01:12 +0200482 # Return the updated volume after the attachment
483 return self.volumes_client.show_volume(volume['id'])['volume']
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900484
Jordan Pittier7cf64762015-10-14 15:01:12 +0200485 def nova_volume_detach(self, server, volume):
486 self.servers_client.detach_volume(server['id'], volume['id'])
Yaroslav Lobankoved3a35b2016-03-24 22:41:30 -0500487 waiters.wait_for_volume_status(self.volumes_client,
488 volume['id'], 'available')
Jordan Pittier7cf64762015-10-14 15:01:12 +0200489
490 volume = self.volumes_client.show_volume(volume['id'])['volume']
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900491 self.assertEqual('available', volume['status'])
492
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700493 def rebuild_server(self, server_id, image=None,
494 preserve_ephemeral=False, wait=True,
495 rebuild_kwargs=None):
496 if image is None:
497 image = CONF.compute.image_ref
498
499 rebuild_kwargs = rebuild_kwargs or {}
500
501 LOG.debug("Rebuilding server (id: %s, image: %s, preserve eph: %s)",
502 server_id, image, preserve_ephemeral)
Ken'ichi Ohmichi5271b0f2015-08-10 07:53:27 +0000503 self.servers_client.rebuild_server(
504 server_id=server_id, image_ref=image,
505 preserve_ephemeral=preserve_ephemeral,
506 **rebuild_kwargs)
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700507 if wait:
Ken'ichi Ohmichi0eb153c2015-07-13 02:18:25 +0000508 waiters.wait_for_server_status(self.servers_client,
509 server_id, 'ACTIVE')
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700510
Steven Hardyda2a8352014-10-02 12:52:20 +0100511 def ping_ip_address(self, ip_address, should_succeed=True,
512 ping_timeout=None):
lanoux5fc14522015-09-21 08:17:35 +0000513 timeout = ping_timeout or CONF.validation.ping_timeout
Aaron Rosena7df13b2014-09-23 09:45:45 -0700514 cmd = ['ping', '-c1', '-w1', ip_address]
515
516 def ping():
517 proc = subprocess.Popen(cmd,
518 stdout=subprocess.PIPE,
519 stderr=subprocess.PIPE)
520 proc.communicate()
Shuquan Huang753629e2015-07-20 08:52:29 +0000521
Aaron Rosena7df13b2014-09-23 09:45:45 -0700522 return (proc.returncode == 0) == should_succeed
523
Jordan Pittier9e227c52016-02-09 14:35:18 +0100524 caller = test_utils.find_test_caller()
Shuquan Huang753629e2015-07-20 08:52:29 +0000525 LOG.debug('%(caller)s begins to ping %(ip)s in %(timeout)s sec and the'
526 ' expected result is %(should_succeed)s' % {
527 'caller': caller, 'ip': ip_address, 'timeout': timeout,
528 'should_succeed':
529 'reachable' if should_succeed else 'unreachable'
530 })
531 result = tempest.test.call_until_true(ping, timeout, 1)
532 LOG.debug('%(caller)s finishes ping %(ip)s in %(timeout)s sec and the '
533 'ping result is %(result)s' % {
534 'caller': caller, 'ip': ip_address, 'timeout': timeout,
535 'result': 'expected' if result else 'unexpected'
536 })
537 return result
Aaron Rosena7df13b2014-09-23 09:45:45 -0700538
Yair Friedae0e73d2014-11-24 11:56:26 +0200539 def check_vm_connectivity(self, ip_address,
540 username=None,
541 private_key=None,
542 should_connect=True):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000543 """Check server connectivity
544
Yair Friedae0e73d2014-11-24 11:56:26 +0200545 :param ip_address: server to test against
546 :param username: server's ssh username
547 :param private_key: server's ssh private key to be used
548 :param should_connect: True/False indicates positive/negative test
549 positive - attempt ping and ssh
550 negative - attempt ping and fail if succeed
551
552 :raises: AssertError if the result of the connectivity check does
553 not match the value of the should_connect param
554 """
555 if should_connect:
556 msg = "Timed out waiting for %s to become reachable" % ip_address
557 else:
558 msg = "ip address %s is reachable" % ip_address
559 self.assertTrue(self.ping_ip_address(ip_address,
560 should_succeed=should_connect),
561 msg=msg)
562 if should_connect:
563 # no need to check ssh for negative connectivity
564 self.get_remote_client(ip_address, username, private_key)
565
566 def check_public_network_connectivity(self, ip_address, username,
567 private_key, should_connect=True,
568 msg=None, servers=None):
569 # The target login is assumed to have been configured for
570 # key-based authentication by cloud-init.
571 LOG.debug('checking network connections to IP %s with user: %s' %
572 (ip_address, username))
573 try:
574 self.check_vm_connectivity(ip_address,
575 username,
576 private_key,
577 should_connect=should_connect)
Matthew Treinish53483132014-12-09 18:50:06 -0500578 except Exception:
Yair Friedae0e73d2014-11-24 11:56:26 +0200579 ex_msg = 'Public network connectivity check failed'
580 if msg:
581 ex_msg += ": " + msg
582 LOG.exception(ex_msg)
583 self._log_console_output(servers)
Yair Friedae0e73d2014-11-24 11:56:26 +0200584 raise
585
586 def create_floating_ip(self, thing, pool_name=None):
Ken'ichi Ohmichia112a592015-11-17 08:49:37 +0000587 """Create a floating IP and associates to a server on Nova"""
Yair Friedae0e73d2014-11-24 11:56:26 +0200588
Marc Koderer3b57d802016-03-22 15:23:31 +0100589 if not pool_name:
590 pool_name = CONF.network.floating_network_name
John Warrene74890a2015-11-11 15:18:01 -0500591 floating_ip = (self.compute_floating_ips_client.
Ken'ichi Ohmichie037a6f2015-12-03 06:41:49 +0000592 create_floating_ip(pool=pool_name)['floating_ip'])
Jordan Pittier9e227c52016-02-09 14:35:18 +0100593 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
John Warrene74890a2015-11-11 15:18:01 -0500594 self.compute_floating_ips_client.delete_floating_ip,
Yair Friedae0e73d2014-11-24 11:56:26 +0200595 floating_ip['id'])
John Warrene74890a2015-11-11 15:18:01 -0500596 self.compute_floating_ips_client.associate_floating_ip_to_server(
Yair Friedae0e73d2014-11-24 11:56:26 +0200597 floating_ip['ip'], thing['id'])
598 return floating_ip
599
Sean Dague20e98612016-01-06 14:33:28 -0500600 def create_timestamp(self, ip_address, dev_name=None, mount_path='/mnt',
Matt Riedemannfd5657d2015-09-30 14:47:07 -0700601 private_key=None):
Sean Dague20e98612016-01-06 14:33:28 -0500602 ssh_client = self.get_remote_client(ip_address,
Matt Riedemannfd5657d2015-09-30 14:47:07 -0700603 private_key=private_key)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300604 if dev_name is not None:
605 ssh_client.make_fs(dev_name)
Matt Riedemann076685a2015-09-30 14:38:16 -0700606 ssh_client.mount(dev_name, mount_path)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300607 cmd_timestamp = 'sudo sh -c "date > %s/timestamp; sync"' % mount_path
608 ssh_client.exec_command(cmd_timestamp)
609 timestamp = ssh_client.exec_command('sudo cat %s/timestamp'
610 % mount_path)
611 if dev_name is not None:
612 ssh_client.umount(mount_path)
613 return timestamp
614
Sean Dague20e98612016-01-06 14:33:28 -0500615 def get_timestamp(self, ip_address, dev_name=None, mount_path='/mnt',
Matt Riedemannfd5657d2015-09-30 14:47:07 -0700616 private_key=None):
Sean Dague20e98612016-01-06 14:33:28 -0500617 ssh_client = self.get_remote_client(ip_address,
Matt Riedemannfd5657d2015-09-30 14:47:07 -0700618 private_key=private_key)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300619 if dev_name is not None:
Matt Riedemann076685a2015-09-30 14:38:16 -0700620 ssh_client.mount(dev_name, mount_path)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300621 timestamp = ssh_client.exec_command('sudo cat %s/timestamp'
622 % mount_path)
623 if dev_name is not None:
624 ssh_client.umount(mount_path)
625 return timestamp
626
Sean Dague20e98612016-01-06 14:33:28 -0500627 def get_server_ip(self, server):
628 """Get the server fixed or floating IP.
629
630 Based on the configuration we're in, return a correct ip
631 address for validating that a guest is up.
632 """
Alexander Gubanovc8829f82015-11-12 10:35:13 +0200633 if CONF.validation.connect_method == 'floating':
Sean Dague20e98612016-01-06 14:33:28 -0500634 # The tests calling this method don't have a floating IP
zhufl0892cb22016-05-06 14:46:00 +0800635 # and can't make use of the validation resources. So the
Sean Dague20e98612016-01-06 14:33:28 -0500636 # method is creating the floating IP there.
637 return self.create_floating_ip(server)['ip']
638 elif CONF.validation.connect_method == 'fixed':
639 addresses = server['addresses'][CONF.validation.network_for_ssh]
640 for address in addresses:
641 if address['version'] == CONF.validation.ip_version_for_ssh:
642 return address['addr']
643 raise exceptions.ServerUnreachable()
Alexander Gubanovc8829f82015-11-12 10:35:13 +0200644 else:
Sean Dague20e98612016-01-06 14:33:28 -0500645 raise exceptions.InvalidConfiguration()
Alexander Gubanovc8829f82015-11-12 10:35:13 +0200646
Andrea Frittoli2e733b52014-07-16 14:12:11 +0100647
Andrea Frittoli4971fc82014-09-25 10:22:20 +0100648class NetworkScenarioTest(ScenarioTest):
Yair Fried1fc32a12014-08-04 09:11:30 +0300649 """Base class for network scenario tests.
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000650
Yair Fried1fc32a12014-08-04 09:11:30 +0300651 This class provide helpers for network scenario tests, using the neutron
652 API. Helpers from ancestor which use the nova network API are overridden
653 with the neutron API.
654
655 This Class also enforces using Neutron instead of novanetwork.
656 Subclassed tests will be skipped if Neutron is not enabled
657
658 """
659
Andrea Frittolib21de6c2015-02-06 20:12:38 +0000660 credentials = ['primary', 'admin']
661
Yair Fried1fc32a12014-08-04 09:11:30 +0300662 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +0000663 def skip_checks(cls):
664 super(NetworkScenarioTest, cls).skip_checks()
Andrea Frittoli2ddc2632014-09-25 11:03:00 +0100665 if not CONF.service_available.neutron:
666 raise cls.skipException('Neutron not available')
Yair Fried1fc32a12014-08-04 09:11:30 +0300667
668 @classmethod
Andrea Frittoliac20b5e2014-09-15 13:31:14 +0100669 def resource_setup(cls):
670 super(NetworkScenarioTest, cls).resource_setup()
Yair Fried1fc32a12014-08-04 09:11:30 +0300671 cls.tenant_id = cls.manager.identity_client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300672
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -0700673 def _create_network(self, networks_client=None,
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000674 routers_client=None, tenant_id=None,
675 namestart='network-smoke-'):
John Warren94d8faf2015-09-15 12:22:24 -0400676 if not networks_client:
677 networks_client = self.networks_client
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000678 if not routers_client:
679 routers_client = self.routers_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300680 if not tenant_id:
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -0700681 tenant_id = networks_client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300682 name = data_utils.rand_name(namestart)
John Warren94d8faf2015-09-15 12:22:24 -0400683 result = networks_client.create_network(name=name, tenant_id=tenant_id)
Ken'ichi Ohmichi69a182a2016-04-29 10:56:27 -0700684 network = network_resources.DeletableNetwork(
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000685 networks_client=networks_client, routers_client=routers_client,
686 **result['network'])
Yair Fried1fc32a12014-08-04 09:11:30 +0300687 self.assertEqual(network.name, name)
Jordan Pittier9e227c52016-02-09 14:35:18 +0100688 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
689 network.delete)
Yair Fried1fc32a12014-08-04 09:11:30 +0300690 return network
691
692 def _list_networks(self, *args, **kwargs):
693 """List networks using admin creds """
John Warren94d8faf2015-09-15 12:22:24 -0400694 networks_list = self.admin_manager.networks_client.list_networks(
ghanshyam2f7cc022015-06-26 18:18:11 +0900695 *args, **kwargs)
696 return networks_list['networks']
Yair Fried1fc32a12014-08-04 09:11:30 +0300697
698 def _list_subnets(self, *args, **kwargs):
699 """List subnets using admin creds """
John Warren3961acd2015-10-02 14:38:53 -0400700 subnets_list = self.admin_manager.subnets_client.list_subnets(
ghanshyam2f7cc022015-06-26 18:18:11 +0900701 *args, **kwargs)
702 return subnets_list['subnets']
Yair Fried1fc32a12014-08-04 09:11:30 +0300703
704 def _list_routers(self, *args, **kwargs):
705 """List routers using admin creds """
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000706 routers_list = self.admin_manager.routers_client.list_routers(
ghanshyam2f7cc022015-06-26 18:18:11 +0900707 *args, **kwargs)
708 return routers_list['routers']
Yair Fried1fc32a12014-08-04 09:11:30 +0300709
710 def _list_ports(self, *args, **kwargs):
711 """List ports using admin creds """
John Warren49c0fe52015-10-22 12:35:54 -0400712 ports_list = self.admin_manager.ports_client.list_ports(
ghanshyam2f7cc022015-06-26 18:18:11 +0900713 *args, **kwargs)
714 return ports_list['ports']
Yair Fried1fc32a12014-08-04 09:11:30 +0300715
Yair Fried564d89d2015-08-06 17:02:12 +0300716 def _list_agents(self, *args, **kwargs):
717 """List agents using admin creds """
Ken'ichi Ohmichi71860062015-12-15 08:20:13 +0000718 agents_list = self.admin_manager.network_agents_client.list_agents(
Yair Fried564d89d2015-08-06 17:02:12 +0300719 *args, **kwargs)
720 return agents_list['agents']
721
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -0700722 def _create_subnet(self, network, subnets_client=None,
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000723 routers_client=None, namestart='subnet-smoke',
724 **kwargs):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000725 """Create a subnet for the given network
726
727 within the cidr block configured for tenant networks.
Yair Fried1fc32a12014-08-04 09:11:30 +0300728 """
John Warren3961acd2015-10-02 14:38:53 -0400729 if not subnets_client:
730 subnets_client = self.subnets_client
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000731 if not routers_client:
732 routers_client = self.routers_client
Yair Fried1fc32a12014-08-04 09:11:30 +0300733
734 def cidr_in_use(cidr, tenant_id):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000735 """Check cidr existence
736
lei zhangdd552b22015-11-25 20:41:48 +0800737 :returns: True if subnet with cidr already exist in tenant
738 False else
Yair Fried1fc32a12014-08-04 09:11:30 +0300739 """
740 cidr_in_use = self._list_subnets(tenant_id=tenant_id, cidr=cidr)
741 return len(cidr_in_use) != 0
742
Kirill Shileev14113572014-11-21 16:58:02 +0300743 ip_version = kwargs.pop('ip_version', 4)
744
745 if ip_version == 6:
746 tenant_cidr = netaddr.IPNetwork(
Sean Dagueed6e5862016-04-04 10:49:13 -0400747 CONF.network.project_network_v6_cidr)
748 num_bits = CONF.network.project_network_v6_mask_bits
Kirill Shileev14113572014-11-21 16:58:02 +0300749 else:
Sean Dagueed6e5862016-04-04 10:49:13 -0400750 tenant_cidr = netaddr.IPNetwork(CONF.network.project_network_cidr)
751 num_bits = CONF.network.project_network_mask_bits
Kirill Shileev14113572014-11-21 16:58:02 +0300752
Yair Fried1fc32a12014-08-04 09:11:30 +0300753 result = None
Kirill Shileev14113572014-11-21 16:58:02 +0300754 str_cidr = None
Yair Fried1fc32a12014-08-04 09:11:30 +0300755 # Repeatedly attempt subnet creation with sequential cidr
756 # blocks until an unallocated block is found.
Kirill Shileev14113572014-11-21 16:58:02 +0300757 for subnet_cidr in tenant_cidr.subnet(num_bits):
Yair Fried1fc32a12014-08-04 09:11:30 +0300758 str_cidr = str(subnet_cidr)
759 if cidr_in_use(str_cidr, tenant_id=network.tenant_id):
760 continue
761
762 subnet = dict(
763 name=data_utils.rand_name(namestart),
Yair Fried1fc32a12014-08-04 09:11:30 +0300764 network_id=network.id,
765 tenant_id=network.tenant_id,
766 cidr=str_cidr,
Kirill Shileev14113572014-11-21 16:58:02 +0300767 ip_version=ip_version,
Yair Fried1fc32a12014-08-04 09:11:30 +0300768 **kwargs
769 )
770 try:
John Warren3961acd2015-10-02 14:38:53 -0400771 result = subnets_client.create_subnet(**subnet)
Yair Fried1fc32a12014-08-04 09:11:30 +0300772 break
Masayuki Igawad9388762015-01-20 14:56:42 +0900773 except lib_exc.Conflict as e:
Yair Fried1fc32a12014-08-04 09:11:30 +0300774 is_overlapping_cidr = 'overlaps with another subnet' in str(e)
775 if not is_overlapping_cidr:
776 raise
777 self.assertIsNotNone(result, 'Unable to allocate tenant network')
Ken'ichi Ohmichi69a182a2016-04-29 10:56:27 -0700778 subnet = network_resources.DeletableSubnet(
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -0700779 subnets_client=subnets_client,
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000780 routers_client=routers_client, **result['subnet'])
Yair Fried1fc32a12014-08-04 09:11:30 +0300781 self.assertEqual(subnet.cidr, str_cidr)
Jordan Pittier9e227c52016-02-09 14:35:18 +0100782 self.addCleanup(test_utils.call_and_ignore_notfound_exc, subnet.delete)
Yair Fried1fc32a12014-08-04 09:11:30 +0300783 return subnet
784
Itzik Brown2ca01cd2014-12-08 12:58:20 +0200785 def _create_port(self, network_id, client=None, namestart='port-quotatest',
786 **kwargs):
Yair Frieddb6c9e92014-08-06 08:53:13 +0300787 if not client:
John Warren49c0fe52015-10-22 12:35:54 -0400788 client = self.ports_client
Yair Fried1fc32a12014-08-04 09:11:30 +0300789 name = data_utils.rand_name(namestart)
David Kranz34e88122014-12-11 15:24:05 -0500790 result = client.create_port(
Yair Fried1fc32a12014-08-04 09:11:30 +0300791 name=name,
Itzik Brown2ca01cd2014-12-08 12:58:20 +0200792 network_id=network_id,
793 **kwargs)
Yair Fried1fc32a12014-08-04 09:11:30 +0300794 self.assertIsNotNone(result, 'Unable to allocate port')
Ken'ichi Ohmichi69a182a2016-04-29 10:56:27 -0700795 port = network_resources.DeletablePort(ports_client=client,
796 **result['port'])
Jordan Pittier9e227c52016-02-09 14:35:18 +0100797 self.addCleanup(test_utils.call_and_ignore_notfound_exc, port.delete)
Yair Fried1fc32a12014-08-04 09:11:30 +0300798 return port
799
Kirill Shileev14113572014-11-21 16:58:02 +0300800 def _get_server_port_id_and_ip4(self, server, ip_addr=None):
Kevin Benton1d0c1dc2016-02-04 14:30:08 -0800801 ports = self._list_ports(device_id=server['id'], fixed_ip=ip_addr)
Sean M. Collins2e896832015-12-15 13:58:47 -0500802 # A port can have more then one IP address in some cases.
803 # If the network is dual-stack (IPv4 + IPv6), this port is associated
804 # with 2 subnets
Vasyl Saienko8fd517c2016-05-30 09:52:54 +0300805 p_status = ['ACTIVE']
806 # NOTE(vsaienko) With Ironic, instances live on separate hardware
807 # servers. Neutron does not bind ports for Ironic instances, as a
808 # result the port remains in the DOWN state.
809 if CONF.service_available.ironic:
810 p_status.append('DOWN')
Daniel Mellado9e3e1062015-08-06 18:07:05 +0200811 port_map = [(p["id"], fxip["ip_address"])
812 for p in ports
813 for fxip in p["fixed_ips"]
Kevin Benton1d0c1dc2016-02-04 14:30:08 -0800814 if netaddr.valid_ipv4(fxip["ip_address"])
Vasyl Saienko8fd517c2016-05-30 09:52:54 +0300815 and p['status'] in p_status]
Kevin Benton1d0c1dc2016-02-04 14:30:08 -0800816 inactive = [p for p in ports if p['status'] != 'ACTIVE']
817 if inactive:
818 LOG.warning("Instance has ports that are not ACTIVE: %s", inactive)
Daniel Mellado9e3e1062015-08-06 18:07:05 +0200819
John L. Villalovosb83286f2015-11-04 14:46:57 -0800820 self.assertNotEqual(0, len(port_map),
821 "No IPv4 addresses found in: %s" % ports)
Daniel Mellado9e3e1062015-08-06 18:07:05 +0200822 self.assertEqual(len(port_map), 1,
823 "Found multiple IPv4 addresses: %s. "
824 "Unable to determine which port to target."
825 % port_map)
826 return port_map[0]
Yair Fried1fc32a12014-08-04 09:11:30 +0300827
David Shrewsbury9bac3662014-08-07 15:07:01 -0400828 def _get_network_by_name(self, network_name):
829 net = self._list_networks(name=network_name)
Adam Gandelman878a5fd2015-03-30 14:33:36 -0700830 self.assertNotEqual(len(net), 0,
831 "Unable to get network by name: %s" % network_name)
Ken'ichi Ohmichi69a182a2016-04-29 10:56:27 -0700832 return network_resources.AttributeDict(net[0])
David Shrewsbury9bac3662014-08-07 15:07:01 -0400833
Yair Friedae0e73d2014-11-24 11:56:26 +0200834 def create_floating_ip(self, thing, external_network_id=None,
835 port_id=None, client=None):
Ken'ichi Ohmichia112a592015-11-17 08:49:37 +0000836 """Create a floating IP and associates to a resource/port on Neutron"""
Yair Friedae0e73d2014-11-24 11:56:26 +0200837 if not external_network_id:
838 external_network_id = CONF.network.public_network_id
Yair Frieddb6c9e92014-08-06 08:53:13 +0300839 if not client:
John Warrenfbf2a892015-11-17 12:36:14 -0500840 client = self.floating_ips_client
Yair Fried1fc32a12014-08-04 09:11:30 +0300841 if not port_id:
Kirill Shileev14113572014-11-21 16:58:02 +0300842 port_id, ip4 = self._get_server_port_id_and_ip4(thing)
843 else:
844 ip4 = None
David Kranz34e88122014-12-11 15:24:05 -0500845 result = client.create_floatingip(
Yair Fried1fc32a12014-08-04 09:11:30 +0300846 floating_network_id=external_network_id,
847 port_id=port_id,
Kirill Shileev14113572014-11-21 16:58:02 +0300848 tenant_id=thing['tenant_id'],
849 fixed_ip_address=ip4
Yair Fried1fc32a12014-08-04 09:11:30 +0300850 )
Ken'ichi Ohmichi69a182a2016-04-29 10:56:27 -0700851 floating_ip = network_resources.DeletableFloatingIp(
Yair Frieddb6c9e92014-08-06 08:53:13 +0300852 client=client,
Yair Fried1fc32a12014-08-04 09:11:30 +0300853 **result['floatingip'])
Jordan Pittier9e227c52016-02-09 14:35:18 +0100854 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
855 floating_ip.delete)
Yair Fried1fc32a12014-08-04 09:11:30 +0300856 return floating_ip
857
858 def _associate_floating_ip(self, floating_ip, server):
Kirill Shileev14113572014-11-21 16:58:02 +0300859 port_id, _ = self._get_server_port_id_and_ip4(server)
Yair Fried1fc32a12014-08-04 09:11:30 +0300860 floating_ip.update(port_id=port_id)
861 self.assertEqual(port_id, floating_ip.port_id)
862 return floating_ip
863
864 def _disassociate_floating_ip(self, floating_ip):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000865 """:param floating_ip: type DeletableFloatingIp"""
Yair Fried1fc32a12014-08-04 09:11:30 +0300866 floating_ip.update(port_id=None)
867 self.assertIsNone(floating_ip.port_id)
868 return floating_ip
869
Yair Fried45f92952014-06-26 05:19:19 +0300870 def check_floating_ip_status(self, floating_ip, status):
Carl Baldwina754e2d2014-10-23 22:47:41 +0000871 """Verifies floatingip reaches the given status
Yair Fried45f92952014-06-26 05:19:19 +0300872
Ken'ichi Ohmichi69a182a2016-04-29 10:56:27 -0700873 :param floating_ip: network_resources.DeletableFloatingIp floating
874 IP to check status
Yair Fried45f92952014-06-26 05:19:19 +0300875 :param status: target status
876 :raises: AssertionError if status doesn't match
877 """
Carl Baldwina754e2d2014-10-23 22:47:41 +0000878 def refresh():
879 floating_ip.refresh()
880 return status == floating_ip.status
881
882 tempest.test.call_until_true(refresh,
883 CONF.network.build_timeout,
884 CONF.network.build_interval)
Yair Fried45f92952014-06-26 05:19:19 +0300885 self.assertEqual(status, floating_ip.status,
886 message="FloatingIP: {fp} is at status: {cst}. "
887 "failed to reach status: {st}"
888 .format(fp=floating_ip, cst=floating_ip.status,
889 st=status))
890 LOG.info("FloatingIP: {fp} is at status: {st}"
891 .format(fp=floating_ip, st=status))
892
Yair Fried1fc32a12014-08-04 09:11:30 +0300893 def _check_tenant_network_connectivity(self, server,
894 username,
895 private_key,
896 should_connect=True,
897 servers_for_debug=None):
Sean Dagueed6e5862016-04-04 10:49:13 -0400898 if not CONF.network.project_networks_reachable:
Yair Fried1fc32a12014-08-04 09:11:30 +0300899 msg = 'Tenant networks not configured to be reachable.'
900 LOG.info(msg)
901 return
902 # The target login is assumed to have been configured for
903 # key-based authentication by cloud-init.
904 try:
Matthew Treinish71426682015-04-23 11:19:38 -0400905 for net_name, ip_addresses in six.iteritems(server['addresses']):
Yair Fried1fc32a12014-08-04 09:11:30 +0300906 for ip_address in ip_addresses:
ghanshyam807211c2014-12-18 13:21:22 +0900907 self.check_vm_connectivity(ip_address['addr'],
Yair Friedae0e73d2014-11-24 11:56:26 +0200908 username,
909 private_key,
910 should_connect=should_connect)
Yair Fried1fc32a12014-08-04 09:11:30 +0300911 except Exception as e:
912 LOG.exception('Tenant network connectivity check failed')
913 self._log_console_output(servers_for_debug)
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000914 self._log_net_info(e)
Yair Fried1fc32a12014-08-04 09:11:30 +0300915 raise
916
Yair Friedbc46f592015-11-18 16:29:34 +0200917 def _check_remote_connectivity(self, source, dest, should_succeed=True,
918 nic=None):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000919 """check ping server via source ssh connection
Yair Fried1fc32a12014-08-04 09:11:30 +0300920
921 :param source: RemoteClient: an ssh connection from which to ping
922 :param dest: and IP to ping against
923 :param should_succeed: boolean should ping succeed or not
Yair Friedbc46f592015-11-18 16:29:34 +0200924 :param nic: specific network interface to ping from
Yair Fried1fc32a12014-08-04 09:11:30 +0300925 :returns: boolean -- should_succeed == ping
926 :returns: ping is false if ping failed
927 """
928 def ping_remote():
929 try:
Yair Friedbc46f592015-11-18 16:29:34 +0200930 source.ping_host(dest, nic=nic)
Andrey Pavlov64723762015-04-29 06:24:58 +0300931 except lib_exc.SSHExecCommandFailed:
zhangguoqing6c096642016-01-04 06:17:21 +0000932 LOG.warning('Failed to ping IP: %s via a ssh connection '
933 'from: %s.' % (dest, source.ssh_client.host))
Yair Fried1fc32a12014-08-04 09:11:30 +0300934 return not should_succeed
935 return should_succeed
936
937 return tempest.test.call_until_true(ping_remote,
lanoux5fc14522015-09-21 08:17:35 +0000938 CONF.validation.ping_timeout,
Yair Fried1fc32a12014-08-04 09:11:30 +0300939 1)
940
John Warren456d9ae2016-01-12 15:36:33 -0500941 def _create_security_group(self, security_group_rules_client=None,
942 tenant_id=None,
John Warrenf9606e92015-12-10 12:12:42 -0500943 namestart='secgroup-smoke',
944 security_groups_client=None):
John Warren456d9ae2016-01-12 15:36:33 -0500945 if security_group_rules_client is None:
946 security_group_rules_client = self.security_group_rules_client
John Warrenf9606e92015-12-10 12:12:42 -0500947 if security_groups_client is None:
948 security_groups_client = self.security_groups_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300949 if tenant_id is None:
John Warrenf9606e92015-12-10 12:12:42 -0500950 tenant_id = security_groups_client.tenant_id
951 secgroup = self._create_empty_security_group(
952 namestart=namestart, client=security_groups_client,
953 tenant_id=tenant_id)
Yair Fried1fc32a12014-08-04 09:11:30 +0300954
955 # Add rules to the security group
John Warrenf9606e92015-12-10 12:12:42 -0500956 rules = self._create_loginable_secgroup_rule(
John Warren456d9ae2016-01-12 15:36:33 -0500957 security_group_rules_client=security_group_rules_client,
958 secgroup=secgroup,
John Warrenf9606e92015-12-10 12:12:42 -0500959 security_groups_client=security_groups_client)
Yair Fried1fc32a12014-08-04 09:11:30 +0300960 for rule in rules:
961 self.assertEqual(tenant_id, rule.tenant_id)
962 self.assertEqual(secgroup.id, rule.security_group_id)
963 return secgroup
964
Yair Frieddb6c9e92014-08-06 08:53:13 +0300965 def _create_empty_security_group(self, client=None, tenant_id=None,
Yair Fried1fc32a12014-08-04 09:11:30 +0300966 namestart='secgroup-smoke'):
967 """Create a security group without rules.
968
969 Default rules will be created:
970 - IPv4 egress to any
971 - IPv6 egress to any
972
973 :param tenant_id: secgroup will be created in this tenant
974 :returns: DeletableSecurityGroup -- containing the secgroup created
975 """
976 if client is None:
John Warrenf9606e92015-12-10 12:12:42 -0500977 client = self.security_groups_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300978 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000979 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300980 sg_name = data_utils.rand_name(namestart)
981 sg_desc = sg_name + " description"
982 sg_dict = dict(name=sg_name,
983 description=sg_desc)
984 sg_dict['tenant_id'] = tenant_id
David Kranz34e88122014-12-11 15:24:05 -0500985 result = client.create_security_group(**sg_dict)
Ken'ichi Ohmichi69a182a2016-04-29 10:56:27 -0700986 secgroup = network_resources.DeletableSecurityGroup(
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000987 client=client, routers_client=self.routers_client,
Yair Fried1fc32a12014-08-04 09:11:30 +0300988 **result['security_group']
989 )
990 self.assertEqual(secgroup.name, sg_name)
991 self.assertEqual(tenant_id, secgroup.tenant_id)
992 self.assertEqual(secgroup.description, sg_desc)
Jordan Pittier9e227c52016-02-09 14:35:18 +0100993 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
994 secgroup.delete)
Yair Fried1fc32a12014-08-04 09:11:30 +0300995 return secgroup
996
Yair Frieddb6c9e92014-08-06 08:53:13 +0300997 def _default_security_group(self, client=None, tenant_id=None):
Yair Fried1fc32a12014-08-04 09:11:30 +0300998 """Get default secgroup for given tenant_id.
999
1000 :returns: DeletableSecurityGroup -- default secgroup for given tenant
1001 """
1002 if client is None:
John Warrenf9606e92015-12-10 12:12:42 -05001003 client = self.security_groups_client
Yair Frieddb6c9e92014-08-06 08:53:13 +03001004 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +00001005 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001006 sgs = [
1007 sg for sg in client.list_security_groups().values()[0]
1008 if sg['tenant_id'] == tenant_id and sg['name'] == 'default'
1009 ]
1010 msg = "No default security group for tenant %s." % (tenant_id)
1011 self.assertTrue(len(sgs) > 0, msg)
Ken'ichi Ohmichi69a182a2016-04-29 10:56:27 -07001012 return network_resources.DeletableSecurityGroup(client=client,
1013 **sgs[0])
Yair Fried1fc32a12014-08-04 09:11:30 +03001014
John Warren456d9ae2016-01-12 15:36:33 -05001015 def _create_security_group_rule(self, secgroup=None,
1016 sec_group_rules_client=None,
John Warrenf9606e92015-12-10 12:12:42 -05001017 tenant_id=None,
1018 security_groups_client=None, **kwargs):
Yair Fried1fc32a12014-08-04 09:11:30 +03001019 """Create a rule from a dictionary of rule parameters.
1020
1021 Create a rule in a secgroup. if secgroup not defined will search for
1022 default secgroup in tenant_id.
1023
1024 :param secgroup: type DeletableSecurityGroup.
Yair Fried1fc32a12014-08-04 09:11:30 +03001025 :param tenant_id: if secgroup not passed -- the tenant in which to
1026 search for default secgroup
1027 :param kwargs: a dictionary containing rule parameters:
1028 for example, to allow incoming ssh:
1029 rule = {
1030 direction: 'ingress'
1031 protocol:'tcp',
1032 port_range_min: 22,
1033 port_range_max: 22
1034 }
1035 """
John Warren456d9ae2016-01-12 15:36:33 -05001036 if sec_group_rules_client is None:
1037 sec_group_rules_client = self.security_group_rules_client
John Warrenf9606e92015-12-10 12:12:42 -05001038 if security_groups_client is None:
1039 security_groups_client = self.security_groups_client
Yair Frieddb6c9e92014-08-06 08:53:13 +03001040 if not tenant_id:
John Warrenf9606e92015-12-10 12:12:42 -05001041 tenant_id = security_groups_client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001042 if secgroup is None:
John Warrenf9606e92015-12-10 12:12:42 -05001043 secgroup = self._default_security_group(
1044 client=security_groups_client, tenant_id=tenant_id)
Yair Fried1fc32a12014-08-04 09:11:30 +03001045
1046 ruleset = dict(security_group_id=secgroup.id,
1047 tenant_id=secgroup.tenant_id)
1048 ruleset.update(kwargs)
1049
John Warren456d9ae2016-01-12 15:36:33 -05001050 sg_rule = sec_group_rules_client.create_security_group_rule(**ruleset)
Ken'ichi Ohmichi69a182a2016-04-29 10:56:27 -07001051 sg_rule = network_resources.DeletableSecurityGroupRule(
John Warren456d9ae2016-01-12 15:36:33 -05001052 client=sec_group_rules_client,
Yair Fried1fc32a12014-08-04 09:11:30 +03001053 **sg_rule['security_group_rule']
1054 )
Yair Fried1fc32a12014-08-04 09:11:30 +03001055 self.assertEqual(secgroup.tenant_id, sg_rule.tenant_id)
1056 self.assertEqual(secgroup.id, sg_rule.security_group_id)
1057
1058 return sg_rule
1059
John Warren456d9ae2016-01-12 15:36:33 -05001060 def _create_loginable_secgroup_rule(self, security_group_rules_client=None,
1061 secgroup=None,
John Warrenf9606e92015-12-10 12:12:42 -05001062 security_groups_client=None):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001063 """Create loginable security group rule
1064
Alex Stafeyevdd5dde92016-05-08 14:35:04 +03001065 This function will create:
1066 1. egress and ingress tcp port 22 allow rule in order to allow ssh
1067 access for ipv4.
1068 2. egress and ingress ipv6 icmp allow rule, in order to allow icmpv6.
1069 3. egress and ingress ipv4 icmp allow rule, in order to allow icmpv4.
Yair Fried1fc32a12014-08-04 09:11:30 +03001070 """
1071
John Warren456d9ae2016-01-12 15:36:33 -05001072 if security_group_rules_client is None:
1073 security_group_rules_client = self.security_group_rules_client
John Warrenf9606e92015-12-10 12:12:42 -05001074 if security_groups_client is None:
1075 security_groups_client = self.security_groups_client
Yair Fried1fc32a12014-08-04 09:11:30 +03001076 rules = []
1077 rulesets = [
1078 dict(
1079 # ssh
1080 protocol='tcp',
1081 port_range_min=22,
1082 port_range_max=22,
1083 ),
1084 dict(
1085 # ping
1086 protocol='icmp',
Andreas Scheuring887ca8e2015-02-03 17:56:12 +01001087 ),
1088 dict(
1089 # ipv6-icmp for ping6
1090 protocol='icmp',
1091 ethertype='IPv6',
Yair Fried1fc32a12014-08-04 09:11:30 +03001092 )
1093 ]
John Warren456d9ae2016-01-12 15:36:33 -05001094 sec_group_rules_client = security_group_rules_client
Yair Fried1fc32a12014-08-04 09:11:30 +03001095 for ruleset in rulesets:
1096 for r_direction in ['ingress', 'egress']:
1097 ruleset['direction'] = r_direction
1098 try:
1099 sg_rule = self._create_security_group_rule(
John Warren456d9ae2016-01-12 15:36:33 -05001100 sec_group_rules_client=sec_group_rules_client,
1101 secgroup=secgroup,
John Warrenf9606e92015-12-10 12:12:42 -05001102 security_groups_client=security_groups_client,
1103 **ruleset)
Masayuki Igawad9388762015-01-20 14:56:42 +09001104 except lib_exc.Conflict as ex:
Yair Fried1fc32a12014-08-04 09:11:30 +03001105 # if rule already exist - skip rule and continue
1106 msg = 'Security group rule already exists'
1107 if msg not in ex._error_string:
1108 raise ex
1109 else:
1110 self.assertEqual(r_direction, sg_rule.direction)
1111 rules.append(sg_rule)
1112
1113 return rules
1114
Yair Frieddb6c9e92014-08-06 08:53:13 +03001115 def _get_router(self, client=None, tenant_id=None):
Yair Fried1fc32a12014-08-04 09:11:30 +03001116 """Retrieve a router for the given tenant id.
1117
1118 If a public router has been configured, it will be returned.
1119
1120 If a public router has not been configured, but a public
1121 network has, a tenant router will be created and returned that
1122 routes traffic to the public network.
1123 """
Yair Frieddb6c9e92014-08-06 08:53:13 +03001124 if not client:
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +00001125 client = self.routers_client
Yair Frieddb6c9e92014-08-06 08:53:13 +03001126 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +00001127 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001128 router_id = CONF.network.public_router_id
1129 network_id = CONF.network.public_network_id
1130 if router_id:
David Kranzca4c7e72015-05-27 11:39:19 -04001131 body = client.show_router(router_id)
Ken'ichi Ohmichi69a182a2016-04-29 10:56:27 -07001132 return network_resources.AttributeDict(**body['router'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001133 elif network_id:
Yair Frieddb6c9e92014-08-06 08:53:13 +03001134 router = self._create_router(client, tenant_id)
Yair Fried1fc32a12014-08-04 09:11:30 +03001135 router.set_gateway(network_id)
1136 return router
1137 else:
1138 raise Exception("Neither of 'public_router_id' or "
1139 "'public_network_id' has been defined.")
1140
Yair Frieddb6c9e92014-08-06 08:53:13 +03001141 def _create_router(self, client=None, tenant_id=None,
1142 namestart='router-smoke'):
1143 if not client:
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +00001144 client = self.routers_client
Yair Frieddb6c9e92014-08-06 08:53:13 +03001145 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +00001146 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001147 name = data_utils.rand_name(namestart)
David Kranz34e88122014-12-11 15:24:05 -05001148 result = client.create_router(name=name,
1149 admin_state_up=True,
1150 tenant_id=tenant_id)
Ken'ichi Ohmichi69a182a2016-04-29 10:56:27 -07001151 router = network_resources.DeletableRouter(routers_client=client,
1152 **result['router'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001153 self.assertEqual(router.name, name)
Jordan Pittier9e227c52016-02-09 14:35:18 +01001154 self.addCleanup(test_utils.call_and_ignore_notfound_exc, router.delete)
Yair Fried1fc32a12014-08-04 09:11:30 +03001155 return router
1156
Alok Maurya6384bbb2014-07-13 06:44:29 -07001157 def _update_router_admin_state(self, router, admin_state_up):
1158 router.update(admin_state_up=admin_state_up)
1159 self.assertEqual(admin_state_up, router.admin_state_up)
1160
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -07001161 def create_networks(self, networks_client=None,
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +00001162 routers_client=None, subnets_client=None,
1163 tenant_id=None, dns_nameservers=None):
Yair Fried1fc32a12014-08-04 09:11:30 +03001164 """Create a network with a subnet connected to a router.
1165
David Shrewsbury9bac3662014-08-07 15:07:01 -04001166 The baremetal driver is a special case since all nodes are
1167 on the same shared network.
1168
Yair Fried413bf2d2014-11-19 17:07:11 +02001169 :param tenant_id: id of tenant to create resources in.
1170 :param dns_nameservers: list of dns servers to send to subnet.
Yair Fried1fc32a12014-08-04 09:11:30 +03001171 :returns: network, subnet, router
1172 """
David Shrewsbury9bac3662014-08-07 15:07:01 -04001173 if CONF.baremetal.driver_enabled:
1174 # NOTE(Shrews): This exception is for environments where tenant
1175 # credential isolation is available, but network separation is
1176 # not (the current baremetal case). Likely can be removed when
1177 # test account mgmt is reworked:
1178 # https://blueprints.launchpad.net/tempest/+spec/test-accounts
Adam Gandelman878a5fd2015-03-30 14:33:36 -07001179 if not CONF.compute.fixed_network_name:
1180 m = 'fixed_network_name must be specified in config'
1181 raise exceptions.InvalidConfiguration(m)
David Shrewsbury9bac3662014-08-07 15:07:01 -04001182 network = self._get_network_by_name(
1183 CONF.compute.fixed_network_name)
1184 router = None
1185 subnet = None
1186 else:
John Warren94d8faf2015-09-15 12:22:24 -04001187 network = self._create_network(
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -07001188 networks_client=networks_client,
John Warren94d8faf2015-09-15 12:22:24 -04001189 tenant_id=tenant_id)
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +00001190 router = self._get_router(client=routers_client,
1191 tenant_id=tenant_id)
Yair Fried413bf2d2014-11-19 17:07:11 +02001192
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -07001193 subnet_kwargs = dict(network=network,
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +00001194 subnets_client=subnets_client,
1195 routers_client=routers_client)
Yair Fried413bf2d2014-11-19 17:07:11 +02001196 # use explicit check because empty list is a valid option
1197 if dns_nameservers is not None:
1198 subnet_kwargs['dns_nameservers'] = dns_nameservers
1199 subnet = self._create_subnet(**subnet_kwargs)
David Shrewsbury9bac3662014-08-07 15:07:01 -04001200 subnet.add_to_router(router.id)
Yair Fried1fc32a12014-08-04 09:11:30 +03001201 return network, subnet, router
1202
1203
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001204# power/provision states as of icehouse
1205class BaremetalPowerStates(object):
1206 """Possible power states of an Ironic node."""
1207 POWER_ON = 'power on'
1208 POWER_OFF = 'power off'
1209 REBOOT = 'rebooting'
1210 SUSPEND = 'suspended'
1211
1212
1213class BaremetalProvisionStates(object):
1214 """Possible provision states of an Ironic node."""
1215 NOSTATE = None
1216 INIT = 'initializing'
1217 ACTIVE = 'active'
1218 BUILDING = 'building'
1219 DEPLOYWAIT = 'wait call-back'
1220 DEPLOYING = 'deploying'
1221 DEPLOYFAIL = 'deploy failed'
1222 DEPLOYDONE = 'deploy complete'
1223 DELETING = 'deleting'
1224 DELETED = 'deleted'
1225 ERROR = 'error'
1226
1227
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001228class BaremetalScenarioTest(ScenarioTest):
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001229
1230 credentials = ['primary', 'admin']
1231
Adam Gandelman4a48a602014-03-20 18:23:18 -07001232 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001233 def skip_checks(cls):
1234 super(BaremetalScenarioTest, cls).skip_checks()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001235 if (not CONF.service_available.ironic or
1236 not CONF.baremetal.driver_enabled):
1237 msg = 'Ironic not available or Ironic compute driver not enabled'
1238 raise cls.skipException(msg)
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001239
1240 @classmethod
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001241 def setup_clients(cls):
1242 super(BaremetalScenarioTest, cls).setup_clients()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001243
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001244 cls.baremetal_client = cls.admin_manager.baremetal_client
Adam Gandelman4a48a602014-03-20 18:23:18 -07001245
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001246 @classmethod
1247 def resource_setup(cls):
1248 super(BaremetalScenarioTest, cls).resource_setup()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001249 # allow any issues obtaining the node list to raise early
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001250 cls.baremetal_client.list_nodes()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001251
1252 def _node_state_timeout(self, node_id, state_attr,
1253 target_states, timeout=10, interval=1):
1254 if not isinstance(target_states, list):
1255 target_states = [target_states]
1256
1257 def check_state():
1258 node = self.get_node(node_id=node_id)
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001259 if node.get(state_attr) in target_states:
Adam Gandelman4a48a602014-03-20 18:23:18 -07001260 return True
1261 return False
1262
1263 if not tempest.test.call_until_true(
1264 check_state, timeout, interval):
1265 msg = ("Timed out waiting for node %s to reach %s state(s) %s" %
1266 (node_id, state_attr, target_states))
1267 raise exceptions.TimeoutException(msg)
1268
1269 def wait_provisioning_state(self, node_id, state, timeout):
1270 self._node_state_timeout(
1271 node_id=node_id, state_attr='provision_state',
1272 target_states=state, timeout=timeout)
1273
1274 def wait_power_state(self, node_id, state):
1275 self._node_state_timeout(
1276 node_id=node_id, state_attr='power_state',
1277 target_states=state, timeout=CONF.baremetal.power_timeout)
1278
1279 def wait_node(self, instance_id):
1280 """Waits for a node to be associated with instance_id."""
Zhi Kun Liu4a8d1ea2014-04-15 22:08:21 -05001281
Adam Gandelman4a48a602014-03-20 18:23:18 -07001282 def _get_node():
Jordan Pittier9e227c52016-02-09 14:35:18 +01001283 node = test_utils.call_and_ignore_notfound_exc(
1284 self.get_node, instance_id=instance_id)
Adam Gandelman4a48a602014-03-20 18:23:18 -07001285 return node is not None
1286
1287 if not tempest.test.call_until_true(
1288 _get_node, CONF.baremetal.association_timeout, 1):
1289 msg = ('Timed out waiting to get Ironic node by instance id %s'
1290 % instance_id)
1291 raise exceptions.TimeoutException(msg)
1292
1293 def get_node(self, node_id=None, instance_id=None):
1294 if node_id:
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001295 _, body = self.baremetal_client.show_node(node_id)
1296 return body
Adam Gandelman4a48a602014-03-20 18:23:18 -07001297 elif instance_id:
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001298 _, body = self.baremetal_client.show_node_by_instance_uuid(
1299 instance_id)
1300 if body['nodes']:
1301 return body['nodes'][0]
Adam Gandelman4a48a602014-03-20 18:23:18 -07001302
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001303 def get_ports(self, node_uuid):
Adam Gandelman4a48a602014-03-20 18:23:18 -07001304 ports = []
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001305 _, body = self.baremetal_client.list_node_ports(node_uuid)
1306 for port in body['ports']:
1307 _, p = self.baremetal_client.show_port(port['uuid'])
1308 ports.append(p)
Adam Gandelman4a48a602014-03-20 18:23:18 -07001309 return ports
1310
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001311 def add_keypair(self):
1312 self.keypair = self.create_keypair()
1313
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001314 def boot_instance(self):
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001315 self.instance = self.create_server(
lanoux5fc14522015-09-21 08:17:35 +00001316 key_name=self.keypair['name'])
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001317
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001318 self.wait_node(self.instance['id'])
1319 self.node = self.get_node(instance_id=self.instance['id'])
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001320
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001321 self.wait_power_state(self.node['uuid'], BaremetalPowerStates.POWER_ON)
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001322
1323 self.wait_provisioning_state(
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001324 self.node['uuid'],
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001325 [BaremetalProvisionStates.DEPLOYWAIT,
1326 BaremetalProvisionStates.ACTIVE],
1327 timeout=15)
1328
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001329 self.wait_provisioning_state(self.node['uuid'],
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001330 BaremetalProvisionStates.ACTIVE,
1331 timeout=CONF.baremetal.active_timeout)
1332
Ken'ichi Ohmichi0eb153c2015-07-13 02:18:25 +00001333 waiters.wait_for_server_status(self.servers_client,
1334 self.instance['id'], 'ACTIVE')
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001335 self.node = self.get_node(instance_id=self.instance['id'])
ghanshyam0f825252015-08-25 16:02:50 +09001336 self.instance = (self.servers_client.show_server(self.instance['id'])
1337 ['server'])
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001338
1339 def terminate_instance(self):
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001340 self.servers_client.delete_server(self.instance['id'])
1341 self.wait_power_state(self.node['uuid'],
1342 BaremetalPowerStates.POWER_OFF)
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001343 self.wait_provisioning_state(
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001344 self.node['uuid'],
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001345 BaremetalProvisionStates.NOSTATE,
1346 timeout=CONF.baremetal.unprovision_timeout)
1347
Adam Gandelman4a48a602014-03-20 18:23:18 -07001348
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001349class EncryptionScenarioTest(ScenarioTest):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001350 """Base class for encryption scenario tests"""
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001351
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001352 credentials = ['primary', 'admin']
David Kranz4cc852b2015-03-09 14:57:11 -04001353
1354 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001355 def setup_clients(cls):
1356 super(EncryptionScenarioTest, cls).setup_clients()
Ivan Kolodyazhnybcfc32e2015-08-06 13:31:36 +03001357 if CONF.volume_feature_enabled.api_v1:
1358 cls.admin_volume_types_client = cls.os_adm.volume_types_client
1359 else:
1360 cls.admin_volume_types_client = cls.os_adm.volume_types_v2_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001361
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001362 def create_volume_type(self, client=None, name=None):
1363 if not client:
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001364 client = self.admin_volume_types_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001365 if not name:
1366 name = 'generic'
Ken'ichi Ohmichi6ded8df2015-03-23 02:00:19 +00001367 randomized_name = data_utils.rand_name('scenario-type-' + name)
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001368 LOG.debug("Creating a volume type: %s", randomized_name)
Joseph Lanoux6809bab2014-12-18 14:57:18 +00001369 body = client.create_volume_type(
lei zhang83c4bbd2015-11-27 00:35:21 +08001370 name=randomized_name)['volume_type']
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001371 self.assertIn('id', body)
1372 self.addCleanup(client.delete_volume_type, body['id'])
1373 return body
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001374
1375 def create_encryption_type(self, client=None, type_id=None, provider=None,
1376 key_size=None, cipher=None,
1377 control_location=None):
1378 if not client:
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001379 client = self.admin_volume_types_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001380 if not type_id:
1381 volume_type = self.create_volume_type()
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001382 type_id = volume_type['id']
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001383 LOG.debug("Creating an encryption type for volume type: %s", type_id)
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001384 client.create_encryption_type(
1385 type_id, provider=provider, key_size=key_size, cipher=cipher,
John Warrend053ded2015-08-13 15:22:48 +00001386 control_location=control_location)['encryption']
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001387
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001388
Masayuki Igawa0870db52015-09-18 21:08:36 +09001389class ObjectStorageScenarioTest(ScenarioTest):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001390 """Provide harness to do Object Storage scenario tests.
Chris Dent0d494112014-08-26 13:48:30 +01001391
1392 Subclasses implement the tests that use the methods provided by this
1393 class.
1394 """
1395
1396 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001397 def skip_checks(cls):
Masayuki Igawa0870db52015-09-18 21:08:36 +09001398 super(ObjectStorageScenarioTest, cls).skip_checks()
Chris Dent0d494112014-08-26 13:48:30 +01001399 if not CONF.service_available.swift:
1400 skip_msg = ("%s skipped as swift is not available" %
1401 cls.__name__)
1402 raise cls.skipException(skip_msg)
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001403
1404 @classmethod
1405 def setup_credentials(cls):
Masayuki Igawa60ea6c52014-10-15 17:32:14 +09001406 cls.set_network_resources()
Masayuki Igawa0870db52015-09-18 21:08:36 +09001407 super(ObjectStorageScenarioTest, cls).setup_credentials()
Matthew Treinish4a596932015-03-06 20:37:01 -05001408 operator_role = CONF.object_storage.operator_role
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +01001409 cls.os_operator = cls.get_client_manager(roles=[operator_role])
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001410
1411 @classmethod
1412 def setup_clients(cls):
Masayuki Igawa0870db52015-09-18 21:08:36 +09001413 super(ObjectStorageScenarioTest, cls).setup_clients()
Chris Dent0d494112014-08-26 13:48:30 +01001414 # Clients for Swift
Matthew Treinish8f268292015-02-24 20:01:36 -05001415 cls.account_client = cls.os_operator.account_client
1416 cls.container_client = cls.os_operator.container_client
1417 cls.object_client = cls.os_operator.object_client
Chris Dent0d494112014-08-26 13:48:30 +01001418
Chris Dentde456a12014-09-10 12:41:15 +01001419 def get_swift_stat(self):
Chris Dent0d494112014-08-26 13:48:30 +01001420 """get swift status for our user account."""
1421 self.account_client.list_account_containers()
1422 LOG.debug('Swift status information obtained successfully')
1423
Chris Dentde456a12014-09-10 12:41:15 +01001424 def create_container(self, container_name=None):
Chris Dent0d494112014-08-26 13:48:30 +01001425 name = container_name or data_utils.rand_name(
1426 'swift-scenario-container')
1427 self.container_client.create_container(name)
1428 # look for the container to assure it is created
Chris Dentde456a12014-09-10 12:41:15 +01001429 self.list_and_check_container_objects(name)
Chris Dent0d494112014-08-26 13:48:30 +01001430 LOG.debug('Container %s created' % (name))
Jordan Pittier9e227c52016-02-09 14:35:18 +01001431 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
Chris Dent1d4313a2014-10-28 12:16:48 +00001432 self.container_client.delete_container,
1433 name)
Chris Dent0d494112014-08-26 13:48:30 +01001434 return name
1435
Chris Dentde456a12014-09-10 12:41:15 +01001436 def delete_container(self, container_name):
Chris Dent0d494112014-08-26 13:48:30 +01001437 self.container_client.delete_container(container_name)
1438 LOG.debug('Container %s deleted' % (container_name))
1439
Chris Dentde456a12014-09-10 12:41:15 +01001440 def upload_object_to_container(self, container_name, obj_name=None):
Chris Dent0d494112014-08-26 13:48:30 +01001441 obj_name = obj_name or data_utils.rand_name('swift-scenario-object')
1442 obj_data = data_utils.arbitrary_string()
1443 self.object_client.create_object(container_name, obj_name, obj_data)
Jordan Pittier9e227c52016-02-09 14:35:18 +01001444 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
Chris Dent1d4313a2014-10-28 12:16:48 +00001445 self.object_client.delete_object,
1446 container_name,
1447 obj_name)
Chris Dent0d494112014-08-26 13:48:30 +01001448 return obj_name, obj_data
1449
Chris Dentde456a12014-09-10 12:41:15 +01001450 def delete_object(self, container_name, filename):
Chris Dent0d494112014-08-26 13:48:30 +01001451 self.object_client.delete_object(container_name, filename)
Chris Dentde456a12014-09-10 12:41:15 +01001452 self.list_and_check_container_objects(container_name,
1453 not_present_obj=[filename])
Chris Dent0d494112014-08-26 13:48:30 +01001454
Chris Dentde456a12014-09-10 12:41:15 +01001455 def list_and_check_container_objects(self, container_name,
1456 present_obj=None,
1457 not_present_obj=None):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001458 # List objects for a given container and assert which are present and
1459 # which are not.
Ghanshyam2a180b82014-06-16 13:54:22 +09001460 if present_obj is None:
1461 present_obj = []
1462 if not_present_obj is None:
1463 not_present_obj = []
Chris Dent0d494112014-08-26 13:48:30 +01001464 _, object_list = self.container_client.list_container_contents(
1465 container_name)
1466 if present_obj:
1467 for obj in present_obj:
1468 self.assertIn(obj, object_list)
1469 if not_present_obj:
1470 for obj in not_present_obj:
1471 self.assertNotIn(obj, object_list)
1472
Chris Dentde456a12014-09-10 12:41:15 +01001473 def change_container_acl(self, container_name, acl):
Chris Dent0d494112014-08-26 13:48:30 +01001474 metadata_param = {'metadata_prefix': 'x-container-',
1475 'metadata': {'read': acl}}
1476 self.container_client.update_container_metadata(container_name,
1477 **metadata_param)
1478 resp, _ = self.container_client.list_container_metadata(container_name)
1479 self.assertEqual(resp['x-container-read'], acl)
1480
Chris Dentde456a12014-09-10 12:41:15 +01001481 def download_and_verify(self, container_name, obj_name, expected_data):
Chris Dent0d494112014-08-26 13:48:30 +01001482 _, obj = self.object_client.get_object(container_name, obj_name)
1483 self.assertEqual(obj, expected_data)