blob: aecb3741ed7ee85ffc1a3cdee60066159f50fb99 [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
Yatin Kumbhareee4924c2016-06-09 15:12:06 +053022from oslo_utils import netutils
Sean Dague6dbc6da2013-05-08 17:49:46 -040023
lanoux5fc14522015-09-21 08:17:35 +000024from tempest.common import compute
Ken'ichi Ohmichi01151e82016-06-10 11:19:52 -070025from tempest.common import image as common_image
Masayuki Igawa4ded9f02014-02-17 15:05:59 +090026from tempest.common.utils.linux import remote_client
Ihar Hrachyshkaf9227c02016-09-15 11:16:47 +000027from tempest.common.utils import net_utils
Ken'ichi Ohmichi0eb153c2015-07-13 02:18:25 +000028from tempest.common import waiters
Matthew Treinish6c072292014-01-29 19:15:52 +000029from tempest import config
Giulio Fidente92f77192013-08-26 17:13:28 +020030from tempest import exceptions
Ken'ichi Ohmichibe4fb502017-03-10 10:04:48 -080031from tempest.lib.common.utils import data_utils
Jordan Pittier9e227c52016-02-09 14:35:18 +010032from tempest.lib.common.utils import test_utils
Andrea Frittoli (andreaf)db9672e2016-02-23 14:07:24 -050033from tempest.lib import exceptions as lib_exc
Sean Dague6dbc6da2013-05-08 17:49:46 -040034import tempest.test
Sean Dague6dbc6da2013-05-08 17:49:46 -040035
Matthew Treinish6c072292014-01-29 19:15:52 +000036CONF = config.CONF
Sean Dague6dbc6da2013-05-08 17:49:46 -040037
Attila Fazekasfb7552a2013-08-27 13:02:26 +020038LOG = log.getLogger(__name__)
39
Sean Dague6dbc6da2013-05-08 17:49:46 -040040
Andrea Frittoli2e733b52014-07-16 14:12:11 +010041class ScenarioTest(tempest.test.BaseTestCase):
Andrea Frittoli486ede72014-09-25 11:50:05 +010042 """Base class for scenario tests. Uses tempest own clients. """
Andrea Frittoli2e733b52014-07-16 14:12:11 +010043
Andrea Frittolib21de6c2015-02-06 20:12:38 +000044 credentials = ['primary']
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +000045
46 @classmethod
47 def setup_clients(cls):
48 super(ScenarioTest, cls).setup_clients()
Andrea Frittoli247058f2014-07-16 16:09:22 +010049 # Clients (in alphabetical order)
jeremy.zhang0343be52017-05-25 21:29:57 +080050 cls.flavors_client = cls.os_primary.flavors_client
John Warrene74890a2015-11-11 15:18:01 -050051 cls.compute_floating_ips_client = (
jeremy.zhang0343be52017-05-25 21:29:57 +080052 cls.os_primary.compute_floating_ips_client)
Jordan Pittier1d2e40f2016-01-05 18:49:14 +010053 if CONF.service_available.glance:
Matt Riedemann2aa19d42016-06-06 17:45:41 -040054 # Check if glance v1 is available to determine which client to use.
55 if CONF.image_feature_enabled.api_v1:
jeremy.zhang0343be52017-05-25 21:29:57 +080056 cls.image_client = cls.os_primary.image_client
Matt Riedemann2aa19d42016-06-06 17:45:41 -040057 elif CONF.image_feature_enabled.api_v2:
jeremy.zhang0343be52017-05-25 21:29:57 +080058 cls.image_client = cls.os_primary.image_client_v2
Matt Riedemann2aa19d42016-06-06 17:45:41 -040059 else:
Matthew Treinish4217a702016-10-07 17:27:11 -040060 raise lib_exc.InvalidConfiguration(
Matt Riedemann2aa19d42016-06-06 17:45:41 -040061 'Either api_v1 or api_v2 must be True in '
62 '[image-feature-enabled].')
nithya-ganesan882595e2014-07-29 18:51:07 +000063 # Compute image client
jeremy.zhang0343be52017-05-25 21:29:57 +080064 cls.compute_images_client = cls.os_primary.compute_images_client
65 cls.keypairs_client = cls.os_primary.keypairs_client
Andrea Frittoli247058f2014-07-16 16:09:22 +010066 # Nova security groups client
John Warrenf2345512015-12-10 13:39:30 -050067 cls.compute_security_groups_client = (
jeremy.zhang0343be52017-05-25 21:29:57 +080068 cls.os_primary.compute_security_groups_client)
John Warren5cdbf422016-01-05 12:42:43 -050069 cls.compute_security_group_rules_client = (
jeremy.zhang0343be52017-05-25 21:29:57 +080070 cls.os_primary.compute_security_group_rules_client)
71 cls.servers_client = cls.os_primary.servers_client
72 cls.interface_client = cls.os_primary.interfaces_client
Yair Fried1fc32a12014-08-04 09:11:30 +030073 # Neutron network client
jeremy.zhang0343be52017-05-25 21:29:57 +080074 cls.networks_client = cls.os_primary.networks_client
75 cls.ports_client = cls.os_primary.ports_client
76 cls.routers_client = cls.os_primary.routers_client
77 cls.subnets_client = cls.os_primary.subnets_client
78 cls.floating_ips_client = cls.os_primary.floating_ips_client
79 cls.security_groups_client = cls.os_primary.security_groups_client
John Warren456d9ae2016-01-12 15:36:33 -050080 cls.security_group_rules_client = (
jeremy.zhang0343be52017-05-25 21:29:57 +080081 cls.os_primary.security_group_rules_client)
82 cls.volumes_client = cls.os_primary.volumes_v2_client
83 cls.snapshots_client = cls.os_primary.snapshots_v2_client
Ivan Kolodyazhnybcfc32e2015-08-06 13:31:36 +030084
Jordan Pittierf672b7d2016-06-20 18:50:40 +020085 # ## Test functions library
86 #
87 # The create_[resource] functions only return body and discard the
88 # resp part which is not used in scenario tests
Andrea Frittoli247058f2014-07-16 16:09:22 +010089
Lenny Verkhovsky136376f2016-06-29 14:33:34 +030090 def _create_port(self, network_id, client=None, namestart='port-quotatest',
91 **kwargs):
92 if not client:
93 client = self.ports_client
94 name = data_utils.rand_name(namestart)
95 result = client.create_port(
96 name=name,
97 network_id=network_id,
98 **kwargs)
99 self.assertIsNotNone(result, 'Unable to allocate port')
100 port = result['port']
101 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
102 client.delete_port, port['id'])
103 return port
104
Yair Frieddb6c9e92014-08-06 08:53:13 +0300105 def create_keypair(self, client=None):
106 if not client:
107 client = self.keypairs_client
Andrea Frittoli247058f2014-07-16 16:09:22 +0100108 name = data_utils.rand_name(self.__class__.__name__)
109 # We don't need to create a keypair by pubkey in scenario
Ken'ichi Ohmichie364bce2015-07-17 10:27:59 +0000110 body = client.create_keypair(name=name)
Yair Frieddb6c9e92014-08-06 08:53:13 +0300111 self.addCleanup(client.delete_keypair, name)
ghanshyamdee01f22015-08-17 11:41:47 +0900112 return body['keypair']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100113
Anusha Ramineni9aaef8b2016-01-19 10:56:40 +0530114 def create_server(self, name=None, image_id=None, flavor=None,
zhufl13c9c892017-02-10 12:04:07 +0800115 validatable=False, wait_until='ACTIVE',
Jordan Pittierf672b7d2016-06-20 18:50:40 +0200116 clients=None, **kwargs):
lanoux5fc14522015-09-21 08:17:35 +0000117 """Wrapper utility that returns a test server.
Andrea Frittoli247058f2014-07-16 16:09:22 +0100118
lanoux5fc14522015-09-21 08:17:35 +0000119 This wrapper utility calls the common create test server and
120 returns a test server. The purpose of this wrapper is to minimize
121 the impact on the code of the tests already using this
122 function.
Andrea Frittoli247058f2014-07-16 16:09:22 +0100123 """
Andrea Frittoli247058f2014-07-16 16:09:22 +0100124
lanoux5fc14522015-09-21 08:17:35 +0000125 # NOTE(jlanoux): As a first step, ssh checks in the scenario
126 # tests need to be run regardless of the run_validation and
127 # validatable parameters and thus until the ssh validation job
128 # becomes voting in CI. The test resources management and IP
129 # association are taken care of in the scenario tests.
130 # Therefore, the validatable parameter is set to false in all
131 # those tests. In this way create_server just return a standard
132 # server and the scenario tests always perform ssh checks.
133
134 # Needed for the cross_tenant_traffic test:
135 if clients is None:
jeremy.zhang0343be52017-05-25 21:29:57 +0800136 clients = self.os_primary
lanoux5fc14522015-09-21 08:17:35 +0000137
zhufl24208c22016-10-25 15:23:48 +0800138 if name is None:
139 name = data_utils.rand_name(self.__class__.__name__ + "-server")
140
lanoux5fc14522015-09-21 08:17:35 +0000141 vnic_type = CONF.network.port_vnic_type
142
143 # If vnic_type is configured create port for
144 # every network
145 if vnic_type:
146 ports = []
Lenny Verkhovsky69363502016-07-17 16:33:33 +0300147
lanoux5fc14522015-09-21 08:17:35 +0000148 create_port_body = {'binding:vnic_type': vnic_type,
149 'namestart': 'port-smoke'}
150 if kwargs:
151 # Convert security group names to security group ids
152 # to pass to create_port
153 if 'security_groups' in kwargs:
Thiago Paiva66cded22016-08-15 14:55:58 -0300154 security_groups = \
John Warrenf9606e92015-12-10 12:12:42 -0500155 clients.security_groups_client.list_security_groups(
lanoux5fc14522015-09-21 08:17:35 +0000156 ).get('security_groups')
157 sec_dict = dict([(s['name'], s['id'])
158 for s in security_groups])
159
160 sec_groups_names = [s['name'] for s in kwargs.pop(
161 'security_groups')]
162 security_groups_ids = [sec_dict[s]
163 for s in sec_groups_names]
164
165 if security_groups_ids:
166 create_port_body[
167 'security_groups'] = security_groups_ids
Lenny Verkhovsky69363502016-07-17 16:33:33 +0300168 networks = kwargs.pop('networks', [])
169 else:
170 networks = []
lanoux5fc14522015-09-21 08:17:35 +0000171
172 # If there are no networks passed to us we look up
Lenny Verkhovsky136376f2016-06-29 14:33:34 +0300173 # for the project's private networks and create a port.
174 # The same behaviour as we would expect when passing
175 # the call to the clients with no networks
lanoux5fc14522015-09-21 08:17:35 +0000176 if not networks:
177 networks = clients.networks_client.list_networks(
Lenny Verkhovsky136376f2016-06-29 14:33:34 +0300178 **{'router:external': False, 'fields': 'id'})['networks']
179
180 # It's net['uuid'] if networks come from kwargs
181 # and net['id'] if they come from
182 # clients.networks_client.list_networks
lanoux5fc14522015-09-21 08:17:35 +0000183 for net in networks:
Lenny Verkhovsky97f7cea2016-08-15 13:29:48 +0000184 net_id = net.get('uuid', net.get('id'))
Lenny Verkhovsky69363502016-07-17 16:33:33 +0300185 if 'port' not in net:
186 port = self._create_port(network_id=net_id,
187 client=clients.ports_client,
188 **create_port_body)
189 ports.append({'port': port['id']})
190 else:
191 ports.append({'port': net['port']})
lanoux5fc14522015-09-21 08:17:35 +0000192 if ports:
193 kwargs['networks'] = ports
194 self.ports = ports
195
196 tenant_network = self.get_tenant_network()
197
Ferenc Horváthbce1fcf2017-06-07 11:19:51 +0200198 body, _ = compute.create_test_server(
lanoux5fc14522015-09-21 08:17:35 +0000199 clients,
200 tenant_network=tenant_network,
201 wait_until=wait_until,
Anusha Ramineni9aaef8b2016-01-19 10:56:40 +0530202 name=name, flavor=flavor,
203 image_id=image_id, **kwargs)
lanoux5fc14522015-09-21 08:17:35 +0000204
Jordan Pittierf672b7d2016-06-20 18:50:40 +0200205 self.addCleanup(waiters.wait_for_server_termination,
206 clients.servers_client, body['id'])
207 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
208 clients.servers_client.delete_server, body['id'])
lanoux5fc14522015-09-21 08:17:35 +0000209 server = clients.servers_client.show_server(body['id'])['server']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100210 return server
211
Markus Zoeller3d2a21c2015-02-27 12:04:22 +0100212 def create_volume(self, size=None, name=None, snapshot_id=None,
Jordan Pittier5e1741c2016-03-02 18:25:51 +0100213 imageRef=None, volume_type=None):
Ken'ichi Ohmichiadb905e2016-08-26 15:16:23 -0700214 if size is None:
215 size = CONF.volume.volume_size
Nuno Santosb746d992016-11-17 15:41:55 -0500216 if imageRef:
217 image = self.compute_images_client.show_image(imageRef)['image']
218 min_disk = image.get('minDisk')
219 size = max(size, min_disk)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100220 if name is None:
zhuflf9d95722016-10-19 16:06:17 +0800221 name = data_utils.rand_name(self.__class__.__name__ + "-volume")
Ghanshyam8fc0ed22015-12-18 10:25:14 +0900222 kwargs = {'display_name': name,
223 'snapshot_id': snapshot_id,
224 'imageRef': imageRef,
Ken'ichi Ohmichiadb905e2016-08-26 15:16:23 -0700225 'volume_type': volume_type,
226 'size': size}
Ghanshyam8fc0ed22015-12-18 10:25:14 +0900227 volume = self.volumes_client.create_volume(**kwargs)['volume']
Matt Riedemanne85c2702014-09-10 11:50:13 -0700228
Jordan Pittier5e1741c2016-03-02 18:25:51 +0100229 self.addCleanup(self.volumes_client.wait_for_resource_deletion,
230 volume['id'])
Jordan Pittier9e227c52016-02-09 14:35:18 +0100231 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
Jordan Pittier5e1741c2016-03-02 18:25:51 +0100232 self.volumes_client.delete_volume, volume['id'])
lkuchlan5cbc00a2017-03-26 11:49:54 +0300233 self.assertEqual(name, volume['name'])
lkuchlan52d7b0d2016-11-07 20:53:19 +0200234 waiters.wait_for_volume_resource_status(self.volumes_client,
235 volume['id'], 'available')
Andrea Frittoli247058f2014-07-16 16:09:22 +0100236 # The volume retrieved on creation has a non-up-to-date status.
237 # Retrieval after it becomes active ensures correct details.
John Warren6177c9e2015-08-19 20:00:17 +0000238 volume = self.volumes_client.show_volume(volume['id'])['volume']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100239 return volume
240
scottda61f68ac2016-06-07 12:07:55 -0600241 def create_volume_type(self, client=None, name=None, backend_name=None):
242 if not client:
243 client = self.admin_volume_types_client
244 if not name:
245 class_name = self.__class__.__name__
246 name = data_utils.rand_name(class_name + '-volume-type')
247 randomized_name = data_utils.rand_name('scenario-type-' + name)
248
249 LOG.debug("Creating a volume type: %s on backend %s",
250 randomized_name, backend_name)
251 extra_specs = {}
252 if backend_name:
253 extra_specs = {"volume_backend_name": backend_name}
254
255 body = client.create_volume_type(name=randomized_name,
256 extra_specs=extra_specs)
257 volume_type = body['volume_type']
258 self.assertIn('id', volume_type)
259 self.addCleanup(client.delete_volume_type, volume_type['id'])
260 return volume_type
261
Yair Fried1fc32a12014-08-04 09:11:30 +0300262 def _create_loginable_secgroup_rule(self, secgroup_id=None):
John Warrenf2345512015-12-10 13:39:30 -0500263 _client = self.compute_security_groups_client
John Warren5cdbf422016-01-05 12:42:43 -0500264 _client_rules = self.compute_security_group_rules_client
Andrea Frittoli247058f2014-07-16 16:09:22 +0100265 if secgroup_id is None:
ghanshyamb610b772015-08-24 17:29:38 +0900266 sgs = _client.list_security_groups()['security_groups']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100267 for sg in sgs:
268 if sg['name'] == 'default':
269 secgroup_id = sg['id']
270
271 # These rules are intended to permit inbound ssh and icmp
272 # traffic from all sources, so no group_id is provided.
273 # Setting a group_id would only permit traffic from ports
274 # belonging to the same security group.
275 rulesets = [
276 {
277 # ssh
Ken'ichi Ohmichieb7eeec2015-07-21 01:00:06 +0000278 'ip_protocol': 'tcp',
Andrea Frittoli247058f2014-07-16 16:09:22 +0100279 'from_port': 22,
280 'to_port': 22,
281 'cidr': '0.0.0.0/0',
282 },
283 {
284 # ping
Ken'ichi Ohmichieb7eeec2015-07-21 01:00:06 +0000285 'ip_protocol': 'icmp',
Andrea Frittoli247058f2014-07-16 16:09:22 +0100286 'from_port': -1,
287 'to_port': -1,
288 'cidr': '0.0.0.0/0',
289 }
290 ]
291 rules = list()
292 for ruleset in rulesets:
Ken'ichi Ohmichieb7eeec2015-07-21 01:00:06 +0000293 sg_rule = _client_rules.create_security_group_rule(
ghanshyam0a5e1232015-08-24 16:59:59 +0900294 parent_group_id=secgroup_id, **ruleset)['security_group_rule']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100295 rules.append(sg_rule)
296 return rules
297
Yair Fried1fc32a12014-08-04 09:11:30 +0300298 def _create_security_group(self):
Andrea Frittoli247058f2014-07-16 16:09:22 +0100299 # Create security group
300 sg_name = data_utils.rand_name(self.__class__.__name__)
301 sg_desc = sg_name + " description"
John Warrenf2345512015-12-10 13:39:30 -0500302 secgroup = self.compute_security_groups_client.create_security_group(
ghanshyamb610b772015-08-24 17:29:38 +0900303 name=sg_name, description=sg_desc)['security_group']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100304 self.assertEqual(secgroup['name'], sg_name)
305 self.assertEqual(secgroup['description'], sg_desc)
John Warrenf2345512015-12-10 13:39:30 -0500306 self.addCleanup(
Jordan Pittier9e227c52016-02-09 14:35:18 +0100307 test_utils.call_and_ignore_notfound_exc,
John Warrenf2345512015-12-10 13:39:30 -0500308 self.compute_security_groups_client.delete_security_group,
309 secgroup['id'])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100310
311 # Add rules to the security group
Yair Fried1fc32a12014-08-04 09:11:30 +0300312 self._create_loginable_secgroup_rule(secgroup['id'])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100313
314 return secgroup
315
zhuflf52c7592017-05-25 13:55:24 +0800316 def get_remote_client(self, ip_address, username=None, private_key=None,
317 server=None):
JordanP3fe2dc32014-11-17 13:06:01 +0100318 """Get a SSH client to a remote server
319
Sean Dague20e98612016-01-06 14:33:28 -0500320 @param ip_address the server floating or fixed IP address to use
321 for ssh validation
JordanP3fe2dc32014-11-17 13:06:01 +0100322 @param username name of the Linux account on the remote server
323 @param private_key the SSH private key to use
zhuflf52c7592017-05-25 13:55:24 +0800324 @param server: server dict, used for debugging purposes
JordanP3fe2dc32014-11-17 13:06:01 +0100325 @return a RemoteClient object
326 """
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700327
Andrea Frittoli247058f2014-07-16 16:09:22 +0100328 if username is None:
lanoux283273b2015-12-04 03:01:54 -0800329 username = CONF.validation.image_ssh_user
wantwatering896300c2015-03-27 15:17:42 +0800330 # Set this with 'keypair' or others to log in with keypair or
331 # username/password.
lanoux5fc14522015-09-21 08:17:35 +0000332 if CONF.validation.auth_method == 'keypair':
wantwatering896300c2015-03-27 15:17:42 +0800333 password = None
334 if private_key is None:
335 private_key = self.keypair['private_key']
336 else:
lanoux283273b2015-12-04 03:01:54 -0800337 password = CONF.validation.image_ssh_password
wantwatering896300c2015-03-27 15:17:42 +0800338 private_key = None
zhuflf52c7592017-05-25 13:55:24 +0800339 linux_client = remote_client.RemoteClient(
340 ip_address, username, pkey=private_key, password=password,
341 server=server, servers_client=self.servers_client)
342 linux_client.validate_authentication()
Andrea Frittoli247058f2014-07-16 16:09:22 +0100343 return linux_client
344
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000345 def _image_create(self, name, fmt, path,
346 disk_format=None, properties=None):
Ghanshyam2a180b82014-06-16 13:54:22 +0900347 if properties is None:
348 properties = {}
Andrea Frittoli247058f2014-07-16 16:09:22 +0100349 name = data_utils.rand_name('%s-' % name)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100350 params = {
351 'name': name,
352 'container_format': fmt,
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000353 'disk_format': disk_format or fmt,
Andrea Frittoli247058f2014-07-16 16:09:22 +0100354 }
Matt Riedemann2aa19d42016-06-06 17:45:41 -0400355 if CONF.image_feature_enabled.api_v1:
356 params['is_public'] = 'False'
357 params['properties'] = properties
Ken'ichi Ohmichi02bcdf32016-06-17 16:41:26 -0700358 params = {'headers': common_image.image_meta_to_headers(**params)}
Matt Riedemann2aa19d42016-06-06 17:45:41 -0400359 else:
360 params['visibility'] = 'private'
361 # Additional properties are flattened out in the v2 API.
362 params.update(properties)
363 body = self.image_client.create_image(**params)
364 image = body['image'] if 'image' in body else body
Andrea Frittoli247058f2014-07-16 16:09:22 +0100365 self.addCleanup(self.image_client.delete_image, image['id'])
366 self.assertEqual("queued", image['status'])
zhang.leia4b1cef2016-03-01 10:50:01 +0800367 with open(path, 'rb') as image_file:
Matt Riedemann2aa19d42016-06-06 17:45:41 -0400368 if CONF.image_feature_enabled.api_v1:
369 self.image_client.update_image(image['id'], data=image_file)
370 else:
371 self.image_client.store_image_file(image['id'], image_file)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100372 return image['id']
373
374 def glance_image_create(self):
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300375 img_path = CONF.scenario.img_dir + "/" + CONF.scenario.img_file
Andrea Frittoli247058f2014-07-16 16:09:22 +0100376 aki_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.aki_img_file
377 ari_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.ari_img_file
378 ami_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.ami_img_file
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300379 img_container_format = CONF.scenario.img_container_format
380 img_disk_format = CONF.scenario.img_disk_format
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000381 img_properties = CONF.scenario.img_properties
PranaliD2aa523c2016-06-07 03:54:34 -0400382 LOG.debug("paths: img: %s, container_format: %s, disk_format: %s, "
Jordan Pittier525ec712016-12-07 17:51:26 +0100383 "properties: %s, ami: %s, ari: %s, aki: %s",
384 img_path, img_container_format, img_disk_format,
385 img_properties, ami_img_path, ari_img_path, aki_img_path)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100386 try:
Jordan Pittier1e443ec2015-11-20 16:15:58 +0100387 image = self._image_create('scenario-img',
388 img_container_format,
389 img_path,
390 disk_format=img_disk_format,
391 properties=img_properties)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100392 except IOError:
393 LOG.debug("A qcow2 image was not found. Try to get a uec image.")
394 kernel = self._image_create('scenario-aki', 'aki', aki_img_path)
395 ramdisk = self._image_create('scenario-ari', 'ari', ari_img_path)
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000396 properties = {'kernel_id': kernel, 'ramdisk_id': ramdisk}
Jordan Pittier1e443ec2015-11-20 16:15:58 +0100397 image = self._image_create('scenario-ami', 'ami',
398 path=ami_img_path,
399 properties=properties)
Jordan Pittier525ec712016-12-07 17:51:26 +0100400 LOG.debug("image:%s", image)
Jordan Pittier1e443ec2015-11-20 16:15:58 +0100401
402 return image
Andrea Frittoli247058f2014-07-16 16:09:22 +0100403
Ihar Hrachyshkaa9dca2b2017-04-04 14:17:11 -0700404 def _log_console_output(self, servers=None, client=None):
Matthew Treinish42a3f3a2014-09-04 15:04:53 -0400405 if not CONF.compute_feature_enabled.console_output:
406 LOG.debug('Console output not supported, cannot log')
407 return
Ihar Hrachyshkaa9dca2b2017-04-04 14:17:11 -0700408 client = client or self.servers_client
Andrea Frittoli247058f2014-07-16 16:09:22 +0100409 if not servers:
Ihar Hrachyshkaa9dca2b2017-04-04 14:17:11 -0700410 servers = client.list_servers()
Andrea Frittoli247058f2014-07-16 16:09:22 +0100411 servers = servers['servers']
412 for server in servers:
Attila Fazekas9a5a1122016-11-08 10:24:57 +0100413 try:
Ihar Hrachyshkaa9dca2b2017-04-04 14:17:11 -0700414 console_output = client.get_console_output(
Attila Fazekas9a5a1122016-11-08 10:24:57 +0100415 server['id'])['output']
416 LOG.debug('Console output for %s\nbody=\n%s',
417 server['id'], console_output)
418 except lib_exc.NotFound:
Attila Fazekase1360482016-11-10 11:28:08 +0100419 LOG.debug("Server %s disappeared(deleted) while looking "
Attila Fazekas9a5a1122016-11-08 10:24:57 +0100420 "for the console log", server['id'])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100421
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000422 def _log_net_info(self, exc):
423 # network debug is called as part of ssh init
Andrey Pavlov64723762015-04-29 06:24:58 +0300424 if not isinstance(exc, lib_exc.SSHTimeout):
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000425 LOG.debug('Network information on a devstack host')
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000426
nithya-ganesan882595e2014-07-29 18:51:07 +0000427 def create_server_snapshot(self, server, name=None):
428 # Glance client
429 _image_client = self.image_client
430 # Compute client
Ghanshyamae76c122015-12-22 13:41:35 +0900431 _images_client = self.compute_images_client
nithya-ganesan882595e2014-07-29 18:51:07 +0000432 if name is None:
zhuflf9d95722016-10-19 16:06:17 +0800433 name = data_utils.rand_name(self.__class__.__name__ + 'snapshot')
nithya-ganesan882595e2014-07-29 18:51:07 +0000434 LOG.debug("Creating a snapshot image for server: %s", server['name'])
Ken'ichi Ohmichi28f18672015-07-17 10:00:38 +0000435 image = _images_client.create_image(server['id'], name=name)
David Kranza5299eb2015-01-15 17:24:05 -0500436 image_id = image.response['location'].split('images/')[1]
Yaroslav Lobankov2fea4052016-04-19 15:05:57 +0300437 waiters.wait_for_image_status(_image_client, image_id, 'active')
Jordan Pittierf672b7d2016-06-20 18:50:40 +0200438
439 self.addCleanup(_image_client.wait_for_resource_deletion,
440 image_id)
441 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
442 _image_client.delete_image, image_id)
443
Matt Riedemann2aa19d42016-06-06 17:45:41 -0400444 if CONF.image_feature_enabled.api_v1:
445 # In glance v1 the additional properties are stored in the headers.
Ken'ichi Ohmichi01151e82016-06-10 11:19:52 -0700446 resp = _image_client.check_image(image_id)
447 snapshot_image = common_image.get_image_meta_from_headers(resp)
Matt Riedemann2aa19d42016-06-06 17:45:41 -0400448 image_props = snapshot_image.get('properties', {})
449 else:
450 # In glance v2 the additional properties are flattened.
451 snapshot_image = _image_client.show_image(image_id)
452 image_props = snapshot_image
Andrey Pavlovc8bd4b12015-08-17 10:20:17 +0300453
Matt Riedemann2aa19d42016-06-06 17:45:41 -0400454 bdm = image_props.get('block_device_mapping')
Andrey Pavlovc8bd4b12015-08-17 10:20:17 +0300455 if bdm:
456 bdm = json.loads(bdm)
457 if bdm and 'snapshot_id' in bdm[0]:
458 snapshot_id = bdm[0]['snapshot_id']
459 self.addCleanup(
460 self.snapshots_client.wait_for_resource_deletion,
461 snapshot_id)
Jordan Pittier9e227c52016-02-09 14:35:18 +0100462 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
463 self.snapshots_client.delete_snapshot,
464 snapshot_id)
lkuchlan52d7b0d2016-11-07 20:53:19 +0200465 waiters.wait_for_volume_resource_status(self.snapshots_client,
466 snapshot_id,
467 'available')
nithya-ganesan882595e2014-07-29 18:51:07 +0000468 image_name = snapshot_image['name']
469 self.assertEqual(name, image_name)
470 LOG.debug("Created snapshot image %s for server %s",
471 image_name, server['name'])
472 return snapshot_image
473
Jordan Pittier7cf64762015-10-14 15:01:12 +0200474 def nova_volume_attach(self, server, volume_to_attach):
Joseph Lanoux6809bab2014-12-18 14:57:18 +0000475 volume = self.servers_client.attach_volume(
Jordan Pittier7cf64762015-10-14 15:01:12 +0200476 server['id'], volumeId=volume_to_attach['id'], device='/dev/%s'
ghanshyam0f825252015-08-25 16:02:50 +0900477 % CONF.compute.volume_device_name)['volumeAttachment']
Jordan Pittier7cf64762015-10-14 15:01:12 +0200478 self.assertEqual(volume_to_attach['id'], volume['id'])
lkuchlan52d7b0d2016-11-07 20:53:19 +0200479 waiters.wait_for_volume_resource_status(self.volumes_client,
480 volume['id'], 'in-use')
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900481
Jordan Pittier7cf64762015-10-14 15:01:12 +0200482 # Return the updated volume after the attachment
483 return self.volumes_client.show_volume(volume['id'])['volume']
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900484
Jordan Pittier7cf64762015-10-14 15:01:12 +0200485 def nova_volume_detach(self, server, volume):
486 self.servers_client.detach_volume(server['id'], volume['id'])
lkuchlan52d7b0d2016-11-07 20:53:19 +0200487 waiters.wait_for_volume_resource_status(self.volumes_client,
488 volume['id'], 'available')
Jordan Pittier7cf64762015-10-14 15:01:12 +0200489
490 volume = self.volumes_client.show_volume(volume['id'])['volume']
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900491 self.assertEqual('available', volume['status'])
492
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700493 def rebuild_server(self, server_id, image=None,
494 preserve_ephemeral=False, wait=True,
495 rebuild_kwargs=None):
496 if image is None:
497 image = CONF.compute.image_ref
498
499 rebuild_kwargs = rebuild_kwargs or {}
500
501 LOG.debug("Rebuilding server (id: %s, image: %s, preserve eph: %s)",
502 server_id, image, preserve_ephemeral)
Ken'ichi Ohmichi5271b0f2015-08-10 07:53:27 +0000503 self.servers_client.rebuild_server(
504 server_id=server_id, image_ref=image,
505 preserve_ephemeral=preserve_ephemeral,
506 **rebuild_kwargs)
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700507 if wait:
Ken'ichi Ohmichi0eb153c2015-07-13 02:18:25 +0000508 waiters.wait_for_server_status(self.servers_client,
509 server_id, 'ACTIVE')
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700510
Steven Hardyda2a8352014-10-02 12:52:20 +0100511 def ping_ip_address(self, ip_address, should_succeed=True,
Ihar Hrachyshkaf9227c02016-09-15 11:16:47 +0000512 ping_timeout=None, mtu=None):
lanoux5fc14522015-09-21 08:17:35 +0000513 timeout = ping_timeout or CONF.validation.ping_timeout
Ihar Hrachyshkaf9227c02016-09-15 11:16:47 +0000514 cmd = ['ping', '-c1', '-w1']
515
516 if mtu:
517 cmd += [
518 # don't fragment
519 '-M', 'do',
520 # ping receives just the size of ICMP payload
521 '-s', str(net_utils.get_ping_payload_size(mtu, 4))
522 ]
523 cmd.append(ip_address)
Aaron Rosena7df13b2014-09-23 09:45:45 -0700524
525 def ping():
526 proc = subprocess.Popen(cmd,
527 stdout=subprocess.PIPE,
528 stderr=subprocess.PIPE)
529 proc.communicate()
Shuquan Huang753629e2015-07-20 08:52:29 +0000530
Aaron Rosena7df13b2014-09-23 09:45:45 -0700531 return (proc.returncode == 0) == should_succeed
532
Jordan Pittier9e227c52016-02-09 14:35:18 +0100533 caller = test_utils.find_test_caller()
Shuquan Huang753629e2015-07-20 08:52:29 +0000534 LOG.debug('%(caller)s begins to ping %(ip)s in %(timeout)s sec and the'
John L. Villalovosa898aec2017-01-13 14:46:46 -0800535 ' expected result is %(should_succeed)s', {
Shuquan Huang753629e2015-07-20 08:52:29 +0000536 'caller': caller, 'ip': ip_address, 'timeout': timeout,
537 'should_succeed':
538 'reachable' if should_succeed else 'unreachable'
539 })
Jordan Pittier35a63752016-08-30 13:09:12 +0200540 result = test_utils.call_until_true(ping, timeout, 1)
Shuquan Huang753629e2015-07-20 08:52:29 +0000541 LOG.debug('%(caller)s finishes ping %(ip)s in %(timeout)s sec and the '
John L. Villalovosa898aec2017-01-13 14:46:46 -0800542 'ping result is %(result)s', {
Shuquan Huang753629e2015-07-20 08:52:29 +0000543 'caller': caller, 'ip': ip_address, 'timeout': timeout,
544 'result': 'expected' if result else 'unexpected'
545 })
546 return result
Aaron Rosena7df13b2014-09-23 09:45:45 -0700547
Yair Friedae0e73d2014-11-24 11:56:26 +0200548 def check_vm_connectivity(self, ip_address,
549 username=None,
550 private_key=None,
Ihar Hrachyshkaf9227c02016-09-15 11:16:47 +0000551 should_connect=True,
552 mtu=None):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000553 """Check server connectivity
554
Yair Friedae0e73d2014-11-24 11:56:26 +0200555 :param ip_address: server to test against
556 :param username: server's ssh username
557 :param private_key: server's ssh private key to be used
558 :param should_connect: True/False indicates positive/negative test
559 positive - attempt ping and ssh
560 negative - attempt ping and fail if succeed
Ihar Hrachyshkaf9227c02016-09-15 11:16:47 +0000561 :param mtu: network MTU to use for connectivity validation
Yair Friedae0e73d2014-11-24 11:56:26 +0200562
563 :raises: AssertError if the result of the connectivity check does
564 not match the value of the should_connect param
565 """
566 if should_connect:
567 msg = "Timed out waiting for %s to become reachable" % ip_address
568 else:
569 msg = "ip address %s is reachable" % ip_address
570 self.assertTrue(self.ping_ip_address(ip_address,
Ihar Hrachyshkaf9227c02016-09-15 11:16:47 +0000571 should_succeed=should_connect,
572 mtu=mtu),
Yair Friedae0e73d2014-11-24 11:56:26 +0200573 msg=msg)
574 if should_connect:
575 # no need to check ssh for negative connectivity
576 self.get_remote_client(ip_address, username, private_key)
577
578 def check_public_network_connectivity(self, ip_address, username,
579 private_key, should_connect=True,
Ihar Hrachyshkaf9227c02016-09-15 11:16:47 +0000580 msg=None, servers=None, mtu=None):
Yair Friedae0e73d2014-11-24 11:56:26 +0200581 # The target login is assumed to have been configured for
582 # key-based authentication by cloud-init.
Jordan Pittier525ec712016-12-07 17:51:26 +0100583 LOG.debug('checking network connections to IP %s with user: %s',
584 ip_address, username)
Yair Friedae0e73d2014-11-24 11:56:26 +0200585 try:
586 self.check_vm_connectivity(ip_address,
587 username,
588 private_key,
Ihar Hrachyshkaf9227c02016-09-15 11:16:47 +0000589 should_connect=should_connect,
590 mtu=mtu)
Matthew Treinish53483132014-12-09 18:50:06 -0500591 except Exception:
Yair Friedae0e73d2014-11-24 11:56:26 +0200592 ex_msg = 'Public network connectivity check failed'
593 if msg:
594 ex_msg += ": " + msg
595 LOG.exception(ex_msg)
596 self._log_console_output(servers)
Yair Friedae0e73d2014-11-24 11:56:26 +0200597 raise
598
599 def create_floating_ip(self, thing, pool_name=None):
Ken'ichi Ohmichia112a592015-11-17 08:49:37 +0000600 """Create a floating IP and associates to a server on Nova"""
Yair Friedae0e73d2014-11-24 11:56:26 +0200601
Marc Koderer3b57d802016-03-22 15:23:31 +0100602 if not pool_name:
603 pool_name = CONF.network.floating_network_name
John Warrene74890a2015-11-11 15:18:01 -0500604 floating_ip = (self.compute_floating_ips_client.
Ken'ichi Ohmichie037a6f2015-12-03 06:41:49 +0000605 create_floating_ip(pool=pool_name)['floating_ip'])
Jordan Pittier9e227c52016-02-09 14:35:18 +0100606 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
John Warrene74890a2015-11-11 15:18:01 -0500607 self.compute_floating_ips_client.delete_floating_ip,
Yair Friedae0e73d2014-11-24 11:56:26 +0200608 floating_ip['id'])
John Warrene74890a2015-11-11 15:18:01 -0500609 self.compute_floating_ips_client.associate_floating_ip_to_server(
Yair Friedae0e73d2014-11-24 11:56:26 +0200610 floating_ip['ip'], thing['id'])
611 return floating_ip
612
Sean Dague20e98612016-01-06 14:33:28 -0500613 def create_timestamp(self, ip_address, dev_name=None, mount_path='/mnt',
Matt Riedemannfd5657d2015-09-30 14:47:07 -0700614 private_key=None):
Sean Dague20e98612016-01-06 14:33:28 -0500615 ssh_client = self.get_remote_client(ip_address,
Matt Riedemannfd5657d2015-09-30 14:47:07 -0700616 private_key=private_key)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300617 if dev_name is not None:
618 ssh_client.make_fs(dev_name)
Ken'ichi Ohmichi4e5a69e2017-03-01 18:15:29 -0800619 ssh_client.exec_command('sudo mount /dev/%s %s' % (dev_name,
620 mount_path))
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300621 cmd_timestamp = 'sudo sh -c "date > %s/timestamp; sync"' % mount_path
622 ssh_client.exec_command(cmd_timestamp)
623 timestamp = ssh_client.exec_command('sudo cat %s/timestamp'
624 % mount_path)
625 if dev_name is not None:
Ken'ichi Ohmichi4e5a69e2017-03-01 18:15:29 -0800626 ssh_client.exec_command('sudo umount %s' % mount_path)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300627 return timestamp
628
Sean Dague20e98612016-01-06 14:33:28 -0500629 def get_timestamp(self, ip_address, dev_name=None, mount_path='/mnt',
Matt Riedemannfd5657d2015-09-30 14:47:07 -0700630 private_key=None):
Sean Dague20e98612016-01-06 14:33:28 -0500631 ssh_client = self.get_remote_client(ip_address,
Matt Riedemannfd5657d2015-09-30 14:47:07 -0700632 private_key=private_key)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300633 if dev_name is not None:
Matt Riedemann076685a2015-09-30 14:38:16 -0700634 ssh_client.mount(dev_name, mount_path)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300635 timestamp = ssh_client.exec_command('sudo cat %s/timestamp'
636 % mount_path)
637 if dev_name is not None:
Ken'ichi Ohmichi4e5a69e2017-03-01 18:15:29 -0800638 ssh_client.exec_command('sudo umount %s' % mount_path)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300639 return timestamp
640
Sean Dague20e98612016-01-06 14:33:28 -0500641 def get_server_ip(self, server):
642 """Get the server fixed or floating IP.
643
644 Based on the configuration we're in, return a correct ip
645 address for validating that a guest is up.
646 """
Alexander Gubanovc8829f82015-11-12 10:35:13 +0200647 if CONF.validation.connect_method == 'floating':
Sean Dague20e98612016-01-06 14:33:28 -0500648 # The tests calling this method don't have a floating IP
zhufl0892cb22016-05-06 14:46:00 +0800649 # and can't make use of the validation resources. So the
Sean Dague20e98612016-01-06 14:33:28 -0500650 # method is creating the floating IP there.
651 return self.create_floating_ip(server)['ip']
652 elif CONF.validation.connect_method == 'fixed':
Matt Riedemanna7782552016-08-08 16:26:01 -0400653 # Determine the network name to look for based on config or creds
654 # provider network resources.
655 if CONF.validation.network_for_ssh:
656 addresses = server['addresses'][
657 CONF.validation.network_for_ssh]
658 else:
659 creds_provider = self._get_credentials_provider()
660 net_creds = creds_provider.get_primary_creds()
661 network = getattr(net_creds, 'network', None)
662 addresses = (server['addresses'][network['name']]
663 if network else [])
Sean Dague20e98612016-01-06 14:33:28 -0500664 for address in addresses:
Matt Riedemanna7782552016-08-08 16:26:01 -0400665 if (address['version'] == CONF.validation.ip_version_for_ssh
666 and address['OS-EXT-IPS:type'] == 'fixed'):
Sean Dague20e98612016-01-06 14:33:28 -0500667 return address['addr']
zhufl955f82b2016-07-22 11:14:34 +0800668 raise exceptions.ServerUnreachable(server_id=server['id'])
Alexander Gubanovc8829f82015-11-12 10:35:13 +0200669 else:
Matthew Treinish4217a702016-10-07 17:27:11 -0400670 raise lib_exc.InvalidConfiguration()
Alexander Gubanovc8829f82015-11-12 10:35:13 +0200671
Andrea Frittoli2e733b52014-07-16 14:12:11 +0100672
Andrea Frittoli4971fc82014-09-25 10:22:20 +0100673class NetworkScenarioTest(ScenarioTest):
Yair Fried1fc32a12014-08-04 09:11:30 +0300674 """Base class for network scenario tests.
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000675
Yair Fried1fc32a12014-08-04 09:11:30 +0300676 This class provide helpers for network scenario tests, using the neutron
677 API. Helpers from ancestor which use the nova network API are overridden
678 with the neutron API.
679
680 This Class also enforces using Neutron instead of novanetwork.
681 Subclassed tests will be skipped if Neutron is not enabled
682
683 """
684
Andrea Frittolib21de6c2015-02-06 20:12:38 +0000685 credentials = ['primary', 'admin']
686
Yair Fried1fc32a12014-08-04 09:11:30 +0300687 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +0000688 def skip_checks(cls):
689 super(NetworkScenarioTest, cls).skip_checks()
Andrea Frittoli2ddc2632014-09-25 11:03:00 +0100690 if not CONF.service_available.neutron:
691 raise cls.skipException('Neutron not available')
Yair Fried1fc32a12014-08-04 09:11:30 +0300692
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -0700693 def _create_network(self, networks_client=None,
zhoubin5058bead72017-02-04 18:01:15 +0800694 tenant_id=None,
Markus Zoeller156b5da2016-07-11 18:10:31 +0200695 namestart='network-smoke-',
696 port_security_enabled=True):
John Warren94d8faf2015-09-15 12:22:24 -0400697 if not networks_client:
698 networks_client = self.networks_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300699 if not tenant_id:
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -0700700 tenant_id = networks_client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300701 name = data_utils.rand_name(namestart)
Matt Riedemann039b2fe2016-09-15 16:12:24 -0400702 network_kwargs = dict(name=name, tenant_id=tenant_id)
703 # Neutron disables port security by default so we have to check the
704 # config before trying to create the network with port_security_enabled
705 if CONF.network_feature_enabled.port_security:
706 network_kwargs['port_security_enabled'] = port_security_enabled
Markus Zoeller156b5da2016-07-11 18:10:31 +0200707 result = networks_client.create_network(**network_kwargs)
Steve Heyman33735f22016-05-24 09:28:08 -0500708 network = result['network']
709
710 self.assertEqual(network['name'], name)
Jordan Pittier9e227c52016-02-09 14:35:18 +0100711 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
zhoubin508bf20b32017-02-03 09:39:14 +0800712 networks_client.delete_network,
Steve Heyman33735f22016-05-24 09:28:08 -0500713 network['id'])
Yair Fried1fc32a12014-08-04 09:11:30 +0300714 return network
715
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -0700716 def _create_subnet(self, network, subnets_client=None,
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000717 routers_client=None, namestart='subnet-smoke',
718 **kwargs):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000719 """Create a subnet for the given network
720
721 within the cidr block configured for tenant networks.
Yair Fried1fc32a12014-08-04 09:11:30 +0300722 """
John Warren3961acd2015-10-02 14:38:53 -0400723 if not subnets_client:
724 subnets_client = self.subnets_client
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000725 if not routers_client:
726 routers_client = self.routers_client
Yair Fried1fc32a12014-08-04 09:11:30 +0300727
728 def cidr_in_use(cidr, tenant_id):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000729 """Check cidr existence
730
lei zhangdd552b22015-11-25 20:41:48 +0800731 :returns: True if subnet with cidr already exist in tenant
732 False else
Yair Fried1fc32a12014-08-04 09:11:30 +0300733 """
jeremy.zhang5870ff12017-05-25 11:24:23 +0800734 cidr_in_use = self.os_admin.subnets_client.list_subnets(
Jordan Pittier64e6b442017-02-20 19:29:02 +0100735 tenant_id=tenant_id, cidr=cidr)['subnets']
Yair Fried1fc32a12014-08-04 09:11:30 +0300736 return len(cidr_in_use) != 0
737
Kirill Shileev14113572014-11-21 16:58:02 +0300738 ip_version = kwargs.pop('ip_version', 4)
739
740 if ip_version == 6:
741 tenant_cidr = netaddr.IPNetwork(
Sean Dagueed6e5862016-04-04 10:49:13 -0400742 CONF.network.project_network_v6_cidr)
743 num_bits = CONF.network.project_network_v6_mask_bits
Kirill Shileev14113572014-11-21 16:58:02 +0300744 else:
Sean Dagueed6e5862016-04-04 10:49:13 -0400745 tenant_cidr = netaddr.IPNetwork(CONF.network.project_network_cidr)
746 num_bits = CONF.network.project_network_mask_bits
Kirill Shileev14113572014-11-21 16:58:02 +0300747
Yair Fried1fc32a12014-08-04 09:11:30 +0300748 result = None
Kirill Shileev14113572014-11-21 16:58:02 +0300749 str_cidr = None
Yair Fried1fc32a12014-08-04 09:11:30 +0300750 # Repeatedly attempt subnet creation with sequential cidr
751 # blocks until an unallocated block is found.
Kirill Shileev14113572014-11-21 16:58:02 +0300752 for subnet_cidr in tenant_cidr.subnet(num_bits):
Yair Fried1fc32a12014-08-04 09:11:30 +0300753 str_cidr = str(subnet_cidr)
Steve Heyman33735f22016-05-24 09:28:08 -0500754 if cidr_in_use(str_cidr, tenant_id=network['tenant_id']):
Yair Fried1fc32a12014-08-04 09:11:30 +0300755 continue
756
757 subnet = dict(
758 name=data_utils.rand_name(namestart),
Steve Heyman33735f22016-05-24 09:28:08 -0500759 network_id=network['id'],
760 tenant_id=network['tenant_id'],
Yair Fried1fc32a12014-08-04 09:11:30 +0300761 cidr=str_cidr,
Kirill Shileev14113572014-11-21 16:58:02 +0300762 ip_version=ip_version,
Yair Fried1fc32a12014-08-04 09:11:30 +0300763 **kwargs
764 )
765 try:
John Warren3961acd2015-10-02 14:38:53 -0400766 result = subnets_client.create_subnet(**subnet)
Yair Fried1fc32a12014-08-04 09:11:30 +0300767 break
Masayuki Igawad9388762015-01-20 14:56:42 +0900768 except lib_exc.Conflict as e:
Yair Fried1fc32a12014-08-04 09:11:30 +0300769 is_overlapping_cidr = 'overlaps with another subnet' in str(e)
770 if not is_overlapping_cidr:
771 raise
772 self.assertIsNotNone(result, 'Unable to allocate tenant network')
Steve Heyman33735f22016-05-24 09:28:08 -0500773
774 subnet = result['subnet']
775 self.assertEqual(subnet['cidr'], str_cidr)
776
777 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
778 subnets_client.delete_subnet, subnet['id'])
779
Yair Fried1fc32a12014-08-04 09:11:30 +0300780 return subnet
781
Kirill Shileev14113572014-11-21 16:58:02 +0300782 def _get_server_port_id_and_ip4(self, server, ip_addr=None):
jeremy.zhang5870ff12017-05-25 11:24:23 +0800783 ports = self.os_admin.ports_client.list_ports(
Jordan Pittier64e6b442017-02-20 19:29:02 +0100784 device_id=server['id'], fixed_ip=ip_addr)['ports']
Kobi Samoray166500a2016-10-09 14:42:48 +0300785 # A port can have more than one IP address in some cases.
Sean M. Collins2e896832015-12-15 13:58:47 -0500786 # If the network is dual-stack (IPv4 + IPv6), this port is associated
787 # with 2 subnets
Vasyl Saienko8fd517c2016-05-30 09:52:54 +0300788 p_status = ['ACTIVE']
789 # NOTE(vsaienko) With Ironic, instances live on separate hardware
790 # servers. Neutron does not bind ports for Ironic instances, as a
791 # result the port remains in the DOWN state.
Vasyl Saienkoc8aa34b2016-08-01 14:18:37 +0300792 # TODO(vsaienko) remove once bug: #1599836 is resolved.
Thiago Paiva66cded22016-08-15 14:55:58 -0300793 if getattr(CONF.service_available, 'ironic', False):
Vasyl Saienko8fd517c2016-05-30 09:52:54 +0300794 p_status.append('DOWN')
Daniel Mellado9e3e1062015-08-06 18:07:05 +0200795 port_map = [(p["id"], fxip["ip_address"])
796 for p in ports
797 for fxip in p["fixed_ips"]
Yatin Kumbhareee4924c2016-06-09 15:12:06 +0530798 if netutils.is_valid_ipv4(fxip["ip_address"])
Vasyl Saienko8fd517c2016-05-30 09:52:54 +0300799 and p['status'] in p_status]
Kevin Benton1d0c1dc2016-02-04 14:30:08 -0800800 inactive = [p for p in ports if p['status'] != 'ACTIVE']
801 if inactive:
802 LOG.warning("Instance has ports that are not ACTIVE: %s", inactive)
Daniel Mellado9e3e1062015-08-06 18:07:05 +0200803
Masayuki Igawaf9009b42017-04-10 14:49:29 +0900804 self.assertNotEmpty(port_map,
John L. Villalovosb83286f2015-11-04 14:46:57 -0800805 "No IPv4 addresses found in: %s" % ports)
Daniel Mellado9e3e1062015-08-06 18:07:05 +0200806 self.assertEqual(len(port_map), 1,
807 "Found multiple IPv4 addresses: %s. "
808 "Unable to determine which port to target."
809 % port_map)
810 return port_map[0]
Yair Fried1fc32a12014-08-04 09:11:30 +0300811
David Shrewsbury9bac3662014-08-07 15:07:01 -0400812 def _get_network_by_name(self, network_name):
jeremy.zhang5870ff12017-05-25 11:24:23 +0800813 net = self.os_admin.networks_client.list_networks(
Jordan Pittier64e6b442017-02-20 19:29:02 +0100814 name=network_name)['networks']
Ferenc Horváth268ccce2017-06-08 12:39:02 +0200815 self.assertNotEmpty(net,
Adam Gandelman878a5fd2015-03-30 14:33:36 -0700816 "Unable to get network by name: %s" % network_name)
Steve Heyman33735f22016-05-24 09:28:08 -0500817 return net[0]
David Shrewsbury9bac3662014-08-07 15:07:01 -0400818
Yair Friedae0e73d2014-11-24 11:56:26 +0200819 def create_floating_ip(self, thing, external_network_id=None,
820 port_id=None, client=None):
Ken'ichi Ohmichia112a592015-11-17 08:49:37 +0000821 """Create a floating IP and associates to a resource/port on Neutron"""
Yair Friedae0e73d2014-11-24 11:56:26 +0200822 if not external_network_id:
823 external_network_id = CONF.network.public_network_id
Yair Frieddb6c9e92014-08-06 08:53:13 +0300824 if not client:
John Warrenfbf2a892015-11-17 12:36:14 -0500825 client = self.floating_ips_client
Yair Fried1fc32a12014-08-04 09:11:30 +0300826 if not port_id:
Kirill Shileev14113572014-11-21 16:58:02 +0300827 port_id, ip4 = self._get_server_port_id_and_ip4(thing)
828 else:
829 ip4 = None
David Kranz34e88122014-12-11 15:24:05 -0500830 result = client.create_floatingip(
Yair Fried1fc32a12014-08-04 09:11:30 +0300831 floating_network_id=external_network_id,
832 port_id=port_id,
Kirill Shileev14113572014-11-21 16:58:02 +0300833 tenant_id=thing['tenant_id'],
834 fixed_ip_address=ip4
Yair Fried1fc32a12014-08-04 09:11:30 +0300835 )
Steve Heyman33735f22016-05-24 09:28:08 -0500836 floating_ip = result['floatingip']
Jordan Pittier9e227c52016-02-09 14:35:18 +0100837 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
zhoubin508bf20b32017-02-03 09:39:14 +0800838 client.delete_floatingip,
Steve Heyman33735f22016-05-24 09:28:08 -0500839 floating_ip['id'])
Yair Fried1fc32a12014-08-04 09:11:30 +0300840 return floating_ip
841
842 def _associate_floating_ip(self, floating_ip, server):
Kirill Shileev14113572014-11-21 16:58:02 +0300843 port_id, _ = self._get_server_port_id_and_ip4(server)
Steve Heyman33735f22016-05-24 09:28:08 -0500844 kwargs = dict(port_id=port_id)
845 floating_ip = self.floating_ips_client.update_floatingip(
846 floating_ip['id'], **kwargs)['floatingip']
847 self.assertEqual(port_id, floating_ip['port_id'])
Yair Fried1fc32a12014-08-04 09:11:30 +0300848 return floating_ip
849
850 def _disassociate_floating_ip(self, floating_ip):
Steve Heyman33735f22016-05-24 09:28:08 -0500851 """:param floating_ip: floating_ips_client.create_floatingip"""
852 kwargs = dict(port_id=None)
853 floating_ip = self.floating_ips_client.update_floatingip(
854 floating_ip['id'], **kwargs)['floatingip']
855 self.assertIsNone(floating_ip['port_id'])
Yair Fried1fc32a12014-08-04 09:11:30 +0300856 return floating_ip
857
Yair Fried45f92952014-06-26 05:19:19 +0300858 def check_floating_ip_status(self, floating_ip, status):
Carl Baldwina754e2d2014-10-23 22:47:41 +0000859 """Verifies floatingip reaches the given status
Yair Fried45f92952014-06-26 05:19:19 +0300860
Steve Heyman33735f22016-05-24 09:28:08 -0500861 :param dict floating_ip: floating IP dict to check status
Yair Fried45f92952014-06-26 05:19:19 +0300862 :param status: target status
863 :raises: AssertionError if status doesn't match
864 """
Steve Heyman33735f22016-05-24 09:28:08 -0500865 floatingip_id = floating_ip['id']
866
Carl Baldwina754e2d2014-10-23 22:47:41 +0000867 def refresh():
Steve Heyman33735f22016-05-24 09:28:08 -0500868 result = (self.floating_ips_client.
869 show_floatingip(floatingip_id)['floatingip'])
870 return status == result['status']
Carl Baldwina754e2d2014-10-23 22:47:41 +0000871
zhufl4dda94e2017-03-14 16:14:46 +0800872 if not test_utils.call_until_true(refresh,
873 CONF.network.build_timeout,
874 CONF.network.build_interval):
875 floating_ip = self.floating_ips_client.show_floatingip(
876 floatingip_id)['floatingip']
877 self.assertEqual(status, floating_ip['status'],
878 message="FloatingIP: {fp} is at status: {cst}. "
879 "failed to reach status: {st}"
880 .format(fp=floating_ip, cst=floating_ip['status'],
881 st=status))
Yair Fried45f92952014-06-26 05:19:19 +0300882 LOG.info("FloatingIP: {fp} is at status: {st}"
883 .format(fp=floating_ip, st=status))
884
Yair Fried1fc32a12014-08-04 09:11:30 +0300885 def _check_tenant_network_connectivity(self, server,
886 username,
887 private_key,
888 should_connect=True,
889 servers_for_debug=None):
Sean Dagueed6e5862016-04-04 10:49:13 -0400890 if not CONF.network.project_networks_reachable:
Yair Fried1fc32a12014-08-04 09:11:30 +0300891 msg = 'Tenant networks not configured to be reachable.'
892 LOG.info(msg)
893 return
894 # The target login is assumed to have been configured for
895 # key-based authentication by cloud-init.
896 try:
Béla Vancsicsb6dfa082017-03-01 10:44:58 +0100897 for ip_addresses in server['addresses'].values():
Yair Fried1fc32a12014-08-04 09:11:30 +0300898 for ip_address in ip_addresses:
ghanshyam807211c2014-12-18 13:21:22 +0900899 self.check_vm_connectivity(ip_address['addr'],
Yair Friedae0e73d2014-11-24 11:56:26 +0200900 username,
901 private_key,
902 should_connect=should_connect)
Yair Fried1fc32a12014-08-04 09:11:30 +0300903 except Exception as e:
904 LOG.exception('Tenant network connectivity check failed')
905 self._log_console_output(servers_for_debug)
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000906 self._log_net_info(e)
Yair Fried1fc32a12014-08-04 09:11:30 +0300907 raise
908
Yair Friedbc46f592015-11-18 16:29:34 +0200909 def _check_remote_connectivity(self, source, dest, should_succeed=True,
910 nic=None):
YAMAMOTO Takashi4c3ebb02017-01-25 16:04:30 +0900911 """assert ping server via source ssh connection
912
913 Note: This is an internal method. Use check_remote_connectivity
914 instead.
Yair Fried1fc32a12014-08-04 09:11:30 +0300915
916 :param source: RemoteClient: an ssh connection from which to ping
917 :param dest: and IP to ping against
918 :param should_succeed: boolean should ping succeed or not
Yair Friedbc46f592015-11-18 16:29:34 +0200919 :param nic: specific network interface to ping from
Yair Fried1fc32a12014-08-04 09:11:30 +0300920 """
921 def ping_remote():
922 try:
Yair Friedbc46f592015-11-18 16:29:34 +0200923 source.ping_host(dest, nic=nic)
Andrey Pavlov64723762015-04-29 06:24:58 +0300924 except lib_exc.SSHExecCommandFailed:
zhangguoqing6c096642016-01-04 06:17:21 +0000925 LOG.warning('Failed to ping IP: %s via a ssh connection '
Jordan Pittier525ec712016-12-07 17:51:26 +0100926 'from: %s.', dest, source.ssh_client.host)
Yair Fried1fc32a12014-08-04 09:11:30 +0300927 return not should_succeed
928 return should_succeed
929
Jordan Pittier35a63752016-08-30 13:09:12 +0200930 return test_utils.call_until_true(ping_remote,
931 CONF.validation.ping_timeout,
932 1)
Yair Fried1fc32a12014-08-04 09:11:30 +0300933
YAMAMOTO Takashi4c3ebb02017-01-25 16:04:30 +0900934 def check_remote_connectivity(self, source, dest, should_succeed=True,
935 nic=None):
936 """assert ping server via source ssh connection
937
938 :param source: RemoteClient: an ssh connection from which to ping
939 :param dest: and IP to ping against
940 :param should_succeed: boolean should ping succeed or not
941 :param nic: specific network interface to ping from
942 """
943 result = self._check_remote_connectivity(source, dest, should_succeed,
944 nic)
945 source_host = source.ssh_client.host
946 if should_succeed:
947 msg = "Timed out waiting for %s to become reachable from %s" \
948 % (dest, source_host)
949 else:
950 msg = "%s is reachable from %s" % (dest, source_host)
951 self.assertTrue(result, msg)
952
John Warren456d9ae2016-01-12 15:36:33 -0500953 def _create_security_group(self, security_group_rules_client=None,
954 tenant_id=None,
John Warrenf9606e92015-12-10 12:12:42 -0500955 namestart='secgroup-smoke',
956 security_groups_client=None):
John Warren456d9ae2016-01-12 15:36:33 -0500957 if security_group_rules_client is None:
958 security_group_rules_client = self.security_group_rules_client
John Warrenf9606e92015-12-10 12:12:42 -0500959 if security_groups_client is None:
960 security_groups_client = self.security_groups_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300961 if tenant_id is None:
John Warrenf9606e92015-12-10 12:12:42 -0500962 tenant_id = security_groups_client.tenant_id
963 secgroup = self._create_empty_security_group(
964 namestart=namestart, client=security_groups_client,
965 tenant_id=tenant_id)
Yair Fried1fc32a12014-08-04 09:11:30 +0300966
967 # Add rules to the security group
John Warrenf9606e92015-12-10 12:12:42 -0500968 rules = self._create_loginable_secgroup_rule(
John Warren456d9ae2016-01-12 15:36:33 -0500969 security_group_rules_client=security_group_rules_client,
970 secgroup=secgroup,
John Warrenf9606e92015-12-10 12:12:42 -0500971 security_groups_client=security_groups_client)
Yair Fried1fc32a12014-08-04 09:11:30 +0300972 for rule in rules:
Steve Heyman33735f22016-05-24 09:28:08 -0500973 self.assertEqual(tenant_id, rule['tenant_id'])
974 self.assertEqual(secgroup['id'], rule['security_group_id'])
Yair Fried1fc32a12014-08-04 09:11:30 +0300975 return secgroup
976
Yair Frieddb6c9e92014-08-06 08:53:13 +0300977 def _create_empty_security_group(self, client=None, tenant_id=None,
Yair Fried1fc32a12014-08-04 09:11:30 +0300978 namestart='secgroup-smoke'):
979 """Create a security group without rules.
980
981 Default rules will be created:
982 - IPv4 egress to any
983 - IPv6 egress to any
984
985 :param tenant_id: secgroup will be created in this tenant
Steve Heyman33735f22016-05-24 09:28:08 -0500986 :returns: the created security group
Yair Fried1fc32a12014-08-04 09:11:30 +0300987 """
988 if client is None:
John Warrenf9606e92015-12-10 12:12:42 -0500989 client = self.security_groups_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300990 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000991 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300992 sg_name = data_utils.rand_name(namestart)
993 sg_desc = sg_name + " description"
994 sg_dict = dict(name=sg_name,
995 description=sg_desc)
996 sg_dict['tenant_id'] = tenant_id
David Kranz34e88122014-12-11 15:24:05 -0500997 result = client.create_security_group(**sg_dict)
Steve Heyman33735f22016-05-24 09:28:08 -0500998
999 secgroup = result['security_group']
1000 self.assertEqual(secgroup['name'], sg_name)
1001 self.assertEqual(tenant_id, secgroup['tenant_id'])
1002 self.assertEqual(secgroup['description'], sg_desc)
1003
Jordan Pittier9e227c52016-02-09 14:35:18 +01001004 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
Steve Heyman33735f22016-05-24 09:28:08 -05001005 client.delete_security_group, secgroup['id'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001006 return secgroup
1007
Yair Frieddb6c9e92014-08-06 08:53:13 +03001008 def _default_security_group(self, client=None, tenant_id=None):
Yair Fried1fc32a12014-08-04 09:11:30 +03001009 """Get default secgroup for given tenant_id.
1010
Ken'ichi Ohmichid67c8da2016-09-13 16:18:11 -07001011 :returns: default secgroup for given tenant
Yair Fried1fc32a12014-08-04 09:11:30 +03001012 """
1013 if client is None:
John Warrenf9606e92015-12-10 12:12:42 -05001014 client = self.security_groups_client
Yair Frieddb6c9e92014-08-06 08:53:13 +03001015 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +00001016 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001017 sgs = [
Jordan Pittier8ad86172016-04-25 16:20:53 +02001018 sg for sg in list(client.list_security_groups().values())[0]
Yair Fried1fc32a12014-08-04 09:11:30 +03001019 if sg['tenant_id'] == tenant_id and sg['name'] == 'default'
1020 ]
1021 msg = "No default security group for tenant %s." % (tenant_id)
Masayuki Igawaf9009b42017-04-10 14:49:29 +09001022 self.assertNotEmpty(sgs, msg)
Steve Heyman33735f22016-05-24 09:28:08 -05001023 return sgs[0]
Yair Fried1fc32a12014-08-04 09:11:30 +03001024
John Warren456d9ae2016-01-12 15:36:33 -05001025 def _create_security_group_rule(self, secgroup=None,
1026 sec_group_rules_client=None,
John Warrenf9606e92015-12-10 12:12:42 -05001027 tenant_id=None,
1028 security_groups_client=None, **kwargs):
Yair Fried1fc32a12014-08-04 09:11:30 +03001029 """Create a rule from a dictionary of rule parameters.
1030
1031 Create a rule in a secgroup. if secgroup not defined will search for
1032 default secgroup in tenant_id.
1033
Steve Heyman33735f22016-05-24 09:28:08 -05001034 :param secgroup: the security group.
Yair Fried1fc32a12014-08-04 09:11:30 +03001035 :param tenant_id: if secgroup not passed -- the tenant in which to
1036 search for default secgroup
1037 :param kwargs: a dictionary containing rule parameters:
1038 for example, to allow incoming ssh:
1039 rule = {
1040 direction: 'ingress'
1041 protocol:'tcp',
1042 port_range_min: 22,
1043 port_range_max: 22
1044 }
1045 """
John Warren456d9ae2016-01-12 15:36:33 -05001046 if sec_group_rules_client is None:
1047 sec_group_rules_client = self.security_group_rules_client
John Warrenf9606e92015-12-10 12:12:42 -05001048 if security_groups_client is None:
1049 security_groups_client = self.security_groups_client
Yair Frieddb6c9e92014-08-06 08:53:13 +03001050 if not tenant_id:
John Warrenf9606e92015-12-10 12:12:42 -05001051 tenant_id = security_groups_client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001052 if secgroup is None:
John Warrenf9606e92015-12-10 12:12:42 -05001053 secgroup = self._default_security_group(
1054 client=security_groups_client, tenant_id=tenant_id)
Yair Fried1fc32a12014-08-04 09:11:30 +03001055
Steve Heyman33735f22016-05-24 09:28:08 -05001056 ruleset = dict(security_group_id=secgroup['id'],
1057 tenant_id=secgroup['tenant_id'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001058 ruleset.update(kwargs)
1059
John Warren456d9ae2016-01-12 15:36:33 -05001060 sg_rule = sec_group_rules_client.create_security_group_rule(**ruleset)
Steve Heyman33735f22016-05-24 09:28:08 -05001061 sg_rule = sg_rule['security_group_rule']
1062
1063 self.assertEqual(secgroup['tenant_id'], sg_rule['tenant_id'])
1064 self.assertEqual(secgroup['id'], sg_rule['security_group_id'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001065
1066 return sg_rule
1067
John Warren456d9ae2016-01-12 15:36:33 -05001068 def _create_loginable_secgroup_rule(self, security_group_rules_client=None,
1069 secgroup=None,
John Warrenf9606e92015-12-10 12:12:42 -05001070 security_groups_client=None):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001071 """Create loginable security group rule
1072
Alex Stafeyevdd5dde92016-05-08 14:35:04 +03001073 This function will create:
1074 1. egress and ingress tcp port 22 allow rule in order to allow ssh
1075 access for ipv4.
1076 2. egress and ingress ipv6 icmp allow rule, in order to allow icmpv6.
1077 3. egress and ingress ipv4 icmp allow rule, in order to allow icmpv4.
Yair Fried1fc32a12014-08-04 09:11:30 +03001078 """
1079
John Warren456d9ae2016-01-12 15:36:33 -05001080 if security_group_rules_client is None:
1081 security_group_rules_client = self.security_group_rules_client
John Warrenf9606e92015-12-10 12:12:42 -05001082 if security_groups_client is None:
1083 security_groups_client = self.security_groups_client
Yair Fried1fc32a12014-08-04 09:11:30 +03001084 rules = []
1085 rulesets = [
1086 dict(
1087 # ssh
1088 protocol='tcp',
1089 port_range_min=22,
1090 port_range_max=22,
1091 ),
1092 dict(
1093 # ping
1094 protocol='icmp',
Andreas Scheuring887ca8e2015-02-03 17:56:12 +01001095 ),
1096 dict(
1097 # ipv6-icmp for ping6
1098 protocol='icmp',
1099 ethertype='IPv6',
Yair Fried1fc32a12014-08-04 09:11:30 +03001100 )
1101 ]
John Warren456d9ae2016-01-12 15:36:33 -05001102 sec_group_rules_client = security_group_rules_client
Yair Fried1fc32a12014-08-04 09:11:30 +03001103 for ruleset in rulesets:
1104 for r_direction in ['ingress', 'egress']:
1105 ruleset['direction'] = r_direction
1106 try:
1107 sg_rule = self._create_security_group_rule(
John Warren456d9ae2016-01-12 15:36:33 -05001108 sec_group_rules_client=sec_group_rules_client,
1109 secgroup=secgroup,
John Warrenf9606e92015-12-10 12:12:42 -05001110 security_groups_client=security_groups_client,
1111 **ruleset)
Masayuki Igawad9388762015-01-20 14:56:42 +09001112 except lib_exc.Conflict as ex:
Yair Fried1fc32a12014-08-04 09:11:30 +03001113 # if rule already exist - skip rule and continue
1114 msg = 'Security group rule already exists'
1115 if msg not in ex._error_string:
1116 raise ex
1117 else:
Steve Heyman33735f22016-05-24 09:28:08 -05001118 self.assertEqual(r_direction, sg_rule['direction'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001119 rules.append(sg_rule)
1120
1121 return rules
1122
Yair Frieddb6c9e92014-08-06 08:53:13 +03001123 def _get_router(self, client=None, tenant_id=None):
Yair Fried1fc32a12014-08-04 09:11:30 +03001124 """Retrieve a router for the given tenant id.
1125
1126 If a public router has been configured, it will be returned.
1127
1128 If a public router has not been configured, but a public
1129 network has, a tenant router will be created and returned that
1130 routes traffic to the public network.
1131 """
Yair Frieddb6c9e92014-08-06 08:53:13 +03001132 if not client:
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +00001133 client = self.routers_client
Yair Frieddb6c9e92014-08-06 08:53:13 +03001134 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +00001135 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001136 router_id = CONF.network.public_router_id
1137 network_id = CONF.network.public_network_id
1138 if router_id:
David Kranzca4c7e72015-05-27 11:39:19 -04001139 body = client.show_router(router_id)
Steve Heyman33735f22016-05-24 09:28:08 -05001140 return body['router']
Yair Fried1fc32a12014-08-04 09:11:30 +03001141 elif network_id:
Yair Frieddb6c9e92014-08-06 08:53:13 +03001142 router = self._create_router(client, tenant_id)
Steve Heyman33735f22016-05-24 09:28:08 -05001143 kwargs = {'external_gateway_info': dict(network_id=network_id)}
1144 router = client.update_router(router['id'], **kwargs)['router']
Yair Fried1fc32a12014-08-04 09:11:30 +03001145 return router
1146 else:
1147 raise Exception("Neither of 'public_router_id' or "
1148 "'public_network_id' has been defined.")
1149
Yair Frieddb6c9e92014-08-06 08:53:13 +03001150 def _create_router(self, client=None, tenant_id=None,
1151 namestart='router-smoke'):
1152 if not client:
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +00001153 client = self.routers_client
Yair Frieddb6c9e92014-08-06 08:53:13 +03001154 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +00001155 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001156 name = data_utils.rand_name(namestart)
David Kranz34e88122014-12-11 15:24:05 -05001157 result = client.create_router(name=name,
1158 admin_state_up=True,
1159 tenant_id=tenant_id)
Steve Heyman33735f22016-05-24 09:28:08 -05001160 router = result['router']
1161 self.assertEqual(router['name'], name)
1162 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
1163 client.delete_router,
1164 router['id'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001165 return router
1166
Alok Maurya6384bbb2014-07-13 06:44:29 -07001167 def _update_router_admin_state(self, router, admin_state_up):
Steve Heyman33735f22016-05-24 09:28:08 -05001168 kwargs = dict(admin_state_up=admin_state_up)
1169 router = self.routers_client.update_router(
1170 router['id'], **kwargs)['router']
1171 self.assertEqual(admin_state_up, router['admin_state_up'])
Alok Maurya6384bbb2014-07-13 06:44:29 -07001172
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -07001173 def create_networks(self, networks_client=None,
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +00001174 routers_client=None, subnets_client=None,
Markus Zoeller156b5da2016-07-11 18:10:31 +02001175 tenant_id=None, dns_nameservers=None,
1176 port_security_enabled=True):
Yair Fried1fc32a12014-08-04 09:11:30 +03001177 """Create a network with a subnet connected to a router.
1178
David Shrewsbury9bac3662014-08-07 15:07:01 -04001179 The baremetal driver is a special case since all nodes are
1180 on the same shared network.
1181
Yair Fried413bf2d2014-11-19 17:07:11 +02001182 :param tenant_id: id of tenant to create resources in.
1183 :param dns_nameservers: list of dns servers to send to subnet.
Yair Fried1fc32a12014-08-04 09:11:30 +03001184 :returns: network, subnet, router
1185 """
Thiago Paiva66cded22016-08-15 14:55:58 -03001186 if CONF.network.shared_physical_network:
David Shrewsbury9bac3662014-08-07 15:07:01 -04001187 # NOTE(Shrews): This exception is for environments where tenant
1188 # credential isolation is available, but network separation is
1189 # not (the current baremetal case). Likely can be removed when
1190 # test account mgmt is reworked:
1191 # https://blueprints.launchpad.net/tempest/+spec/test-accounts
Adam Gandelman878a5fd2015-03-30 14:33:36 -07001192 if not CONF.compute.fixed_network_name:
1193 m = 'fixed_network_name must be specified in config'
Matthew Treinish4217a702016-10-07 17:27:11 -04001194 raise lib_exc.InvalidConfiguration(m)
David Shrewsbury9bac3662014-08-07 15:07:01 -04001195 network = self._get_network_by_name(
1196 CONF.compute.fixed_network_name)
1197 router = None
1198 subnet = None
1199 else:
John Warren94d8faf2015-09-15 12:22:24 -04001200 network = self._create_network(
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -07001201 networks_client=networks_client,
Markus Zoeller156b5da2016-07-11 18:10:31 +02001202 tenant_id=tenant_id,
1203 port_security_enabled=port_security_enabled)
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +00001204 router = self._get_router(client=routers_client,
1205 tenant_id=tenant_id)
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -07001206 subnet_kwargs = dict(network=network,
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +00001207 subnets_client=subnets_client,
1208 routers_client=routers_client)
Yair Fried413bf2d2014-11-19 17:07:11 +02001209 # use explicit check because empty list is a valid option
1210 if dns_nameservers is not None:
1211 subnet_kwargs['dns_nameservers'] = dns_nameservers
1212 subnet = self._create_subnet(**subnet_kwargs)
Steve Heyman33735f22016-05-24 09:28:08 -05001213 if not routers_client:
1214 routers_client = self.routers_client
1215 router_id = router['id']
1216 routers_client.add_router_interface(router_id,
1217 subnet_id=subnet['id'])
1218
1219 # save a cleanup job to remove this association between
1220 # router and subnet
1221 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
1222 routers_client.remove_router_interface, router_id,
1223 subnet_id=subnet['id'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001224 return network, subnet, router
1225
1226
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001227class EncryptionScenarioTest(ScenarioTest):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001228 """Base class for encryption scenario tests"""
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001229
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001230 credentials = ['primary', 'admin']
David Kranz4cc852b2015-03-09 14:57:11 -04001231
1232 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001233 def setup_clients(cls):
1234 super(EncryptionScenarioTest, cls).setup_clients()
Jordan Pittier8160d312017-04-18 11:52:23 +02001235 cls.admin_volume_types_client = cls.os_admin.volume_types_v2_client
ghanshyam3bd0d2b2017-03-23 01:57:28 +00001236 cls.admin_encryption_types_client =\
Jordan Pittier8160d312017-04-18 11:52:23 +02001237 cls.os_admin.encryption_types_v2_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001238
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001239 def create_encryption_type(self, client=None, type_id=None, provider=None,
1240 key_size=None, cipher=None,
1241 control_location=None):
1242 if not client:
Ken'ichi Ohmichia6ebf622016-08-25 11:52:27 -07001243 client = self.admin_encryption_types_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001244 if not type_id:
1245 volume_type = self.create_volume_type()
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001246 type_id = volume_type['id']
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001247 LOG.debug("Creating an encryption type for volume type: %s", type_id)
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001248 client.create_encryption_type(
1249 type_id, provider=provider, key_size=key_size, cipher=cipher,
John Warrend053ded2015-08-13 15:22:48 +00001250 control_location=control_location)['encryption']
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001251
lkuchlan3023e752017-06-08 12:53:13 +03001252 def create_encrypted_volume(self, encryption_provider, volume_type,
1253 key_size=256, cipher='aes-xts-plain64',
1254 control_location='front-end'):
1255 volume_type = self.create_volume_type(name=volume_type)
1256 self.create_encryption_type(type_id=volume_type['id'],
1257 provider=encryption_provider,
1258 key_size=key_size,
1259 cipher=cipher,
1260 control_location=control_location)
1261 return self.create_volume(volume_type=volume_type['name'])
1262
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001263
Masayuki Igawa0870db52015-09-18 21:08:36 +09001264class ObjectStorageScenarioTest(ScenarioTest):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001265 """Provide harness to do Object Storage scenario tests.
Chris Dent0d494112014-08-26 13:48:30 +01001266
1267 Subclasses implement the tests that use the methods provided by this
1268 class.
1269 """
1270
1271 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001272 def skip_checks(cls):
Masayuki Igawa0870db52015-09-18 21:08:36 +09001273 super(ObjectStorageScenarioTest, cls).skip_checks()
Chris Dent0d494112014-08-26 13:48:30 +01001274 if not CONF.service_available.swift:
1275 skip_msg = ("%s skipped as swift is not available" %
1276 cls.__name__)
1277 raise cls.skipException(skip_msg)
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001278
1279 @classmethod
1280 def setup_credentials(cls):
Masayuki Igawa60ea6c52014-10-15 17:32:14 +09001281 cls.set_network_resources()
Masayuki Igawa0870db52015-09-18 21:08:36 +09001282 super(ObjectStorageScenarioTest, cls).setup_credentials()
Matthew Treinish4a596932015-03-06 20:37:01 -05001283 operator_role = CONF.object_storage.operator_role
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +01001284 cls.os_operator = cls.get_client_manager(roles=[operator_role])
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001285
1286 @classmethod
1287 def setup_clients(cls):
Masayuki Igawa0870db52015-09-18 21:08:36 +09001288 super(ObjectStorageScenarioTest, cls).setup_clients()
Chris Dent0d494112014-08-26 13:48:30 +01001289 # Clients for Swift
Matthew Treinish8f268292015-02-24 20:01:36 -05001290 cls.account_client = cls.os_operator.account_client
1291 cls.container_client = cls.os_operator.container_client
1292 cls.object_client = cls.os_operator.object_client
Chris Dent0d494112014-08-26 13:48:30 +01001293
Chris Dentde456a12014-09-10 12:41:15 +01001294 def get_swift_stat(self):
Chris Dent0d494112014-08-26 13:48:30 +01001295 """get swift status for our user account."""
1296 self.account_client.list_account_containers()
1297 LOG.debug('Swift status information obtained successfully')
1298
Chris Dentde456a12014-09-10 12:41:15 +01001299 def create_container(self, container_name=None):
Chris Dent0d494112014-08-26 13:48:30 +01001300 name = container_name or data_utils.rand_name(
1301 'swift-scenario-container')
1302 self.container_client.create_container(name)
1303 # look for the container to assure it is created
Chris Dentde456a12014-09-10 12:41:15 +01001304 self.list_and_check_container_objects(name)
Jordan Pittier525ec712016-12-07 17:51:26 +01001305 LOG.debug('Container %s created', name)
Jordan Pittier9e227c52016-02-09 14:35:18 +01001306 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
Chris Dent1d4313a2014-10-28 12:16:48 +00001307 self.container_client.delete_container,
1308 name)
Chris Dent0d494112014-08-26 13:48:30 +01001309 return name
1310
Chris Dentde456a12014-09-10 12:41:15 +01001311 def delete_container(self, container_name):
Chris Dent0d494112014-08-26 13:48:30 +01001312 self.container_client.delete_container(container_name)
Jordan Pittier525ec712016-12-07 17:51:26 +01001313 LOG.debug('Container %s deleted', container_name)
Chris Dent0d494112014-08-26 13:48:30 +01001314
Chris Dentde456a12014-09-10 12:41:15 +01001315 def upload_object_to_container(self, container_name, obj_name=None):
Chris Dent0d494112014-08-26 13:48:30 +01001316 obj_name = obj_name or data_utils.rand_name('swift-scenario-object')
Jordan Pittierb84f2d42016-12-21 19:02:15 +01001317 obj_data = data_utils.random_bytes()
Chris Dent0d494112014-08-26 13:48:30 +01001318 self.object_client.create_object(container_name, obj_name, obj_data)
Jordan Pittier9e227c52016-02-09 14:35:18 +01001319 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
Chris Dent1d4313a2014-10-28 12:16:48 +00001320 self.object_client.delete_object,
1321 container_name,
1322 obj_name)
Chris Dent0d494112014-08-26 13:48:30 +01001323 return obj_name, obj_data
1324
Chris Dentde456a12014-09-10 12:41:15 +01001325 def delete_object(self, container_name, filename):
Chris Dent0d494112014-08-26 13:48:30 +01001326 self.object_client.delete_object(container_name, filename)
Chris Dentde456a12014-09-10 12:41:15 +01001327 self.list_and_check_container_objects(container_name,
1328 not_present_obj=[filename])
Chris Dent0d494112014-08-26 13:48:30 +01001329
Chris Dentde456a12014-09-10 12:41:15 +01001330 def list_and_check_container_objects(self, container_name,
1331 present_obj=None,
1332 not_present_obj=None):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001333 # List objects for a given container and assert which are present and
1334 # which are not.
Ghanshyam2a180b82014-06-16 13:54:22 +09001335 if present_obj is None:
1336 present_obj = []
1337 if not_present_obj is None:
1338 not_present_obj = []
Chris Dent0d494112014-08-26 13:48:30 +01001339 _, object_list = self.container_client.list_container_contents(
1340 container_name)
1341 if present_obj:
1342 for obj in present_obj:
1343 self.assertIn(obj, object_list)
1344 if not_present_obj:
1345 for obj in not_present_obj:
1346 self.assertNotIn(obj, object_list)
1347
Chris Dentde456a12014-09-10 12:41:15 +01001348 def change_container_acl(self, container_name, acl):
Chris Dent0d494112014-08-26 13:48:30 +01001349 metadata_param = {'metadata_prefix': 'x-container-',
1350 'metadata': {'read': acl}}
1351 self.container_client.update_container_metadata(container_name,
1352 **metadata_param)
1353 resp, _ = self.container_client.list_container_metadata(container_name)
1354 self.assertEqual(resp['x-container-read'], acl)
1355
Chris Dentde456a12014-09-10 12:41:15 +01001356 def download_and_verify(self, container_name, obj_name, expected_data):
Chris Dent0d494112014-08-26 13:48:30 +01001357 _, obj = self.object_client.get_object(container_name, obj_name)
1358 self.assertEqual(obj, expected_data)