blob: 65677a0e7047f29bae9f93f742df68bc3339c5ef [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]
Yaroslav Lobankov2fea4052016-04-19 15:05:57 +0300462 waiters.wait_for_image_status(_image_client, image_id, 'active')
nithya-ganesan882595e2014-07-29 18:51:07 +0000463 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])
Yaroslav Lobankov9d28a0f2016-04-19 15:05:57 +0300468 snapshot_image = _image_client.check_image(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
zhufl0892cb22016-05-06 14:46:00 +0800651 # and can't make use of the validation resources. So the
Sean Dague20e98612016-01-06 14:33:28 -0500652 # 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
1072 These rules are intended to permit inbound ssh and icmp
Yair Fried1fc32a12014-08-04 09:11:30 +03001073 traffic from all sources, so no group_id is provided.
1074 Setting a group_id would only permit traffic from ports
1075 belonging to the same security group.
1076 """
1077
John Warren456d9ae2016-01-12 15:36:33 -05001078 if security_group_rules_client is None:
1079 security_group_rules_client = self.security_group_rules_client
John Warrenf9606e92015-12-10 12:12:42 -05001080 if security_groups_client is None:
1081 security_groups_client = self.security_groups_client
Yair Fried1fc32a12014-08-04 09:11:30 +03001082 rules = []
1083 rulesets = [
1084 dict(
1085 # ssh
1086 protocol='tcp',
1087 port_range_min=22,
1088 port_range_max=22,
1089 ),
1090 dict(
1091 # ping
1092 protocol='icmp',
Andreas Scheuring887ca8e2015-02-03 17:56:12 +01001093 ),
1094 dict(
1095 # ipv6-icmp for ping6
1096 protocol='icmp',
1097 ethertype='IPv6',
Yair Fried1fc32a12014-08-04 09:11:30 +03001098 )
1099 ]
John Warren456d9ae2016-01-12 15:36:33 -05001100 sec_group_rules_client = security_group_rules_client
Yair Fried1fc32a12014-08-04 09:11:30 +03001101 for ruleset in rulesets:
1102 for r_direction in ['ingress', 'egress']:
1103 ruleset['direction'] = r_direction
1104 try:
1105 sg_rule = self._create_security_group_rule(
John Warren456d9ae2016-01-12 15:36:33 -05001106 sec_group_rules_client=sec_group_rules_client,
1107 secgroup=secgroup,
John Warrenf9606e92015-12-10 12:12:42 -05001108 security_groups_client=security_groups_client,
1109 **ruleset)
Masayuki Igawad9388762015-01-20 14:56:42 +09001110 except lib_exc.Conflict as ex:
Yair Fried1fc32a12014-08-04 09:11:30 +03001111 # if rule already exist - skip rule and continue
1112 msg = 'Security group rule already exists'
1113 if msg not in ex._error_string:
1114 raise ex
1115 else:
1116 self.assertEqual(r_direction, sg_rule.direction)
1117 rules.append(sg_rule)
1118
1119 return rules
1120
Yair Frieddb6c9e92014-08-06 08:53:13 +03001121 def _get_router(self, client=None, tenant_id=None):
Yair Fried1fc32a12014-08-04 09:11:30 +03001122 """Retrieve a router for the given tenant id.
1123
1124 If a public router has been configured, it will be returned.
1125
1126 If a public router has not been configured, but a public
1127 network has, a tenant router will be created and returned that
1128 routes traffic to the public network.
1129 """
Yair Frieddb6c9e92014-08-06 08:53:13 +03001130 if not client:
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +00001131 client = self.routers_client
Yair Frieddb6c9e92014-08-06 08:53:13 +03001132 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +00001133 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001134 router_id = CONF.network.public_router_id
1135 network_id = CONF.network.public_network_id
1136 if router_id:
David Kranzca4c7e72015-05-27 11:39:19 -04001137 body = client.show_router(router_id)
Ken'ichi Ohmichi69a182a2016-04-29 10:56:27 -07001138 return network_resources.AttributeDict(**body['router'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001139 elif network_id:
Yair Frieddb6c9e92014-08-06 08:53:13 +03001140 router = self._create_router(client, tenant_id)
Yair Fried1fc32a12014-08-04 09:11:30 +03001141 router.set_gateway(network_id)
1142 return router
1143 else:
1144 raise Exception("Neither of 'public_router_id' or "
1145 "'public_network_id' has been defined.")
1146
Yair Frieddb6c9e92014-08-06 08:53:13 +03001147 def _create_router(self, client=None, tenant_id=None,
1148 namestart='router-smoke'):
1149 if not client:
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +00001150 client = self.routers_client
Yair Frieddb6c9e92014-08-06 08:53:13 +03001151 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +00001152 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001153 name = data_utils.rand_name(namestart)
David Kranz34e88122014-12-11 15:24:05 -05001154 result = client.create_router(name=name,
1155 admin_state_up=True,
1156 tenant_id=tenant_id)
Ken'ichi Ohmichi69a182a2016-04-29 10:56:27 -07001157 router = network_resources.DeletableRouter(routers_client=client,
1158 **result['router'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001159 self.assertEqual(router.name, name)
1160 self.addCleanup(self.delete_wrapper, router.delete)
1161 return router
1162
Alok Maurya6384bbb2014-07-13 06:44:29 -07001163 def _update_router_admin_state(self, router, admin_state_up):
1164 router.update(admin_state_up=admin_state_up)
1165 self.assertEqual(admin_state_up, router.admin_state_up)
1166
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -07001167 def create_networks(self, networks_client=None,
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +00001168 routers_client=None, subnets_client=None,
1169 tenant_id=None, dns_nameservers=None):
Yair Fried1fc32a12014-08-04 09:11:30 +03001170 """Create a network with a subnet connected to a router.
1171
David Shrewsbury9bac3662014-08-07 15:07:01 -04001172 The baremetal driver is a special case since all nodes are
1173 on the same shared network.
1174
Yair Fried413bf2d2014-11-19 17:07:11 +02001175 :param tenant_id: id of tenant to create resources in.
1176 :param dns_nameservers: list of dns servers to send to subnet.
Yair Fried1fc32a12014-08-04 09:11:30 +03001177 :returns: network, subnet, router
1178 """
David Shrewsbury9bac3662014-08-07 15:07:01 -04001179 if CONF.baremetal.driver_enabled:
1180 # NOTE(Shrews): This exception is for environments where tenant
1181 # credential isolation is available, but network separation is
1182 # not (the current baremetal case). Likely can be removed when
1183 # test account mgmt is reworked:
1184 # https://blueprints.launchpad.net/tempest/+spec/test-accounts
Adam Gandelman878a5fd2015-03-30 14:33:36 -07001185 if not CONF.compute.fixed_network_name:
1186 m = 'fixed_network_name must be specified in config'
1187 raise exceptions.InvalidConfiguration(m)
David Shrewsbury9bac3662014-08-07 15:07:01 -04001188 network = self._get_network_by_name(
1189 CONF.compute.fixed_network_name)
1190 router = None
1191 subnet = None
1192 else:
John Warren94d8faf2015-09-15 12:22:24 -04001193 network = self._create_network(
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -07001194 networks_client=networks_client,
John Warren94d8faf2015-09-15 12:22:24 -04001195 tenant_id=tenant_id)
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +00001196 router = self._get_router(client=routers_client,
1197 tenant_id=tenant_id)
Yair Fried413bf2d2014-11-19 17:07:11 +02001198
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -07001199 subnet_kwargs = dict(network=network,
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +00001200 subnets_client=subnets_client,
1201 routers_client=routers_client)
Yair Fried413bf2d2014-11-19 17:07:11 +02001202 # use explicit check because empty list is a valid option
1203 if dns_nameservers is not None:
1204 subnet_kwargs['dns_nameservers'] = dns_nameservers
1205 subnet = self._create_subnet(**subnet_kwargs)
David Shrewsbury9bac3662014-08-07 15:07:01 -04001206 subnet.add_to_router(router.id)
Yair Fried1fc32a12014-08-04 09:11:30 +03001207 return network, subnet, router
1208
1209
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001210# power/provision states as of icehouse
1211class BaremetalPowerStates(object):
1212 """Possible power states of an Ironic node."""
1213 POWER_ON = 'power on'
1214 POWER_OFF = 'power off'
1215 REBOOT = 'rebooting'
1216 SUSPEND = 'suspended'
1217
1218
1219class BaremetalProvisionStates(object):
1220 """Possible provision states of an Ironic node."""
1221 NOSTATE = None
1222 INIT = 'initializing'
1223 ACTIVE = 'active'
1224 BUILDING = 'building'
1225 DEPLOYWAIT = 'wait call-back'
1226 DEPLOYING = 'deploying'
1227 DEPLOYFAIL = 'deploy failed'
1228 DEPLOYDONE = 'deploy complete'
1229 DELETING = 'deleting'
1230 DELETED = 'deleted'
1231 ERROR = 'error'
1232
1233
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001234class BaremetalScenarioTest(ScenarioTest):
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001235
1236 credentials = ['primary', 'admin']
1237
Adam Gandelman4a48a602014-03-20 18:23:18 -07001238 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001239 def skip_checks(cls):
1240 super(BaremetalScenarioTest, cls).skip_checks()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001241 if (not CONF.service_available.ironic or
1242 not CONF.baremetal.driver_enabled):
1243 msg = 'Ironic not available or Ironic compute driver not enabled'
1244 raise cls.skipException(msg)
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001245
1246 @classmethod
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001247 def setup_clients(cls):
1248 super(BaremetalScenarioTest, cls).setup_clients()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001249
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001250 cls.baremetal_client = cls.admin_manager.baremetal_client
Adam Gandelman4a48a602014-03-20 18:23:18 -07001251
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001252 @classmethod
1253 def resource_setup(cls):
1254 super(BaremetalScenarioTest, cls).resource_setup()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001255 # allow any issues obtaining the node list to raise early
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001256 cls.baremetal_client.list_nodes()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001257
1258 def _node_state_timeout(self, node_id, state_attr,
1259 target_states, timeout=10, interval=1):
1260 if not isinstance(target_states, list):
1261 target_states = [target_states]
1262
1263 def check_state():
1264 node = self.get_node(node_id=node_id)
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001265 if node.get(state_attr) in target_states:
Adam Gandelman4a48a602014-03-20 18:23:18 -07001266 return True
1267 return False
1268
1269 if not tempest.test.call_until_true(
1270 check_state, timeout, interval):
1271 msg = ("Timed out waiting for node %s to reach %s state(s) %s" %
1272 (node_id, state_attr, target_states))
1273 raise exceptions.TimeoutException(msg)
1274
1275 def wait_provisioning_state(self, node_id, state, timeout):
1276 self._node_state_timeout(
1277 node_id=node_id, state_attr='provision_state',
1278 target_states=state, timeout=timeout)
1279
1280 def wait_power_state(self, node_id, state):
1281 self._node_state_timeout(
1282 node_id=node_id, state_attr='power_state',
1283 target_states=state, timeout=CONF.baremetal.power_timeout)
1284
1285 def wait_node(self, instance_id):
1286 """Waits for a node to be associated with instance_id."""
Zhi Kun Liu4a8d1ea2014-04-15 22:08:21 -05001287
Adam Gandelman4a48a602014-03-20 18:23:18 -07001288 def _get_node():
1289 node = None
1290 try:
1291 node = self.get_node(instance_id=instance_id)
Masayuki Igawabfa07602015-01-20 18:47:17 +09001292 except lib_exc.NotFound:
Adam Gandelman4a48a602014-03-20 18:23:18 -07001293 pass
1294 return node is not None
1295
1296 if not tempest.test.call_until_true(
1297 _get_node, CONF.baremetal.association_timeout, 1):
1298 msg = ('Timed out waiting to get Ironic node by instance id %s'
1299 % instance_id)
1300 raise exceptions.TimeoutException(msg)
1301
1302 def get_node(self, node_id=None, instance_id=None):
1303 if node_id:
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001304 _, body = self.baremetal_client.show_node(node_id)
1305 return body
Adam Gandelman4a48a602014-03-20 18:23:18 -07001306 elif instance_id:
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001307 _, body = self.baremetal_client.show_node_by_instance_uuid(
1308 instance_id)
1309 if body['nodes']:
1310 return body['nodes'][0]
Adam Gandelman4a48a602014-03-20 18:23:18 -07001311
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001312 def get_ports(self, node_uuid):
Adam Gandelman4a48a602014-03-20 18:23:18 -07001313 ports = []
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001314 _, body = self.baremetal_client.list_node_ports(node_uuid)
1315 for port in body['ports']:
1316 _, p = self.baremetal_client.show_port(port['uuid'])
1317 ports.append(p)
Adam Gandelman4a48a602014-03-20 18:23:18 -07001318 return ports
1319
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001320 def add_keypair(self):
1321 self.keypair = self.create_keypair()
1322
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001323 def boot_instance(self):
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001324 self.instance = self.create_server(
lanoux5fc14522015-09-21 08:17:35 +00001325 key_name=self.keypair['name'])
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001326
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001327 self.wait_node(self.instance['id'])
1328 self.node = self.get_node(instance_id=self.instance['id'])
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001329
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001330 self.wait_power_state(self.node['uuid'], BaremetalPowerStates.POWER_ON)
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001331
1332 self.wait_provisioning_state(
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001333 self.node['uuid'],
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001334 [BaremetalProvisionStates.DEPLOYWAIT,
1335 BaremetalProvisionStates.ACTIVE],
1336 timeout=15)
1337
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001338 self.wait_provisioning_state(self.node['uuid'],
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001339 BaremetalProvisionStates.ACTIVE,
1340 timeout=CONF.baremetal.active_timeout)
1341
Ken'ichi Ohmichi0eb153c2015-07-13 02:18:25 +00001342 waiters.wait_for_server_status(self.servers_client,
1343 self.instance['id'], 'ACTIVE')
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001344 self.node = self.get_node(instance_id=self.instance['id'])
ghanshyam0f825252015-08-25 16:02:50 +09001345 self.instance = (self.servers_client.show_server(self.instance['id'])
1346 ['server'])
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001347
1348 def terminate_instance(self):
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001349 self.servers_client.delete_server(self.instance['id'])
1350 self.wait_power_state(self.node['uuid'],
1351 BaremetalPowerStates.POWER_OFF)
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001352 self.wait_provisioning_state(
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001353 self.node['uuid'],
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001354 BaremetalProvisionStates.NOSTATE,
1355 timeout=CONF.baremetal.unprovision_timeout)
1356
Adam Gandelman4a48a602014-03-20 18:23:18 -07001357
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001358class EncryptionScenarioTest(ScenarioTest):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001359 """Base class for encryption scenario tests"""
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001360
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001361 credentials = ['primary', 'admin']
David Kranz4cc852b2015-03-09 14:57:11 -04001362
1363 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001364 def setup_clients(cls):
1365 super(EncryptionScenarioTest, cls).setup_clients()
Ivan Kolodyazhnybcfc32e2015-08-06 13:31:36 +03001366 if CONF.volume_feature_enabled.api_v1:
1367 cls.admin_volume_types_client = cls.os_adm.volume_types_client
1368 else:
1369 cls.admin_volume_types_client = cls.os_adm.volume_types_v2_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001370
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001371 def create_volume_type(self, client=None, name=None):
1372 if not client:
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001373 client = self.admin_volume_types_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001374 if not name:
1375 name = 'generic'
Ken'ichi Ohmichi6ded8df2015-03-23 02:00:19 +00001376 randomized_name = data_utils.rand_name('scenario-type-' + name)
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001377 LOG.debug("Creating a volume type: %s", randomized_name)
Joseph Lanoux6809bab2014-12-18 14:57:18 +00001378 body = client.create_volume_type(
lei zhang83c4bbd2015-11-27 00:35:21 +08001379 name=randomized_name)['volume_type']
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001380 self.assertIn('id', body)
1381 self.addCleanup(client.delete_volume_type, body['id'])
1382 return body
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001383
1384 def create_encryption_type(self, client=None, type_id=None, provider=None,
1385 key_size=None, cipher=None,
1386 control_location=None):
1387 if not client:
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001388 client = self.admin_volume_types_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001389 if not type_id:
1390 volume_type = self.create_volume_type()
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001391 type_id = volume_type['id']
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001392 LOG.debug("Creating an encryption type for volume type: %s", type_id)
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001393 client.create_encryption_type(
1394 type_id, provider=provider, key_size=key_size, cipher=cipher,
John Warrend053ded2015-08-13 15:22:48 +00001395 control_location=control_location)['encryption']
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001396
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001397
Masayuki Igawa0870db52015-09-18 21:08:36 +09001398class ObjectStorageScenarioTest(ScenarioTest):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001399 """Provide harness to do Object Storage scenario tests.
Chris Dent0d494112014-08-26 13:48:30 +01001400
1401 Subclasses implement the tests that use the methods provided by this
1402 class.
1403 """
1404
1405 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001406 def skip_checks(cls):
Masayuki Igawa0870db52015-09-18 21:08:36 +09001407 super(ObjectStorageScenarioTest, cls).skip_checks()
Chris Dent0d494112014-08-26 13:48:30 +01001408 if not CONF.service_available.swift:
1409 skip_msg = ("%s skipped as swift is not available" %
1410 cls.__name__)
1411 raise cls.skipException(skip_msg)
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001412
1413 @classmethod
1414 def setup_credentials(cls):
Masayuki Igawa60ea6c52014-10-15 17:32:14 +09001415 cls.set_network_resources()
Masayuki Igawa0870db52015-09-18 21:08:36 +09001416 super(ObjectStorageScenarioTest, cls).setup_credentials()
Matthew Treinish4a596932015-03-06 20:37:01 -05001417 operator_role = CONF.object_storage.operator_role
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +01001418 cls.os_operator = cls.get_client_manager(roles=[operator_role])
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001419
1420 @classmethod
1421 def setup_clients(cls):
Masayuki Igawa0870db52015-09-18 21:08:36 +09001422 super(ObjectStorageScenarioTest, cls).setup_clients()
Chris Dent0d494112014-08-26 13:48:30 +01001423 # Clients for Swift
Matthew Treinish8f268292015-02-24 20:01:36 -05001424 cls.account_client = cls.os_operator.account_client
1425 cls.container_client = cls.os_operator.container_client
1426 cls.object_client = cls.os_operator.object_client
Chris Dent0d494112014-08-26 13:48:30 +01001427
Chris Dentde456a12014-09-10 12:41:15 +01001428 def get_swift_stat(self):
Chris Dent0d494112014-08-26 13:48:30 +01001429 """get swift status for our user account."""
1430 self.account_client.list_account_containers()
1431 LOG.debug('Swift status information obtained successfully')
1432
Chris Dentde456a12014-09-10 12:41:15 +01001433 def create_container(self, container_name=None):
Chris Dent0d494112014-08-26 13:48:30 +01001434 name = container_name or data_utils.rand_name(
1435 'swift-scenario-container')
1436 self.container_client.create_container(name)
1437 # look for the container to assure it is created
Chris Dentde456a12014-09-10 12:41:15 +01001438 self.list_and_check_container_objects(name)
Chris Dent0d494112014-08-26 13:48:30 +01001439 LOG.debug('Container %s created' % (name))
Chris Dent1d4313a2014-10-28 12:16:48 +00001440 self.addCleanup(self.delete_wrapper,
1441 self.container_client.delete_container,
1442 name)
Chris Dent0d494112014-08-26 13:48:30 +01001443 return name
1444
Chris Dentde456a12014-09-10 12:41:15 +01001445 def delete_container(self, container_name):
Chris Dent0d494112014-08-26 13:48:30 +01001446 self.container_client.delete_container(container_name)
1447 LOG.debug('Container %s deleted' % (container_name))
1448
Chris Dentde456a12014-09-10 12:41:15 +01001449 def upload_object_to_container(self, container_name, obj_name=None):
Chris Dent0d494112014-08-26 13:48:30 +01001450 obj_name = obj_name or data_utils.rand_name('swift-scenario-object')
1451 obj_data = data_utils.arbitrary_string()
1452 self.object_client.create_object(container_name, obj_name, obj_data)
Chris Dent1d4313a2014-10-28 12:16:48 +00001453 self.addCleanup(self.delete_wrapper,
1454 self.object_client.delete_object,
1455 container_name,
1456 obj_name)
Chris Dent0d494112014-08-26 13:48:30 +01001457 return obj_name, obj_data
1458
Chris Dentde456a12014-09-10 12:41:15 +01001459 def delete_object(self, container_name, filename):
Chris Dent0d494112014-08-26 13:48:30 +01001460 self.object_client.delete_object(container_name, filename)
Chris Dentde456a12014-09-10 12:41:15 +01001461 self.list_and_check_container_objects(container_name,
1462 not_present_obj=[filename])
Chris Dent0d494112014-08-26 13:48:30 +01001463
Chris Dentde456a12014-09-10 12:41:15 +01001464 def list_and_check_container_objects(self, container_name,
1465 present_obj=None,
1466 not_present_obj=None):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001467 # List objects for a given container and assert which are present and
1468 # which are not.
Ghanshyam2a180b82014-06-16 13:54:22 +09001469 if present_obj is None:
1470 present_obj = []
1471 if not_present_obj is None:
1472 not_present_obj = []
Chris Dent0d494112014-08-26 13:48:30 +01001473 _, object_list = self.container_client.list_container_contents(
1474 container_name)
1475 if present_obj:
1476 for obj in present_obj:
1477 self.assertIn(obj, object_list)
1478 if not_present_obj:
1479 for obj in not_present_obj:
1480 self.assertNotIn(obj, object_list)
1481
Chris Dentde456a12014-09-10 12:41:15 +01001482 def change_container_acl(self, container_name, acl):
Chris Dent0d494112014-08-26 13:48:30 +01001483 metadata_param = {'metadata_prefix': 'x-container-',
1484 'metadata': {'read': acl}}
1485 self.container_client.update_container_metadata(container_name,
1486 **metadata_param)
1487 resp, _ = self.container_client.list_container_metadata(container_name)
1488 self.assertEqual(resp['x-container-read'], acl)
1489
Chris Dentde456a12014-09-10 12:41:15 +01001490 def download_and_verify(self, container_name, obj_name, expected_data):
Chris Dent0d494112014-08-26 13:48:30 +01001491 _, obj = self.object_client.get_object(container_name, obj_name)
1492 self.assertEqual(obj, expected_data)