blob: 06b4b59466b235f23f302ad7d8a86d99fb9a865f [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)
Andrea Frittolia6b30152017-08-04 10:46:10 +010082 # Use the latest available volume clients
83 if CONF.service_available.cinder:
84 cls.volumes_client = cls.os_primary.volumes_client_latest
85 cls.snapshots_client = cls.os_primary.snapshots_client_latest
Ivan Kolodyazhnybcfc32e2015-08-06 13:31:36 +030086
Jordan Pittierf672b7d2016-06-20 18:50:40 +020087 # ## Test functions library
88 #
89 # The create_[resource] functions only return body and discard the
90 # resp part which is not used in scenario tests
Andrea Frittoli247058f2014-07-16 16:09:22 +010091
zhufl1e446b52017-10-16 16:54:57 +080092 def create_port(self, network_id, client=None, **kwargs):
Lenny Verkhovsky136376f2016-06-29 14:33:34 +030093 if not client:
94 client = self.ports_client
zhufl1e446b52017-10-16 16:54:57 +080095 name = data_utils.rand_name(self.__class__.__name__)
Lenny Verkhovsky136376f2016-06-29 14:33:34 +030096 result = client.create_port(
97 name=name,
98 network_id=network_id,
99 **kwargs)
Lenny Verkhovsky136376f2016-06-29 14:33:34 +0300100 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
zhufl1e446b52017-10-16 16:54:57 +0800148 create_port_body = {'binding:vnic_type': vnic_type}
lanoux5fc14522015-09-21 08:17:35 +0000149 if kwargs:
150 # Convert security group names to security group ids
151 # to pass to create_port
152 if 'security_groups' in kwargs:
Thiago Paiva66cded22016-08-15 14:55:58 -0300153 security_groups = \
John Warrenf9606e92015-12-10 12:12:42 -0500154 clients.security_groups_client.list_security_groups(
lanoux5fc14522015-09-21 08:17:35 +0000155 ).get('security_groups')
156 sec_dict = dict([(s['name'], s['id'])
157 for s in security_groups])
158
159 sec_groups_names = [s['name'] for s in kwargs.pop(
160 'security_groups')]
161 security_groups_ids = [sec_dict[s]
162 for s in sec_groups_names]
163
164 if security_groups_ids:
165 create_port_body[
166 'security_groups'] = security_groups_ids
Lenny Verkhovsky69363502016-07-17 16:33:33 +0300167 networks = kwargs.pop('networks', [])
168 else:
169 networks = []
lanoux5fc14522015-09-21 08:17:35 +0000170
171 # If there are no networks passed to us we look up
Lenny Verkhovsky136376f2016-06-29 14:33:34 +0300172 # for the project's private networks and create a port.
173 # The same behaviour as we would expect when passing
174 # the call to the clients with no networks
lanoux5fc14522015-09-21 08:17:35 +0000175 if not networks:
176 networks = clients.networks_client.list_networks(
Lenny Verkhovsky136376f2016-06-29 14:33:34 +0300177 **{'router:external': False, 'fields': 'id'})['networks']
178
179 # It's net['uuid'] if networks come from kwargs
180 # and net['id'] if they come from
181 # clients.networks_client.list_networks
lanoux5fc14522015-09-21 08:17:35 +0000182 for net in networks:
Lenny Verkhovsky97f7cea2016-08-15 13:29:48 +0000183 net_id = net.get('uuid', net.get('id'))
Lenny Verkhovsky69363502016-07-17 16:33:33 +0300184 if 'port' not in net:
zhufl1e446b52017-10-16 16:54:57 +0800185 port = self.create_port(network_id=net_id,
186 client=clients.ports_client,
187 **create_port_body)
Lenny Verkhovsky69363502016-07-17 16:33:33 +0300188 ports.append({'port': port['id']})
189 else:
190 ports.append({'port': net['port']})
lanoux5fc14522015-09-21 08:17:35 +0000191 if ports:
192 kwargs['networks'] = ports
193 self.ports = ports
194
195 tenant_network = self.get_tenant_network()
196
Ferenc Horváthbce1fcf2017-06-07 11:19:51 +0200197 body, _ = compute.create_test_server(
lanoux5fc14522015-09-21 08:17:35 +0000198 clients,
199 tenant_network=tenant_network,
200 wait_until=wait_until,
Anusha Ramineni9aaef8b2016-01-19 10:56:40 +0530201 name=name, flavor=flavor,
202 image_id=image_id, **kwargs)
lanoux5fc14522015-09-21 08:17:35 +0000203
Jordan Pittierf672b7d2016-06-20 18:50:40 +0200204 self.addCleanup(waiters.wait_for_server_termination,
205 clients.servers_client, body['id'])
206 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
207 clients.servers_client.delete_server, body['id'])
lanoux5fc14522015-09-21 08:17:35 +0000208 server = clients.servers_client.show_server(body['id'])['server']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100209 return server
210
Markus Zoeller3d2a21c2015-02-27 12:04:22 +0100211 def create_volume(self, size=None, name=None, snapshot_id=None,
Jordan Pittier5e1741c2016-03-02 18:25:51 +0100212 imageRef=None, volume_type=None):
Ken'ichi Ohmichiadb905e2016-08-26 15:16:23 -0700213 if size is None:
214 size = CONF.volume.volume_size
Nuno Santosb746d992016-11-17 15:41:55 -0500215 if imageRef:
216 image = self.compute_images_client.show_image(imageRef)['image']
217 min_disk = image.get('minDisk')
218 size = max(size, min_disk)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100219 if name is None:
zhuflf9d95722016-10-19 16:06:17 +0800220 name = data_utils.rand_name(self.__class__.__name__ + "-volume")
Ghanshyam8fc0ed22015-12-18 10:25:14 +0900221 kwargs = {'display_name': name,
222 'snapshot_id': snapshot_id,
223 'imageRef': imageRef,
Ken'ichi Ohmichiadb905e2016-08-26 15:16:23 -0700224 'volume_type': volume_type,
225 'size': size}
Ghanshyam8fc0ed22015-12-18 10:25:14 +0900226 volume = self.volumes_client.create_volume(**kwargs)['volume']
Matt Riedemanne85c2702014-09-10 11:50:13 -0700227
Jordan Pittier5e1741c2016-03-02 18:25:51 +0100228 self.addCleanup(self.volumes_client.wait_for_resource_deletion,
229 volume['id'])
Jordan Pittier9e227c52016-02-09 14:35:18 +0100230 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
Jordan Pittier5e1741c2016-03-02 18:25:51 +0100231 self.volumes_client.delete_volume, volume['id'])
lkuchlan5cbc00a2017-03-26 11:49:54 +0300232 self.assertEqual(name, volume['name'])
lkuchlan52d7b0d2016-11-07 20:53:19 +0200233 waiters.wait_for_volume_resource_status(self.volumes_client,
234 volume['id'], 'available')
Andrea Frittoli247058f2014-07-16 16:09:22 +0100235 # The volume retrieved on creation has a non-up-to-date status.
236 # Retrieval after it becomes active ensures correct details.
John Warren6177c9e2015-08-19 20:00:17 +0000237 volume = self.volumes_client.show_volume(volume['id'])['volume']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100238 return volume
239
lkuchlan73ed1f32017-07-06 16:22:12 +0300240 def create_volume_snapshot(self, volume_id, name=None, description=None,
241 metadata=None, force=False):
242 name = name or data_utils.rand_name(
243 self.__class__.__name__ + '-snapshot')
244 snapshot = self.snapshots_client.create_snapshot(
245 volume_id=volume_id,
246 force=force,
247 display_name=name,
248 description=description,
249 metadata=metadata)['snapshot']
250 self.addCleanup(self.snapshots_client.wait_for_resource_deletion,
251 snapshot['id'])
252 self.addCleanup(self.snapshots_client.delete_snapshot, snapshot['id'])
253 waiters.wait_for_volume_resource_status(self.snapshots_client,
254 snapshot['id'], 'available')
255 return snapshot
256
scottda61f68ac2016-06-07 12:07:55 -0600257 def create_volume_type(self, client=None, name=None, backend_name=None):
258 if not client:
zhufl708821c2017-07-12 16:08:34 +0800259 client = self.os_admin.volume_types_v2_client
scottda61f68ac2016-06-07 12:07:55 -0600260 if not name:
261 class_name = self.__class__.__name__
262 name = data_utils.rand_name(class_name + '-volume-type')
263 randomized_name = data_utils.rand_name('scenario-type-' + name)
264
265 LOG.debug("Creating a volume type: %s on backend %s",
266 randomized_name, backend_name)
267 extra_specs = {}
268 if backend_name:
269 extra_specs = {"volume_backend_name": backend_name}
270
lkuchlanbbabe542017-09-26 10:47:23 +0300271 volume_type = client.create_volume_type(
272 name=randomized_name, extra_specs=extra_specs)['volume_type']
scottda61f68ac2016-06-07 12:07:55 -0600273 self.addCleanup(client.delete_volume_type, volume_type['id'])
274 return volume_type
275
Yair Fried1fc32a12014-08-04 09:11:30 +0300276 def _create_loginable_secgroup_rule(self, secgroup_id=None):
John Warrenf2345512015-12-10 13:39:30 -0500277 _client = self.compute_security_groups_client
John Warren5cdbf422016-01-05 12:42:43 -0500278 _client_rules = self.compute_security_group_rules_client
Andrea Frittoli247058f2014-07-16 16:09:22 +0100279 if secgroup_id is None:
ghanshyamb610b772015-08-24 17:29:38 +0900280 sgs = _client.list_security_groups()['security_groups']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100281 for sg in sgs:
282 if sg['name'] == 'default':
283 secgroup_id = sg['id']
284
285 # These rules are intended to permit inbound ssh and icmp
286 # traffic from all sources, so no group_id is provided.
287 # Setting a group_id would only permit traffic from ports
288 # belonging to the same security group.
289 rulesets = [
290 {
291 # ssh
Ken'ichi Ohmichieb7eeec2015-07-21 01:00:06 +0000292 'ip_protocol': 'tcp',
Andrea Frittoli247058f2014-07-16 16:09:22 +0100293 'from_port': 22,
294 'to_port': 22,
295 'cidr': '0.0.0.0/0',
296 },
297 {
298 # ping
Ken'ichi Ohmichieb7eeec2015-07-21 01:00:06 +0000299 'ip_protocol': 'icmp',
Andrea Frittoli247058f2014-07-16 16:09:22 +0100300 'from_port': -1,
301 'to_port': -1,
302 'cidr': '0.0.0.0/0',
303 }
304 ]
305 rules = list()
306 for ruleset in rulesets:
Ken'ichi Ohmichieb7eeec2015-07-21 01:00:06 +0000307 sg_rule = _client_rules.create_security_group_rule(
ghanshyam0a5e1232015-08-24 16:59:59 +0900308 parent_group_id=secgroup_id, **ruleset)['security_group_rule']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100309 rules.append(sg_rule)
310 return rules
311
Yair Fried1fc32a12014-08-04 09:11:30 +0300312 def _create_security_group(self):
Andrea Frittoli247058f2014-07-16 16:09:22 +0100313 # Create security group
314 sg_name = data_utils.rand_name(self.__class__.__name__)
315 sg_desc = sg_name + " description"
John Warrenf2345512015-12-10 13:39:30 -0500316 secgroup = self.compute_security_groups_client.create_security_group(
ghanshyamb610b772015-08-24 17:29:38 +0900317 name=sg_name, description=sg_desc)['security_group']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100318 self.assertEqual(secgroup['name'], sg_name)
319 self.assertEqual(secgroup['description'], sg_desc)
John Warrenf2345512015-12-10 13:39:30 -0500320 self.addCleanup(
Jordan Pittier9e227c52016-02-09 14:35:18 +0100321 test_utils.call_and_ignore_notfound_exc,
John Warrenf2345512015-12-10 13:39:30 -0500322 self.compute_security_groups_client.delete_security_group,
323 secgroup['id'])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100324
325 # Add rules to the security group
Yair Fried1fc32a12014-08-04 09:11:30 +0300326 self._create_loginable_secgroup_rule(secgroup['id'])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100327
328 return secgroup
329
zhuflf52c7592017-05-25 13:55:24 +0800330 def get_remote_client(self, ip_address, username=None, private_key=None,
331 server=None):
JordanP3fe2dc32014-11-17 13:06:01 +0100332 """Get a SSH client to a remote server
333
Sean Dague20e98612016-01-06 14:33:28 -0500334 @param ip_address the server floating or fixed IP address to use
335 for ssh validation
JordanP3fe2dc32014-11-17 13:06:01 +0100336 @param username name of the Linux account on the remote server
337 @param private_key the SSH private key to use
zhuflf52c7592017-05-25 13:55:24 +0800338 @param server: server dict, used for debugging purposes
JordanP3fe2dc32014-11-17 13:06:01 +0100339 @return a RemoteClient object
340 """
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700341
Andrea Frittoli247058f2014-07-16 16:09:22 +0100342 if username is None:
lanoux283273b2015-12-04 03:01:54 -0800343 username = CONF.validation.image_ssh_user
wantwatering896300c2015-03-27 15:17:42 +0800344 # Set this with 'keypair' or others to log in with keypair or
345 # username/password.
lanoux5fc14522015-09-21 08:17:35 +0000346 if CONF.validation.auth_method == 'keypair':
wantwatering896300c2015-03-27 15:17:42 +0800347 password = None
348 if private_key is None:
349 private_key = self.keypair['private_key']
350 else:
lanoux283273b2015-12-04 03:01:54 -0800351 password = CONF.validation.image_ssh_password
wantwatering896300c2015-03-27 15:17:42 +0800352 private_key = None
zhuflf52c7592017-05-25 13:55:24 +0800353 linux_client = remote_client.RemoteClient(
354 ip_address, username, pkey=private_key, password=password,
355 server=server, servers_client=self.servers_client)
356 linux_client.validate_authentication()
Andrea Frittoli247058f2014-07-16 16:09:22 +0100357 return linux_client
358
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000359 def _image_create(self, name, fmt, path,
360 disk_format=None, properties=None):
Ghanshyam2a180b82014-06-16 13:54:22 +0900361 if properties is None:
362 properties = {}
Andrea Frittoli247058f2014-07-16 16:09:22 +0100363 name = data_utils.rand_name('%s-' % name)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100364 params = {
365 'name': name,
366 'container_format': fmt,
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000367 'disk_format': disk_format or fmt,
Andrea Frittoli247058f2014-07-16 16:09:22 +0100368 }
Matt Riedemann2aa19d42016-06-06 17:45:41 -0400369 if CONF.image_feature_enabled.api_v1:
370 params['is_public'] = 'False'
371 params['properties'] = properties
Ken'ichi Ohmichi02bcdf32016-06-17 16:41:26 -0700372 params = {'headers': common_image.image_meta_to_headers(**params)}
Matt Riedemann2aa19d42016-06-06 17:45:41 -0400373 else:
374 params['visibility'] = 'private'
375 # Additional properties are flattened out in the v2 API.
376 params.update(properties)
377 body = self.image_client.create_image(**params)
378 image = body['image'] if 'image' in body else body
Andrea Frittoli247058f2014-07-16 16:09:22 +0100379 self.addCleanup(self.image_client.delete_image, image['id'])
380 self.assertEqual("queued", image['status'])
zhang.leia4b1cef2016-03-01 10:50:01 +0800381 with open(path, 'rb') as image_file:
Matt Riedemann2aa19d42016-06-06 17:45:41 -0400382 if CONF.image_feature_enabled.api_v1:
383 self.image_client.update_image(image['id'], data=image_file)
384 else:
385 self.image_client.store_image_file(image['id'], image_file)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100386 return image['id']
387
388 def glance_image_create(self):
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300389 img_path = CONF.scenario.img_dir + "/" + CONF.scenario.img_file
Andrea Frittoli247058f2014-07-16 16:09:22 +0100390 aki_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.aki_img_file
391 ari_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.ari_img_file
392 ami_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.ami_img_file
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300393 img_container_format = CONF.scenario.img_container_format
394 img_disk_format = CONF.scenario.img_disk_format
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000395 img_properties = CONF.scenario.img_properties
PranaliD2aa523c2016-06-07 03:54:34 -0400396 LOG.debug("paths: img: %s, container_format: %s, disk_format: %s, "
Jordan Pittier525ec712016-12-07 17:51:26 +0100397 "properties: %s, ami: %s, ari: %s, aki: %s",
398 img_path, img_container_format, img_disk_format,
399 img_properties, ami_img_path, ari_img_path, aki_img_path)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100400 try:
Jordan Pittier1e443ec2015-11-20 16:15:58 +0100401 image = self._image_create('scenario-img',
402 img_container_format,
403 img_path,
404 disk_format=img_disk_format,
405 properties=img_properties)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100406 except IOError:
407 LOG.debug("A qcow2 image was not found. Try to get a uec image.")
408 kernel = self._image_create('scenario-aki', 'aki', aki_img_path)
409 ramdisk = self._image_create('scenario-ari', 'ari', ari_img_path)
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000410 properties = {'kernel_id': kernel, 'ramdisk_id': ramdisk}
Jordan Pittier1e443ec2015-11-20 16:15:58 +0100411 image = self._image_create('scenario-ami', 'ami',
412 path=ami_img_path,
413 properties=properties)
Jordan Pittier525ec712016-12-07 17:51:26 +0100414 LOG.debug("image:%s", image)
Jordan Pittier1e443ec2015-11-20 16:15:58 +0100415
416 return image
Andrea Frittoli247058f2014-07-16 16:09:22 +0100417
Ihar Hrachyshkaa9dca2b2017-04-04 14:17:11 -0700418 def _log_console_output(self, servers=None, client=None):
Matthew Treinish42a3f3a2014-09-04 15:04:53 -0400419 if not CONF.compute_feature_enabled.console_output:
420 LOG.debug('Console output not supported, cannot log')
421 return
Ihar Hrachyshkaa9dca2b2017-04-04 14:17:11 -0700422 client = client or self.servers_client
Andrea Frittoli247058f2014-07-16 16:09:22 +0100423 if not servers:
Ihar Hrachyshkaa9dca2b2017-04-04 14:17:11 -0700424 servers = client.list_servers()
Andrea Frittoli247058f2014-07-16 16:09:22 +0100425 servers = servers['servers']
426 for server in servers:
Attila Fazekas9a5a1122016-11-08 10:24:57 +0100427 try:
Ihar Hrachyshkaa9dca2b2017-04-04 14:17:11 -0700428 console_output = client.get_console_output(
Attila Fazekas9a5a1122016-11-08 10:24:57 +0100429 server['id'])['output']
430 LOG.debug('Console output for %s\nbody=\n%s',
431 server['id'], console_output)
432 except lib_exc.NotFound:
Attila Fazekase1360482016-11-10 11:28:08 +0100433 LOG.debug("Server %s disappeared(deleted) while looking "
Attila Fazekas9a5a1122016-11-08 10:24:57 +0100434 "for the console log", server['id'])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100435
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000436 def _log_net_info(self, exc):
437 # network debug is called as part of ssh init
Andrey Pavlov64723762015-04-29 06:24:58 +0300438 if not isinstance(exc, lib_exc.SSHTimeout):
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000439 LOG.debug('Network information on a devstack host')
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000440
nithya-ganesan882595e2014-07-29 18:51:07 +0000441 def create_server_snapshot(self, server, name=None):
442 # Glance client
443 _image_client = self.image_client
444 # Compute client
Ghanshyamae76c122015-12-22 13:41:35 +0900445 _images_client = self.compute_images_client
nithya-ganesan882595e2014-07-29 18:51:07 +0000446 if name is None:
zhuflf9d95722016-10-19 16:06:17 +0800447 name = data_utils.rand_name(self.__class__.__name__ + 'snapshot')
nithya-ganesan882595e2014-07-29 18:51:07 +0000448 LOG.debug("Creating a snapshot image for server: %s", server['name'])
Ken'ichi Ohmichi28f18672015-07-17 10:00:38 +0000449 image = _images_client.create_image(server['id'], name=name)
David Kranza5299eb2015-01-15 17:24:05 -0500450 image_id = image.response['location'].split('images/')[1]
Yaroslav Lobankov2fea4052016-04-19 15:05:57 +0300451 waiters.wait_for_image_status(_image_client, image_id, 'active')
Jordan Pittierf672b7d2016-06-20 18:50:40 +0200452
453 self.addCleanup(_image_client.wait_for_resource_deletion,
454 image_id)
455 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
456 _image_client.delete_image, image_id)
457
Matt Riedemann2aa19d42016-06-06 17:45:41 -0400458 if CONF.image_feature_enabled.api_v1:
459 # In glance v1 the additional properties are stored in the headers.
Ken'ichi Ohmichi01151e82016-06-10 11:19:52 -0700460 resp = _image_client.check_image(image_id)
461 snapshot_image = common_image.get_image_meta_from_headers(resp)
Matt Riedemann2aa19d42016-06-06 17:45:41 -0400462 image_props = snapshot_image.get('properties', {})
463 else:
464 # In glance v2 the additional properties are flattened.
465 snapshot_image = _image_client.show_image(image_id)
466 image_props = snapshot_image
Andrey Pavlovc8bd4b12015-08-17 10:20:17 +0300467
Matt Riedemann2aa19d42016-06-06 17:45:41 -0400468 bdm = image_props.get('block_device_mapping')
Andrey Pavlovc8bd4b12015-08-17 10:20:17 +0300469 if bdm:
470 bdm = json.loads(bdm)
471 if bdm and 'snapshot_id' in bdm[0]:
472 snapshot_id = bdm[0]['snapshot_id']
473 self.addCleanup(
474 self.snapshots_client.wait_for_resource_deletion,
475 snapshot_id)
Jordan Pittier9e227c52016-02-09 14:35:18 +0100476 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
477 self.snapshots_client.delete_snapshot,
478 snapshot_id)
lkuchlan52d7b0d2016-11-07 20:53:19 +0200479 waiters.wait_for_volume_resource_status(self.snapshots_client,
480 snapshot_id,
481 'available')
nithya-ganesan882595e2014-07-29 18:51:07 +0000482 image_name = snapshot_image['name']
483 self.assertEqual(name, image_name)
484 LOG.debug("Created snapshot image %s for server %s",
485 image_name, server['name'])
486 return snapshot_image
487
Jordan Pittier7cf64762015-10-14 15:01:12 +0200488 def nova_volume_attach(self, server, volume_to_attach):
Joseph Lanoux6809bab2014-12-18 14:57:18 +0000489 volume = self.servers_client.attach_volume(
Jordan Pittier7cf64762015-10-14 15:01:12 +0200490 server['id'], volumeId=volume_to_attach['id'], device='/dev/%s'
ghanshyam0f825252015-08-25 16:02:50 +0900491 % CONF.compute.volume_device_name)['volumeAttachment']
Jordan Pittier7cf64762015-10-14 15:01:12 +0200492 self.assertEqual(volume_to_attach['id'], volume['id'])
lkuchlan52d7b0d2016-11-07 20:53:19 +0200493 waiters.wait_for_volume_resource_status(self.volumes_client,
494 volume['id'], 'in-use')
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900495
Jordan Pittier7cf64762015-10-14 15:01:12 +0200496 # Return the updated volume after the attachment
497 return self.volumes_client.show_volume(volume['id'])['volume']
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900498
Jordan Pittier7cf64762015-10-14 15:01:12 +0200499 def nova_volume_detach(self, server, volume):
500 self.servers_client.detach_volume(server['id'], volume['id'])
lkuchlan52d7b0d2016-11-07 20:53:19 +0200501 waiters.wait_for_volume_resource_status(self.volumes_client,
502 volume['id'], 'available')
Jordan Pittier7cf64762015-10-14 15:01:12 +0200503
Steven Hardyda2a8352014-10-02 12:52:20 +0100504 def ping_ip_address(self, ip_address, should_succeed=True,
Ihar Hrachyshkaf9227c02016-09-15 11:16:47 +0000505 ping_timeout=None, mtu=None):
lanoux5fc14522015-09-21 08:17:35 +0000506 timeout = ping_timeout or CONF.validation.ping_timeout
Ihar Hrachyshkaf9227c02016-09-15 11:16:47 +0000507 cmd = ['ping', '-c1', '-w1']
508
509 if mtu:
510 cmd += [
511 # don't fragment
512 '-M', 'do',
513 # ping receives just the size of ICMP payload
514 '-s', str(net_utils.get_ping_payload_size(mtu, 4))
515 ]
516 cmd.append(ip_address)
Aaron Rosena7df13b2014-09-23 09:45:45 -0700517
518 def ping():
519 proc = subprocess.Popen(cmd,
520 stdout=subprocess.PIPE,
521 stderr=subprocess.PIPE)
522 proc.communicate()
Shuquan Huang753629e2015-07-20 08:52:29 +0000523
Aaron Rosena7df13b2014-09-23 09:45:45 -0700524 return (proc.returncode == 0) == should_succeed
525
Jordan Pittier9e227c52016-02-09 14:35:18 +0100526 caller = test_utils.find_test_caller()
Shuquan Huang753629e2015-07-20 08:52:29 +0000527 LOG.debug('%(caller)s begins to ping %(ip)s in %(timeout)s sec and the'
John L. Villalovosa898aec2017-01-13 14:46:46 -0800528 ' expected result is %(should_succeed)s', {
Shuquan Huang753629e2015-07-20 08:52:29 +0000529 'caller': caller, 'ip': ip_address, 'timeout': timeout,
530 'should_succeed':
531 'reachable' if should_succeed else 'unreachable'
532 })
Jordan Pittier35a63752016-08-30 13:09:12 +0200533 result = test_utils.call_until_true(ping, timeout, 1)
Shuquan Huang753629e2015-07-20 08:52:29 +0000534 LOG.debug('%(caller)s finishes ping %(ip)s in %(timeout)s sec and the '
John L. Villalovosa898aec2017-01-13 14:46:46 -0800535 'ping result is %(result)s', {
Shuquan Huang753629e2015-07-20 08:52:29 +0000536 'caller': caller, 'ip': ip_address, 'timeout': timeout,
537 'result': 'expected' if result else 'unexpected'
538 })
539 return result
Aaron Rosena7df13b2014-09-23 09:45:45 -0700540
Yair Friedae0e73d2014-11-24 11:56:26 +0200541 def check_vm_connectivity(self, ip_address,
542 username=None,
543 private_key=None,
Ihar Hrachyshkaf9227c02016-09-15 11:16:47 +0000544 should_connect=True,
545 mtu=None):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000546 """Check server connectivity
547
Yair Friedae0e73d2014-11-24 11:56:26 +0200548 :param ip_address: server to test against
549 :param username: server's ssh username
550 :param private_key: server's ssh private key to be used
551 :param should_connect: True/False indicates positive/negative test
552 positive - attempt ping and ssh
553 negative - attempt ping and fail if succeed
Ihar Hrachyshkaf9227c02016-09-15 11:16:47 +0000554 :param mtu: network MTU to use for connectivity validation
Yair Friedae0e73d2014-11-24 11:56:26 +0200555
556 :raises: AssertError if the result of the connectivity check does
557 not match the value of the should_connect param
558 """
559 if should_connect:
560 msg = "Timed out waiting for %s to become reachable" % ip_address
561 else:
562 msg = "ip address %s is reachable" % ip_address
563 self.assertTrue(self.ping_ip_address(ip_address,
Ihar Hrachyshkaf9227c02016-09-15 11:16:47 +0000564 should_succeed=should_connect,
565 mtu=mtu),
Yair Friedae0e73d2014-11-24 11:56:26 +0200566 msg=msg)
567 if should_connect:
568 # no need to check ssh for negative connectivity
569 self.get_remote_client(ip_address, username, private_key)
570
571 def check_public_network_connectivity(self, ip_address, username,
572 private_key, should_connect=True,
Ihar Hrachyshkaf9227c02016-09-15 11:16:47 +0000573 msg=None, servers=None, mtu=None):
Yair Friedae0e73d2014-11-24 11:56:26 +0200574 # The target login is assumed to have been configured for
575 # key-based authentication by cloud-init.
Jordan Pittier525ec712016-12-07 17:51:26 +0100576 LOG.debug('checking network connections to IP %s with user: %s',
577 ip_address, username)
Yair Friedae0e73d2014-11-24 11:56:26 +0200578 try:
579 self.check_vm_connectivity(ip_address,
580 username,
581 private_key,
Ihar Hrachyshkaf9227c02016-09-15 11:16:47 +0000582 should_connect=should_connect,
583 mtu=mtu)
Matthew Treinish53483132014-12-09 18:50:06 -0500584 except Exception:
Yair Friedae0e73d2014-11-24 11:56:26 +0200585 ex_msg = 'Public network connectivity check failed'
586 if msg:
587 ex_msg += ": " + msg
588 LOG.exception(ex_msg)
589 self._log_console_output(servers)
Yair Friedae0e73d2014-11-24 11:56:26 +0200590 raise
591
592 def create_floating_ip(self, thing, pool_name=None):
Ken'ichi Ohmichia112a592015-11-17 08:49:37 +0000593 """Create a floating IP and associates to a server on Nova"""
Yair Friedae0e73d2014-11-24 11:56:26 +0200594
Marc Koderer3b57d802016-03-22 15:23:31 +0100595 if not pool_name:
596 pool_name = CONF.network.floating_network_name
John Warrene74890a2015-11-11 15:18:01 -0500597 floating_ip = (self.compute_floating_ips_client.
Ken'ichi Ohmichie037a6f2015-12-03 06:41:49 +0000598 create_floating_ip(pool=pool_name)['floating_ip'])
Jordan Pittier9e227c52016-02-09 14:35:18 +0100599 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
John Warrene74890a2015-11-11 15:18:01 -0500600 self.compute_floating_ips_client.delete_floating_ip,
Yair Friedae0e73d2014-11-24 11:56:26 +0200601 floating_ip['id'])
John Warrene74890a2015-11-11 15:18:01 -0500602 self.compute_floating_ips_client.associate_floating_ip_to_server(
Yair Friedae0e73d2014-11-24 11:56:26 +0200603 floating_ip['ip'], thing['id'])
604 return floating_ip
605
Sean Dague20e98612016-01-06 14:33:28 -0500606 def create_timestamp(self, ip_address, dev_name=None, mount_path='/mnt',
Matt Riedemannfd5657d2015-09-30 14:47:07 -0700607 private_key=None):
Sean Dague20e98612016-01-06 14:33:28 -0500608 ssh_client = self.get_remote_client(ip_address,
Matt Riedemannfd5657d2015-09-30 14:47:07 -0700609 private_key=private_key)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300610 if dev_name is not None:
611 ssh_client.make_fs(dev_name)
Ken'ichi Ohmichi4e5a69e2017-03-01 18:15:29 -0800612 ssh_client.exec_command('sudo mount /dev/%s %s' % (dev_name,
613 mount_path))
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300614 cmd_timestamp = 'sudo sh -c "date > %s/timestamp; sync"' % mount_path
615 ssh_client.exec_command(cmd_timestamp)
616 timestamp = ssh_client.exec_command('sudo cat %s/timestamp'
617 % mount_path)
618 if dev_name is not None:
Ken'ichi Ohmichi4e5a69e2017-03-01 18:15:29 -0800619 ssh_client.exec_command('sudo umount %s' % mount_path)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300620 return timestamp
621
Sean Dague20e98612016-01-06 14:33:28 -0500622 def get_timestamp(self, ip_address, dev_name=None, mount_path='/mnt',
Matt Riedemannfd5657d2015-09-30 14:47:07 -0700623 private_key=None):
Sean Dague20e98612016-01-06 14:33:28 -0500624 ssh_client = self.get_remote_client(ip_address,
Matt Riedemannfd5657d2015-09-30 14:47:07 -0700625 private_key=private_key)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300626 if dev_name is not None:
Matt Riedemann076685a2015-09-30 14:38:16 -0700627 ssh_client.mount(dev_name, mount_path)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300628 timestamp = ssh_client.exec_command('sudo cat %s/timestamp'
629 % mount_path)
630 if dev_name is not None:
Ken'ichi Ohmichi4e5a69e2017-03-01 18:15:29 -0800631 ssh_client.exec_command('sudo umount %s' % mount_path)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300632 return timestamp
633
Sean Dague20e98612016-01-06 14:33:28 -0500634 def get_server_ip(self, server):
635 """Get the server fixed or floating IP.
636
637 Based on the configuration we're in, return a correct ip
638 address for validating that a guest is up.
639 """
Alexander Gubanovc8829f82015-11-12 10:35:13 +0200640 if CONF.validation.connect_method == 'floating':
Sean Dague20e98612016-01-06 14:33:28 -0500641 # The tests calling this method don't have a floating IP
zhufl0892cb22016-05-06 14:46:00 +0800642 # and can't make use of the validation resources. So the
Sean Dague20e98612016-01-06 14:33:28 -0500643 # method is creating the floating IP there.
644 return self.create_floating_ip(server)['ip']
645 elif CONF.validation.connect_method == 'fixed':
Matt Riedemanna7782552016-08-08 16:26:01 -0400646 # Determine the network name to look for based on config or creds
647 # provider network resources.
648 if CONF.validation.network_for_ssh:
649 addresses = server['addresses'][
650 CONF.validation.network_for_ssh]
651 else:
zhufl7b4a7202017-09-28 10:29:27 +0800652 network = self.get_tenant_network()
Matt Riedemanna7782552016-08-08 16:26:01 -0400653 addresses = (server['addresses'][network['name']]
654 if network else [])
Sean Dague20e98612016-01-06 14:33:28 -0500655 for address in addresses:
Matt Riedemanna7782552016-08-08 16:26:01 -0400656 if (address['version'] == CONF.validation.ip_version_for_ssh
657 and address['OS-EXT-IPS:type'] == 'fixed'):
Sean Dague20e98612016-01-06 14:33:28 -0500658 return address['addr']
zhufl955f82b2016-07-22 11:14:34 +0800659 raise exceptions.ServerUnreachable(server_id=server['id'])
Alexander Gubanovc8829f82015-11-12 10:35:13 +0200660 else:
Matthew Treinish4217a702016-10-07 17:27:11 -0400661 raise lib_exc.InvalidConfiguration()
Alexander Gubanovc8829f82015-11-12 10:35:13 +0200662
Andrea Frittoli2e733b52014-07-16 14:12:11 +0100663
Andrea Frittoli4971fc82014-09-25 10:22:20 +0100664class NetworkScenarioTest(ScenarioTest):
Yair Fried1fc32a12014-08-04 09:11:30 +0300665 """Base class for network scenario tests.
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000666
Yair Fried1fc32a12014-08-04 09:11:30 +0300667 This class provide helpers for network scenario tests, using the neutron
668 API. Helpers from ancestor which use the nova network API are overridden
669 with the neutron API.
670
671 This Class also enforces using Neutron instead of novanetwork.
672 Subclassed tests will be skipped if Neutron is not enabled
673
674 """
675
Andrea Frittolib21de6c2015-02-06 20:12:38 +0000676 credentials = ['primary', 'admin']
677
Yair Fried1fc32a12014-08-04 09:11:30 +0300678 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +0000679 def skip_checks(cls):
680 super(NetworkScenarioTest, cls).skip_checks()
Andrea Frittoli2ddc2632014-09-25 11:03:00 +0100681 if not CONF.service_available.neutron:
682 raise cls.skipException('Neutron not available')
Yair Fried1fc32a12014-08-04 09:11:30 +0300683
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -0700684 def _create_network(self, networks_client=None,
zhoubin5058bead72017-02-04 18:01:15 +0800685 tenant_id=None,
Markus Zoeller156b5da2016-07-11 18:10:31 +0200686 namestart='network-smoke-',
687 port_security_enabled=True):
John Warren94d8faf2015-09-15 12:22:24 -0400688 if not networks_client:
689 networks_client = self.networks_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300690 if not tenant_id:
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -0700691 tenant_id = networks_client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300692 name = data_utils.rand_name(namestart)
Matt Riedemann039b2fe2016-09-15 16:12:24 -0400693 network_kwargs = dict(name=name, tenant_id=tenant_id)
694 # Neutron disables port security by default so we have to check the
695 # config before trying to create the network with port_security_enabled
696 if CONF.network_feature_enabled.port_security:
697 network_kwargs['port_security_enabled'] = port_security_enabled
Markus Zoeller156b5da2016-07-11 18:10:31 +0200698 result = networks_client.create_network(**network_kwargs)
Steve Heyman33735f22016-05-24 09:28:08 -0500699 network = result['network']
700
701 self.assertEqual(network['name'], name)
Jordan Pittier9e227c52016-02-09 14:35:18 +0100702 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
zhoubin508bf20b32017-02-03 09:39:14 +0800703 networks_client.delete_network,
Steve Heyman33735f22016-05-24 09:28:08 -0500704 network['id'])
Yair Fried1fc32a12014-08-04 09:11:30 +0300705 return network
706
zhufl5b0a52f2017-10-24 15:48:20 +0800707 def create_subnet(self, network, subnets_client=None,
708 namestart='subnet-smoke', **kwargs):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000709 """Create a subnet for the given network
710
711 within the cidr block configured for tenant networks.
Yair Fried1fc32a12014-08-04 09:11:30 +0300712 """
John Warren3961acd2015-10-02 14:38:53 -0400713 if not subnets_client:
714 subnets_client = self.subnets_client
Yair Fried1fc32a12014-08-04 09:11:30 +0300715
716 def cidr_in_use(cidr, tenant_id):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000717 """Check cidr existence
718
lei zhangdd552b22015-11-25 20:41:48 +0800719 :returns: True if subnet with cidr already exist in tenant
720 False else
Yair Fried1fc32a12014-08-04 09:11:30 +0300721 """
jeremy.zhang5870ff12017-05-25 11:24:23 +0800722 cidr_in_use = self.os_admin.subnets_client.list_subnets(
Jordan Pittier64e6b442017-02-20 19:29:02 +0100723 tenant_id=tenant_id, cidr=cidr)['subnets']
Yair Fried1fc32a12014-08-04 09:11:30 +0300724 return len(cidr_in_use) != 0
725
Kirill Shileev14113572014-11-21 16:58:02 +0300726 ip_version = kwargs.pop('ip_version', 4)
727
728 if ip_version == 6:
729 tenant_cidr = netaddr.IPNetwork(
Sean Dagueed6e5862016-04-04 10:49:13 -0400730 CONF.network.project_network_v6_cidr)
731 num_bits = CONF.network.project_network_v6_mask_bits
Kirill Shileev14113572014-11-21 16:58:02 +0300732 else:
Sean Dagueed6e5862016-04-04 10:49:13 -0400733 tenant_cidr = netaddr.IPNetwork(CONF.network.project_network_cidr)
734 num_bits = CONF.network.project_network_mask_bits
Kirill Shileev14113572014-11-21 16:58:02 +0300735
Yair Fried1fc32a12014-08-04 09:11:30 +0300736 result = None
Kirill Shileev14113572014-11-21 16:58:02 +0300737 str_cidr = None
Yair Fried1fc32a12014-08-04 09:11:30 +0300738 # Repeatedly attempt subnet creation with sequential cidr
739 # blocks until an unallocated block is found.
Kirill Shileev14113572014-11-21 16:58:02 +0300740 for subnet_cidr in tenant_cidr.subnet(num_bits):
Yair Fried1fc32a12014-08-04 09:11:30 +0300741 str_cidr = str(subnet_cidr)
Steve Heyman33735f22016-05-24 09:28:08 -0500742 if cidr_in_use(str_cidr, tenant_id=network['tenant_id']):
Yair Fried1fc32a12014-08-04 09:11:30 +0300743 continue
744
745 subnet = dict(
746 name=data_utils.rand_name(namestart),
Steve Heyman33735f22016-05-24 09:28:08 -0500747 network_id=network['id'],
748 tenant_id=network['tenant_id'],
Yair Fried1fc32a12014-08-04 09:11:30 +0300749 cidr=str_cidr,
Kirill Shileev14113572014-11-21 16:58:02 +0300750 ip_version=ip_version,
Yair Fried1fc32a12014-08-04 09:11:30 +0300751 **kwargs
752 )
753 try:
John Warren3961acd2015-10-02 14:38:53 -0400754 result = subnets_client.create_subnet(**subnet)
Yair Fried1fc32a12014-08-04 09:11:30 +0300755 break
Masayuki Igawad9388762015-01-20 14:56:42 +0900756 except lib_exc.Conflict as e:
Yair Fried1fc32a12014-08-04 09:11:30 +0300757 is_overlapping_cidr = 'overlaps with another subnet' in str(e)
758 if not is_overlapping_cidr:
759 raise
760 self.assertIsNotNone(result, 'Unable to allocate tenant network')
Steve Heyman33735f22016-05-24 09:28:08 -0500761
762 subnet = result['subnet']
763 self.assertEqual(subnet['cidr'], str_cidr)
764
765 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
766 subnets_client.delete_subnet, subnet['id'])
767
Yair Fried1fc32a12014-08-04 09:11:30 +0300768 return subnet
769
Kirill Shileev14113572014-11-21 16:58:02 +0300770 def _get_server_port_id_and_ip4(self, server, ip_addr=None):
jeremy.zhang5870ff12017-05-25 11:24:23 +0800771 ports = self.os_admin.ports_client.list_ports(
Jordan Pittier64e6b442017-02-20 19:29:02 +0100772 device_id=server['id'], fixed_ip=ip_addr)['ports']
Kobi Samoray166500a2016-10-09 14:42:48 +0300773 # A port can have more than one IP address in some cases.
Sean M. Collins2e896832015-12-15 13:58:47 -0500774 # If the network is dual-stack (IPv4 + IPv6), this port is associated
775 # with 2 subnets
Vasyl Saienko8fd517c2016-05-30 09:52:54 +0300776 p_status = ['ACTIVE']
777 # NOTE(vsaienko) With Ironic, instances live on separate hardware
778 # servers. Neutron does not bind ports for Ironic instances, as a
779 # result the port remains in the DOWN state.
Vasyl Saienkoc8aa34b2016-08-01 14:18:37 +0300780 # TODO(vsaienko) remove once bug: #1599836 is resolved.
Thiago Paiva66cded22016-08-15 14:55:58 -0300781 if getattr(CONF.service_available, 'ironic', False):
Vasyl Saienko8fd517c2016-05-30 09:52:54 +0300782 p_status.append('DOWN')
Daniel Mellado9e3e1062015-08-06 18:07:05 +0200783 port_map = [(p["id"], fxip["ip_address"])
784 for p in ports
785 for fxip in p["fixed_ips"]
Yatin Kumbhareee4924c2016-06-09 15:12:06 +0530786 if netutils.is_valid_ipv4(fxip["ip_address"])
Vasyl Saienko8fd517c2016-05-30 09:52:54 +0300787 and p['status'] in p_status]
Kevin Benton1d0c1dc2016-02-04 14:30:08 -0800788 inactive = [p for p in ports if p['status'] != 'ACTIVE']
789 if inactive:
790 LOG.warning("Instance has ports that are not ACTIVE: %s", inactive)
Daniel Mellado9e3e1062015-08-06 18:07:05 +0200791
Masayuki Igawaf9009b42017-04-10 14:49:29 +0900792 self.assertNotEmpty(port_map,
John L. Villalovosb83286f2015-11-04 14:46:57 -0800793 "No IPv4 addresses found in: %s" % ports)
Daniel Mellado9e3e1062015-08-06 18:07:05 +0200794 self.assertEqual(len(port_map), 1,
795 "Found multiple IPv4 addresses: %s. "
796 "Unable to determine which port to target."
797 % port_map)
798 return port_map[0]
Yair Fried1fc32a12014-08-04 09:11:30 +0300799
David Shrewsbury9bac3662014-08-07 15:07:01 -0400800 def _get_network_by_name(self, network_name):
jeremy.zhang5870ff12017-05-25 11:24:23 +0800801 net = self.os_admin.networks_client.list_networks(
Jordan Pittier64e6b442017-02-20 19:29:02 +0100802 name=network_name)['networks']
Ferenc Horváth268ccce2017-06-08 12:39:02 +0200803 self.assertNotEmpty(net,
Adam Gandelman878a5fd2015-03-30 14:33:36 -0700804 "Unable to get network by name: %s" % network_name)
Steve Heyman33735f22016-05-24 09:28:08 -0500805 return net[0]
David Shrewsbury9bac3662014-08-07 15:07:01 -0400806
Yair Friedae0e73d2014-11-24 11:56:26 +0200807 def create_floating_ip(self, thing, external_network_id=None,
808 port_id=None, client=None):
Ken'ichi Ohmichia112a592015-11-17 08:49:37 +0000809 """Create a floating IP and associates to a resource/port on Neutron"""
Yair Friedae0e73d2014-11-24 11:56:26 +0200810 if not external_network_id:
811 external_network_id = CONF.network.public_network_id
Yair Frieddb6c9e92014-08-06 08:53:13 +0300812 if not client:
John Warrenfbf2a892015-11-17 12:36:14 -0500813 client = self.floating_ips_client
Yair Fried1fc32a12014-08-04 09:11:30 +0300814 if not port_id:
Kirill Shileev14113572014-11-21 16:58:02 +0300815 port_id, ip4 = self._get_server_port_id_and_ip4(thing)
816 else:
817 ip4 = None
David Kranz34e88122014-12-11 15:24:05 -0500818 result = client.create_floatingip(
Yair Fried1fc32a12014-08-04 09:11:30 +0300819 floating_network_id=external_network_id,
820 port_id=port_id,
Kirill Shileev14113572014-11-21 16:58:02 +0300821 tenant_id=thing['tenant_id'],
822 fixed_ip_address=ip4
Yair Fried1fc32a12014-08-04 09:11:30 +0300823 )
Steve Heyman33735f22016-05-24 09:28:08 -0500824 floating_ip = result['floatingip']
Jordan Pittier9e227c52016-02-09 14:35:18 +0100825 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
zhoubin508bf20b32017-02-03 09:39:14 +0800826 client.delete_floatingip,
Steve Heyman33735f22016-05-24 09:28:08 -0500827 floating_ip['id'])
Yair Fried1fc32a12014-08-04 09:11:30 +0300828 return floating_ip
829
Yair Fried45f92952014-06-26 05:19:19 +0300830 def check_floating_ip_status(self, floating_ip, status):
Carl Baldwina754e2d2014-10-23 22:47:41 +0000831 """Verifies floatingip reaches the given status
Yair Fried45f92952014-06-26 05:19:19 +0300832
Steve Heyman33735f22016-05-24 09:28:08 -0500833 :param dict floating_ip: floating IP dict to check status
Yair Fried45f92952014-06-26 05:19:19 +0300834 :param status: target status
835 :raises: AssertionError if status doesn't match
836 """
Steve Heyman33735f22016-05-24 09:28:08 -0500837 floatingip_id = floating_ip['id']
838
Carl Baldwina754e2d2014-10-23 22:47:41 +0000839 def refresh():
Steve Heyman33735f22016-05-24 09:28:08 -0500840 result = (self.floating_ips_client.
841 show_floatingip(floatingip_id)['floatingip'])
842 return status == result['status']
Carl Baldwina754e2d2014-10-23 22:47:41 +0000843
zhufl4dda94e2017-03-14 16:14:46 +0800844 if not test_utils.call_until_true(refresh,
845 CONF.network.build_timeout,
846 CONF.network.build_interval):
847 floating_ip = self.floating_ips_client.show_floatingip(
848 floatingip_id)['floatingip']
849 self.assertEqual(status, floating_ip['status'],
850 message="FloatingIP: {fp} is at status: {cst}. "
851 "failed to reach status: {st}"
852 .format(fp=floating_ip, cst=floating_ip['status'],
853 st=status))
Yair Fried45f92952014-06-26 05:19:19 +0300854 LOG.info("FloatingIP: {fp} is at status: {st}"
855 .format(fp=floating_ip, st=status))
856
zhufl420a0192017-09-28 11:04:50 +0800857 def check_tenant_network_connectivity(self, server,
858 username,
859 private_key,
860 should_connect=True,
861 servers_for_debug=None):
Sean Dagueed6e5862016-04-04 10:49:13 -0400862 if not CONF.network.project_networks_reachable:
Yair Fried1fc32a12014-08-04 09:11:30 +0300863 msg = 'Tenant networks not configured to be reachable.'
864 LOG.info(msg)
865 return
866 # The target login is assumed to have been configured for
867 # key-based authentication by cloud-init.
868 try:
Béla Vancsicsb6dfa082017-03-01 10:44:58 +0100869 for ip_addresses in server['addresses'].values():
Yair Fried1fc32a12014-08-04 09:11:30 +0300870 for ip_address in ip_addresses:
ghanshyam807211c2014-12-18 13:21:22 +0900871 self.check_vm_connectivity(ip_address['addr'],
Yair Friedae0e73d2014-11-24 11:56:26 +0200872 username,
873 private_key,
874 should_connect=should_connect)
Yair Fried1fc32a12014-08-04 09:11:30 +0300875 except Exception as e:
876 LOG.exception('Tenant network connectivity check failed')
877 self._log_console_output(servers_for_debug)
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000878 self._log_net_info(e)
Yair Fried1fc32a12014-08-04 09:11:30 +0300879 raise
880
zhufle9877c62017-10-13 09:38:19 +0800881 def check_remote_connectivity(self, source, dest, should_succeed=True,
882 nic=None):
YAMAMOTO Takashi4c3ebb02017-01-25 16:04:30 +0900883 """assert ping server via source ssh connection
884
Yair Fried1fc32a12014-08-04 09:11:30 +0300885 :param source: RemoteClient: an ssh connection from which to ping
zhufle9877c62017-10-13 09:38:19 +0800886 :param dest: an IP to ping against
887 :param should_succeed: boolean: should ping succeed or not
Yair Friedbc46f592015-11-18 16:29:34 +0200888 :param nic: specific network interface to ping from
Yair Fried1fc32a12014-08-04 09:11:30 +0300889 """
890 def ping_remote():
891 try:
Yair Friedbc46f592015-11-18 16:29:34 +0200892 source.ping_host(dest, nic=nic)
Andrey Pavlov64723762015-04-29 06:24:58 +0300893 except lib_exc.SSHExecCommandFailed:
zhangguoqing6c096642016-01-04 06:17:21 +0000894 LOG.warning('Failed to ping IP: %s via a ssh connection '
Jordan Pittier525ec712016-12-07 17:51:26 +0100895 'from: %s.', dest, source.ssh_client.host)
Yair Fried1fc32a12014-08-04 09:11:30 +0300896 return not should_succeed
897 return should_succeed
898
zhufle9877c62017-10-13 09:38:19 +0800899 result = test_utils.call_until_true(ping_remote,
900 CONF.validation.ping_timeout, 1)
Ihar Hrachyshkaf9fda2d2017-11-06 13:16:09 -0800901 if result:
902 return
903
YAMAMOTO Takashi4c3ebb02017-01-25 16:04:30 +0900904 source_host = source.ssh_client.host
905 if should_succeed:
906 msg = "Timed out waiting for %s to become reachable from %s" \
907 % (dest, source_host)
908 else:
909 msg = "%s is reachable from %s" % (dest, source_host)
Ihar Hrachyshkaf9fda2d2017-11-06 13:16:09 -0800910 self._log_console_output()
911 self.fail(msg)
YAMAMOTO Takashi4c3ebb02017-01-25 16:04:30 +0900912
John Warren456d9ae2016-01-12 15:36:33 -0500913 def _create_security_group(self, security_group_rules_client=None,
914 tenant_id=None,
John Warrenf9606e92015-12-10 12:12:42 -0500915 namestart='secgroup-smoke',
916 security_groups_client=None):
John Warren456d9ae2016-01-12 15:36:33 -0500917 if security_group_rules_client is None:
918 security_group_rules_client = self.security_group_rules_client
John Warrenf9606e92015-12-10 12:12:42 -0500919 if security_groups_client is None:
920 security_groups_client = self.security_groups_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300921 if tenant_id is None:
John Warrenf9606e92015-12-10 12:12:42 -0500922 tenant_id = security_groups_client.tenant_id
923 secgroup = self._create_empty_security_group(
924 namestart=namestart, client=security_groups_client,
925 tenant_id=tenant_id)
Yair Fried1fc32a12014-08-04 09:11:30 +0300926
927 # Add rules to the security group
John Warrenf9606e92015-12-10 12:12:42 -0500928 rules = self._create_loginable_secgroup_rule(
John Warren456d9ae2016-01-12 15:36:33 -0500929 security_group_rules_client=security_group_rules_client,
930 secgroup=secgroup,
John Warrenf9606e92015-12-10 12:12:42 -0500931 security_groups_client=security_groups_client)
Yair Fried1fc32a12014-08-04 09:11:30 +0300932 for rule in rules:
Steve Heyman33735f22016-05-24 09:28:08 -0500933 self.assertEqual(tenant_id, rule['tenant_id'])
934 self.assertEqual(secgroup['id'], rule['security_group_id'])
Yair Fried1fc32a12014-08-04 09:11:30 +0300935 return secgroup
936
Yair Frieddb6c9e92014-08-06 08:53:13 +0300937 def _create_empty_security_group(self, client=None, tenant_id=None,
Yair Fried1fc32a12014-08-04 09:11:30 +0300938 namestart='secgroup-smoke'):
939 """Create a security group without rules.
940
941 Default rules will be created:
942 - IPv4 egress to any
943 - IPv6 egress to any
944
945 :param tenant_id: secgroup will be created in this tenant
Steve Heyman33735f22016-05-24 09:28:08 -0500946 :returns: the created security group
Yair Fried1fc32a12014-08-04 09:11:30 +0300947 """
948 if client is None:
John Warrenf9606e92015-12-10 12:12:42 -0500949 client = self.security_groups_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300950 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000951 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300952 sg_name = data_utils.rand_name(namestart)
953 sg_desc = sg_name + " description"
954 sg_dict = dict(name=sg_name,
955 description=sg_desc)
956 sg_dict['tenant_id'] = tenant_id
David Kranz34e88122014-12-11 15:24:05 -0500957 result = client.create_security_group(**sg_dict)
Steve Heyman33735f22016-05-24 09:28:08 -0500958
959 secgroup = result['security_group']
960 self.assertEqual(secgroup['name'], sg_name)
961 self.assertEqual(tenant_id, secgroup['tenant_id'])
962 self.assertEqual(secgroup['description'], sg_desc)
963
Jordan Pittier9e227c52016-02-09 14:35:18 +0100964 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
Steve Heyman33735f22016-05-24 09:28:08 -0500965 client.delete_security_group, secgroup['id'])
Yair Fried1fc32a12014-08-04 09:11:30 +0300966 return secgroup
967
John Warren456d9ae2016-01-12 15:36:33 -0500968 def _create_security_group_rule(self, secgroup=None,
969 sec_group_rules_client=None,
John Warrenf9606e92015-12-10 12:12:42 -0500970 tenant_id=None,
971 security_groups_client=None, **kwargs):
Yair Fried1fc32a12014-08-04 09:11:30 +0300972 """Create a rule from a dictionary of rule parameters.
973
974 Create a rule in a secgroup. if secgroup not defined will search for
975 default secgroup in tenant_id.
976
Steve Heyman33735f22016-05-24 09:28:08 -0500977 :param secgroup: the security group.
Yair Fried1fc32a12014-08-04 09:11:30 +0300978 :param tenant_id: if secgroup not passed -- the tenant in which to
979 search for default secgroup
980 :param kwargs: a dictionary containing rule parameters:
981 for example, to allow incoming ssh:
982 rule = {
983 direction: 'ingress'
984 protocol:'tcp',
985 port_range_min: 22,
986 port_range_max: 22
987 }
988 """
John Warren456d9ae2016-01-12 15:36:33 -0500989 if sec_group_rules_client is None:
990 sec_group_rules_client = self.security_group_rules_client
John Warrenf9606e92015-12-10 12:12:42 -0500991 if security_groups_client is None:
992 security_groups_client = self.security_groups_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300993 if not tenant_id:
John Warrenf9606e92015-12-10 12:12:42 -0500994 tenant_id = security_groups_client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300995 if secgroup is None:
zhuflb0b272e2017-09-22 16:01:46 +0800996 # Get default secgroup for tenant_id
997 default_secgroups = security_groups_client.list_security_groups(
998 name='default', tenant_id=tenant_id)['security_groups']
999 msg = "No default security group for tenant %s." % (tenant_id)
1000 self.assertNotEmpty(default_secgroups, msg)
1001 secgroup = default_secgroups[0]
Yair Fried1fc32a12014-08-04 09:11:30 +03001002
Steve Heyman33735f22016-05-24 09:28:08 -05001003 ruleset = dict(security_group_id=secgroup['id'],
1004 tenant_id=secgroup['tenant_id'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001005 ruleset.update(kwargs)
1006
John Warren456d9ae2016-01-12 15:36:33 -05001007 sg_rule = sec_group_rules_client.create_security_group_rule(**ruleset)
Steve Heyman33735f22016-05-24 09:28:08 -05001008 sg_rule = sg_rule['security_group_rule']
1009
1010 self.assertEqual(secgroup['tenant_id'], sg_rule['tenant_id'])
1011 self.assertEqual(secgroup['id'], sg_rule['security_group_id'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001012
1013 return sg_rule
1014
John Warren456d9ae2016-01-12 15:36:33 -05001015 def _create_loginable_secgroup_rule(self, security_group_rules_client=None,
1016 secgroup=None,
John Warrenf9606e92015-12-10 12:12:42 -05001017 security_groups_client=None):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001018 """Create loginable security group rule
1019
Alex Stafeyevdd5dde92016-05-08 14:35:04 +03001020 This function will create:
1021 1. egress and ingress tcp port 22 allow rule in order to allow ssh
1022 access for ipv4.
1023 2. egress and ingress ipv6 icmp allow rule, in order to allow icmpv6.
1024 3. egress and ingress ipv4 icmp allow rule, in order to allow icmpv4.
Yair Fried1fc32a12014-08-04 09:11:30 +03001025 """
1026
John Warren456d9ae2016-01-12 15:36:33 -05001027 if security_group_rules_client is None:
1028 security_group_rules_client = self.security_group_rules_client
John Warrenf9606e92015-12-10 12:12:42 -05001029 if security_groups_client is None:
1030 security_groups_client = self.security_groups_client
Yair Fried1fc32a12014-08-04 09:11:30 +03001031 rules = []
1032 rulesets = [
1033 dict(
1034 # ssh
1035 protocol='tcp',
1036 port_range_min=22,
1037 port_range_max=22,
1038 ),
1039 dict(
1040 # ping
1041 protocol='icmp',
Andreas Scheuring887ca8e2015-02-03 17:56:12 +01001042 ),
1043 dict(
1044 # ipv6-icmp for ping6
1045 protocol='icmp',
1046 ethertype='IPv6',
Yair Fried1fc32a12014-08-04 09:11:30 +03001047 )
1048 ]
John Warren456d9ae2016-01-12 15:36:33 -05001049 sec_group_rules_client = security_group_rules_client
Yair Fried1fc32a12014-08-04 09:11:30 +03001050 for ruleset in rulesets:
1051 for r_direction in ['ingress', 'egress']:
1052 ruleset['direction'] = r_direction
1053 try:
1054 sg_rule = self._create_security_group_rule(
John Warren456d9ae2016-01-12 15:36:33 -05001055 sec_group_rules_client=sec_group_rules_client,
1056 secgroup=secgroup,
John Warrenf9606e92015-12-10 12:12:42 -05001057 security_groups_client=security_groups_client,
1058 **ruleset)
Masayuki Igawad9388762015-01-20 14:56:42 +09001059 except lib_exc.Conflict as ex:
Yair Fried1fc32a12014-08-04 09:11:30 +03001060 # if rule already exist - skip rule and continue
1061 msg = 'Security group rule already exists'
1062 if msg not in ex._error_string:
1063 raise ex
1064 else:
Steve Heyman33735f22016-05-24 09:28:08 -05001065 self.assertEqual(r_direction, sg_rule['direction'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001066 rules.append(sg_rule)
1067
1068 return rules
1069
Yair Frieddb6c9e92014-08-06 08:53:13 +03001070 def _get_router(self, client=None, tenant_id=None):
Yair Fried1fc32a12014-08-04 09:11:30 +03001071 """Retrieve a router for the given tenant id.
1072
1073 If a public router has been configured, it will be returned.
1074
1075 If a public router has not been configured, but a public
1076 network has, a tenant router will be created and returned that
1077 routes traffic to the public network.
1078 """
Yair Frieddb6c9e92014-08-06 08:53:13 +03001079 if not client:
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +00001080 client = self.routers_client
Yair Frieddb6c9e92014-08-06 08:53:13 +03001081 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +00001082 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001083 router_id = CONF.network.public_router_id
1084 network_id = CONF.network.public_network_id
1085 if router_id:
David Kranzca4c7e72015-05-27 11:39:19 -04001086 body = client.show_router(router_id)
Steve Heyman33735f22016-05-24 09:28:08 -05001087 return body['router']
Yair Fried1fc32a12014-08-04 09:11:30 +03001088 elif network_id:
zhufl3484f992017-10-10 16:18:29 +08001089 router = client.create_router(
1090 name=data_utils.rand_name(self.__class__.__name__ + '-router'),
1091 admin_state_up=True,
1092 tenant_id=tenant_id,
1093 external_gateway_info=dict(network_id=network_id))['router']
1094 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
1095 client.delete_router, router['id'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001096 return router
1097 else:
1098 raise Exception("Neither of 'public_router_id' or "
1099 "'public_network_id' has been defined.")
1100
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -07001101 def create_networks(self, networks_client=None,
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +00001102 routers_client=None, subnets_client=None,
Markus Zoeller156b5da2016-07-11 18:10:31 +02001103 tenant_id=None, dns_nameservers=None,
1104 port_security_enabled=True):
Yair Fried1fc32a12014-08-04 09:11:30 +03001105 """Create a network with a subnet connected to a router.
1106
David Shrewsbury9bac3662014-08-07 15:07:01 -04001107 The baremetal driver is a special case since all nodes are
1108 on the same shared network.
1109
Yair Fried413bf2d2014-11-19 17:07:11 +02001110 :param tenant_id: id of tenant to create resources in.
1111 :param dns_nameservers: list of dns servers to send to subnet.
Yair Fried1fc32a12014-08-04 09:11:30 +03001112 :returns: network, subnet, router
1113 """
Thiago Paiva66cded22016-08-15 14:55:58 -03001114 if CONF.network.shared_physical_network:
David Shrewsbury9bac3662014-08-07 15:07:01 -04001115 # NOTE(Shrews): This exception is for environments where tenant
1116 # credential isolation is available, but network separation is
1117 # not (the current baremetal case). Likely can be removed when
1118 # test account mgmt is reworked:
1119 # https://blueprints.launchpad.net/tempest/+spec/test-accounts
Adam Gandelman878a5fd2015-03-30 14:33:36 -07001120 if not CONF.compute.fixed_network_name:
1121 m = 'fixed_network_name must be specified in config'
Matthew Treinish4217a702016-10-07 17:27:11 -04001122 raise lib_exc.InvalidConfiguration(m)
David Shrewsbury9bac3662014-08-07 15:07:01 -04001123 network = self._get_network_by_name(
1124 CONF.compute.fixed_network_name)
1125 router = None
1126 subnet = None
1127 else:
John Warren94d8faf2015-09-15 12:22:24 -04001128 network = self._create_network(
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -07001129 networks_client=networks_client,
Markus Zoeller156b5da2016-07-11 18:10:31 +02001130 tenant_id=tenant_id,
1131 port_security_enabled=port_security_enabled)
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +00001132 router = self._get_router(client=routers_client,
1133 tenant_id=tenant_id)
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -07001134 subnet_kwargs = dict(network=network,
zhufl5b0a52f2017-10-24 15:48:20 +08001135 subnets_client=subnets_client)
Yair Fried413bf2d2014-11-19 17:07:11 +02001136 # use explicit check because empty list is a valid option
1137 if dns_nameservers is not None:
1138 subnet_kwargs['dns_nameservers'] = dns_nameservers
zhufl5b0a52f2017-10-24 15:48:20 +08001139 subnet = self.create_subnet(**subnet_kwargs)
Steve Heyman33735f22016-05-24 09:28:08 -05001140 if not routers_client:
1141 routers_client = self.routers_client
1142 router_id = router['id']
1143 routers_client.add_router_interface(router_id,
1144 subnet_id=subnet['id'])
1145
1146 # save a cleanup job to remove this association between
1147 # router and subnet
1148 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
1149 routers_client.remove_router_interface, router_id,
1150 subnet_id=subnet['id'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001151 return network, subnet, router
1152
1153
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001154class EncryptionScenarioTest(ScenarioTest):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001155 """Base class for encryption scenario tests"""
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001156
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001157 credentials = ['primary', 'admin']
David Kranz4cc852b2015-03-09 14:57:11 -04001158
1159 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001160 def setup_clients(cls):
1161 super(EncryptionScenarioTest, cls).setup_clients()
Jordan Pittier8160d312017-04-18 11:52:23 +02001162 cls.admin_volume_types_client = cls.os_admin.volume_types_v2_client
ghanshyam3bd0d2b2017-03-23 01:57:28 +00001163 cls.admin_encryption_types_client =\
Jordan Pittier8160d312017-04-18 11:52:23 +02001164 cls.os_admin.encryption_types_v2_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001165
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001166 def create_encryption_type(self, client=None, type_id=None, provider=None,
1167 key_size=None, cipher=None,
1168 control_location=None):
1169 if not client:
Ken'ichi Ohmichia6ebf622016-08-25 11:52:27 -07001170 client = self.admin_encryption_types_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001171 if not type_id:
1172 volume_type = self.create_volume_type()
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001173 type_id = volume_type['id']
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001174 LOG.debug("Creating an encryption type for volume type: %s", type_id)
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001175 client.create_encryption_type(
1176 type_id, provider=provider, key_size=key_size, cipher=cipher,
John Warrend053ded2015-08-13 15:22:48 +00001177 control_location=control_location)['encryption']
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001178
lkuchlan3023e752017-06-08 12:53:13 +03001179 def create_encrypted_volume(self, encryption_provider, volume_type,
1180 key_size=256, cipher='aes-xts-plain64',
1181 control_location='front-end'):
1182 volume_type = self.create_volume_type(name=volume_type)
1183 self.create_encryption_type(type_id=volume_type['id'],
1184 provider=encryption_provider,
1185 key_size=key_size,
1186 cipher=cipher,
1187 control_location=control_location)
1188 return self.create_volume(volume_type=volume_type['name'])
1189
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001190
Masayuki Igawa0870db52015-09-18 21:08:36 +09001191class ObjectStorageScenarioTest(ScenarioTest):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001192 """Provide harness to do Object Storage scenario tests.
Chris Dent0d494112014-08-26 13:48:30 +01001193
1194 Subclasses implement the tests that use the methods provided by this
1195 class.
1196 """
1197
1198 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001199 def skip_checks(cls):
Masayuki Igawa0870db52015-09-18 21:08:36 +09001200 super(ObjectStorageScenarioTest, cls).skip_checks()
Chris Dent0d494112014-08-26 13:48:30 +01001201 if not CONF.service_available.swift:
1202 skip_msg = ("%s skipped as swift is not available" %
1203 cls.__name__)
1204 raise cls.skipException(skip_msg)
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001205
1206 @classmethod
1207 def setup_credentials(cls):
Masayuki Igawa60ea6c52014-10-15 17:32:14 +09001208 cls.set_network_resources()
Masayuki Igawa0870db52015-09-18 21:08:36 +09001209 super(ObjectStorageScenarioTest, cls).setup_credentials()
Matthew Treinish4a596932015-03-06 20:37:01 -05001210 operator_role = CONF.object_storage.operator_role
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +01001211 cls.os_operator = cls.get_client_manager(roles=[operator_role])
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001212
1213 @classmethod
1214 def setup_clients(cls):
Masayuki Igawa0870db52015-09-18 21:08:36 +09001215 super(ObjectStorageScenarioTest, cls).setup_clients()
Chris Dent0d494112014-08-26 13:48:30 +01001216 # Clients for Swift
Matthew Treinish8f268292015-02-24 20:01:36 -05001217 cls.account_client = cls.os_operator.account_client
1218 cls.container_client = cls.os_operator.container_client
1219 cls.object_client = cls.os_operator.object_client
Chris Dent0d494112014-08-26 13:48:30 +01001220
Chris Dentde456a12014-09-10 12:41:15 +01001221 def get_swift_stat(self):
Chris Dent0d494112014-08-26 13:48:30 +01001222 """get swift status for our user account."""
1223 self.account_client.list_account_containers()
1224 LOG.debug('Swift status information obtained successfully')
1225
Chris Dentde456a12014-09-10 12:41:15 +01001226 def create_container(self, container_name=None):
Chris Dent0d494112014-08-26 13:48:30 +01001227 name = container_name or data_utils.rand_name(
1228 'swift-scenario-container')
ghanshyameed40312017-09-15 18:30:04 +03001229 self.container_client.update_container(name)
Chris Dent0d494112014-08-26 13:48:30 +01001230 # look for the container to assure it is created
Chris Dentde456a12014-09-10 12:41:15 +01001231 self.list_and_check_container_objects(name)
Jordan Pittier525ec712016-12-07 17:51:26 +01001232 LOG.debug('Container %s created', name)
Jordan Pittier9e227c52016-02-09 14:35:18 +01001233 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
Chris Dent1d4313a2014-10-28 12:16:48 +00001234 self.container_client.delete_container,
1235 name)
Chris Dent0d494112014-08-26 13:48:30 +01001236 return name
1237
Chris Dentde456a12014-09-10 12:41:15 +01001238 def delete_container(self, container_name):
Chris Dent0d494112014-08-26 13:48:30 +01001239 self.container_client.delete_container(container_name)
Jordan Pittier525ec712016-12-07 17:51:26 +01001240 LOG.debug('Container %s deleted', container_name)
Chris Dent0d494112014-08-26 13:48:30 +01001241
Chris Dentde456a12014-09-10 12:41:15 +01001242 def upload_object_to_container(self, container_name, obj_name=None):
Chris Dent0d494112014-08-26 13:48:30 +01001243 obj_name = obj_name or data_utils.rand_name('swift-scenario-object')
Jordan Pittierb84f2d42016-12-21 19:02:15 +01001244 obj_data = data_utils.random_bytes()
Chris Dent0d494112014-08-26 13:48:30 +01001245 self.object_client.create_object(container_name, obj_name, obj_data)
Jordan Pittier9e227c52016-02-09 14:35:18 +01001246 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
Chris Dent1d4313a2014-10-28 12:16:48 +00001247 self.object_client.delete_object,
1248 container_name,
1249 obj_name)
Chris Dent0d494112014-08-26 13:48:30 +01001250 return obj_name, obj_data
1251
Chris Dentde456a12014-09-10 12:41:15 +01001252 def delete_object(self, container_name, filename):
Chris Dent0d494112014-08-26 13:48:30 +01001253 self.object_client.delete_object(container_name, filename)
Chris Dentde456a12014-09-10 12:41:15 +01001254 self.list_and_check_container_objects(container_name,
1255 not_present_obj=[filename])
Chris Dent0d494112014-08-26 13:48:30 +01001256
Chris Dentde456a12014-09-10 12:41:15 +01001257 def list_and_check_container_objects(self, container_name,
1258 present_obj=None,
1259 not_present_obj=None):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001260 # List objects for a given container and assert which are present and
1261 # which are not.
Ghanshyam2a180b82014-06-16 13:54:22 +09001262 if present_obj is None:
1263 present_obj = []
1264 if not_present_obj is None:
1265 not_present_obj = []
ghanshyam871b1a82017-09-14 02:56:16 +03001266 _, object_list = self.container_client.list_container_objects(
Chris Dent0d494112014-08-26 13:48:30 +01001267 container_name)
1268 if present_obj:
1269 for obj in present_obj:
1270 self.assertIn(obj, object_list)
1271 if not_present_obj:
1272 for obj in not_present_obj:
1273 self.assertNotIn(obj, object_list)
1274
Chris Dentde456a12014-09-10 12:41:15 +01001275 def download_and_verify(self, container_name, obj_name, expected_data):
Chris Dent0d494112014-08-26 13:48:30 +01001276 _, obj = self.object_client.get_object(container_name, obj_name)
1277 self.assertEqual(obj, expected_data)