blob: a47b6f24229d455c9b3bc3444fd6987bae415dfc [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:
652 creds_provider = self._get_credentials_provider()
653 net_creds = creds_provider.get_primary_creds()
654 network = getattr(net_creds, 'network', None)
655 addresses = (server['addresses'][network['name']]
656 if network else [])
Sean Dague20e98612016-01-06 14:33:28 -0500657 for address in addresses:
Matt Riedemanna7782552016-08-08 16:26:01 -0400658 if (address['version'] == CONF.validation.ip_version_for_ssh
659 and address['OS-EXT-IPS:type'] == 'fixed'):
Sean Dague20e98612016-01-06 14:33:28 -0500660 return address['addr']
zhufl955f82b2016-07-22 11:14:34 +0800661 raise exceptions.ServerUnreachable(server_id=server['id'])
Alexander Gubanovc8829f82015-11-12 10:35:13 +0200662 else:
Matthew Treinish4217a702016-10-07 17:27:11 -0400663 raise lib_exc.InvalidConfiguration()
Alexander Gubanovc8829f82015-11-12 10:35:13 +0200664
Andrea Frittoli2e733b52014-07-16 14:12:11 +0100665
Andrea Frittoli4971fc82014-09-25 10:22:20 +0100666class NetworkScenarioTest(ScenarioTest):
Yair Fried1fc32a12014-08-04 09:11:30 +0300667 """Base class for network scenario tests.
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000668
Yair Fried1fc32a12014-08-04 09:11:30 +0300669 This class provide helpers for network scenario tests, using the neutron
670 API. Helpers from ancestor which use the nova network API are overridden
671 with the neutron API.
672
673 This Class also enforces using Neutron instead of novanetwork.
674 Subclassed tests will be skipped if Neutron is not enabled
675
676 """
677
Andrea Frittolib21de6c2015-02-06 20:12:38 +0000678 credentials = ['primary', 'admin']
679
Yair Fried1fc32a12014-08-04 09:11:30 +0300680 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +0000681 def skip_checks(cls):
682 super(NetworkScenarioTest, cls).skip_checks()
Andrea Frittoli2ddc2632014-09-25 11:03:00 +0100683 if not CONF.service_available.neutron:
684 raise cls.skipException('Neutron not available')
Yair Fried1fc32a12014-08-04 09:11:30 +0300685
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -0700686 def _create_network(self, networks_client=None,
zhoubin5058bead72017-02-04 18:01:15 +0800687 tenant_id=None,
Markus Zoeller156b5da2016-07-11 18:10:31 +0200688 namestart='network-smoke-',
689 port_security_enabled=True):
John Warren94d8faf2015-09-15 12:22:24 -0400690 if not networks_client:
691 networks_client = self.networks_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300692 if not tenant_id:
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -0700693 tenant_id = networks_client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300694 name = data_utils.rand_name(namestart)
Matt Riedemann039b2fe2016-09-15 16:12:24 -0400695 network_kwargs = dict(name=name, tenant_id=tenant_id)
696 # Neutron disables port security by default so we have to check the
697 # config before trying to create the network with port_security_enabled
698 if CONF.network_feature_enabled.port_security:
699 network_kwargs['port_security_enabled'] = port_security_enabled
Markus Zoeller156b5da2016-07-11 18:10:31 +0200700 result = networks_client.create_network(**network_kwargs)
Steve Heyman33735f22016-05-24 09:28:08 -0500701 network = result['network']
702
703 self.assertEqual(network['name'], name)
Jordan Pittier9e227c52016-02-09 14:35:18 +0100704 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
zhoubin508bf20b32017-02-03 09:39:14 +0800705 networks_client.delete_network,
Steve Heyman33735f22016-05-24 09:28:08 -0500706 network['id'])
Yair Fried1fc32a12014-08-04 09:11:30 +0300707 return network
708
zhufl5b0a52f2017-10-24 15:48:20 +0800709 def create_subnet(self, network, subnets_client=None,
710 namestart='subnet-smoke', **kwargs):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000711 """Create a subnet for the given network
712
713 within the cidr block configured for tenant networks.
Yair Fried1fc32a12014-08-04 09:11:30 +0300714 """
John Warren3961acd2015-10-02 14:38:53 -0400715 if not subnets_client:
716 subnets_client = self.subnets_client
Yair Fried1fc32a12014-08-04 09:11:30 +0300717
718 def cidr_in_use(cidr, tenant_id):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000719 """Check cidr existence
720
lei zhangdd552b22015-11-25 20:41:48 +0800721 :returns: True if subnet with cidr already exist in tenant
722 False else
Yair Fried1fc32a12014-08-04 09:11:30 +0300723 """
jeremy.zhang5870ff12017-05-25 11:24:23 +0800724 cidr_in_use = self.os_admin.subnets_client.list_subnets(
Jordan Pittier64e6b442017-02-20 19:29:02 +0100725 tenant_id=tenant_id, cidr=cidr)['subnets']
Yair Fried1fc32a12014-08-04 09:11:30 +0300726 return len(cidr_in_use) != 0
727
Kirill Shileev14113572014-11-21 16:58:02 +0300728 ip_version = kwargs.pop('ip_version', 4)
729
730 if ip_version == 6:
731 tenant_cidr = netaddr.IPNetwork(
Sean Dagueed6e5862016-04-04 10:49:13 -0400732 CONF.network.project_network_v6_cidr)
733 num_bits = CONF.network.project_network_v6_mask_bits
Kirill Shileev14113572014-11-21 16:58:02 +0300734 else:
Sean Dagueed6e5862016-04-04 10:49:13 -0400735 tenant_cidr = netaddr.IPNetwork(CONF.network.project_network_cidr)
736 num_bits = CONF.network.project_network_mask_bits
Kirill Shileev14113572014-11-21 16:58:02 +0300737
Yair Fried1fc32a12014-08-04 09:11:30 +0300738 result = None
Kirill Shileev14113572014-11-21 16:58:02 +0300739 str_cidr = None
Yair Fried1fc32a12014-08-04 09:11:30 +0300740 # Repeatedly attempt subnet creation with sequential cidr
741 # blocks until an unallocated block is found.
Kirill Shileev14113572014-11-21 16:58:02 +0300742 for subnet_cidr in tenant_cidr.subnet(num_bits):
Yair Fried1fc32a12014-08-04 09:11:30 +0300743 str_cidr = str(subnet_cidr)
Steve Heyman33735f22016-05-24 09:28:08 -0500744 if cidr_in_use(str_cidr, tenant_id=network['tenant_id']):
Yair Fried1fc32a12014-08-04 09:11:30 +0300745 continue
746
747 subnet = dict(
748 name=data_utils.rand_name(namestart),
Steve Heyman33735f22016-05-24 09:28:08 -0500749 network_id=network['id'],
750 tenant_id=network['tenant_id'],
Yair Fried1fc32a12014-08-04 09:11:30 +0300751 cidr=str_cidr,
Kirill Shileev14113572014-11-21 16:58:02 +0300752 ip_version=ip_version,
Yair Fried1fc32a12014-08-04 09:11:30 +0300753 **kwargs
754 )
755 try:
John Warren3961acd2015-10-02 14:38:53 -0400756 result = subnets_client.create_subnet(**subnet)
Yair Fried1fc32a12014-08-04 09:11:30 +0300757 break
Masayuki Igawad9388762015-01-20 14:56:42 +0900758 except lib_exc.Conflict as e:
Yair Fried1fc32a12014-08-04 09:11:30 +0300759 is_overlapping_cidr = 'overlaps with another subnet' in str(e)
760 if not is_overlapping_cidr:
761 raise
762 self.assertIsNotNone(result, 'Unable to allocate tenant network')
Steve Heyman33735f22016-05-24 09:28:08 -0500763
764 subnet = result['subnet']
765 self.assertEqual(subnet['cidr'], str_cidr)
766
767 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
768 subnets_client.delete_subnet, subnet['id'])
769
Yair Fried1fc32a12014-08-04 09:11:30 +0300770 return subnet
771
Kirill Shileev14113572014-11-21 16:58:02 +0300772 def _get_server_port_id_and_ip4(self, server, ip_addr=None):
jeremy.zhang5870ff12017-05-25 11:24:23 +0800773 ports = self.os_admin.ports_client.list_ports(
Jordan Pittier64e6b442017-02-20 19:29:02 +0100774 device_id=server['id'], fixed_ip=ip_addr)['ports']
Kobi Samoray166500a2016-10-09 14:42:48 +0300775 # A port can have more than one IP address in some cases.
Sean M. Collins2e896832015-12-15 13:58:47 -0500776 # If the network is dual-stack (IPv4 + IPv6), this port is associated
777 # with 2 subnets
Vasyl Saienko8fd517c2016-05-30 09:52:54 +0300778 p_status = ['ACTIVE']
779 # NOTE(vsaienko) With Ironic, instances live on separate hardware
780 # servers. Neutron does not bind ports for Ironic instances, as a
781 # result the port remains in the DOWN state.
Vasyl Saienkoc8aa34b2016-08-01 14:18:37 +0300782 # TODO(vsaienko) remove once bug: #1599836 is resolved.
Thiago Paiva66cded22016-08-15 14:55:58 -0300783 if getattr(CONF.service_available, 'ironic', False):
Vasyl Saienko8fd517c2016-05-30 09:52:54 +0300784 p_status.append('DOWN')
Daniel Mellado9e3e1062015-08-06 18:07:05 +0200785 port_map = [(p["id"], fxip["ip_address"])
786 for p in ports
787 for fxip in p["fixed_ips"]
Yatin Kumbhareee4924c2016-06-09 15:12:06 +0530788 if netutils.is_valid_ipv4(fxip["ip_address"])
Vasyl Saienko8fd517c2016-05-30 09:52:54 +0300789 and p['status'] in p_status]
Kevin Benton1d0c1dc2016-02-04 14:30:08 -0800790 inactive = [p for p in ports if p['status'] != 'ACTIVE']
791 if inactive:
792 LOG.warning("Instance has ports that are not ACTIVE: %s", inactive)
Daniel Mellado9e3e1062015-08-06 18:07:05 +0200793
Masayuki Igawaf9009b42017-04-10 14:49:29 +0900794 self.assertNotEmpty(port_map,
John L. Villalovosb83286f2015-11-04 14:46:57 -0800795 "No IPv4 addresses found in: %s" % ports)
Daniel Mellado9e3e1062015-08-06 18:07:05 +0200796 self.assertEqual(len(port_map), 1,
797 "Found multiple IPv4 addresses: %s. "
798 "Unable to determine which port to target."
799 % port_map)
800 return port_map[0]
Yair Fried1fc32a12014-08-04 09:11:30 +0300801
David Shrewsbury9bac3662014-08-07 15:07:01 -0400802 def _get_network_by_name(self, network_name):
jeremy.zhang5870ff12017-05-25 11:24:23 +0800803 net = self.os_admin.networks_client.list_networks(
Jordan Pittier64e6b442017-02-20 19:29:02 +0100804 name=network_name)['networks']
Ferenc Horváth268ccce2017-06-08 12:39:02 +0200805 self.assertNotEmpty(net,
Adam Gandelman878a5fd2015-03-30 14:33:36 -0700806 "Unable to get network by name: %s" % network_name)
Steve Heyman33735f22016-05-24 09:28:08 -0500807 return net[0]
David Shrewsbury9bac3662014-08-07 15:07:01 -0400808
Yair Friedae0e73d2014-11-24 11:56:26 +0200809 def create_floating_ip(self, thing, external_network_id=None,
810 port_id=None, client=None):
Ken'ichi Ohmichia112a592015-11-17 08:49:37 +0000811 """Create a floating IP and associates to a resource/port on Neutron"""
Yair Friedae0e73d2014-11-24 11:56:26 +0200812 if not external_network_id:
813 external_network_id = CONF.network.public_network_id
Yair Frieddb6c9e92014-08-06 08:53:13 +0300814 if not client:
John Warrenfbf2a892015-11-17 12:36:14 -0500815 client = self.floating_ips_client
Yair Fried1fc32a12014-08-04 09:11:30 +0300816 if not port_id:
Kirill Shileev14113572014-11-21 16:58:02 +0300817 port_id, ip4 = self._get_server_port_id_and_ip4(thing)
818 else:
819 ip4 = None
David Kranz34e88122014-12-11 15:24:05 -0500820 result = client.create_floatingip(
Yair Fried1fc32a12014-08-04 09:11:30 +0300821 floating_network_id=external_network_id,
822 port_id=port_id,
Kirill Shileev14113572014-11-21 16:58:02 +0300823 tenant_id=thing['tenant_id'],
824 fixed_ip_address=ip4
Yair Fried1fc32a12014-08-04 09:11:30 +0300825 )
Steve Heyman33735f22016-05-24 09:28:08 -0500826 floating_ip = result['floatingip']
Jordan Pittier9e227c52016-02-09 14:35:18 +0100827 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
zhoubin508bf20b32017-02-03 09:39:14 +0800828 client.delete_floatingip,
Steve Heyman33735f22016-05-24 09:28:08 -0500829 floating_ip['id'])
Yair Fried1fc32a12014-08-04 09:11:30 +0300830 return floating_ip
831
Yair Fried45f92952014-06-26 05:19:19 +0300832 def check_floating_ip_status(self, floating_ip, status):
Carl Baldwina754e2d2014-10-23 22:47:41 +0000833 """Verifies floatingip reaches the given status
Yair Fried45f92952014-06-26 05:19:19 +0300834
Steve Heyman33735f22016-05-24 09:28:08 -0500835 :param dict floating_ip: floating IP dict to check status
Yair Fried45f92952014-06-26 05:19:19 +0300836 :param status: target status
837 :raises: AssertionError if status doesn't match
838 """
Steve Heyman33735f22016-05-24 09:28:08 -0500839 floatingip_id = floating_ip['id']
840
Carl Baldwina754e2d2014-10-23 22:47:41 +0000841 def refresh():
Steve Heyman33735f22016-05-24 09:28:08 -0500842 result = (self.floating_ips_client.
843 show_floatingip(floatingip_id)['floatingip'])
844 return status == result['status']
Carl Baldwina754e2d2014-10-23 22:47:41 +0000845
zhufl4dda94e2017-03-14 16:14:46 +0800846 if not test_utils.call_until_true(refresh,
847 CONF.network.build_timeout,
848 CONF.network.build_interval):
849 floating_ip = self.floating_ips_client.show_floatingip(
850 floatingip_id)['floatingip']
851 self.assertEqual(status, floating_ip['status'],
852 message="FloatingIP: {fp} is at status: {cst}. "
853 "failed to reach status: {st}"
854 .format(fp=floating_ip, cst=floating_ip['status'],
855 st=status))
Yair Fried45f92952014-06-26 05:19:19 +0300856 LOG.info("FloatingIP: {fp} is at status: {st}"
857 .format(fp=floating_ip, st=status))
858
zhufl420a0192017-09-28 11:04:50 +0800859 def check_tenant_network_connectivity(self, server,
860 username,
861 private_key,
862 should_connect=True,
863 servers_for_debug=None):
Sean Dagueed6e5862016-04-04 10:49:13 -0400864 if not CONF.network.project_networks_reachable:
Yair Fried1fc32a12014-08-04 09:11:30 +0300865 msg = 'Tenant networks not configured to be reachable.'
866 LOG.info(msg)
867 return
868 # The target login is assumed to have been configured for
869 # key-based authentication by cloud-init.
870 try:
Béla Vancsicsb6dfa082017-03-01 10:44:58 +0100871 for ip_addresses in server['addresses'].values():
Yair Fried1fc32a12014-08-04 09:11:30 +0300872 for ip_address in ip_addresses:
ghanshyam807211c2014-12-18 13:21:22 +0900873 self.check_vm_connectivity(ip_address['addr'],
Yair Friedae0e73d2014-11-24 11:56:26 +0200874 username,
875 private_key,
876 should_connect=should_connect)
Yair Fried1fc32a12014-08-04 09:11:30 +0300877 except Exception as e:
878 LOG.exception('Tenant network connectivity check failed')
879 self._log_console_output(servers_for_debug)
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000880 self._log_net_info(e)
Yair Fried1fc32a12014-08-04 09:11:30 +0300881 raise
882
zhufle9877c62017-10-13 09:38:19 +0800883 def check_remote_connectivity(self, source, dest, should_succeed=True,
Claudiu Belu33c3e602014-08-28 16:38:01 +0300884 nic=None, protocol='icmp'):
885 """check server connectivity via source ssh connection
YAMAMOTO Takashi4c3ebb02017-01-25 16:04:30 +0900886
Claudiu Belu33c3e602014-08-28 16:38:01 +0300887 :param source: RemoteClient: an ssh connection from which to execute
888 the check
889 :param dest: an IP to check connectivity against
890 :param should_succeed: boolean should connection succeed or not
891 :param nic: specific network interface to test connectivity from
892 :param protocol: the protocol used to test connectivity with.
893 :returns: True, if the connection succeeded and it was expected to
894 succeed. False otherwise.
Yair Fried1fc32a12014-08-04 09:11:30 +0300895 """
Claudiu Belu33c3e602014-08-28 16:38:01 +0300896 method_name = '%s_check' % protocol
897 connectivity_checker = getattr(source, method_name)
898
899 def connect_remote():
Yair Fried1fc32a12014-08-04 09:11:30 +0300900 try:
Claudiu Belu33c3e602014-08-28 16:38:01 +0300901 connectivity_checker(dest, nic=nic)
Andrey Pavlov64723762015-04-29 06:24:58 +0300902 except lib_exc.SSHExecCommandFailed:
Claudiu Belu33c3e602014-08-28 16:38:01 +0300903 LOG.warning('Failed to check %(protocol)s connectivity for '
904 'IP %(dest)s via a ssh connection from: %(src)s.',
905 dict(protocol=protocol, dest=dest,
906 src=source.ssh_client.host))
Yair Fried1fc32a12014-08-04 09:11:30 +0300907 return not should_succeed
908 return should_succeed
909
Claudiu Belu33c3e602014-08-28 16:38:01 +0300910 result = test_utils.call_until_true(connect_remote,
zhufle9877c62017-10-13 09:38:19 +0800911 CONF.validation.ping_timeout, 1)
YAMAMOTO Takashi4c3ebb02017-01-25 16:04:30 +0900912 source_host = source.ssh_client.host
913 if should_succeed:
914 msg = "Timed out waiting for %s to become reachable from %s" \
915 % (dest, source_host)
916 else:
917 msg = "%s is reachable from %s" % (dest, source_host)
918 self.assertTrue(result, msg)
919
John Warren456d9ae2016-01-12 15:36:33 -0500920 def _create_security_group(self, security_group_rules_client=None,
921 tenant_id=None,
John Warrenf9606e92015-12-10 12:12:42 -0500922 namestart='secgroup-smoke',
923 security_groups_client=None):
John Warren456d9ae2016-01-12 15:36:33 -0500924 if security_group_rules_client is None:
925 security_group_rules_client = self.security_group_rules_client
John Warrenf9606e92015-12-10 12:12:42 -0500926 if security_groups_client is None:
927 security_groups_client = self.security_groups_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300928 if tenant_id is None:
John Warrenf9606e92015-12-10 12:12:42 -0500929 tenant_id = security_groups_client.tenant_id
930 secgroup = self._create_empty_security_group(
931 namestart=namestart, client=security_groups_client,
932 tenant_id=tenant_id)
Yair Fried1fc32a12014-08-04 09:11:30 +0300933
934 # Add rules to the security group
John Warrenf9606e92015-12-10 12:12:42 -0500935 rules = self._create_loginable_secgroup_rule(
John Warren456d9ae2016-01-12 15:36:33 -0500936 security_group_rules_client=security_group_rules_client,
937 secgroup=secgroup,
John Warrenf9606e92015-12-10 12:12:42 -0500938 security_groups_client=security_groups_client)
Yair Fried1fc32a12014-08-04 09:11:30 +0300939 for rule in rules:
Steve Heyman33735f22016-05-24 09:28:08 -0500940 self.assertEqual(tenant_id, rule['tenant_id'])
941 self.assertEqual(secgroup['id'], rule['security_group_id'])
Yair Fried1fc32a12014-08-04 09:11:30 +0300942 return secgroup
943
Yair Frieddb6c9e92014-08-06 08:53:13 +0300944 def _create_empty_security_group(self, client=None, tenant_id=None,
Yair Fried1fc32a12014-08-04 09:11:30 +0300945 namestart='secgroup-smoke'):
946 """Create a security group without rules.
947
948 Default rules will be created:
949 - IPv4 egress to any
950 - IPv6 egress to any
951
952 :param tenant_id: secgroup will be created in this tenant
Steve Heyman33735f22016-05-24 09:28:08 -0500953 :returns: the created security group
Yair Fried1fc32a12014-08-04 09:11:30 +0300954 """
955 if client is None:
John Warrenf9606e92015-12-10 12:12:42 -0500956 client = self.security_groups_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300957 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000958 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300959 sg_name = data_utils.rand_name(namestart)
960 sg_desc = sg_name + " description"
961 sg_dict = dict(name=sg_name,
962 description=sg_desc)
963 sg_dict['tenant_id'] = tenant_id
David Kranz34e88122014-12-11 15:24:05 -0500964 result = client.create_security_group(**sg_dict)
Steve Heyman33735f22016-05-24 09:28:08 -0500965
966 secgroup = result['security_group']
967 self.assertEqual(secgroup['name'], sg_name)
968 self.assertEqual(tenant_id, secgroup['tenant_id'])
969 self.assertEqual(secgroup['description'], sg_desc)
970
Jordan Pittier9e227c52016-02-09 14:35:18 +0100971 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
Steve Heyman33735f22016-05-24 09:28:08 -0500972 client.delete_security_group, secgroup['id'])
Yair Fried1fc32a12014-08-04 09:11:30 +0300973 return secgroup
974
John Warren456d9ae2016-01-12 15:36:33 -0500975 def _create_security_group_rule(self, secgroup=None,
976 sec_group_rules_client=None,
John Warrenf9606e92015-12-10 12:12:42 -0500977 tenant_id=None,
978 security_groups_client=None, **kwargs):
Yair Fried1fc32a12014-08-04 09:11:30 +0300979 """Create a rule from a dictionary of rule parameters.
980
981 Create a rule in a secgroup. if secgroup not defined will search for
982 default secgroup in tenant_id.
983
Steve Heyman33735f22016-05-24 09:28:08 -0500984 :param secgroup: the security group.
Yair Fried1fc32a12014-08-04 09:11:30 +0300985 :param tenant_id: if secgroup not passed -- the tenant in which to
986 search for default secgroup
987 :param kwargs: a dictionary containing rule parameters:
988 for example, to allow incoming ssh:
989 rule = {
990 direction: 'ingress'
991 protocol:'tcp',
992 port_range_min: 22,
993 port_range_max: 22
994 }
995 """
John Warren456d9ae2016-01-12 15:36:33 -0500996 if sec_group_rules_client is None:
997 sec_group_rules_client = self.security_group_rules_client
John Warrenf9606e92015-12-10 12:12:42 -0500998 if security_groups_client is None:
999 security_groups_client = self.security_groups_client
Yair Frieddb6c9e92014-08-06 08:53:13 +03001000 if not tenant_id:
John Warrenf9606e92015-12-10 12:12:42 -05001001 tenant_id = security_groups_client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001002 if secgroup is None:
zhuflb0b272e2017-09-22 16:01:46 +08001003 # Get default secgroup for tenant_id
1004 default_secgroups = security_groups_client.list_security_groups(
1005 name='default', tenant_id=tenant_id)['security_groups']
1006 msg = "No default security group for tenant %s." % (tenant_id)
1007 self.assertNotEmpty(default_secgroups, msg)
1008 secgroup = default_secgroups[0]
Yair Fried1fc32a12014-08-04 09:11:30 +03001009
Steve Heyman33735f22016-05-24 09:28:08 -05001010 ruleset = dict(security_group_id=secgroup['id'],
1011 tenant_id=secgroup['tenant_id'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001012 ruleset.update(kwargs)
1013
John Warren456d9ae2016-01-12 15:36:33 -05001014 sg_rule = sec_group_rules_client.create_security_group_rule(**ruleset)
Steve Heyman33735f22016-05-24 09:28:08 -05001015 sg_rule = sg_rule['security_group_rule']
1016
1017 self.assertEqual(secgroup['tenant_id'], sg_rule['tenant_id'])
1018 self.assertEqual(secgroup['id'], sg_rule['security_group_id'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001019
1020 return sg_rule
1021
John Warren456d9ae2016-01-12 15:36:33 -05001022 def _create_loginable_secgroup_rule(self, security_group_rules_client=None,
1023 secgroup=None,
John Warrenf9606e92015-12-10 12:12:42 -05001024 security_groups_client=None):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001025 """Create loginable security group rule
1026
Alex Stafeyevdd5dde92016-05-08 14:35:04 +03001027 This function will create:
1028 1. egress and ingress tcp port 22 allow rule in order to allow ssh
1029 access for ipv4.
1030 2. egress and ingress ipv6 icmp allow rule, in order to allow icmpv6.
1031 3. egress and ingress ipv4 icmp allow rule, in order to allow icmpv4.
Yair Fried1fc32a12014-08-04 09:11:30 +03001032 """
1033
John Warren456d9ae2016-01-12 15:36:33 -05001034 if security_group_rules_client is None:
1035 security_group_rules_client = self.security_group_rules_client
John Warrenf9606e92015-12-10 12:12:42 -05001036 if security_groups_client is None:
1037 security_groups_client = self.security_groups_client
Yair Fried1fc32a12014-08-04 09:11:30 +03001038 rules = []
1039 rulesets = [
1040 dict(
1041 # ssh
1042 protocol='tcp',
1043 port_range_min=22,
1044 port_range_max=22,
1045 ),
1046 dict(
1047 # ping
1048 protocol='icmp',
Andreas Scheuring887ca8e2015-02-03 17:56:12 +01001049 ),
1050 dict(
1051 # ipv6-icmp for ping6
1052 protocol='icmp',
1053 ethertype='IPv6',
Yair Fried1fc32a12014-08-04 09:11:30 +03001054 )
1055 ]
John Warren456d9ae2016-01-12 15:36:33 -05001056 sec_group_rules_client = security_group_rules_client
Yair Fried1fc32a12014-08-04 09:11:30 +03001057 for ruleset in rulesets:
1058 for r_direction in ['ingress', 'egress']:
1059 ruleset['direction'] = r_direction
1060 try:
1061 sg_rule = self._create_security_group_rule(
John Warren456d9ae2016-01-12 15:36:33 -05001062 sec_group_rules_client=sec_group_rules_client,
1063 secgroup=secgroup,
John Warrenf9606e92015-12-10 12:12:42 -05001064 security_groups_client=security_groups_client,
1065 **ruleset)
Masayuki Igawad9388762015-01-20 14:56:42 +09001066 except lib_exc.Conflict as ex:
Yair Fried1fc32a12014-08-04 09:11:30 +03001067 # if rule already exist - skip rule and continue
1068 msg = 'Security group rule already exists'
1069 if msg not in ex._error_string:
1070 raise ex
1071 else:
Steve Heyman33735f22016-05-24 09:28:08 -05001072 self.assertEqual(r_direction, sg_rule['direction'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001073 rules.append(sg_rule)
1074
1075 return rules
1076
Yair Frieddb6c9e92014-08-06 08:53:13 +03001077 def _get_router(self, client=None, tenant_id=None):
Yair Fried1fc32a12014-08-04 09:11:30 +03001078 """Retrieve a router for the given tenant id.
1079
1080 If a public router has been configured, it will be returned.
1081
1082 If a public router has not been configured, but a public
1083 network has, a tenant router will be created and returned that
1084 routes traffic to the public network.
1085 """
Yair Frieddb6c9e92014-08-06 08:53:13 +03001086 if not client:
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +00001087 client = self.routers_client
Yair Frieddb6c9e92014-08-06 08:53:13 +03001088 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +00001089 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001090 router_id = CONF.network.public_router_id
1091 network_id = CONF.network.public_network_id
1092 if router_id:
David Kranzca4c7e72015-05-27 11:39:19 -04001093 body = client.show_router(router_id)
Steve Heyman33735f22016-05-24 09:28:08 -05001094 return body['router']
Yair Fried1fc32a12014-08-04 09:11:30 +03001095 elif network_id:
zhufl3484f992017-10-10 16:18:29 +08001096 router = client.create_router(
1097 name=data_utils.rand_name(self.__class__.__name__ + '-router'),
1098 admin_state_up=True,
1099 tenant_id=tenant_id,
1100 external_gateway_info=dict(network_id=network_id))['router']
1101 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
1102 client.delete_router, router['id'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001103 return router
1104 else:
1105 raise Exception("Neither of 'public_router_id' or "
1106 "'public_network_id' has been defined.")
1107
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -07001108 def create_networks(self, networks_client=None,
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +00001109 routers_client=None, subnets_client=None,
Markus Zoeller156b5da2016-07-11 18:10:31 +02001110 tenant_id=None, dns_nameservers=None,
1111 port_security_enabled=True):
Yair Fried1fc32a12014-08-04 09:11:30 +03001112 """Create a network with a subnet connected to a router.
1113
David Shrewsbury9bac3662014-08-07 15:07:01 -04001114 The baremetal driver is a special case since all nodes are
1115 on the same shared network.
1116
Yair Fried413bf2d2014-11-19 17:07:11 +02001117 :param tenant_id: id of tenant to create resources in.
1118 :param dns_nameservers: list of dns servers to send to subnet.
Yair Fried1fc32a12014-08-04 09:11:30 +03001119 :returns: network, subnet, router
1120 """
Thiago Paiva66cded22016-08-15 14:55:58 -03001121 if CONF.network.shared_physical_network:
David Shrewsbury9bac3662014-08-07 15:07:01 -04001122 # NOTE(Shrews): This exception is for environments where tenant
1123 # credential isolation is available, but network separation is
1124 # not (the current baremetal case). Likely can be removed when
1125 # test account mgmt is reworked:
1126 # https://blueprints.launchpad.net/tempest/+spec/test-accounts
Adam Gandelman878a5fd2015-03-30 14:33:36 -07001127 if not CONF.compute.fixed_network_name:
1128 m = 'fixed_network_name must be specified in config'
Matthew Treinish4217a702016-10-07 17:27:11 -04001129 raise lib_exc.InvalidConfiguration(m)
David Shrewsbury9bac3662014-08-07 15:07:01 -04001130 network = self._get_network_by_name(
1131 CONF.compute.fixed_network_name)
1132 router = None
1133 subnet = None
1134 else:
John Warren94d8faf2015-09-15 12:22:24 -04001135 network = self._create_network(
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -07001136 networks_client=networks_client,
Markus Zoeller156b5da2016-07-11 18:10:31 +02001137 tenant_id=tenant_id,
1138 port_security_enabled=port_security_enabled)
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +00001139 router = self._get_router(client=routers_client,
1140 tenant_id=tenant_id)
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -07001141 subnet_kwargs = dict(network=network,
zhufl5b0a52f2017-10-24 15:48:20 +08001142 subnets_client=subnets_client)
Yair Fried413bf2d2014-11-19 17:07:11 +02001143 # use explicit check because empty list is a valid option
1144 if dns_nameservers is not None:
1145 subnet_kwargs['dns_nameservers'] = dns_nameservers
zhufl5b0a52f2017-10-24 15:48:20 +08001146 subnet = self.create_subnet(**subnet_kwargs)
Steve Heyman33735f22016-05-24 09:28:08 -05001147 if not routers_client:
1148 routers_client = self.routers_client
1149 router_id = router['id']
1150 routers_client.add_router_interface(router_id,
1151 subnet_id=subnet['id'])
1152
1153 # save a cleanup job to remove this association between
1154 # router and subnet
1155 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
1156 routers_client.remove_router_interface, router_id,
1157 subnet_id=subnet['id'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001158 return network, subnet, router
1159
1160
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001161class EncryptionScenarioTest(ScenarioTest):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001162 """Base class for encryption scenario tests"""
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001163
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001164 credentials = ['primary', 'admin']
David Kranz4cc852b2015-03-09 14:57:11 -04001165
1166 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001167 def setup_clients(cls):
1168 super(EncryptionScenarioTest, cls).setup_clients()
Jordan Pittier8160d312017-04-18 11:52:23 +02001169 cls.admin_volume_types_client = cls.os_admin.volume_types_v2_client
ghanshyam3bd0d2b2017-03-23 01:57:28 +00001170 cls.admin_encryption_types_client =\
Jordan Pittier8160d312017-04-18 11:52:23 +02001171 cls.os_admin.encryption_types_v2_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001172
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001173 def create_encryption_type(self, client=None, type_id=None, provider=None,
1174 key_size=None, cipher=None,
1175 control_location=None):
1176 if not client:
Ken'ichi Ohmichia6ebf622016-08-25 11:52:27 -07001177 client = self.admin_encryption_types_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001178 if not type_id:
1179 volume_type = self.create_volume_type()
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001180 type_id = volume_type['id']
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001181 LOG.debug("Creating an encryption type for volume type: %s", type_id)
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001182 client.create_encryption_type(
1183 type_id, provider=provider, key_size=key_size, cipher=cipher,
John Warrend053ded2015-08-13 15:22:48 +00001184 control_location=control_location)['encryption']
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001185
lkuchlan3023e752017-06-08 12:53:13 +03001186 def create_encrypted_volume(self, encryption_provider, volume_type,
1187 key_size=256, cipher='aes-xts-plain64',
1188 control_location='front-end'):
1189 volume_type = self.create_volume_type(name=volume_type)
1190 self.create_encryption_type(type_id=volume_type['id'],
1191 provider=encryption_provider,
1192 key_size=key_size,
1193 cipher=cipher,
1194 control_location=control_location)
1195 return self.create_volume(volume_type=volume_type['name'])
1196
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001197
Masayuki Igawa0870db52015-09-18 21:08:36 +09001198class ObjectStorageScenarioTest(ScenarioTest):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001199 """Provide harness to do Object Storage scenario tests.
Chris Dent0d494112014-08-26 13:48:30 +01001200
1201 Subclasses implement the tests that use the methods provided by this
1202 class.
1203 """
1204
1205 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001206 def skip_checks(cls):
Masayuki Igawa0870db52015-09-18 21:08:36 +09001207 super(ObjectStorageScenarioTest, cls).skip_checks()
Chris Dent0d494112014-08-26 13:48:30 +01001208 if not CONF.service_available.swift:
1209 skip_msg = ("%s skipped as swift is not available" %
1210 cls.__name__)
1211 raise cls.skipException(skip_msg)
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001212
1213 @classmethod
1214 def setup_credentials(cls):
Masayuki Igawa60ea6c52014-10-15 17:32:14 +09001215 cls.set_network_resources()
Masayuki Igawa0870db52015-09-18 21:08:36 +09001216 super(ObjectStorageScenarioTest, cls).setup_credentials()
Matthew Treinish4a596932015-03-06 20:37:01 -05001217 operator_role = CONF.object_storage.operator_role
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +01001218 cls.os_operator = cls.get_client_manager(roles=[operator_role])
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001219
1220 @classmethod
1221 def setup_clients(cls):
Masayuki Igawa0870db52015-09-18 21:08:36 +09001222 super(ObjectStorageScenarioTest, cls).setup_clients()
Chris Dent0d494112014-08-26 13:48:30 +01001223 # Clients for Swift
Matthew Treinish8f268292015-02-24 20:01:36 -05001224 cls.account_client = cls.os_operator.account_client
1225 cls.container_client = cls.os_operator.container_client
1226 cls.object_client = cls.os_operator.object_client
Chris Dent0d494112014-08-26 13:48:30 +01001227
Chris Dentde456a12014-09-10 12:41:15 +01001228 def get_swift_stat(self):
Chris Dent0d494112014-08-26 13:48:30 +01001229 """get swift status for our user account."""
1230 self.account_client.list_account_containers()
1231 LOG.debug('Swift status information obtained successfully')
1232
Chris Dentde456a12014-09-10 12:41:15 +01001233 def create_container(self, container_name=None):
Chris Dent0d494112014-08-26 13:48:30 +01001234 name = container_name or data_utils.rand_name(
1235 'swift-scenario-container')
ghanshyameed40312017-09-15 18:30:04 +03001236 self.container_client.update_container(name)
Chris Dent0d494112014-08-26 13:48:30 +01001237 # look for the container to assure it is created
Chris Dentde456a12014-09-10 12:41:15 +01001238 self.list_and_check_container_objects(name)
Jordan Pittier525ec712016-12-07 17:51:26 +01001239 LOG.debug('Container %s created', name)
Jordan Pittier9e227c52016-02-09 14:35:18 +01001240 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
Chris Dent1d4313a2014-10-28 12:16:48 +00001241 self.container_client.delete_container,
1242 name)
Chris Dent0d494112014-08-26 13:48:30 +01001243 return name
1244
Chris Dentde456a12014-09-10 12:41:15 +01001245 def delete_container(self, container_name):
Chris Dent0d494112014-08-26 13:48:30 +01001246 self.container_client.delete_container(container_name)
Jordan Pittier525ec712016-12-07 17:51:26 +01001247 LOG.debug('Container %s deleted', container_name)
Chris Dent0d494112014-08-26 13:48:30 +01001248
Chris Dentde456a12014-09-10 12:41:15 +01001249 def upload_object_to_container(self, container_name, obj_name=None):
Chris Dent0d494112014-08-26 13:48:30 +01001250 obj_name = obj_name or data_utils.rand_name('swift-scenario-object')
Jordan Pittierb84f2d42016-12-21 19:02:15 +01001251 obj_data = data_utils.random_bytes()
Chris Dent0d494112014-08-26 13:48:30 +01001252 self.object_client.create_object(container_name, obj_name, obj_data)
Jordan Pittier9e227c52016-02-09 14:35:18 +01001253 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
Chris Dent1d4313a2014-10-28 12:16:48 +00001254 self.object_client.delete_object,
1255 container_name,
1256 obj_name)
Chris Dent0d494112014-08-26 13:48:30 +01001257 return obj_name, obj_data
1258
Chris Dentde456a12014-09-10 12:41:15 +01001259 def delete_object(self, container_name, filename):
Chris Dent0d494112014-08-26 13:48:30 +01001260 self.object_client.delete_object(container_name, filename)
Chris Dentde456a12014-09-10 12:41:15 +01001261 self.list_and_check_container_objects(container_name,
1262 not_present_obj=[filename])
Chris Dent0d494112014-08-26 13:48:30 +01001263
Chris Dentde456a12014-09-10 12:41:15 +01001264 def list_and_check_container_objects(self, container_name,
1265 present_obj=None,
1266 not_present_obj=None):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001267 # List objects for a given container and assert which are present and
1268 # which are not.
Ghanshyam2a180b82014-06-16 13:54:22 +09001269 if present_obj is None:
1270 present_obj = []
1271 if not_present_obj is None:
1272 not_present_obj = []
ghanshyam871b1a82017-09-14 02:56:16 +03001273 _, object_list = self.container_client.list_container_objects(
Chris Dent0d494112014-08-26 13:48:30 +01001274 container_name)
1275 if present_obj:
1276 for obj in present_obj:
1277 self.assertIn(obj, object_list)
1278 if not_present_obj:
1279 for obj in not_present_obj:
1280 self.assertNotIn(obj, object_list)
1281
Chris Dentde456a12014-09-10 12:41:15 +01001282 def download_and_verify(self, container_name, obj_name, expected_data):
Chris Dent0d494112014-08-26 13:48:30 +01001283 _, obj = self.object_client.get_object(container_name, obj_name)
1284 self.assertEqual(obj, expected_data)