blob: 9b8c7a01f14ec9d4b5209763b651bb84d72e8b3c [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
lkuchlan73ed1f32017-07-06 16:22:12 +0300241 def create_volume_snapshot(self, volume_id, name=None, description=None,
242 metadata=None, force=False):
243 name = name or data_utils.rand_name(
244 self.__class__.__name__ + '-snapshot')
245 snapshot = self.snapshots_client.create_snapshot(
246 volume_id=volume_id,
247 force=force,
248 display_name=name,
249 description=description,
250 metadata=metadata)['snapshot']
251 self.addCleanup(self.snapshots_client.wait_for_resource_deletion,
252 snapshot['id'])
253 self.addCleanup(self.snapshots_client.delete_snapshot, snapshot['id'])
254 waiters.wait_for_volume_resource_status(self.snapshots_client,
255 snapshot['id'], 'available')
256 return snapshot
257
scottda61f68ac2016-06-07 12:07:55 -0600258 def create_volume_type(self, client=None, name=None, backend_name=None):
259 if not client:
zhufl708821c2017-07-12 16:08:34 +0800260 client = self.os_admin.volume_types_v2_client
scottda61f68ac2016-06-07 12:07:55 -0600261 if not name:
262 class_name = self.__class__.__name__
263 name = data_utils.rand_name(class_name + '-volume-type')
264 randomized_name = data_utils.rand_name('scenario-type-' + name)
265
266 LOG.debug("Creating a volume type: %s on backend %s",
267 randomized_name, backend_name)
268 extra_specs = {}
269 if backend_name:
270 extra_specs = {"volume_backend_name": backend_name}
271
272 body = client.create_volume_type(name=randomized_name,
273 extra_specs=extra_specs)
274 volume_type = body['volume_type']
275 self.assertIn('id', volume_type)
276 self.addCleanup(client.delete_volume_type, volume_type['id'])
277 return volume_type
278
Yair Fried1fc32a12014-08-04 09:11:30 +0300279 def _create_loginable_secgroup_rule(self, secgroup_id=None):
John Warrenf2345512015-12-10 13:39:30 -0500280 _client = self.compute_security_groups_client
John Warren5cdbf422016-01-05 12:42:43 -0500281 _client_rules = self.compute_security_group_rules_client
Andrea Frittoli247058f2014-07-16 16:09:22 +0100282 if secgroup_id is None:
ghanshyamb610b772015-08-24 17:29:38 +0900283 sgs = _client.list_security_groups()['security_groups']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100284 for sg in sgs:
285 if sg['name'] == 'default':
286 secgroup_id = sg['id']
287
288 # These rules are intended to permit inbound ssh and icmp
289 # traffic from all sources, so no group_id is provided.
290 # Setting a group_id would only permit traffic from ports
291 # belonging to the same security group.
292 rulesets = [
293 {
294 # ssh
Ken'ichi Ohmichieb7eeec2015-07-21 01:00:06 +0000295 'ip_protocol': 'tcp',
Andrea Frittoli247058f2014-07-16 16:09:22 +0100296 'from_port': 22,
297 'to_port': 22,
298 'cidr': '0.0.0.0/0',
299 },
300 {
301 # ping
Ken'ichi Ohmichieb7eeec2015-07-21 01:00:06 +0000302 'ip_protocol': 'icmp',
Andrea Frittoli247058f2014-07-16 16:09:22 +0100303 'from_port': -1,
304 'to_port': -1,
305 'cidr': '0.0.0.0/0',
306 }
307 ]
308 rules = list()
309 for ruleset in rulesets:
Ken'ichi Ohmichieb7eeec2015-07-21 01:00:06 +0000310 sg_rule = _client_rules.create_security_group_rule(
ghanshyam0a5e1232015-08-24 16:59:59 +0900311 parent_group_id=secgroup_id, **ruleset)['security_group_rule']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100312 rules.append(sg_rule)
313 return rules
314
Yair Fried1fc32a12014-08-04 09:11:30 +0300315 def _create_security_group(self):
Andrea Frittoli247058f2014-07-16 16:09:22 +0100316 # Create security group
317 sg_name = data_utils.rand_name(self.__class__.__name__)
318 sg_desc = sg_name + " description"
John Warrenf2345512015-12-10 13:39:30 -0500319 secgroup = self.compute_security_groups_client.create_security_group(
ghanshyamb610b772015-08-24 17:29:38 +0900320 name=sg_name, description=sg_desc)['security_group']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100321 self.assertEqual(secgroup['name'], sg_name)
322 self.assertEqual(secgroup['description'], sg_desc)
John Warrenf2345512015-12-10 13:39:30 -0500323 self.addCleanup(
Jordan Pittier9e227c52016-02-09 14:35:18 +0100324 test_utils.call_and_ignore_notfound_exc,
John Warrenf2345512015-12-10 13:39:30 -0500325 self.compute_security_groups_client.delete_security_group,
326 secgroup['id'])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100327
328 # Add rules to the security group
Yair Fried1fc32a12014-08-04 09:11:30 +0300329 self._create_loginable_secgroup_rule(secgroup['id'])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100330
331 return secgroup
332
zhuflf52c7592017-05-25 13:55:24 +0800333 def get_remote_client(self, ip_address, username=None, private_key=None,
334 server=None):
JordanP3fe2dc32014-11-17 13:06:01 +0100335 """Get a SSH client to a remote server
336
Sean Dague20e98612016-01-06 14:33:28 -0500337 @param ip_address the server floating or fixed IP address to use
338 for ssh validation
JordanP3fe2dc32014-11-17 13:06:01 +0100339 @param username name of the Linux account on the remote server
340 @param private_key the SSH private key to use
zhuflf52c7592017-05-25 13:55:24 +0800341 @param server: server dict, used for debugging purposes
JordanP3fe2dc32014-11-17 13:06:01 +0100342 @return a RemoteClient object
343 """
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700344
Andrea Frittoli247058f2014-07-16 16:09:22 +0100345 if username is None:
lanoux283273b2015-12-04 03:01:54 -0800346 username = CONF.validation.image_ssh_user
wantwatering896300c2015-03-27 15:17:42 +0800347 # Set this with 'keypair' or others to log in with keypair or
348 # username/password.
lanoux5fc14522015-09-21 08:17:35 +0000349 if CONF.validation.auth_method == 'keypair':
wantwatering896300c2015-03-27 15:17:42 +0800350 password = None
351 if private_key is None:
352 private_key = self.keypair['private_key']
353 else:
lanoux283273b2015-12-04 03:01:54 -0800354 password = CONF.validation.image_ssh_password
wantwatering896300c2015-03-27 15:17:42 +0800355 private_key = None
zhuflf52c7592017-05-25 13:55:24 +0800356 linux_client = remote_client.RemoteClient(
357 ip_address, username, pkey=private_key, password=password,
358 server=server, servers_client=self.servers_client)
359 linux_client.validate_authentication()
Andrea Frittoli247058f2014-07-16 16:09:22 +0100360 return linux_client
361
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000362 def _image_create(self, name, fmt, path,
363 disk_format=None, properties=None):
Ghanshyam2a180b82014-06-16 13:54:22 +0900364 if properties is None:
365 properties = {}
Andrea Frittoli247058f2014-07-16 16:09:22 +0100366 name = data_utils.rand_name('%s-' % name)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100367 params = {
368 'name': name,
369 'container_format': fmt,
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000370 'disk_format': disk_format or fmt,
Andrea Frittoli247058f2014-07-16 16:09:22 +0100371 }
Matt Riedemann2aa19d42016-06-06 17:45:41 -0400372 if CONF.image_feature_enabled.api_v1:
373 params['is_public'] = 'False'
374 params['properties'] = properties
Ken'ichi Ohmichi02bcdf32016-06-17 16:41:26 -0700375 params = {'headers': common_image.image_meta_to_headers(**params)}
Matt Riedemann2aa19d42016-06-06 17:45:41 -0400376 else:
377 params['visibility'] = 'private'
378 # Additional properties are flattened out in the v2 API.
379 params.update(properties)
380 body = self.image_client.create_image(**params)
381 image = body['image'] if 'image' in body else body
Andrea Frittoli247058f2014-07-16 16:09:22 +0100382 self.addCleanup(self.image_client.delete_image, image['id'])
383 self.assertEqual("queued", image['status'])
zhang.leia4b1cef2016-03-01 10:50:01 +0800384 with open(path, 'rb') as image_file:
Matt Riedemann2aa19d42016-06-06 17:45:41 -0400385 if CONF.image_feature_enabled.api_v1:
386 self.image_client.update_image(image['id'], data=image_file)
387 else:
388 self.image_client.store_image_file(image['id'], image_file)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100389 return image['id']
390
391 def glance_image_create(self):
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300392 img_path = CONF.scenario.img_dir + "/" + CONF.scenario.img_file
Andrea Frittoli247058f2014-07-16 16:09:22 +0100393 aki_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.aki_img_file
394 ari_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.ari_img_file
395 ami_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.ami_img_file
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300396 img_container_format = CONF.scenario.img_container_format
397 img_disk_format = CONF.scenario.img_disk_format
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000398 img_properties = CONF.scenario.img_properties
PranaliD2aa523c2016-06-07 03:54:34 -0400399 LOG.debug("paths: img: %s, container_format: %s, disk_format: %s, "
Jordan Pittier525ec712016-12-07 17:51:26 +0100400 "properties: %s, ami: %s, ari: %s, aki: %s",
401 img_path, img_container_format, img_disk_format,
402 img_properties, ami_img_path, ari_img_path, aki_img_path)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100403 try:
Jordan Pittier1e443ec2015-11-20 16:15:58 +0100404 image = self._image_create('scenario-img',
405 img_container_format,
406 img_path,
407 disk_format=img_disk_format,
408 properties=img_properties)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100409 except IOError:
410 LOG.debug("A qcow2 image was not found. Try to get a uec image.")
411 kernel = self._image_create('scenario-aki', 'aki', aki_img_path)
412 ramdisk = self._image_create('scenario-ari', 'ari', ari_img_path)
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000413 properties = {'kernel_id': kernel, 'ramdisk_id': ramdisk}
Jordan Pittier1e443ec2015-11-20 16:15:58 +0100414 image = self._image_create('scenario-ami', 'ami',
415 path=ami_img_path,
416 properties=properties)
Jordan Pittier525ec712016-12-07 17:51:26 +0100417 LOG.debug("image:%s", image)
Jordan Pittier1e443ec2015-11-20 16:15:58 +0100418
419 return image
Andrea Frittoli247058f2014-07-16 16:09:22 +0100420
Ihar Hrachyshkaa9dca2b2017-04-04 14:17:11 -0700421 def _log_console_output(self, servers=None, client=None):
Matthew Treinish42a3f3a2014-09-04 15:04:53 -0400422 if not CONF.compute_feature_enabled.console_output:
423 LOG.debug('Console output not supported, cannot log')
424 return
Ihar Hrachyshkaa9dca2b2017-04-04 14:17:11 -0700425 client = client or self.servers_client
Andrea Frittoli247058f2014-07-16 16:09:22 +0100426 if not servers:
Ihar Hrachyshkaa9dca2b2017-04-04 14:17:11 -0700427 servers = client.list_servers()
Andrea Frittoli247058f2014-07-16 16:09:22 +0100428 servers = servers['servers']
429 for server in servers:
Attila Fazekas9a5a1122016-11-08 10:24:57 +0100430 try:
Ihar Hrachyshkaa9dca2b2017-04-04 14:17:11 -0700431 console_output = client.get_console_output(
Attila Fazekas9a5a1122016-11-08 10:24:57 +0100432 server['id'])['output']
433 LOG.debug('Console output for %s\nbody=\n%s',
434 server['id'], console_output)
435 except lib_exc.NotFound:
Attila Fazekase1360482016-11-10 11:28:08 +0100436 LOG.debug("Server %s disappeared(deleted) while looking "
Attila Fazekas9a5a1122016-11-08 10:24:57 +0100437 "for the console log", server['id'])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100438
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000439 def _log_net_info(self, exc):
440 # network debug is called as part of ssh init
Andrey Pavlov64723762015-04-29 06:24:58 +0300441 if not isinstance(exc, lib_exc.SSHTimeout):
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000442 LOG.debug('Network information on a devstack host')
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000443
nithya-ganesan882595e2014-07-29 18:51:07 +0000444 def create_server_snapshot(self, server, name=None):
445 # Glance client
446 _image_client = self.image_client
447 # Compute client
Ghanshyamae76c122015-12-22 13:41:35 +0900448 _images_client = self.compute_images_client
nithya-ganesan882595e2014-07-29 18:51:07 +0000449 if name is None:
zhuflf9d95722016-10-19 16:06:17 +0800450 name = data_utils.rand_name(self.__class__.__name__ + 'snapshot')
nithya-ganesan882595e2014-07-29 18:51:07 +0000451 LOG.debug("Creating a snapshot image for server: %s", server['name'])
Ken'ichi Ohmichi28f18672015-07-17 10:00:38 +0000452 image = _images_client.create_image(server['id'], name=name)
David Kranza5299eb2015-01-15 17:24:05 -0500453 image_id = image.response['location'].split('images/')[1]
Yaroslav Lobankov2fea4052016-04-19 15:05:57 +0300454 waiters.wait_for_image_status(_image_client, image_id, 'active')
Jordan Pittierf672b7d2016-06-20 18:50:40 +0200455
456 self.addCleanup(_image_client.wait_for_resource_deletion,
457 image_id)
458 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
459 _image_client.delete_image, image_id)
460
Matt Riedemann2aa19d42016-06-06 17:45:41 -0400461 if CONF.image_feature_enabled.api_v1:
462 # In glance v1 the additional properties are stored in the headers.
Ken'ichi Ohmichi01151e82016-06-10 11:19:52 -0700463 resp = _image_client.check_image(image_id)
464 snapshot_image = common_image.get_image_meta_from_headers(resp)
Matt Riedemann2aa19d42016-06-06 17:45:41 -0400465 image_props = snapshot_image.get('properties', {})
466 else:
467 # In glance v2 the additional properties are flattened.
468 snapshot_image = _image_client.show_image(image_id)
469 image_props = snapshot_image
Andrey Pavlovc8bd4b12015-08-17 10:20:17 +0300470
Matt Riedemann2aa19d42016-06-06 17:45:41 -0400471 bdm = image_props.get('block_device_mapping')
Andrey Pavlovc8bd4b12015-08-17 10:20:17 +0300472 if bdm:
473 bdm = json.loads(bdm)
474 if bdm and 'snapshot_id' in bdm[0]:
475 snapshot_id = bdm[0]['snapshot_id']
476 self.addCleanup(
477 self.snapshots_client.wait_for_resource_deletion,
478 snapshot_id)
Jordan Pittier9e227c52016-02-09 14:35:18 +0100479 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
480 self.snapshots_client.delete_snapshot,
481 snapshot_id)
lkuchlan52d7b0d2016-11-07 20:53:19 +0200482 waiters.wait_for_volume_resource_status(self.snapshots_client,
483 snapshot_id,
484 'available')
nithya-ganesan882595e2014-07-29 18:51:07 +0000485 image_name = snapshot_image['name']
486 self.assertEqual(name, image_name)
487 LOG.debug("Created snapshot image %s for server %s",
488 image_name, server['name'])
489 return snapshot_image
490
Jordan Pittier7cf64762015-10-14 15:01:12 +0200491 def nova_volume_attach(self, server, volume_to_attach):
Joseph Lanoux6809bab2014-12-18 14:57:18 +0000492 volume = self.servers_client.attach_volume(
Jordan Pittier7cf64762015-10-14 15:01:12 +0200493 server['id'], volumeId=volume_to_attach['id'], device='/dev/%s'
ghanshyam0f825252015-08-25 16:02:50 +0900494 % CONF.compute.volume_device_name)['volumeAttachment']
Jordan Pittier7cf64762015-10-14 15:01:12 +0200495 self.assertEqual(volume_to_attach['id'], volume['id'])
lkuchlan52d7b0d2016-11-07 20:53:19 +0200496 waiters.wait_for_volume_resource_status(self.volumes_client,
497 volume['id'], 'in-use')
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900498
Jordan Pittier7cf64762015-10-14 15:01:12 +0200499 # Return the updated volume after the attachment
500 return self.volumes_client.show_volume(volume['id'])['volume']
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900501
Jordan Pittier7cf64762015-10-14 15:01:12 +0200502 def nova_volume_detach(self, server, volume):
503 self.servers_client.detach_volume(server['id'], volume['id'])
lkuchlan52d7b0d2016-11-07 20:53:19 +0200504 waiters.wait_for_volume_resource_status(self.volumes_client,
505 volume['id'], 'available')
Jordan Pittier7cf64762015-10-14 15:01:12 +0200506
507 volume = self.volumes_client.show_volume(volume['id'])['volume']
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900508 self.assertEqual('available', volume['status'])
509
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700510 def rebuild_server(self, server_id, image=None,
511 preserve_ephemeral=False, wait=True,
512 rebuild_kwargs=None):
513 if image is None:
514 image = CONF.compute.image_ref
515
516 rebuild_kwargs = rebuild_kwargs or {}
517
518 LOG.debug("Rebuilding server (id: %s, image: %s, preserve eph: %s)",
519 server_id, image, preserve_ephemeral)
Ken'ichi Ohmichi5271b0f2015-08-10 07:53:27 +0000520 self.servers_client.rebuild_server(
521 server_id=server_id, image_ref=image,
522 preserve_ephemeral=preserve_ephemeral,
523 **rebuild_kwargs)
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700524 if wait:
Ken'ichi Ohmichi0eb153c2015-07-13 02:18:25 +0000525 waiters.wait_for_server_status(self.servers_client,
526 server_id, 'ACTIVE')
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700527
Steven Hardyda2a8352014-10-02 12:52:20 +0100528 def ping_ip_address(self, ip_address, should_succeed=True,
Ihar Hrachyshkaf9227c02016-09-15 11:16:47 +0000529 ping_timeout=None, mtu=None):
lanoux5fc14522015-09-21 08:17:35 +0000530 timeout = ping_timeout or CONF.validation.ping_timeout
Ihar Hrachyshkaf9227c02016-09-15 11:16:47 +0000531 cmd = ['ping', '-c1', '-w1']
532
533 if mtu:
534 cmd += [
535 # don't fragment
536 '-M', 'do',
537 # ping receives just the size of ICMP payload
538 '-s', str(net_utils.get_ping_payload_size(mtu, 4))
539 ]
540 cmd.append(ip_address)
Aaron Rosena7df13b2014-09-23 09:45:45 -0700541
542 def ping():
543 proc = subprocess.Popen(cmd,
544 stdout=subprocess.PIPE,
545 stderr=subprocess.PIPE)
546 proc.communicate()
Shuquan Huang753629e2015-07-20 08:52:29 +0000547
Aaron Rosena7df13b2014-09-23 09:45:45 -0700548 return (proc.returncode == 0) == should_succeed
549
Jordan Pittier9e227c52016-02-09 14:35:18 +0100550 caller = test_utils.find_test_caller()
Shuquan Huang753629e2015-07-20 08:52:29 +0000551 LOG.debug('%(caller)s begins to ping %(ip)s in %(timeout)s sec and the'
John L. Villalovosa898aec2017-01-13 14:46:46 -0800552 ' expected result is %(should_succeed)s', {
Shuquan Huang753629e2015-07-20 08:52:29 +0000553 'caller': caller, 'ip': ip_address, 'timeout': timeout,
554 'should_succeed':
555 'reachable' if should_succeed else 'unreachable'
556 })
Jordan Pittier35a63752016-08-30 13:09:12 +0200557 result = test_utils.call_until_true(ping, timeout, 1)
Shuquan Huang753629e2015-07-20 08:52:29 +0000558 LOG.debug('%(caller)s finishes ping %(ip)s in %(timeout)s sec and the '
John L. Villalovosa898aec2017-01-13 14:46:46 -0800559 'ping result is %(result)s', {
Shuquan Huang753629e2015-07-20 08:52:29 +0000560 'caller': caller, 'ip': ip_address, 'timeout': timeout,
561 'result': 'expected' if result else 'unexpected'
562 })
563 return result
Aaron Rosena7df13b2014-09-23 09:45:45 -0700564
Yair Friedae0e73d2014-11-24 11:56:26 +0200565 def check_vm_connectivity(self, ip_address,
566 username=None,
567 private_key=None,
Ihar Hrachyshkaf9227c02016-09-15 11:16:47 +0000568 should_connect=True,
569 mtu=None):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000570 """Check server connectivity
571
Yair Friedae0e73d2014-11-24 11:56:26 +0200572 :param ip_address: server to test against
573 :param username: server's ssh username
574 :param private_key: server's ssh private key to be used
575 :param should_connect: True/False indicates positive/negative test
576 positive - attempt ping and ssh
577 negative - attempt ping and fail if succeed
Ihar Hrachyshkaf9227c02016-09-15 11:16:47 +0000578 :param mtu: network MTU to use for connectivity validation
Yair Friedae0e73d2014-11-24 11:56:26 +0200579
580 :raises: AssertError if the result of the connectivity check does
581 not match the value of the should_connect param
582 """
583 if should_connect:
584 msg = "Timed out waiting for %s to become reachable" % ip_address
585 else:
586 msg = "ip address %s is reachable" % ip_address
587 self.assertTrue(self.ping_ip_address(ip_address,
Ihar Hrachyshkaf9227c02016-09-15 11:16:47 +0000588 should_succeed=should_connect,
589 mtu=mtu),
Yair Friedae0e73d2014-11-24 11:56:26 +0200590 msg=msg)
591 if should_connect:
592 # no need to check ssh for negative connectivity
593 self.get_remote_client(ip_address, username, private_key)
594
595 def check_public_network_connectivity(self, ip_address, username,
596 private_key, should_connect=True,
Ihar Hrachyshkaf9227c02016-09-15 11:16:47 +0000597 msg=None, servers=None, mtu=None):
Yair Friedae0e73d2014-11-24 11:56:26 +0200598 # The target login is assumed to have been configured for
599 # key-based authentication by cloud-init.
Jordan Pittier525ec712016-12-07 17:51:26 +0100600 LOG.debug('checking network connections to IP %s with user: %s',
601 ip_address, username)
Yair Friedae0e73d2014-11-24 11:56:26 +0200602 try:
603 self.check_vm_connectivity(ip_address,
604 username,
605 private_key,
Ihar Hrachyshkaf9227c02016-09-15 11:16:47 +0000606 should_connect=should_connect,
607 mtu=mtu)
Matthew Treinish53483132014-12-09 18:50:06 -0500608 except Exception:
Yair Friedae0e73d2014-11-24 11:56:26 +0200609 ex_msg = 'Public network connectivity check failed'
610 if msg:
611 ex_msg += ": " + msg
612 LOG.exception(ex_msg)
613 self._log_console_output(servers)
Yair Friedae0e73d2014-11-24 11:56:26 +0200614 raise
615
616 def create_floating_ip(self, thing, pool_name=None):
Ken'ichi Ohmichia112a592015-11-17 08:49:37 +0000617 """Create a floating IP and associates to a server on Nova"""
Yair Friedae0e73d2014-11-24 11:56:26 +0200618
Marc Koderer3b57d802016-03-22 15:23:31 +0100619 if not pool_name:
620 pool_name = CONF.network.floating_network_name
John Warrene74890a2015-11-11 15:18:01 -0500621 floating_ip = (self.compute_floating_ips_client.
Ken'ichi Ohmichie037a6f2015-12-03 06:41:49 +0000622 create_floating_ip(pool=pool_name)['floating_ip'])
Jordan Pittier9e227c52016-02-09 14:35:18 +0100623 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
John Warrene74890a2015-11-11 15:18:01 -0500624 self.compute_floating_ips_client.delete_floating_ip,
Yair Friedae0e73d2014-11-24 11:56:26 +0200625 floating_ip['id'])
John Warrene74890a2015-11-11 15:18:01 -0500626 self.compute_floating_ips_client.associate_floating_ip_to_server(
Yair Friedae0e73d2014-11-24 11:56:26 +0200627 floating_ip['ip'], thing['id'])
628 return floating_ip
629
Sean Dague20e98612016-01-06 14:33:28 -0500630 def create_timestamp(self, ip_address, dev_name=None, mount_path='/mnt',
Matt Riedemannfd5657d2015-09-30 14:47:07 -0700631 private_key=None):
Sean Dague20e98612016-01-06 14:33:28 -0500632 ssh_client = self.get_remote_client(ip_address,
Matt Riedemannfd5657d2015-09-30 14:47:07 -0700633 private_key=private_key)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300634 if dev_name is not None:
635 ssh_client.make_fs(dev_name)
Ken'ichi Ohmichi4e5a69e2017-03-01 18:15:29 -0800636 ssh_client.exec_command('sudo mount /dev/%s %s' % (dev_name,
637 mount_path))
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300638 cmd_timestamp = 'sudo sh -c "date > %s/timestamp; sync"' % mount_path
639 ssh_client.exec_command(cmd_timestamp)
640 timestamp = ssh_client.exec_command('sudo cat %s/timestamp'
641 % mount_path)
642 if dev_name is not None:
Ken'ichi Ohmichi4e5a69e2017-03-01 18:15:29 -0800643 ssh_client.exec_command('sudo umount %s' % mount_path)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300644 return timestamp
645
Sean Dague20e98612016-01-06 14:33:28 -0500646 def get_timestamp(self, ip_address, dev_name=None, mount_path='/mnt',
Matt Riedemannfd5657d2015-09-30 14:47:07 -0700647 private_key=None):
Sean Dague20e98612016-01-06 14:33:28 -0500648 ssh_client = self.get_remote_client(ip_address,
Matt Riedemannfd5657d2015-09-30 14:47:07 -0700649 private_key=private_key)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300650 if dev_name is not None:
Matt Riedemann076685a2015-09-30 14:38:16 -0700651 ssh_client.mount(dev_name, mount_path)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300652 timestamp = ssh_client.exec_command('sudo cat %s/timestamp'
653 % mount_path)
654 if dev_name is not None:
Ken'ichi Ohmichi4e5a69e2017-03-01 18:15:29 -0800655 ssh_client.exec_command('sudo umount %s' % mount_path)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300656 return timestamp
657
Sean Dague20e98612016-01-06 14:33:28 -0500658 def get_server_ip(self, server):
659 """Get the server fixed or floating IP.
660
661 Based on the configuration we're in, return a correct ip
662 address for validating that a guest is up.
663 """
Alexander Gubanovc8829f82015-11-12 10:35:13 +0200664 if CONF.validation.connect_method == 'floating':
Sean Dague20e98612016-01-06 14:33:28 -0500665 # The tests calling this method don't have a floating IP
zhufl0892cb22016-05-06 14:46:00 +0800666 # and can't make use of the validation resources. So the
Sean Dague20e98612016-01-06 14:33:28 -0500667 # method is creating the floating IP there.
668 return self.create_floating_ip(server)['ip']
669 elif CONF.validation.connect_method == 'fixed':
Matt Riedemanna7782552016-08-08 16:26:01 -0400670 # Determine the network name to look for based on config or creds
671 # provider network resources.
672 if CONF.validation.network_for_ssh:
673 addresses = server['addresses'][
674 CONF.validation.network_for_ssh]
675 else:
676 creds_provider = self._get_credentials_provider()
677 net_creds = creds_provider.get_primary_creds()
678 network = getattr(net_creds, 'network', None)
679 addresses = (server['addresses'][network['name']]
680 if network else [])
Sean Dague20e98612016-01-06 14:33:28 -0500681 for address in addresses:
Matt Riedemanna7782552016-08-08 16:26:01 -0400682 if (address['version'] == CONF.validation.ip_version_for_ssh
683 and address['OS-EXT-IPS:type'] == 'fixed'):
Sean Dague20e98612016-01-06 14:33:28 -0500684 return address['addr']
zhufl955f82b2016-07-22 11:14:34 +0800685 raise exceptions.ServerUnreachable(server_id=server['id'])
Alexander Gubanovc8829f82015-11-12 10:35:13 +0200686 else:
Matthew Treinish4217a702016-10-07 17:27:11 -0400687 raise lib_exc.InvalidConfiguration()
Alexander Gubanovc8829f82015-11-12 10:35:13 +0200688
Andrea Frittoli2e733b52014-07-16 14:12:11 +0100689
Andrea Frittoli4971fc82014-09-25 10:22:20 +0100690class NetworkScenarioTest(ScenarioTest):
Yair Fried1fc32a12014-08-04 09:11:30 +0300691 """Base class for network scenario tests.
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000692
Yair Fried1fc32a12014-08-04 09:11:30 +0300693 This class provide helpers for network scenario tests, using the neutron
694 API. Helpers from ancestor which use the nova network API are overridden
695 with the neutron API.
696
697 This Class also enforces using Neutron instead of novanetwork.
698 Subclassed tests will be skipped if Neutron is not enabled
699
700 """
701
Andrea Frittolib21de6c2015-02-06 20:12:38 +0000702 credentials = ['primary', 'admin']
703
Yair Fried1fc32a12014-08-04 09:11:30 +0300704 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +0000705 def skip_checks(cls):
706 super(NetworkScenarioTest, cls).skip_checks()
Andrea Frittoli2ddc2632014-09-25 11:03:00 +0100707 if not CONF.service_available.neutron:
708 raise cls.skipException('Neutron not available')
Yair Fried1fc32a12014-08-04 09:11:30 +0300709
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -0700710 def _create_network(self, networks_client=None,
zhoubin5058bead72017-02-04 18:01:15 +0800711 tenant_id=None,
Markus Zoeller156b5da2016-07-11 18:10:31 +0200712 namestart='network-smoke-',
713 port_security_enabled=True):
John Warren94d8faf2015-09-15 12:22:24 -0400714 if not networks_client:
715 networks_client = self.networks_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300716 if not tenant_id:
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -0700717 tenant_id = networks_client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300718 name = data_utils.rand_name(namestart)
Matt Riedemann039b2fe2016-09-15 16:12:24 -0400719 network_kwargs = dict(name=name, tenant_id=tenant_id)
720 # Neutron disables port security by default so we have to check the
721 # config before trying to create the network with port_security_enabled
722 if CONF.network_feature_enabled.port_security:
723 network_kwargs['port_security_enabled'] = port_security_enabled
Markus Zoeller156b5da2016-07-11 18:10:31 +0200724 result = networks_client.create_network(**network_kwargs)
Steve Heyman33735f22016-05-24 09:28:08 -0500725 network = result['network']
726
727 self.assertEqual(network['name'], name)
Jordan Pittier9e227c52016-02-09 14:35:18 +0100728 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
zhoubin508bf20b32017-02-03 09:39:14 +0800729 networks_client.delete_network,
Steve Heyman33735f22016-05-24 09:28:08 -0500730 network['id'])
Yair Fried1fc32a12014-08-04 09:11:30 +0300731 return network
732
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -0700733 def _create_subnet(self, network, subnets_client=None,
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000734 routers_client=None, namestart='subnet-smoke',
735 **kwargs):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000736 """Create a subnet for the given network
737
738 within the cidr block configured for tenant networks.
Yair Fried1fc32a12014-08-04 09:11:30 +0300739 """
John Warren3961acd2015-10-02 14:38:53 -0400740 if not subnets_client:
741 subnets_client = self.subnets_client
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000742 if not routers_client:
743 routers_client = self.routers_client
Yair Fried1fc32a12014-08-04 09:11:30 +0300744
745 def cidr_in_use(cidr, tenant_id):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000746 """Check cidr existence
747
lei zhangdd552b22015-11-25 20:41:48 +0800748 :returns: True if subnet with cidr already exist in tenant
749 False else
Yair Fried1fc32a12014-08-04 09:11:30 +0300750 """
jeremy.zhang5870ff12017-05-25 11:24:23 +0800751 cidr_in_use = self.os_admin.subnets_client.list_subnets(
Jordan Pittier64e6b442017-02-20 19:29:02 +0100752 tenant_id=tenant_id, cidr=cidr)['subnets']
Yair Fried1fc32a12014-08-04 09:11:30 +0300753 return len(cidr_in_use) != 0
754
Kirill Shileev14113572014-11-21 16:58:02 +0300755 ip_version = kwargs.pop('ip_version', 4)
756
757 if ip_version == 6:
758 tenant_cidr = netaddr.IPNetwork(
Sean Dagueed6e5862016-04-04 10:49:13 -0400759 CONF.network.project_network_v6_cidr)
760 num_bits = CONF.network.project_network_v6_mask_bits
Kirill Shileev14113572014-11-21 16:58:02 +0300761 else:
Sean Dagueed6e5862016-04-04 10:49:13 -0400762 tenant_cidr = netaddr.IPNetwork(CONF.network.project_network_cidr)
763 num_bits = CONF.network.project_network_mask_bits
Kirill Shileev14113572014-11-21 16:58:02 +0300764
Yair Fried1fc32a12014-08-04 09:11:30 +0300765 result = None
Kirill Shileev14113572014-11-21 16:58:02 +0300766 str_cidr = None
Yair Fried1fc32a12014-08-04 09:11:30 +0300767 # Repeatedly attempt subnet creation with sequential cidr
768 # blocks until an unallocated block is found.
Kirill Shileev14113572014-11-21 16:58:02 +0300769 for subnet_cidr in tenant_cidr.subnet(num_bits):
Yair Fried1fc32a12014-08-04 09:11:30 +0300770 str_cidr = str(subnet_cidr)
Steve Heyman33735f22016-05-24 09:28:08 -0500771 if cidr_in_use(str_cidr, tenant_id=network['tenant_id']):
Yair Fried1fc32a12014-08-04 09:11:30 +0300772 continue
773
774 subnet = dict(
775 name=data_utils.rand_name(namestart),
Steve Heyman33735f22016-05-24 09:28:08 -0500776 network_id=network['id'],
777 tenant_id=network['tenant_id'],
Yair Fried1fc32a12014-08-04 09:11:30 +0300778 cidr=str_cidr,
Kirill Shileev14113572014-11-21 16:58:02 +0300779 ip_version=ip_version,
Yair Fried1fc32a12014-08-04 09:11:30 +0300780 **kwargs
781 )
782 try:
John Warren3961acd2015-10-02 14:38:53 -0400783 result = subnets_client.create_subnet(**subnet)
Yair Fried1fc32a12014-08-04 09:11:30 +0300784 break
Masayuki Igawad9388762015-01-20 14:56:42 +0900785 except lib_exc.Conflict as e:
Yair Fried1fc32a12014-08-04 09:11:30 +0300786 is_overlapping_cidr = 'overlaps with another subnet' in str(e)
787 if not is_overlapping_cidr:
788 raise
789 self.assertIsNotNone(result, 'Unable to allocate tenant network')
Steve Heyman33735f22016-05-24 09:28:08 -0500790
791 subnet = result['subnet']
792 self.assertEqual(subnet['cidr'], str_cidr)
793
794 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
795 subnets_client.delete_subnet, subnet['id'])
796
Yair Fried1fc32a12014-08-04 09:11:30 +0300797 return subnet
798
Kirill Shileev14113572014-11-21 16:58:02 +0300799 def _get_server_port_id_and_ip4(self, server, ip_addr=None):
jeremy.zhang5870ff12017-05-25 11:24:23 +0800800 ports = self.os_admin.ports_client.list_ports(
Jordan Pittier64e6b442017-02-20 19:29:02 +0100801 device_id=server['id'], fixed_ip=ip_addr)['ports']
Kobi Samoray166500a2016-10-09 14:42:48 +0300802 # A port can have more than one IP address in some cases.
Sean M. Collins2e896832015-12-15 13:58:47 -0500803 # If the network is dual-stack (IPv4 + IPv6), this port is associated
804 # with 2 subnets
Vasyl Saienko8fd517c2016-05-30 09:52:54 +0300805 p_status = ['ACTIVE']
806 # NOTE(vsaienko) With Ironic, instances live on separate hardware
807 # servers. Neutron does not bind ports for Ironic instances, as a
808 # result the port remains in the DOWN state.
Vasyl Saienkoc8aa34b2016-08-01 14:18:37 +0300809 # TODO(vsaienko) remove once bug: #1599836 is resolved.
Thiago Paiva66cded22016-08-15 14:55:58 -0300810 if getattr(CONF.service_available, 'ironic', False):
Vasyl Saienko8fd517c2016-05-30 09:52:54 +0300811 p_status.append('DOWN')
Daniel Mellado9e3e1062015-08-06 18:07:05 +0200812 port_map = [(p["id"], fxip["ip_address"])
813 for p in ports
814 for fxip in p["fixed_ips"]
Yatin Kumbhareee4924c2016-06-09 15:12:06 +0530815 if netutils.is_valid_ipv4(fxip["ip_address"])
Vasyl Saienko8fd517c2016-05-30 09:52:54 +0300816 and p['status'] in p_status]
Kevin Benton1d0c1dc2016-02-04 14:30:08 -0800817 inactive = [p for p in ports if p['status'] != 'ACTIVE']
818 if inactive:
819 LOG.warning("Instance has ports that are not ACTIVE: %s", inactive)
Daniel Mellado9e3e1062015-08-06 18:07:05 +0200820
Masayuki Igawaf9009b42017-04-10 14:49:29 +0900821 self.assertNotEmpty(port_map,
John L. Villalovosb83286f2015-11-04 14:46:57 -0800822 "No IPv4 addresses found in: %s" % ports)
Daniel Mellado9e3e1062015-08-06 18:07:05 +0200823 self.assertEqual(len(port_map), 1,
824 "Found multiple IPv4 addresses: %s. "
825 "Unable to determine which port to target."
826 % port_map)
827 return port_map[0]
Yair Fried1fc32a12014-08-04 09:11:30 +0300828
David Shrewsbury9bac3662014-08-07 15:07:01 -0400829 def _get_network_by_name(self, network_name):
jeremy.zhang5870ff12017-05-25 11:24:23 +0800830 net = self.os_admin.networks_client.list_networks(
Jordan Pittier64e6b442017-02-20 19:29:02 +0100831 name=network_name)['networks']
Ferenc Horváth268ccce2017-06-08 12:39:02 +0200832 self.assertNotEmpty(net,
Adam Gandelman878a5fd2015-03-30 14:33:36 -0700833 "Unable to get network by name: %s" % network_name)
Steve Heyman33735f22016-05-24 09:28:08 -0500834 return net[0]
David Shrewsbury9bac3662014-08-07 15:07:01 -0400835
Yair Friedae0e73d2014-11-24 11:56:26 +0200836 def create_floating_ip(self, thing, external_network_id=None,
837 port_id=None, client=None):
Ken'ichi Ohmichia112a592015-11-17 08:49:37 +0000838 """Create a floating IP and associates to a resource/port on Neutron"""
Yair Friedae0e73d2014-11-24 11:56:26 +0200839 if not external_network_id:
840 external_network_id = CONF.network.public_network_id
Yair Frieddb6c9e92014-08-06 08:53:13 +0300841 if not client:
John Warrenfbf2a892015-11-17 12:36:14 -0500842 client = self.floating_ips_client
Yair Fried1fc32a12014-08-04 09:11:30 +0300843 if not port_id:
Kirill Shileev14113572014-11-21 16:58:02 +0300844 port_id, ip4 = self._get_server_port_id_and_ip4(thing)
845 else:
846 ip4 = None
David Kranz34e88122014-12-11 15:24:05 -0500847 result = client.create_floatingip(
Yair Fried1fc32a12014-08-04 09:11:30 +0300848 floating_network_id=external_network_id,
849 port_id=port_id,
Kirill Shileev14113572014-11-21 16:58:02 +0300850 tenant_id=thing['tenant_id'],
851 fixed_ip_address=ip4
Yair Fried1fc32a12014-08-04 09:11:30 +0300852 )
Steve Heyman33735f22016-05-24 09:28:08 -0500853 floating_ip = result['floatingip']
Jordan Pittier9e227c52016-02-09 14:35:18 +0100854 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
zhoubin508bf20b32017-02-03 09:39:14 +0800855 client.delete_floatingip,
Steve Heyman33735f22016-05-24 09:28:08 -0500856 floating_ip['id'])
Yair Fried1fc32a12014-08-04 09:11:30 +0300857 return floating_ip
858
859 def _associate_floating_ip(self, floating_ip, server):
Kirill Shileev14113572014-11-21 16:58:02 +0300860 port_id, _ = self._get_server_port_id_and_ip4(server)
Steve Heyman33735f22016-05-24 09:28:08 -0500861 kwargs = dict(port_id=port_id)
862 floating_ip = self.floating_ips_client.update_floatingip(
863 floating_ip['id'], **kwargs)['floatingip']
864 self.assertEqual(port_id, floating_ip['port_id'])
Yair Fried1fc32a12014-08-04 09:11:30 +0300865 return floating_ip
866
867 def _disassociate_floating_ip(self, floating_ip):
Steve Heyman33735f22016-05-24 09:28:08 -0500868 """:param floating_ip: floating_ips_client.create_floatingip"""
869 kwargs = dict(port_id=None)
870 floating_ip = self.floating_ips_client.update_floatingip(
871 floating_ip['id'], **kwargs)['floatingip']
872 self.assertIsNone(floating_ip['port_id'])
Yair Fried1fc32a12014-08-04 09:11:30 +0300873 return floating_ip
874
Yair Fried45f92952014-06-26 05:19:19 +0300875 def check_floating_ip_status(self, floating_ip, status):
Carl Baldwina754e2d2014-10-23 22:47:41 +0000876 """Verifies floatingip reaches the given status
Yair Fried45f92952014-06-26 05:19:19 +0300877
Steve Heyman33735f22016-05-24 09:28:08 -0500878 :param dict floating_ip: floating IP dict to check status
Yair Fried45f92952014-06-26 05:19:19 +0300879 :param status: target status
880 :raises: AssertionError if status doesn't match
881 """
Steve Heyman33735f22016-05-24 09:28:08 -0500882 floatingip_id = floating_ip['id']
883
Carl Baldwina754e2d2014-10-23 22:47:41 +0000884 def refresh():
Steve Heyman33735f22016-05-24 09:28:08 -0500885 result = (self.floating_ips_client.
886 show_floatingip(floatingip_id)['floatingip'])
887 return status == result['status']
Carl Baldwina754e2d2014-10-23 22:47:41 +0000888
zhufl4dda94e2017-03-14 16:14:46 +0800889 if not test_utils.call_until_true(refresh,
890 CONF.network.build_timeout,
891 CONF.network.build_interval):
892 floating_ip = self.floating_ips_client.show_floatingip(
893 floatingip_id)['floatingip']
894 self.assertEqual(status, floating_ip['status'],
895 message="FloatingIP: {fp} is at status: {cst}. "
896 "failed to reach status: {st}"
897 .format(fp=floating_ip, cst=floating_ip['status'],
898 st=status))
Yair Fried45f92952014-06-26 05:19:19 +0300899 LOG.info("FloatingIP: {fp} is at status: {st}"
900 .format(fp=floating_ip, st=status))
901
Yair Fried1fc32a12014-08-04 09:11:30 +0300902 def _check_tenant_network_connectivity(self, server,
903 username,
904 private_key,
905 should_connect=True,
906 servers_for_debug=None):
Sean Dagueed6e5862016-04-04 10:49:13 -0400907 if not CONF.network.project_networks_reachable:
Yair Fried1fc32a12014-08-04 09:11:30 +0300908 msg = 'Tenant networks not configured to be reachable.'
909 LOG.info(msg)
910 return
911 # The target login is assumed to have been configured for
912 # key-based authentication by cloud-init.
913 try:
Béla Vancsicsb6dfa082017-03-01 10:44:58 +0100914 for ip_addresses in server['addresses'].values():
Yair Fried1fc32a12014-08-04 09:11:30 +0300915 for ip_address in ip_addresses:
ghanshyam807211c2014-12-18 13:21:22 +0900916 self.check_vm_connectivity(ip_address['addr'],
Yair Friedae0e73d2014-11-24 11:56:26 +0200917 username,
918 private_key,
919 should_connect=should_connect)
Yair Fried1fc32a12014-08-04 09:11:30 +0300920 except Exception as e:
921 LOG.exception('Tenant network connectivity check failed')
922 self._log_console_output(servers_for_debug)
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000923 self._log_net_info(e)
Yair Fried1fc32a12014-08-04 09:11:30 +0300924 raise
925
Yair Friedbc46f592015-11-18 16:29:34 +0200926 def _check_remote_connectivity(self, source, dest, should_succeed=True,
927 nic=None):
YAMAMOTO Takashi4c3ebb02017-01-25 16:04:30 +0900928 """assert ping server via source ssh connection
929
930 Note: This is an internal method. Use check_remote_connectivity
931 instead.
Yair Fried1fc32a12014-08-04 09:11:30 +0300932
933 :param source: RemoteClient: an ssh connection from which to ping
934 :param dest: and IP to ping against
935 :param should_succeed: boolean should ping succeed or not
Yair Friedbc46f592015-11-18 16:29:34 +0200936 :param nic: specific network interface to ping from
Yair Fried1fc32a12014-08-04 09:11:30 +0300937 """
938 def ping_remote():
939 try:
Yair Friedbc46f592015-11-18 16:29:34 +0200940 source.ping_host(dest, nic=nic)
Andrey Pavlov64723762015-04-29 06:24:58 +0300941 except lib_exc.SSHExecCommandFailed:
zhangguoqing6c096642016-01-04 06:17:21 +0000942 LOG.warning('Failed to ping IP: %s via a ssh connection '
Jordan Pittier525ec712016-12-07 17:51:26 +0100943 'from: %s.', dest, source.ssh_client.host)
Yair Fried1fc32a12014-08-04 09:11:30 +0300944 return not should_succeed
945 return should_succeed
946
Jordan Pittier35a63752016-08-30 13:09:12 +0200947 return test_utils.call_until_true(ping_remote,
948 CONF.validation.ping_timeout,
949 1)
Yair Fried1fc32a12014-08-04 09:11:30 +0300950
YAMAMOTO Takashi4c3ebb02017-01-25 16:04:30 +0900951 def check_remote_connectivity(self, source, dest, should_succeed=True,
952 nic=None):
953 """assert ping server via source ssh connection
954
955 :param source: RemoteClient: an ssh connection from which to ping
956 :param dest: and IP to ping against
957 :param should_succeed: boolean should ping succeed or not
958 :param nic: specific network interface to ping from
959 """
960 result = self._check_remote_connectivity(source, dest, should_succeed,
961 nic)
962 source_host = source.ssh_client.host
963 if should_succeed:
964 msg = "Timed out waiting for %s to become reachable from %s" \
965 % (dest, source_host)
966 else:
967 msg = "%s is reachable from %s" % (dest, source_host)
968 self.assertTrue(result, msg)
969
John Warren456d9ae2016-01-12 15:36:33 -0500970 def _create_security_group(self, security_group_rules_client=None,
971 tenant_id=None,
John Warrenf9606e92015-12-10 12:12:42 -0500972 namestart='secgroup-smoke',
973 security_groups_client=None):
John Warren456d9ae2016-01-12 15:36:33 -0500974 if security_group_rules_client is None:
975 security_group_rules_client = self.security_group_rules_client
John Warrenf9606e92015-12-10 12:12:42 -0500976 if security_groups_client is None:
977 security_groups_client = self.security_groups_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300978 if tenant_id is None:
John Warrenf9606e92015-12-10 12:12:42 -0500979 tenant_id = security_groups_client.tenant_id
980 secgroup = self._create_empty_security_group(
981 namestart=namestart, client=security_groups_client,
982 tenant_id=tenant_id)
Yair Fried1fc32a12014-08-04 09:11:30 +0300983
984 # Add rules to the security group
John Warrenf9606e92015-12-10 12:12:42 -0500985 rules = self._create_loginable_secgroup_rule(
John Warren456d9ae2016-01-12 15:36:33 -0500986 security_group_rules_client=security_group_rules_client,
987 secgroup=secgroup,
John Warrenf9606e92015-12-10 12:12:42 -0500988 security_groups_client=security_groups_client)
Yair Fried1fc32a12014-08-04 09:11:30 +0300989 for rule in rules:
Steve Heyman33735f22016-05-24 09:28:08 -0500990 self.assertEqual(tenant_id, rule['tenant_id'])
991 self.assertEqual(secgroup['id'], rule['security_group_id'])
Yair Fried1fc32a12014-08-04 09:11:30 +0300992 return secgroup
993
Yair Frieddb6c9e92014-08-06 08:53:13 +0300994 def _create_empty_security_group(self, client=None, tenant_id=None,
Yair Fried1fc32a12014-08-04 09:11:30 +0300995 namestart='secgroup-smoke'):
996 """Create a security group without rules.
997
998 Default rules will be created:
999 - IPv4 egress to any
1000 - IPv6 egress to any
1001
1002 :param tenant_id: secgroup will be created in this tenant
Steve Heyman33735f22016-05-24 09:28:08 -05001003 :returns: the created security group
Yair Fried1fc32a12014-08-04 09:11:30 +03001004 """
1005 if client is None:
John Warrenf9606e92015-12-10 12:12:42 -05001006 client = self.security_groups_client
Yair Frieddb6c9e92014-08-06 08:53:13 +03001007 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +00001008 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001009 sg_name = data_utils.rand_name(namestart)
1010 sg_desc = sg_name + " description"
1011 sg_dict = dict(name=sg_name,
1012 description=sg_desc)
1013 sg_dict['tenant_id'] = tenant_id
David Kranz34e88122014-12-11 15:24:05 -05001014 result = client.create_security_group(**sg_dict)
Steve Heyman33735f22016-05-24 09:28:08 -05001015
1016 secgroup = result['security_group']
1017 self.assertEqual(secgroup['name'], sg_name)
1018 self.assertEqual(tenant_id, secgroup['tenant_id'])
1019 self.assertEqual(secgroup['description'], sg_desc)
1020
Jordan Pittier9e227c52016-02-09 14:35:18 +01001021 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
Steve Heyman33735f22016-05-24 09:28:08 -05001022 client.delete_security_group, secgroup['id'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001023 return secgroup
1024
Yair Frieddb6c9e92014-08-06 08:53:13 +03001025 def _default_security_group(self, client=None, tenant_id=None):
Yair Fried1fc32a12014-08-04 09:11:30 +03001026 """Get default secgroup for given tenant_id.
1027
Ken'ichi Ohmichid67c8da2016-09-13 16:18:11 -07001028 :returns: default secgroup for given tenant
Yair Fried1fc32a12014-08-04 09:11:30 +03001029 """
1030 if client is None:
John Warrenf9606e92015-12-10 12:12:42 -05001031 client = self.security_groups_client
Yair Frieddb6c9e92014-08-06 08:53:13 +03001032 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +00001033 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001034 sgs = [
Jordan Pittier8ad86172016-04-25 16:20:53 +02001035 sg for sg in list(client.list_security_groups().values())[0]
Yair Fried1fc32a12014-08-04 09:11:30 +03001036 if sg['tenant_id'] == tenant_id and sg['name'] == 'default'
1037 ]
1038 msg = "No default security group for tenant %s." % (tenant_id)
Masayuki Igawaf9009b42017-04-10 14:49:29 +09001039 self.assertNotEmpty(sgs, msg)
Steve Heyman33735f22016-05-24 09:28:08 -05001040 return sgs[0]
Yair Fried1fc32a12014-08-04 09:11:30 +03001041
John Warren456d9ae2016-01-12 15:36:33 -05001042 def _create_security_group_rule(self, secgroup=None,
1043 sec_group_rules_client=None,
John Warrenf9606e92015-12-10 12:12:42 -05001044 tenant_id=None,
1045 security_groups_client=None, **kwargs):
Yair Fried1fc32a12014-08-04 09:11:30 +03001046 """Create a rule from a dictionary of rule parameters.
1047
1048 Create a rule in a secgroup. if secgroup not defined will search for
1049 default secgroup in tenant_id.
1050
Steve Heyman33735f22016-05-24 09:28:08 -05001051 :param secgroup: the security group.
Yair Fried1fc32a12014-08-04 09:11:30 +03001052 :param tenant_id: if secgroup not passed -- the tenant in which to
1053 search for default secgroup
1054 :param kwargs: a dictionary containing rule parameters:
1055 for example, to allow incoming ssh:
1056 rule = {
1057 direction: 'ingress'
1058 protocol:'tcp',
1059 port_range_min: 22,
1060 port_range_max: 22
1061 }
1062 """
John Warren456d9ae2016-01-12 15:36:33 -05001063 if sec_group_rules_client is None:
1064 sec_group_rules_client = self.security_group_rules_client
John Warrenf9606e92015-12-10 12:12:42 -05001065 if security_groups_client is None:
1066 security_groups_client = self.security_groups_client
Yair Frieddb6c9e92014-08-06 08:53:13 +03001067 if not tenant_id:
John Warrenf9606e92015-12-10 12:12:42 -05001068 tenant_id = security_groups_client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001069 if secgroup is None:
John Warrenf9606e92015-12-10 12:12:42 -05001070 secgroup = self._default_security_group(
1071 client=security_groups_client, tenant_id=tenant_id)
Yair Fried1fc32a12014-08-04 09:11:30 +03001072
Steve Heyman33735f22016-05-24 09:28:08 -05001073 ruleset = dict(security_group_id=secgroup['id'],
1074 tenant_id=secgroup['tenant_id'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001075 ruleset.update(kwargs)
1076
John Warren456d9ae2016-01-12 15:36:33 -05001077 sg_rule = sec_group_rules_client.create_security_group_rule(**ruleset)
Steve Heyman33735f22016-05-24 09:28:08 -05001078 sg_rule = sg_rule['security_group_rule']
1079
1080 self.assertEqual(secgroup['tenant_id'], sg_rule['tenant_id'])
1081 self.assertEqual(secgroup['id'], sg_rule['security_group_id'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001082
1083 return sg_rule
1084
John Warren456d9ae2016-01-12 15:36:33 -05001085 def _create_loginable_secgroup_rule(self, security_group_rules_client=None,
1086 secgroup=None,
John Warrenf9606e92015-12-10 12:12:42 -05001087 security_groups_client=None):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001088 """Create loginable security group rule
1089
Alex Stafeyevdd5dde92016-05-08 14:35:04 +03001090 This function will create:
1091 1. egress and ingress tcp port 22 allow rule in order to allow ssh
1092 access for ipv4.
1093 2. egress and ingress ipv6 icmp allow rule, in order to allow icmpv6.
1094 3. egress and ingress ipv4 icmp allow rule, in order to allow icmpv4.
Yair Fried1fc32a12014-08-04 09:11:30 +03001095 """
1096
John Warren456d9ae2016-01-12 15:36:33 -05001097 if security_group_rules_client is None:
1098 security_group_rules_client = self.security_group_rules_client
John Warrenf9606e92015-12-10 12:12:42 -05001099 if security_groups_client is None:
1100 security_groups_client = self.security_groups_client
Yair Fried1fc32a12014-08-04 09:11:30 +03001101 rules = []
1102 rulesets = [
1103 dict(
1104 # ssh
1105 protocol='tcp',
1106 port_range_min=22,
1107 port_range_max=22,
1108 ),
1109 dict(
1110 # ping
1111 protocol='icmp',
Andreas Scheuring887ca8e2015-02-03 17:56:12 +01001112 ),
1113 dict(
1114 # ipv6-icmp for ping6
1115 protocol='icmp',
1116 ethertype='IPv6',
Yair Fried1fc32a12014-08-04 09:11:30 +03001117 )
1118 ]
John Warren456d9ae2016-01-12 15:36:33 -05001119 sec_group_rules_client = security_group_rules_client
Yair Fried1fc32a12014-08-04 09:11:30 +03001120 for ruleset in rulesets:
1121 for r_direction in ['ingress', 'egress']:
1122 ruleset['direction'] = r_direction
1123 try:
1124 sg_rule = self._create_security_group_rule(
John Warren456d9ae2016-01-12 15:36:33 -05001125 sec_group_rules_client=sec_group_rules_client,
1126 secgroup=secgroup,
John Warrenf9606e92015-12-10 12:12:42 -05001127 security_groups_client=security_groups_client,
1128 **ruleset)
Masayuki Igawad9388762015-01-20 14:56:42 +09001129 except lib_exc.Conflict as ex:
Yair Fried1fc32a12014-08-04 09:11:30 +03001130 # if rule already exist - skip rule and continue
1131 msg = 'Security group rule already exists'
1132 if msg not in ex._error_string:
1133 raise ex
1134 else:
Steve Heyman33735f22016-05-24 09:28:08 -05001135 self.assertEqual(r_direction, sg_rule['direction'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001136 rules.append(sg_rule)
1137
1138 return rules
1139
Yair Frieddb6c9e92014-08-06 08:53:13 +03001140 def _get_router(self, client=None, tenant_id=None):
Yair Fried1fc32a12014-08-04 09:11:30 +03001141 """Retrieve a router for the given tenant id.
1142
1143 If a public router has been configured, it will be returned.
1144
1145 If a public router has not been configured, but a public
1146 network has, a tenant router will be created and returned that
1147 routes traffic to the public network.
1148 """
Yair Frieddb6c9e92014-08-06 08:53:13 +03001149 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 router_id = CONF.network.public_router_id
1154 network_id = CONF.network.public_network_id
1155 if router_id:
David Kranzca4c7e72015-05-27 11:39:19 -04001156 body = client.show_router(router_id)
Steve Heyman33735f22016-05-24 09:28:08 -05001157 return body['router']
Yair Fried1fc32a12014-08-04 09:11:30 +03001158 elif network_id:
Yair Frieddb6c9e92014-08-06 08:53:13 +03001159 router = self._create_router(client, tenant_id)
Steve Heyman33735f22016-05-24 09:28:08 -05001160 kwargs = {'external_gateway_info': dict(network_id=network_id)}
1161 router = client.update_router(router['id'], **kwargs)['router']
Yair Fried1fc32a12014-08-04 09:11:30 +03001162 return router
1163 else:
1164 raise Exception("Neither of 'public_router_id' or "
1165 "'public_network_id' has been defined.")
1166
Yair Frieddb6c9e92014-08-06 08:53:13 +03001167 def _create_router(self, client=None, tenant_id=None,
1168 namestart='router-smoke'):
1169 if not client:
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +00001170 client = self.routers_client
Yair Frieddb6c9e92014-08-06 08:53:13 +03001171 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +00001172 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001173 name = data_utils.rand_name(namestart)
David Kranz34e88122014-12-11 15:24:05 -05001174 result = client.create_router(name=name,
1175 admin_state_up=True,
1176 tenant_id=tenant_id)
Steve Heyman33735f22016-05-24 09:28:08 -05001177 router = result['router']
1178 self.assertEqual(router['name'], name)
1179 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
1180 client.delete_router,
1181 router['id'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001182 return router
1183
Alok Maurya6384bbb2014-07-13 06:44:29 -07001184 def _update_router_admin_state(self, router, admin_state_up):
Steve Heyman33735f22016-05-24 09:28:08 -05001185 kwargs = dict(admin_state_up=admin_state_up)
1186 router = self.routers_client.update_router(
1187 router['id'], **kwargs)['router']
1188 self.assertEqual(admin_state_up, router['admin_state_up'])
Alok Maurya6384bbb2014-07-13 06:44:29 -07001189
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -07001190 def create_networks(self, networks_client=None,
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +00001191 routers_client=None, subnets_client=None,
Markus Zoeller156b5da2016-07-11 18:10:31 +02001192 tenant_id=None, dns_nameservers=None,
1193 port_security_enabled=True):
Yair Fried1fc32a12014-08-04 09:11:30 +03001194 """Create a network with a subnet connected to a router.
1195
David Shrewsbury9bac3662014-08-07 15:07:01 -04001196 The baremetal driver is a special case since all nodes are
1197 on the same shared network.
1198
Yair Fried413bf2d2014-11-19 17:07:11 +02001199 :param tenant_id: id of tenant to create resources in.
1200 :param dns_nameservers: list of dns servers to send to subnet.
Yair Fried1fc32a12014-08-04 09:11:30 +03001201 :returns: network, subnet, router
1202 """
Thiago Paiva66cded22016-08-15 14:55:58 -03001203 if CONF.network.shared_physical_network:
David Shrewsbury9bac3662014-08-07 15:07:01 -04001204 # NOTE(Shrews): This exception is for environments where tenant
1205 # credential isolation is available, but network separation is
1206 # not (the current baremetal case). Likely can be removed when
1207 # test account mgmt is reworked:
1208 # https://blueprints.launchpad.net/tempest/+spec/test-accounts
Adam Gandelman878a5fd2015-03-30 14:33:36 -07001209 if not CONF.compute.fixed_network_name:
1210 m = 'fixed_network_name must be specified in config'
Matthew Treinish4217a702016-10-07 17:27:11 -04001211 raise lib_exc.InvalidConfiguration(m)
David Shrewsbury9bac3662014-08-07 15:07:01 -04001212 network = self._get_network_by_name(
1213 CONF.compute.fixed_network_name)
1214 router = None
1215 subnet = None
1216 else:
John Warren94d8faf2015-09-15 12:22:24 -04001217 network = self._create_network(
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -07001218 networks_client=networks_client,
Markus Zoeller156b5da2016-07-11 18:10:31 +02001219 tenant_id=tenant_id,
1220 port_security_enabled=port_security_enabled)
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +00001221 router = self._get_router(client=routers_client,
1222 tenant_id=tenant_id)
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -07001223 subnet_kwargs = dict(network=network,
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +00001224 subnets_client=subnets_client,
1225 routers_client=routers_client)
Yair Fried413bf2d2014-11-19 17:07:11 +02001226 # use explicit check because empty list is a valid option
1227 if dns_nameservers is not None:
1228 subnet_kwargs['dns_nameservers'] = dns_nameservers
1229 subnet = self._create_subnet(**subnet_kwargs)
Steve Heyman33735f22016-05-24 09:28:08 -05001230 if not routers_client:
1231 routers_client = self.routers_client
1232 router_id = router['id']
1233 routers_client.add_router_interface(router_id,
1234 subnet_id=subnet['id'])
1235
1236 # save a cleanup job to remove this association between
1237 # router and subnet
1238 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
1239 routers_client.remove_router_interface, router_id,
1240 subnet_id=subnet['id'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001241 return network, subnet, router
1242
1243
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001244class EncryptionScenarioTest(ScenarioTest):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001245 """Base class for encryption scenario tests"""
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001246
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001247 credentials = ['primary', 'admin']
David Kranz4cc852b2015-03-09 14:57:11 -04001248
1249 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001250 def setup_clients(cls):
1251 super(EncryptionScenarioTest, cls).setup_clients()
Jordan Pittier8160d312017-04-18 11:52:23 +02001252 cls.admin_volume_types_client = cls.os_admin.volume_types_v2_client
ghanshyam3bd0d2b2017-03-23 01:57:28 +00001253 cls.admin_encryption_types_client =\
Jordan Pittier8160d312017-04-18 11:52:23 +02001254 cls.os_admin.encryption_types_v2_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001255
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001256 def create_encryption_type(self, client=None, type_id=None, provider=None,
1257 key_size=None, cipher=None,
1258 control_location=None):
1259 if not client:
Ken'ichi Ohmichia6ebf622016-08-25 11:52:27 -07001260 client = self.admin_encryption_types_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001261 if not type_id:
1262 volume_type = self.create_volume_type()
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001263 type_id = volume_type['id']
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001264 LOG.debug("Creating an encryption type for volume type: %s", type_id)
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001265 client.create_encryption_type(
1266 type_id, provider=provider, key_size=key_size, cipher=cipher,
John Warrend053ded2015-08-13 15:22:48 +00001267 control_location=control_location)['encryption']
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001268
lkuchlan3023e752017-06-08 12:53:13 +03001269 def create_encrypted_volume(self, encryption_provider, volume_type,
1270 key_size=256, cipher='aes-xts-plain64',
1271 control_location='front-end'):
1272 volume_type = self.create_volume_type(name=volume_type)
1273 self.create_encryption_type(type_id=volume_type['id'],
1274 provider=encryption_provider,
1275 key_size=key_size,
1276 cipher=cipher,
1277 control_location=control_location)
1278 return self.create_volume(volume_type=volume_type['name'])
1279
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001280
Masayuki Igawa0870db52015-09-18 21:08:36 +09001281class ObjectStorageScenarioTest(ScenarioTest):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001282 """Provide harness to do Object Storage scenario tests.
Chris Dent0d494112014-08-26 13:48:30 +01001283
1284 Subclasses implement the tests that use the methods provided by this
1285 class.
1286 """
1287
1288 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001289 def skip_checks(cls):
Masayuki Igawa0870db52015-09-18 21:08:36 +09001290 super(ObjectStorageScenarioTest, cls).skip_checks()
Chris Dent0d494112014-08-26 13:48:30 +01001291 if not CONF.service_available.swift:
1292 skip_msg = ("%s skipped as swift is not available" %
1293 cls.__name__)
1294 raise cls.skipException(skip_msg)
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001295
1296 @classmethod
1297 def setup_credentials(cls):
Masayuki Igawa60ea6c52014-10-15 17:32:14 +09001298 cls.set_network_resources()
Masayuki Igawa0870db52015-09-18 21:08:36 +09001299 super(ObjectStorageScenarioTest, cls).setup_credentials()
Matthew Treinish4a596932015-03-06 20:37:01 -05001300 operator_role = CONF.object_storage.operator_role
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +01001301 cls.os_operator = cls.get_client_manager(roles=[operator_role])
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001302
1303 @classmethod
1304 def setup_clients(cls):
Masayuki Igawa0870db52015-09-18 21:08:36 +09001305 super(ObjectStorageScenarioTest, cls).setup_clients()
Chris Dent0d494112014-08-26 13:48:30 +01001306 # Clients for Swift
Matthew Treinish8f268292015-02-24 20:01:36 -05001307 cls.account_client = cls.os_operator.account_client
1308 cls.container_client = cls.os_operator.container_client
1309 cls.object_client = cls.os_operator.object_client
Chris Dent0d494112014-08-26 13:48:30 +01001310
Chris Dentde456a12014-09-10 12:41:15 +01001311 def get_swift_stat(self):
Chris Dent0d494112014-08-26 13:48:30 +01001312 """get swift status for our user account."""
1313 self.account_client.list_account_containers()
1314 LOG.debug('Swift status information obtained successfully')
1315
Chris Dentde456a12014-09-10 12:41:15 +01001316 def create_container(self, container_name=None):
Chris Dent0d494112014-08-26 13:48:30 +01001317 name = container_name or data_utils.rand_name(
1318 'swift-scenario-container')
1319 self.container_client.create_container(name)
1320 # look for the container to assure it is created
Chris Dentde456a12014-09-10 12:41:15 +01001321 self.list_and_check_container_objects(name)
Jordan Pittier525ec712016-12-07 17:51:26 +01001322 LOG.debug('Container %s created', name)
Jordan Pittier9e227c52016-02-09 14:35:18 +01001323 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
Chris Dent1d4313a2014-10-28 12:16:48 +00001324 self.container_client.delete_container,
1325 name)
Chris Dent0d494112014-08-26 13:48:30 +01001326 return name
1327
Chris Dentde456a12014-09-10 12:41:15 +01001328 def delete_container(self, container_name):
Chris Dent0d494112014-08-26 13:48:30 +01001329 self.container_client.delete_container(container_name)
Jordan Pittier525ec712016-12-07 17:51:26 +01001330 LOG.debug('Container %s deleted', container_name)
Chris Dent0d494112014-08-26 13:48:30 +01001331
Chris Dentde456a12014-09-10 12:41:15 +01001332 def upload_object_to_container(self, container_name, obj_name=None):
Chris Dent0d494112014-08-26 13:48:30 +01001333 obj_name = obj_name or data_utils.rand_name('swift-scenario-object')
Jordan Pittierb84f2d42016-12-21 19:02:15 +01001334 obj_data = data_utils.random_bytes()
Chris Dent0d494112014-08-26 13:48:30 +01001335 self.object_client.create_object(container_name, obj_name, obj_data)
Jordan Pittier9e227c52016-02-09 14:35:18 +01001336 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
Chris Dent1d4313a2014-10-28 12:16:48 +00001337 self.object_client.delete_object,
1338 container_name,
1339 obj_name)
Chris Dent0d494112014-08-26 13:48:30 +01001340 return obj_name, obj_data
1341
Chris Dentde456a12014-09-10 12:41:15 +01001342 def delete_object(self, container_name, filename):
Chris Dent0d494112014-08-26 13:48:30 +01001343 self.object_client.delete_object(container_name, filename)
Chris Dentde456a12014-09-10 12:41:15 +01001344 self.list_and_check_container_objects(container_name,
1345 not_present_obj=[filename])
Chris Dent0d494112014-08-26 13:48:30 +01001346
Chris Dentde456a12014-09-10 12:41:15 +01001347 def list_and_check_container_objects(self, container_name,
1348 present_obj=None,
1349 not_present_obj=None):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001350 # List objects for a given container and assert which are present and
1351 # which are not.
Ghanshyam2a180b82014-06-16 13:54:22 +09001352 if present_obj is None:
1353 present_obj = []
1354 if not_present_obj is None:
1355 not_present_obj = []
Chris Dent0d494112014-08-26 13:48:30 +01001356 _, object_list = self.container_client.list_container_contents(
1357 container_name)
1358 if present_obj:
1359 for obj in present_obj:
1360 self.assertIn(obj, object_list)
1361 if not_present_obj:
1362 for obj in not_present_obj:
1363 self.assertNotIn(obj, object_list)
1364
Chris Dentde456a12014-09-10 12:41:15 +01001365 def change_container_acl(self, container_name, acl):
Chris Dent0d494112014-08-26 13:48:30 +01001366 metadata_param = {'metadata_prefix': 'x-container-',
1367 'metadata': {'read': acl}}
1368 self.container_client.update_container_metadata(container_name,
1369 **metadata_param)
1370 resp, _ = self.container_client.list_container_metadata(container_name)
1371 self.assertEqual(resp['x-container-read'], acl)
1372
Chris Dentde456a12014-09-10 12:41:15 +01001373 def download_and_verify(self, container_name, obj_name, expected_data):
Chris Dent0d494112014-08-26 13:48:30 +01001374 _, obj = self.object_client.get_object(container_name, obj_name)
1375 self.assertEqual(obj, expected_data)