blob: 643720606801664ba3965ba2381332603a53c000 [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
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
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
Sean Dagueed6e5862016-04-04 10:49:13 -0400219 # for the project's private networks and create a port
lanoux5fc14522015-09-21 08:17:35 +0000220 # 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,
Jordan Pittier5e1741c2016-03-02 18:25:51 +0100264 imageRef=None, volume_type=None):
Andrea Frittoli247058f2014-07-16 16:09:22 +0100265 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
Jordan Pittier5e1741c2016-03-02 18:25:51 +0100275 self.addCleanup(self.volumes_client.wait_for_resource_deletion,
276 volume['id'])
277 self.addCleanup(self.delete_wrapper,
278 self.volumes_client.delete_volume, volume['id'])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100279
Ivan Kolodyazhnybcfc32e2015-08-06 13:31:36 +0300280 # NOTE(e0ne): Cinder API v2 uses name instead of display_name
281 if 'display_name' in volume:
282 self.assertEqual(name, volume['display_name'])
283 else:
284 self.assertEqual(name, volume['name'])
Yaroslav Lobankoved3a35b2016-03-24 22:41:30 -0500285 waiters.wait_for_volume_status(self.volumes_client,
286 volume['id'], 'available')
Andrea Frittoli247058f2014-07-16 16:09:22 +0100287 # The volume retrieved on creation has a non-up-to-date status.
288 # Retrieval after it becomes active ensures correct details.
John Warren6177c9e2015-08-19 20:00:17 +0000289 volume = self.volumes_client.show_volume(volume['id'])['volume']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100290 return volume
291
Yair Fried1fc32a12014-08-04 09:11:30 +0300292 def _create_loginable_secgroup_rule(self, secgroup_id=None):
John Warrenf2345512015-12-10 13:39:30 -0500293 _client = self.compute_security_groups_client
John Warren5cdbf422016-01-05 12:42:43 -0500294 _client_rules = self.compute_security_group_rules_client
Andrea Frittoli247058f2014-07-16 16:09:22 +0100295 if secgroup_id is None:
ghanshyamb610b772015-08-24 17:29:38 +0900296 sgs = _client.list_security_groups()['security_groups']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100297 for sg in sgs:
298 if sg['name'] == 'default':
299 secgroup_id = sg['id']
300
301 # These rules are intended to permit inbound ssh and icmp
302 # traffic from all sources, so no group_id is provided.
303 # Setting a group_id would only permit traffic from ports
304 # belonging to the same security group.
305 rulesets = [
306 {
307 # ssh
Ken'ichi Ohmichieb7eeec2015-07-21 01:00:06 +0000308 'ip_protocol': 'tcp',
Andrea Frittoli247058f2014-07-16 16:09:22 +0100309 'from_port': 22,
310 'to_port': 22,
311 'cidr': '0.0.0.0/0',
312 },
313 {
314 # ping
Ken'ichi Ohmichieb7eeec2015-07-21 01:00:06 +0000315 'ip_protocol': 'icmp',
Andrea Frittoli247058f2014-07-16 16:09:22 +0100316 'from_port': -1,
317 'to_port': -1,
318 'cidr': '0.0.0.0/0',
319 }
320 ]
321 rules = list()
322 for ruleset in rulesets:
Ken'ichi Ohmichieb7eeec2015-07-21 01:00:06 +0000323 sg_rule = _client_rules.create_security_group_rule(
ghanshyam0a5e1232015-08-24 16:59:59 +0900324 parent_group_id=secgroup_id, **ruleset)['security_group_rule']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100325 rules.append(sg_rule)
326 return rules
327
Yair Fried1fc32a12014-08-04 09:11:30 +0300328 def _create_security_group(self):
Andrea Frittoli247058f2014-07-16 16:09:22 +0100329 # Create security group
330 sg_name = data_utils.rand_name(self.__class__.__name__)
331 sg_desc = sg_name + " description"
John Warrenf2345512015-12-10 13:39:30 -0500332 secgroup = self.compute_security_groups_client.create_security_group(
ghanshyamb610b772015-08-24 17:29:38 +0900333 name=sg_name, description=sg_desc)['security_group']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100334 self.assertEqual(secgroup['name'], sg_name)
335 self.assertEqual(secgroup['description'], sg_desc)
John Warrenf2345512015-12-10 13:39:30 -0500336 self.addCleanup(
337 self.delete_wrapper,
338 self.compute_security_groups_client.delete_security_group,
339 secgroup['id'])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100340
341 # Add rules to the security group
Yair Fried1fc32a12014-08-04 09:11:30 +0300342 self._create_loginable_secgroup_rule(secgroup['id'])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100343
344 return secgroup
345
Sean Dague20e98612016-01-06 14:33:28 -0500346 def get_remote_client(self, ip_address, username=None, private_key=None):
JordanP3fe2dc32014-11-17 13:06:01 +0100347 """Get a SSH client to a remote server
348
Sean Dague20e98612016-01-06 14:33:28 -0500349 @param ip_address the server floating or fixed IP address to use
350 for ssh validation
JordanP3fe2dc32014-11-17 13:06:01 +0100351 @param username name of the Linux account on the remote server
352 @param private_key the SSH private key to use
JordanP3fe2dc32014-11-17 13:06:01 +0100353 @return a RemoteClient object
354 """
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700355
Andrea Frittoli247058f2014-07-16 16:09:22 +0100356 if username is None:
lanoux283273b2015-12-04 03:01:54 -0800357 username = CONF.validation.image_ssh_user
wantwatering896300c2015-03-27 15:17:42 +0800358 # Set this with 'keypair' or others to log in with keypair or
359 # username/password.
lanoux5fc14522015-09-21 08:17:35 +0000360 if CONF.validation.auth_method == 'keypair':
wantwatering896300c2015-03-27 15:17:42 +0800361 password = None
362 if private_key is None:
363 private_key = self.keypair['private_key']
364 else:
lanoux283273b2015-12-04 03:01:54 -0800365 password = CONF.validation.image_ssh_password
wantwatering896300c2015-03-27 15:17:42 +0800366 private_key = None
Sean Dague20e98612016-01-06 14:33:28 -0500367 linux_client = remote_client.RemoteClient(ip_address, username,
wantwatering896300c2015-03-27 15:17:42 +0800368 pkey=private_key,
369 password=password)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100370 try:
371 linux_client.validate_authentication()
Matt Riedemann5f0ac522015-05-21 09:16:24 -0700372 except Exception as e:
373 message = ('Initializing SSH connection to %(ip)s failed. '
Eric Brown0911af62016-02-08 17:15:40 -0800374 'Error: %(error)s' % {'ip': ip_address,
Sean Dague20e98612016-01-06 14:33:28 -0500375 'error': e})
Matt Riedemann5f0ac522015-05-21 09:16:24 -0700376 caller = misc_utils.find_test_caller()
377 if caller:
378 message = '(%s) %s' % (caller, message)
379 LOG.exception(message)
Sean Dague2c98a162016-01-06 14:11:13 -0500380 self._log_console_output()
Andrea Frittoli247058f2014-07-16 16:09:22 +0100381 raise
382
383 return linux_client
384
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000385 def _image_create(self, name, fmt, path,
386 disk_format=None, properties=None):
Ghanshyam2a180b82014-06-16 13:54:22 +0900387 if properties is None:
388 properties = {}
Andrea Frittoli247058f2014-07-16 16:09:22 +0100389 name = data_utils.rand_name('%s-' % name)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100390 params = {
391 'name': name,
392 'container_format': fmt,
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000393 'disk_format': disk_format or fmt,
Andrea Frittoli247058f2014-07-16 16:09:22 +0100394 'is_public': 'False',
395 }
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000396 params['properties'] = properties
John Warren66207252015-07-31 15:51:02 -0400397 image = self.image_client.create_image(**params)['image']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100398 self.addCleanup(self.image_client.delete_image, image['id'])
399 self.assertEqual("queued", image['status'])
zhang.leia4b1cef2016-03-01 10:50:01 +0800400 with open(path, 'rb') as image_file:
401 self.image_client.update_image(image['id'], data=image_file)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100402 return image['id']
403
404 def glance_image_create(self):
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300405 img_path = CONF.scenario.img_dir + "/" + CONF.scenario.img_file
Andrea Frittoli247058f2014-07-16 16:09:22 +0100406 aki_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.aki_img_file
407 ari_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.ari_img_file
408 ami_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.ami_img_file
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300409 img_container_format = CONF.scenario.img_container_format
410 img_disk_format = CONF.scenario.img_disk_format
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000411 img_properties = CONF.scenario.img_properties
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300412 LOG.debug("paths: img: %s, container_fomat: %s, disk_format: %s, "
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000413 "properties: %s, ami: %s, ari: %s, aki: %s" %
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300414 (img_path, img_container_format, img_disk_format,
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000415 img_properties, ami_img_path, ari_img_path, aki_img_path))
Andrea Frittoli247058f2014-07-16 16:09:22 +0100416 try:
Jordan Pittier1e443ec2015-11-20 16:15:58 +0100417 image = self._image_create('scenario-img',
418 img_container_format,
419 img_path,
420 disk_format=img_disk_format,
421 properties=img_properties)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100422 except IOError:
423 LOG.debug("A qcow2 image was not found. Try to get a uec image.")
424 kernel = self._image_create('scenario-aki', 'aki', aki_img_path)
425 ramdisk = self._image_create('scenario-ari', 'ari', ari_img_path)
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000426 properties = {'kernel_id': kernel, 'ramdisk_id': ramdisk}
Jordan Pittier1e443ec2015-11-20 16:15:58 +0100427 image = self._image_create('scenario-ami', 'ami',
428 path=ami_img_path,
429 properties=properties)
430 LOG.debug("image:%s" % image)
431
432 return image
Andrea Frittoli247058f2014-07-16 16:09:22 +0100433
434 def _log_console_output(self, servers=None):
Matthew Treinish42a3f3a2014-09-04 15:04:53 -0400435 if not CONF.compute_feature_enabled.console_output:
436 LOG.debug('Console output not supported, cannot log')
437 return
Andrea Frittoli247058f2014-07-16 16:09:22 +0100438 if not servers:
David Kranzae99b9a2015-02-16 13:37:01 -0500439 servers = self.servers_client.list_servers()
Andrea Frittoli247058f2014-07-16 16:09:22 +0100440 servers = servers['servers']
441 for server in servers:
Brant Knudson566c5712014-09-24 20:04:50 -0500442 console_output = self.servers_client.get_console_output(
Ken'ichi Ohmichibf4766a2015-12-09 07:48:43 +0000443 server['id'])['output']
David Kranzae99b9a2015-02-16 13:37:01 -0500444 LOG.debug('Console output for %s\nbody=\n%s',
445 server['id'], console_output)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100446
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000447 def _log_net_info(self, exc):
448 # network debug is called as part of ssh init
Andrey Pavlov64723762015-04-29 06:24:58 +0300449 if not isinstance(exc, lib_exc.SSHTimeout):
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000450 LOG.debug('Network information on a devstack host')
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000451
nithya-ganesan882595e2014-07-29 18:51:07 +0000452 def create_server_snapshot(self, server, name=None):
453 # Glance client
454 _image_client = self.image_client
455 # Compute client
Ghanshyamae76c122015-12-22 13:41:35 +0900456 _images_client = self.compute_images_client
nithya-ganesan882595e2014-07-29 18:51:07 +0000457 if name is None:
Ken'ichi Ohmichi6ded8df2015-03-23 02:00:19 +0000458 name = data_utils.rand_name('scenario-snapshot')
nithya-ganesan882595e2014-07-29 18:51:07 +0000459 LOG.debug("Creating a snapshot image for server: %s", server['name'])
Ken'ichi Ohmichi28f18672015-07-17 10:00:38 +0000460 image = _images_client.create_image(server['id'], name=name)
David Kranza5299eb2015-01-15 17:24:05 -0500461 image_id = image.response['location'].split('images/')[1]
nithya-ganesan882595e2014-07-29 18:51:07 +0000462 _image_client.wait_for_image_status(image_id, 'active')
463 self.addCleanup_with_wait(
464 waiter_callable=_image_client.wait_for_resource_deletion,
465 thing_id=image_id, thing_id_param='id',
466 cleanup_callable=self.delete_wrapper,
467 cleanup_args=[_image_client.delete_image, image_id])
David Kranz34f18782015-01-06 13:43:55 -0500468 snapshot_image = _image_client.get_image_meta(image_id)
Andrey Pavlovc8bd4b12015-08-17 10:20:17 +0300469
470 bdm = snapshot_image.get('properties', {}).get('block_device_mapping')
471 if bdm:
472 bdm = json.loads(bdm)
473 if bdm and 'snapshot_id' in bdm[0]:
474 snapshot_id = bdm[0]['snapshot_id']
475 self.addCleanup(
476 self.snapshots_client.wait_for_resource_deletion,
477 snapshot_id)
478 self.addCleanup(
479 self.delete_wrapper, self.snapshots_client.delete_snapshot,
480 snapshot_id)
Yaroslav Lobankov667aaa22016-03-24 23:13:28 -0500481 waiters.wait_for_snapshot_status(self.snapshots_client,
482 snapshot_id, 'available')
Andrey Pavlovc8bd4b12015-08-17 10:20:17 +0300483
nithya-ganesan882595e2014-07-29 18:51:07 +0000484 image_name = snapshot_image['name']
485 self.assertEqual(name, image_name)
486 LOG.debug("Created snapshot image %s for server %s",
487 image_name, server['name'])
488 return snapshot_image
489
Jordan Pittier7cf64762015-10-14 15:01:12 +0200490 def nova_volume_attach(self, server, volume_to_attach):
Joseph Lanoux6809bab2014-12-18 14:57:18 +0000491 volume = self.servers_client.attach_volume(
Jordan Pittier7cf64762015-10-14 15:01:12 +0200492 server['id'], volumeId=volume_to_attach['id'], device='/dev/%s'
ghanshyam0f825252015-08-25 16:02:50 +0900493 % CONF.compute.volume_device_name)['volumeAttachment']
Jordan Pittier7cf64762015-10-14 15:01:12 +0200494 self.assertEqual(volume_to_attach['id'], volume['id'])
Yaroslav Lobankoved3a35b2016-03-24 22:41:30 -0500495 waiters.wait_for_volume_status(self.volumes_client,
496 volume['id'], 'in-use')
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900497
Jordan Pittier7cf64762015-10-14 15:01:12 +0200498 # Return the updated volume after the attachment
499 return self.volumes_client.show_volume(volume['id'])['volume']
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900500
Jordan Pittier7cf64762015-10-14 15:01:12 +0200501 def nova_volume_detach(self, server, volume):
502 self.servers_client.detach_volume(server['id'], volume['id'])
Yaroslav Lobankoved3a35b2016-03-24 22:41:30 -0500503 waiters.wait_for_volume_status(self.volumes_client,
504 volume['id'], 'available')
Jordan Pittier7cf64762015-10-14 15:01:12 +0200505
506 volume = self.volumes_client.show_volume(volume['id'])['volume']
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900507 self.assertEqual('available', volume['status'])
508
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700509 def rebuild_server(self, server_id, image=None,
510 preserve_ephemeral=False, wait=True,
511 rebuild_kwargs=None):
512 if image is None:
513 image = CONF.compute.image_ref
514
515 rebuild_kwargs = rebuild_kwargs or {}
516
517 LOG.debug("Rebuilding server (id: %s, image: %s, preserve eph: %s)",
518 server_id, image, preserve_ephemeral)
Ken'ichi Ohmichi5271b0f2015-08-10 07:53:27 +0000519 self.servers_client.rebuild_server(
520 server_id=server_id, image_ref=image,
521 preserve_ephemeral=preserve_ephemeral,
522 **rebuild_kwargs)
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700523 if wait:
Ken'ichi Ohmichi0eb153c2015-07-13 02:18:25 +0000524 waiters.wait_for_server_status(self.servers_client,
525 server_id, 'ACTIVE')
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700526
Steven Hardyda2a8352014-10-02 12:52:20 +0100527 def ping_ip_address(self, ip_address, should_succeed=True,
528 ping_timeout=None):
lanoux5fc14522015-09-21 08:17:35 +0000529 timeout = ping_timeout or CONF.validation.ping_timeout
Aaron Rosena7df13b2014-09-23 09:45:45 -0700530 cmd = ['ping', '-c1', '-w1', ip_address]
531
532 def ping():
533 proc = subprocess.Popen(cmd,
534 stdout=subprocess.PIPE,
535 stderr=subprocess.PIPE)
536 proc.communicate()
Shuquan Huang753629e2015-07-20 08:52:29 +0000537
Aaron Rosena7df13b2014-09-23 09:45:45 -0700538 return (proc.returncode == 0) == should_succeed
539
Shuquan Huang753629e2015-07-20 08:52:29 +0000540 caller = misc_utils.find_test_caller()
541 LOG.debug('%(caller)s begins to ping %(ip)s in %(timeout)s sec and the'
542 ' expected result is %(should_succeed)s' % {
543 'caller': caller, 'ip': ip_address, 'timeout': timeout,
544 'should_succeed':
545 'reachable' if should_succeed else 'unreachable'
546 })
547 result = tempest.test.call_until_true(ping, timeout, 1)
548 LOG.debug('%(caller)s finishes ping %(ip)s in %(timeout)s sec and the '
549 'ping result is %(result)s' % {
550 'caller': caller, 'ip': ip_address, 'timeout': timeout,
551 'result': 'expected' if result else 'unexpected'
552 })
553 return result
Aaron Rosena7df13b2014-09-23 09:45:45 -0700554
Yair Friedae0e73d2014-11-24 11:56:26 +0200555 def check_vm_connectivity(self, ip_address,
556 username=None,
557 private_key=None,
558 should_connect=True):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000559 """Check server connectivity
560
Yair Friedae0e73d2014-11-24 11:56:26 +0200561 :param ip_address: server to test against
562 :param username: server's ssh username
563 :param private_key: server's ssh private key to be used
564 :param should_connect: True/False indicates positive/negative test
565 positive - attempt ping and ssh
566 negative - attempt ping and fail if succeed
567
568 :raises: AssertError if the result of the connectivity check does
569 not match the value of the should_connect param
570 """
571 if should_connect:
572 msg = "Timed out waiting for %s to become reachable" % ip_address
573 else:
574 msg = "ip address %s is reachable" % ip_address
575 self.assertTrue(self.ping_ip_address(ip_address,
576 should_succeed=should_connect),
577 msg=msg)
578 if should_connect:
579 # no need to check ssh for negative connectivity
580 self.get_remote_client(ip_address, username, private_key)
581
582 def check_public_network_connectivity(self, ip_address, username,
583 private_key, should_connect=True,
584 msg=None, servers=None):
585 # The target login is assumed to have been configured for
586 # key-based authentication by cloud-init.
587 LOG.debug('checking network connections to IP %s with user: %s' %
588 (ip_address, username))
589 try:
590 self.check_vm_connectivity(ip_address,
591 username,
592 private_key,
593 should_connect=should_connect)
Matthew Treinish53483132014-12-09 18:50:06 -0500594 except Exception:
Yair Friedae0e73d2014-11-24 11:56:26 +0200595 ex_msg = 'Public network connectivity check failed'
596 if msg:
597 ex_msg += ": " + msg
598 LOG.exception(ex_msg)
599 self._log_console_output(servers)
Yair Friedae0e73d2014-11-24 11:56:26 +0200600 raise
601
602 def create_floating_ip(self, thing, pool_name=None):
Ken'ichi Ohmichia112a592015-11-17 08:49:37 +0000603 """Create a floating IP and associates to a server on Nova"""
Yair Friedae0e73d2014-11-24 11:56:26 +0200604
Marc Koderer3b57d802016-03-22 15:23:31 +0100605 if not pool_name:
606 pool_name = CONF.network.floating_network_name
John Warrene74890a2015-11-11 15:18:01 -0500607 floating_ip = (self.compute_floating_ips_client.
Ken'ichi Ohmichie037a6f2015-12-03 06:41:49 +0000608 create_floating_ip(pool=pool_name)['floating_ip'])
Yair Friedae0e73d2014-11-24 11:56:26 +0200609 self.addCleanup(self.delete_wrapper,
John Warrene74890a2015-11-11 15:18:01 -0500610 self.compute_floating_ips_client.delete_floating_ip,
Yair Friedae0e73d2014-11-24 11:56:26 +0200611 floating_ip['id'])
John Warrene74890a2015-11-11 15:18:01 -0500612 self.compute_floating_ips_client.associate_floating_ip_to_server(
Yair Friedae0e73d2014-11-24 11:56:26 +0200613 floating_ip['ip'], thing['id'])
614 return floating_ip
615
Sean Dague20e98612016-01-06 14:33:28 -0500616 def create_timestamp(self, ip_address, dev_name=None, mount_path='/mnt',
Matt Riedemannfd5657d2015-09-30 14:47:07 -0700617 private_key=None):
Sean Dague20e98612016-01-06 14:33:28 -0500618 ssh_client = self.get_remote_client(ip_address,
Matt Riedemannfd5657d2015-09-30 14:47:07 -0700619 private_key=private_key)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300620 if dev_name is not None:
621 ssh_client.make_fs(dev_name)
Matt Riedemann076685a2015-09-30 14:38:16 -0700622 ssh_client.mount(dev_name, mount_path)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300623 cmd_timestamp = 'sudo sh -c "date > %s/timestamp; sync"' % mount_path
624 ssh_client.exec_command(cmd_timestamp)
625 timestamp = ssh_client.exec_command('sudo cat %s/timestamp'
626 % mount_path)
627 if dev_name is not None:
628 ssh_client.umount(mount_path)
629 return timestamp
630
Sean Dague20e98612016-01-06 14:33:28 -0500631 def get_timestamp(self, ip_address, dev_name=None, mount_path='/mnt',
Matt Riedemannfd5657d2015-09-30 14:47:07 -0700632 private_key=None):
Sean Dague20e98612016-01-06 14:33:28 -0500633 ssh_client = self.get_remote_client(ip_address,
Matt Riedemannfd5657d2015-09-30 14:47:07 -0700634 private_key=private_key)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300635 if dev_name is not None:
Matt Riedemann076685a2015-09-30 14:38:16 -0700636 ssh_client.mount(dev_name, mount_path)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300637 timestamp = ssh_client.exec_command('sudo cat %s/timestamp'
638 % mount_path)
639 if dev_name is not None:
640 ssh_client.umount(mount_path)
641 return timestamp
642
Sean Dague20e98612016-01-06 14:33:28 -0500643 def get_server_ip(self, server):
644 """Get the server fixed or floating IP.
645
646 Based on the configuration we're in, return a correct ip
647 address for validating that a guest is up.
648 """
Alexander Gubanovc8829f82015-11-12 10:35:13 +0200649 if CONF.validation.connect_method == 'floating':
Sean Dague20e98612016-01-06 14:33:28 -0500650 # The tests calling this method don't have a floating IP
651 # and can't make use of the validattion resources. So the
652 # method is creating the floating IP there.
653 return self.create_floating_ip(server)['ip']
654 elif CONF.validation.connect_method == 'fixed':
655 addresses = server['addresses'][CONF.validation.network_for_ssh]
656 for address in addresses:
657 if address['version'] == CONF.validation.ip_version_for_ssh:
658 return address['addr']
659 raise exceptions.ServerUnreachable()
Alexander Gubanovc8829f82015-11-12 10:35:13 +0200660 else:
Sean Dague20e98612016-01-06 14:33:28 -0500661 raise exceptions.InvalidConfiguration()
Alexander Gubanovc8829f82015-11-12 10:35:13 +0200662
Andrea Frittoli2e733b52014-07-16 14:12:11 +0100663
Andrea Frittoli4971fc82014-09-25 10:22:20 +0100664class NetworkScenarioTest(ScenarioTest):
Yair Fried1fc32a12014-08-04 09:11:30 +0300665 """Base class for network scenario tests.
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000666
Yair Fried1fc32a12014-08-04 09:11:30 +0300667 This class provide helpers for network scenario tests, using the neutron
668 API. Helpers from ancestor which use the nova network API are overridden
669 with the neutron API.
670
671 This Class also enforces using Neutron instead of novanetwork.
672 Subclassed tests will be skipped if Neutron is not enabled
673
674 """
675
Andrea Frittolib21de6c2015-02-06 20:12:38 +0000676 credentials = ['primary', 'admin']
677
Yair Fried1fc32a12014-08-04 09:11:30 +0300678 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +0000679 def skip_checks(cls):
680 super(NetworkScenarioTest, cls).skip_checks()
Andrea Frittoli2ddc2632014-09-25 11:03:00 +0100681 if not CONF.service_available.neutron:
682 raise cls.skipException('Neutron not available')
Yair Fried1fc32a12014-08-04 09:11:30 +0300683
684 @classmethod
Andrea Frittoliac20b5e2014-09-15 13:31:14 +0100685 def resource_setup(cls):
686 super(NetworkScenarioTest, cls).resource_setup()
Yair Fried1fc32a12014-08-04 09:11:30 +0300687 cls.tenant_id = cls.manager.identity_client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300688
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -0700689 def _create_network(self, networks_client=None,
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000690 routers_client=None, tenant_id=None,
691 namestart='network-smoke-'):
John Warren94d8faf2015-09-15 12:22:24 -0400692 if not networks_client:
693 networks_client = self.networks_client
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000694 if not routers_client:
695 routers_client = self.routers_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300696 if not tenant_id:
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -0700697 tenant_id = networks_client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300698 name = data_utils.rand_name(namestart)
John Warren94d8faf2015-09-15 12:22:24 -0400699 result = networks_client.create_network(name=name, tenant_id=tenant_id)
Ken'ichi Ohmichi69a182a2016-04-29 10:56:27 -0700700 network = network_resources.DeletableNetwork(
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000701 networks_client=networks_client, routers_client=routers_client,
702 **result['network'])
Yair Fried1fc32a12014-08-04 09:11:30 +0300703 self.assertEqual(network.name, name)
704 self.addCleanup(self.delete_wrapper, network.delete)
705 return network
706
707 def _list_networks(self, *args, **kwargs):
708 """List networks using admin creds """
John Warren94d8faf2015-09-15 12:22:24 -0400709 networks_list = self.admin_manager.networks_client.list_networks(
ghanshyam2f7cc022015-06-26 18:18:11 +0900710 *args, **kwargs)
711 return networks_list['networks']
Yair Fried1fc32a12014-08-04 09:11:30 +0300712
713 def _list_subnets(self, *args, **kwargs):
714 """List subnets using admin creds """
John Warren3961acd2015-10-02 14:38:53 -0400715 subnets_list = self.admin_manager.subnets_client.list_subnets(
ghanshyam2f7cc022015-06-26 18:18:11 +0900716 *args, **kwargs)
717 return subnets_list['subnets']
Yair Fried1fc32a12014-08-04 09:11:30 +0300718
719 def _list_routers(self, *args, **kwargs):
720 """List routers using admin creds """
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000721 routers_list = self.admin_manager.routers_client.list_routers(
ghanshyam2f7cc022015-06-26 18:18:11 +0900722 *args, **kwargs)
723 return routers_list['routers']
Yair Fried1fc32a12014-08-04 09:11:30 +0300724
725 def _list_ports(self, *args, **kwargs):
726 """List ports using admin creds """
John Warren49c0fe52015-10-22 12:35:54 -0400727 ports_list = self.admin_manager.ports_client.list_ports(
ghanshyam2f7cc022015-06-26 18:18:11 +0900728 *args, **kwargs)
729 return ports_list['ports']
Yair Fried1fc32a12014-08-04 09:11:30 +0300730
Yair Fried564d89d2015-08-06 17:02:12 +0300731 def _list_agents(self, *args, **kwargs):
732 """List agents using admin creds """
Ken'ichi Ohmichi71860062015-12-15 08:20:13 +0000733 agents_list = self.admin_manager.network_agents_client.list_agents(
Yair Fried564d89d2015-08-06 17:02:12 +0300734 *args, **kwargs)
735 return agents_list['agents']
736
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -0700737 def _create_subnet(self, network, subnets_client=None,
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000738 routers_client=None, namestart='subnet-smoke',
739 **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 """
John Warren3961acd2015-10-02 14:38:53 -0400744 if not subnets_client:
745 subnets_client = self.subnets_client
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000746 if not routers_client:
747 routers_client = self.routers_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(
Sean Dagueed6e5862016-04-04 10:49:13 -0400762 CONF.network.project_network_v6_cidr)
763 num_bits = CONF.network.project_network_v6_mask_bits
Kirill Shileev14113572014-11-21 16:58:02 +0300764 else:
Sean Dagueed6e5862016-04-04 10:49:13 -0400765 tenant_cidr = netaddr.IPNetwork(CONF.network.project_network_cidr)
766 num_bits = CONF.network.project_network_mask_bits
Kirill Shileev14113572014-11-21 16:58:02 +0300767
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')
Ken'ichi Ohmichi69a182a2016-04-29 10:56:27 -0700793 subnet = network_resources.DeletableSubnet(
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -0700794 subnets_client=subnets_client,
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000795 routers_client=routers_client, **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')
Ken'ichi Ohmichi69a182a2016-04-29 10:56:27 -0700810 port = network_resources.DeletablePort(ports_client=client,
811 **result['port'])
Yair Fried1fc32a12014-08-04 09:11:30 +0300812 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)
Ken'ichi Ohmichi69a182a2016-04-29 10:56:27 -0700841 return network_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 )
Ken'ichi Ohmichi69a182a2016-04-29 10:56:27 -0700860 floating_ip = network_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
Ken'ichi Ohmichi69a182a2016-04-29 10:56:27 -0700881 :param floating_ip: network_resources.DeletableFloatingIp floating
882 IP to check status
Yair Fried45f92952014-06-26 05:19:19 +0300883 :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):
Sean Dagueed6e5862016-04-04 10:49:13 -0400906 if not CONF.network.project_networks_reachable:
Yair Fried1fc32a12014-08-04 09:11:30 +0300907 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)
Ken'ichi Ohmichi69a182a2016-04-29 10:56:27 -0700994 secgroup = network_resources.DeletableSecurityGroup(
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000995 client=client, routers_client=self.routers_client,
Yair Fried1fc32a12014-08-04 09:11:30 +0300996 **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)
Ken'ichi Ohmichi69a182a2016-04-29 10:56:27 -07001019 return network_resources.DeletableSecurityGroup(client=client,
1020 **sgs[0])
Yair Fried1fc32a12014-08-04 09:11:30 +03001021
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)
Ken'ichi Ohmichi69a182a2016-04-29 10:56:27 -07001058 sg_rule = network_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
Alex Stafeyevdd5dde92016-05-08 14:35:04 +03001072 This function will create:
1073 1. egress and ingress tcp port 22 allow rule in order to allow ssh
1074 access for ipv4.
1075 2. egress and ingress ipv6 icmp allow rule, in order to allow icmpv6.
1076 3. egress and ingress ipv4 icmp allow rule, in order to allow icmpv4.
Yair Fried1fc32a12014-08-04 09:11:30 +03001077 """
1078
John Warren456d9ae2016-01-12 15:36:33 -05001079 if security_group_rules_client is None:
1080 security_group_rules_client = self.security_group_rules_client
John Warrenf9606e92015-12-10 12:12:42 -05001081 if security_groups_client is None:
1082 security_groups_client = self.security_groups_client
Yair Fried1fc32a12014-08-04 09:11:30 +03001083 rules = []
1084 rulesets = [
1085 dict(
1086 # ssh
1087 protocol='tcp',
1088 port_range_min=22,
1089 port_range_max=22,
1090 ),
1091 dict(
1092 # ping
1093 protocol='icmp',
Andreas Scheuring887ca8e2015-02-03 17:56:12 +01001094 ),
1095 dict(
1096 # ipv6-icmp for ping6
1097 protocol='icmp',
1098 ethertype='IPv6',
Yair Fried1fc32a12014-08-04 09:11:30 +03001099 )
1100 ]
John Warren456d9ae2016-01-12 15:36:33 -05001101 sec_group_rules_client = security_group_rules_client
Yair Fried1fc32a12014-08-04 09:11:30 +03001102 for ruleset in rulesets:
1103 for r_direction in ['ingress', 'egress']:
1104 ruleset['direction'] = r_direction
1105 try:
1106 sg_rule = self._create_security_group_rule(
John Warren456d9ae2016-01-12 15:36:33 -05001107 sec_group_rules_client=sec_group_rules_client,
1108 secgroup=secgroup,
John Warrenf9606e92015-12-10 12:12:42 -05001109 security_groups_client=security_groups_client,
1110 **ruleset)
Masayuki Igawad9388762015-01-20 14:56:42 +09001111 except lib_exc.Conflict as ex:
Yair Fried1fc32a12014-08-04 09:11:30 +03001112 # if rule already exist - skip rule and continue
1113 msg = 'Security group rule already exists'
1114 if msg not in ex._error_string:
1115 raise ex
1116 else:
1117 self.assertEqual(r_direction, sg_rule.direction)
1118 rules.append(sg_rule)
1119
1120 return rules
1121
Yair Frieddb6c9e92014-08-06 08:53:13 +03001122 def _get_router(self, client=None, tenant_id=None):
Yair Fried1fc32a12014-08-04 09:11:30 +03001123 """Retrieve a router for the given tenant id.
1124
1125 If a public router has been configured, it will be returned.
1126
1127 If a public router has not been configured, but a public
1128 network has, a tenant router will be created and returned that
1129 routes traffic to the public network.
1130 """
Yair Frieddb6c9e92014-08-06 08:53:13 +03001131 if not client:
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +00001132 client = self.routers_client
Yair Frieddb6c9e92014-08-06 08:53:13 +03001133 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +00001134 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001135 router_id = CONF.network.public_router_id
1136 network_id = CONF.network.public_network_id
1137 if router_id:
David Kranzca4c7e72015-05-27 11:39:19 -04001138 body = client.show_router(router_id)
Ken'ichi Ohmichi69a182a2016-04-29 10:56:27 -07001139 return network_resources.AttributeDict(**body['router'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001140 elif network_id:
Yair Frieddb6c9e92014-08-06 08:53:13 +03001141 router = self._create_router(client, tenant_id)
Yair Fried1fc32a12014-08-04 09:11:30 +03001142 router.set_gateway(network_id)
1143 return router
1144 else:
1145 raise Exception("Neither of 'public_router_id' or "
1146 "'public_network_id' has been defined.")
1147
Yair Frieddb6c9e92014-08-06 08:53:13 +03001148 def _create_router(self, client=None, tenant_id=None,
1149 namestart='router-smoke'):
1150 if not client:
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +00001151 client = self.routers_client
Yair Frieddb6c9e92014-08-06 08:53:13 +03001152 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +00001153 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001154 name = data_utils.rand_name(namestart)
David Kranz34e88122014-12-11 15:24:05 -05001155 result = client.create_router(name=name,
1156 admin_state_up=True,
1157 tenant_id=tenant_id)
Ken'ichi Ohmichi69a182a2016-04-29 10:56:27 -07001158 router = network_resources.DeletableRouter(routers_client=client,
1159 **result['router'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001160 self.assertEqual(router.name, name)
1161 self.addCleanup(self.delete_wrapper, router.delete)
1162 return router
1163
Alok Maurya6384bbb2014-07-13 06:44:29 -07001164 def _update_router_admin_state(self, router, admin_state_up):
1165 router.update(admin_state_up=admin_state_up)
1166 self.assertEqual(admin_state_up, router.admin_state_up)
1167
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -07001168 def create_networks(self, networks_client=None,
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +00001169 routers_client=None, subnets_client=None,
1170 tenant_id=None, dns_nameservers=None):
Yair Fried1fc32a12014-08-04 09:11:30 +03001171 """Create a network with a subnet connected to a router.
1172
David Shrewsbury9bac3662014-08-07 15:07:01 -04001173 The baremetal driver is a special case since all nodes are
1174 on the same shared network.
1175
Yair Fried413bf2d2014-11-19 17:07:11 +02001176 :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(
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -07001195 networks_client=networks_client,
John Warren94d8faf2015-09-15 12:22:24 -04001196 tenant_id=tenant_id)
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +00001197 router = self._get_router(client=routers_client,
1198 tenant_id=tenant_id)
Yair Fried413bf2d2014-11-19 17:07:11 +02001199
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -07001200 subnet_kwargs = dict(network=network,
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +00001201 subnets_client=subnets_client,
1202 routers_client=routers_client)
Yair Fried413bf2d2014-11-19 17:07:11 +02001203 # use explicit check because empty list is a valid option
1204 if dns_nameservers is not None:
1205 subnet_kwargs['dns_nameservers'] = dns_nameservers
1206 subnet = self._create_subnet(**subnet_kwargs)
David Shrewsbury9bac3662014-08-07 15:07:01 -04001207 subnet.add_to_router(router.id)
Yair Fried1fc32a12014-08-04 09:11:30 +03001208 return network, subnet, router
1209
1210
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001211# power/provision states as of icehouse
1212class BaremetalPowerStates(object):
1213 """Possible power states of an Ironic node."""
1214 POWER_ON = 'power on'
1215 POWER_OFF = 'power off'
1216 REBOOT = 'rebooting'
1217 SUSPEND = 'suspended'
1218
1219
1220class BaremetalProvisionStates(object):
1221 """Possible provision states of an Ironic node."""
1222 NOSTATE = None
1223 INIT = 'initializing'
1224 ACTIVE = 'active'
1225 BUILDING = 'building'
1226 DEPLOYWAIT = 'wait call-back'
1227 DEPLOYING = 'deploying'
1228 DEPLOYFAIL = 'deploy failed'
1229 DEPLOYDONE = 'deploy complete'
1230 DELETING = 'deleting'
1231 DELETED = 'deleted'
1232 ERROR = 'error'
1233
1234
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001235class BaremetalScenarioTest(ScenarioTest):
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001236
1237 credentials = ['primary', 'admin']
1238
Adam Gandelman4a48a602014-03-20 18:23:18 -07001239 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001240 def skip_checks(cls):
1241 super(BaremetalScenarioTest, cls).skip_checks()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001242 if (not CONF.service_available.ironic or
1243 not CONF.baremetal.driver_enabled):
1244 msg = 'Ironic not available or Ironic compute driver not enabled'
1245 raise cls.skipException(msg)
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001246
1247 @classmethod
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001248 def setup_clients(cls):
1249 super(BaremetalScenarioTest, cls).setup_clients()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001250
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001251 cls.baremetal_client = cls.admin_manager.baremetal_client
Adam Gandelman4a48a602014-03-20 18:23:18 -07001252
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001253 @classmethod
1254 def resource_setup(cls):
1255 super(BaremetalScenarioTest, cls).resource_setup()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001256 # allow any issues obtaining the node list to raise early
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001257 cls.baremetal_client.list_nodes()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001258
1259 def _node_state_timeout(self, node_id, state_attr,
1260 target_states, timeout=10, interval=1):
1261 if not isinstance(target_states, list):
1262 target_states = [target_states]
1263
1264 def check_state():
1265 node = self.get_node(node_id=node_id)
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001266 if node.get(state_attr) in target_states:
Adam Gandelman4a48a602014-03-20 18:23:18 -07001267 return True
1268 return False
1269
1270 if not tempest.test.call_until_true(
1271 check_state, timeout, interval):
1272 msg = ("Timed out waiting for node %s to reach %s state(s) %s" %
1273 (node_id, state_attr, target_states))
1274 raise exceptions.TimeoutException(msg)
1275
1276 def wait_provisioning_state(self, node_id, state, timeout):
1277 self._node_state_timeout(
1278 node_id=node_id, state_attr='provision_state',
1279 target_states=state, timeout=timeout)
1280
1281 def wait_power_state(self, node_id, state):
1282 self._node_state_timeout(
1283 node_id=node_id, state_attr='power_state',
1284 target_states=state, timeout=CONF.baremetal.power_timeout)
1285
1286 def wait_node(self, instance_id):
1287 """Waits for a node to be associated with instance_id."""
Zhi Kun Liu4a8d1ea2014-04-15 22:08:21 -05001288
Adam Gandelman4a48a602014-03-20 18:23:18 -07001289 def _get_node():
1290 node = None
1291 try:
1292 node = self.get_node(instance_id=instance_id)
Masayuki Igawabfa07602015-01-20 18:47:17 +09001293 except lib_exc.NotFound:
Adam Gandelman4a48a602014-03-20 18:23:18 -07001294 pass
1295 return node is not None
1296
1297 if not tempest.test.call_until_true(
1298 _get_node, CONF.baremetal.association_timeout, 1):
1299 msg = ('Timed out waiting to get Ironic node by instance id %s'
1300 % instance_id)
1301 raise exceptions.TimeoutException(msg)
1302
1303 def get_node(self, node_id=None, instance_id=None):
1304 if node_id:
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001305 _, body = self.baremetal_client.show_node(node_id)
1306 return body
Adam Gandelman4a48a602014-03-20 18:23:18 -07001307 elif instance_id:
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001308 _, body = self.baremetal_client.show_node_by_instance_uuid(
1309 instance_id)
1310 if body['nodes']:
1311 return body['nodes'][0]
Adam Gandelman4a48a602014-03-20 18:23:18 -07001312
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001313 def get_ports(self, node_uuid):
Adam Gandelman4a48a602014-03-20 18:23:18 -07001314 ports = []
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001315 _, body = self.baremetal_client.list_node_ports(node_uuid)
1316 for port in body['ports']:
1317 _, p = self.baremetal_client.show_port(port['uuid'])
1318 ports.append(p)
Adam Gandelman4a48a602014-03-20 18:23:18 -07001319 return ports
1320
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001321 def add_keypair(self):
1322 self.keypair = self.create_keypair()
1323
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001324 def boot_instance(self):
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001325 self.instance = self.create_server(
lanoux5fc14522015-09-21 08:17:35 +00001326 key_name=self.keypair['name'])
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001327
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001328 self.wait_node(self.instance['id'])
1329 self.node = self.get_node(instance_id=self.instance['id'])
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001330
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001331 self.wait_power_state(self.node['uuid'], BaremetalPowerStates.POWER_ON)
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001332
1333 self.wait_provisioning_state(
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001334 self.node['uuid'],
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001335 [BaremetalProvisionStates.DEPLOYWAIT,
1336 BaremetalProvisionStates.ACTIVE],
1337 timeout=15)
1338
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001339 self.wait_provisioning_state(self.node['uuid'],
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001340 BaremetalProvisionStates.ACTIVE,
1341 timeout=CONF.baremetal.active_timeout)
1342
Ken'ichi Ohmichi0eb153c2015-07-13 02:18:25 +00001343 waiters.wait_for_server_status(self.servers_client,
1344 self.instance['id'], 'ACTIVE')
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001345 self.node = self.get_node(instance_id=self.instance['id'])
ghanshyam0f825252015-08-25 16:02:50 +09001346 self.instance = (self.servers_client.show_server(self.instance['id'])
1347 ['server'])
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001348
1349 def terminate_instance(self):
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001350 self.servers_client.delete_server(self.instance['id'])
1351 self.wait_power_state(self.node['uuid'],
1352 BaremetalPowerStates.POWER_OFF)
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001353 self.wait_provisioning_state(
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001354 self.node['uuid'],
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001355 BaremetalProvisionStates.NOSTATE,
1356 timeout=CONF.baremetal.unprovision_timeout)
1357
Adam Gandelman4a48a602014-03-20 18:23:18 -07001358
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001359class EncryptionScenarioTest(ScenarioTest):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001360 """Base class for encryption scenario tests"""
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001361
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001362 credentials = ['primary', 'admin']
David Kranz4cc852b2015-03-09 14:57:11 -04001363
1364 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001365 def setup_clients(cls):
1366 super(EncryptionScenarioTest, cls).setup_clients()
Ivan Kolodyazhnybcfc32e2015-08-06 13:31:36 +03001367 if CONF.volume_feature_enabled.api_v1:
1368 cls.admin_volume_types_client = cls.os_adm.volume_types_client
1369 else:
1370 cls.admin_volume_types_client = cls.os_adm.volume_types_v2_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001371
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001372 def create_volume_type(self, client=None, name=None):
1373 if not client:
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001374 client = self.admin_volume_types_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001375 if not name:
1376 name = 'generic'
Ken'ichi Ohmichi6ded8df2015-03-23 02:00:19 +00001377 randomized_name = data_utils.rand_name('scenario-type-' + name)
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001378 LOG.debug("Creating a volume type: %s", randomized_name)
Joseph Lanoux6809bab2014-12-18 14:57:18 +00001379 body = client.create_volume_type(
lei zhang83c4bbd2015-11-27 00:35:21 +08001380 name=randomized_name)['volume_type']
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001381 self.assertIn('id', body)
1382 self.addCleanup(client.delete_volume_type, body['id'])
1383 return body
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001384
1385 def create_encryption_type(self, client=None, type_id=None, provider=None,
1386 key_size=None, cipher=None,
1387 control_location=None):
1388 if not client:
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001389 client = self.admin_volume_types_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001390 if not type_id:
1391 volume_type = self.create_volume_type()
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001392 type_id = volume_type['id']
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001393 LOG.debug("Creating an encryption type for volume type: %s", type_id)
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001394 client.create_encryption_type(
1395 type_id, provider=provider, key_size=key_size, cipher=cipher,
John Warrend053ded2015-08-13 15:22:48 +00001396 control_location=control_location)['encryption']
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001397
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001398
Masayuki Igawa0870db52015-09-18 21:08:36 +09001399class ObjectStorageScenarioTest(ScenarioTest):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001400 """Provide harness to do Object Storage scenario tests.
Chris Dent0d494112014-08-26 13:48:30 +01001401
1402 Subclasses implement the tests that use the methods provided by this
1403 class.
1404 """
1405
1406 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001407 def skip_checks(cls):
Masayuki Igawa0870db52015-09-18 21:08:36 +09001408 super(ObjectStorageScenarioTest, cls).skip_checks()
Chris Dent0d494112014-08-26 13:48:30 +01001409 if not CONF.service_available.swift:
1410 skip_msg = ("%s skipped as swift is not available" %
1411 cls.__name__)
1412 raise cls.skipException(skip_msg)
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001413
1414 @classmethod
1415 def setup_credentials(cls):
Masayuki Igawa60ea6c52014-10-15 17:32:14 +09001416 cls.set_network_resources()
Masayuki Igawa0870db52015-09-18 21:08:36 +09001417 super(ObjectStorageScenarioTest, cls).setup_credentials()
Matthew Treinish4a596932015-03-06 20:37:01 -05001418 operator_role = CONF.object_storage.operator_role
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +01001419 cls.os_operator = cls.get_client_manager(roles=[operator_role])
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001420
1421 @classmethod
1422 def setup_clients(cls):
Masayuki Igawa0870db52015-09-18 21:08:36 +09001423 super(ObjectStorageScenarioTest, cls).setup_clients()
Chris Dent0d494112014-08-26 13:48:30 +01001424 # Clients for Swift
Matthew Treinish8f268292015-02-24 20:01:36 -05001425 cls.account_client = cls.os_operator.account_client
1426 cls.container_client = cls.os_operator.container_client
1427 cls.object_client = cls.os_operator.object_client
Chris Dent0d494112014-08-26 13:48:30 +01001428
Chris Dentde456a12014-09-10 12:41:15 +01001429 def get_swift_stat(self):
Chris Dent0d494112014-08-26 13:48:30 +01001430 """get swift status for our user account."""
1431 self.account_client.list_account_containers()
1432 LOG.debug('Swift status information obtained successfully')
1433
Chris Dentde456a12014-09-10 12:41:15 +01001434 def create_container(self, container_name=None):
Chris Dent0d494112014-08-26 13:48:30 +01001435 name = container_name or data_utils.rand_name(
1436 'swift-scenario-container')
1437 self.container_client.create_container(name)
1438 # look for the container to assure it is created
Chris Dentde456a12014-09-10 12:41:15 +01001439 self.list_and_check_container_objects(name)
Chris Dent0d494112014-08-26 13:48:30 +01001440 LOG.debug('Container %s created' % (name))
Chris Dent1d4313a2014-10-28 12:16:48 +00001441 self.addCleanup(self.delete_wrapper,
1442 self.container_client.delete_container,
1443 name)
Chris Dent0d494112014-08-26 13:48:30 +01001444 return name
1445
Chris Dentde456a12014-09-10 12:41:15 +01001446 def delete_container(self, container_name):
Chris Dent0d494112014-08-26 13:48:30 +01001447 self.container_client.delete_container(container_name)
1448 LOG.debug('Container %s deleted' % (container_name))
1449
Chris Dentde456a12014-09-10 12:41:15 +01001450 def upload_object_to_container(self, container_name, obj_name=None):
Chris Dent0d494112014-08-26 13:48:30 +01001451 obj_name = obj_name or data_utils.rand_name('swift-scenario-object')
1452 obj_data = data_utils.arbitrary_string()
1453 self.object_client.create_object(container_name, obj_name, obj_data)
Chris Dent1d4313a2014-10-28 12:16:48 +00001454 self.addCleanup(self.delete_wrapper,
1455 self.object_client.delete_object,
1456 container_name,
1457 obj_name)
Chris Dent0d494112014-08-26 13:48:30 +01001458 return obj_name, obj_data
1459
Chris Dentde456a12014-09-10 12:41:15 +01001460 def delete_object(self, container_name, filename):
Chris Dent0d494112014-08-26 13:48:30 +01001461 self.object_client.delete_object(container_name, filename)
Chris Dentde456a12014-09-10 12:41:15 +01001462 self.list_and_check_container_objects(container_name,
1463 not_present_obj=[filename])
Chris Dent0d494112014-08-26 13:48:30 +01001464
Chris Dentde456a12014-09-10 12:41:15 +01001465 def list_and_check_container_objects(self, container_name,
1466 present_obj=None,
1467 not_present_obj=None):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001468 # List objects for a given container and assert which are present and
1469 # which are not.
Ghanshyam2a180b82014-06-16 13:54:22 +09001470 if present_obj is None:
1471 present_obj = []
1472 if not_present_obj is None:
1473 not_present_obj = []
Chris Dent0d494112014-08-26 13:48:30 +01001474 _, object_list = self.container_client.list_container_contents(
1475 container_name)
1476 if present_obj:
1477 for obj in present_obj:
1478 self.assertIn(obj, object_list)
1479 if not_present_obj:
1480 for obj in not_present_obj:
1481 self.assertNotIn(obj, object_list)
1482
Chris Dentde456a12014-09-10 12:41:15 +01001483 def change_container_acl(self, container_name, acl):
Chris Dent0d494112014-08-26 13:48:30 +01001484 metadata_param = {'metadata_prefix': 'x-container-',
1485 'metadata': {'read': acl}}
1486 self.container_client.update_container_metadata(container_name,
1487 **metadata_param)
1488 resp, _ = self.container_client.list_container_metadata(container_name)
1489 self.assertEqual(resp['x-container-read'], acl)
1490
Chris Dentde456a12014-09-10 12:41:15 +01001491 def download_and_verify(self, container_name, obj_name, expected_data):
Chris Dent0d494112014-08-26 13:48:30 +01001492 _, obj = self.object_client.get_object(container_name, obj_name)
1493 self.assertEqual(obj, expected_data)