blob: 629541d5f51dd9ddf144597ea985f88ef195e9e4 [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')
Benny Kopilov11b28002017-12-19 12:46:19 +0200255 snapshot = self.snapshots_client.show_snapshot(
256 snapshot['id'])['snapshot']
lkuchlan73ed1f32017-07-06 16:22:12 +0300257 return snapshot
258
scottda61f68ac2016-06-07 12:07:55 -0600259 def create_volume_type(self, client=None, name=None, backend_name=None):
260 if not client:
zhufl708821c2017-07-12 16:08:34 +0800261 client = self.os_admin.volume_types_v2_client
scottda61f68ac2016-06-07 12:07:55 -0600262 if not name:
263 class_name = self.__class__.__name__
264 name = data_utils.rand_name(class_name + '-volume-type')
265 randomized_name = data_utils.rand_name('scenario-type-' + name)
266
267 LOG.debug("Creating a volume type: %s on backend %s",
268 randomized_name, backend_name)
269 extra_specs = {}
270 if backend_name:
271 extra_specs = {"volume_backend_name": backend_name}
272
lkuchlanbbabe542017-09-26 10:47:23 +0300273 volume_type = client.create_volume_type(
274 name=randomized_name, extra_specs=extra_specs)['volume_type']
scottda61f68ac2016-06-07 12:07:55 -0600275 self.addCleanup(client.delete_volume_type, volume_type['id'])
276 return volume_type
277
Yair Fried1fc32a12014-08-04 09:11:30 +0300278 def _create_loginable_secgroup_rule(self, secgroup_id=None):
John Warrenf2345512015-12-10 13:39:30 -0500279 _client = self.compute_security_groups_client
John Warren5cdbf422016-01-05 12:42:43 -0500280 _client_rules = self.compute_security_group_rules_client
Andrea Frittoli247058f2014-07-16 16:09:22 +0100281 if secgroup_id is None:
ghanshyamb610b772015-08-24 17:29:38 +0900282 sgs = _client.list_security_groups()['security_groups']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100283 for sg in sgs:
284 if sg['name'] == 'default':
285 secgroup_id = sg['id']
286
287 # These rules are intended to permit inbound ssh and icmp
288 # traffic from all sources, so no group_id is provided.
289 # Setting a group_id would only permit traffic from ports
290 # belonging to the same security group.
291 rulesets = [
292 {
293 # ssh
Ken'ichi Ohmichieb7eeec2015-07-21 01:00:06 +0000294 'ip_protocol': 'tcp',
Andrea Frittoli247058f2014-07-16 16:09:22 +0100295 'from_port': 22,
296 'to_port': 22,
297 'cidr': '0.0.0.0/0',
298 },
299 {
300 # ping
Ken'ichi Ohmichieb7eeec2015-07-21 01:00:06 +0000301 'ip_protocol': 'icmp',
Andrea Frittoli247058f2014-07-16 16:09:22 +0100302 'from_port': -1,
303 'to_port': -1,
304 'cidr': '0.0.0.0/0',
305 }
306 ]
307 rules = list()
308 for ruleset in rulesets:
Ken'ichi Ohmichieb7eeec2015-07-21 01:00:06 +0000309 sg_rule = _client_rules.create_security_group_rule(
ghanshyam0a5e1232015-08-24 16:59:59 +0900310 parent_group_id=secgroup_id, **ruleset)['security_group_rule']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100311 rules.append(sg_rule)
312 return rules
313
Yair Fried1fc32a12014-08-04 09:11:30 +0300314 def _create_security_group(self):
Andrea Frittoli247058f2014-07-16 16:09:22 +0100315 # Create security group
316 sg_name = data_utils.rand_name(self.__class__.__name__)
317 sg_desc = sg_name + " description"
John Warrenf2345512015-12-10 13:39:30 -0500318 secgroup = self.compute_security_groups_client.create_security_group(
ghanshyamb610b772015-08-24 17:29:38 +0900319 name=sg_name, description=sg_desc)['security_group']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100320 self.assertEqual(secgroup['name'], sg_name)
321 self.assertEqual(secgroup['description'], sg_desc)
John Warrenf2345512015-12-10 13:39:30 -0500322 self.addCleanup(
Jordan Pittier9e227c52016-02-09 14:35:18 +0100323 test_utils.call_and_ignore_notfound_exc,
John Warrenf2345512015-12-10 13:39:30 -0500324 self.compute_security_groups_client.delete_security_group,
325 secgroup['id'])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100326
327 # Add rules to the security group
Yair Fried1fc32a12014-08-04 09:11:30 +0300328 self._create_loginable_secgroup_rule(secgroup['id'])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100329
330 return secgroup
331
zhuflf52c7592017-05-25 13:55:24 +0800332 def get_remote_client(self, ip_address, username=None, private_key=None,
333 server=None):
JordanP3fe2dc32014-11-17 13:06:01 +0100334 """Get a SSH client to a remote server
335
Sean Dague20e98612016-01-06 14:33:28 -0500336 @param ip_address the server floating or fixed IP address to use
337 for ssh validation
JordanP3fe2dc32014-11-17 13:06:01 +0100338 @param username name of the Linux account on the remote server
339 @param private_key the SSH private key to use
zhuflf52c7592017-05-25 13:55:24 +0800340 @param server: server dict, used for debugging purposes
JordanP3fe2dc32014-11-17 13:06:01 +0100341 @return a RemoteClient object
342 """
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700343
Andrea Frittoli247058f2014-07-16 16:09:22 +0100344 if username is None:
lanoux283273b2015-12-04 03:01:54 -0800345 username = CONF.validation.image_ssh_user
wantwatering896300c2015-03-27 15:17:42 +0800346 # Set this with 'keypair' or others to log in with keypair or
347 # username/password.
lanoux5fc14522015-09-21 08:17:35 +0000348 if CONF.validation.auth_method == 'keypair':
wantwatering896300c2015-03-27 15:17:42 +0800349 password = None
350 if private_key is None:
351 private_key = self.keypair['private_key']
352 else:
lanoux283273b2015-12-04 03:01:54 -0800353 password = CONF.validation.image_ssh_password
wantwatering896300c2015-03-27 15:17:42 +0800354 private_key = None
zhuflf52c7592017-05-25 13:55:24 +0800355 linux_client = remote_client.RemoteClient(
356 ip_address, username, pkey=private_key, password=password,
357 server=server, servers_client=self.servers_client)
358 linux_client.validate_authentication()
Andrea Frittoli247058f2014-07-16 16:09:22 +0100359 return linux_client
360
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000361 def _image_create(self, name, fmt, path,
362 disk_format=None, properties=None):
Ghanshyam2a180b82014-06-16 13:54:22 +0900363 if properties is None:
364 properties = {}
Andrea Frittoli247058f2014-07-16 16:09:22 +0100365 name = data_utils.rand_name('%s-' % name)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100366 params = {
367 'name': name,
368 'container_format': fmt,
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000369 'disk_format': disk_format or fmt,
Andrea Frittoli247058f2014-07-16 16:09:22 +0100370 }
Matt Riedemann2aa19d42016-06-06 17:45:41 -0400371 if CONF.image_feature_enabled.api_v1:
372 params['is_public'] = 'False'
373 params['properties'] = properties
Ken'ichi Ohmichi02bcdf32016-06-17 16:41:26 -0700374 params = {'headers': common_image.image_meta_to_headers(**params)}
Matt Riedemann2aa19d42016-06-06 17:45:41 -0400375 else:
376 params['visibility'] = 'private'
377 # Additional properties are flattened out in the v2 API.
378 params.update(properties)
379 body = self.image_client.create_image(**params)
380 image = body['image'] if 'image' in body else body
Andrea Frittoli247058f2014-07-16 16:09:22 +0100381 self.addCleanup(self.image_client.delete_image, image['id'])
382 self.assertEqual("queued", image['status'])
zhang.leia4b1cef2016-03-01 10:50:01 +0800383 with open(path, 'rb') as image_file:
Matt Riedemann2aa19d42016-06-06 17:45:41 -0400384 if CONF.image_feature_enabled.api_v1:
385 self.image_client.update_image(image['id'], data=image_file)
386 else:
387 self.image_client.store_image_file(image['id'], image_file)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100388 return image['id']
389
390 def glance_image_create(self):
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300391 img_path = CONF.scenario.img_dir + "/" + CONF.scenario.img_file
Andrea Frittoli247058f2014-07-16 16:09:22 +0100392 aki_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.aki_img_file
393 ari_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.ari_img_file
394 ami_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.ami_img_file
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300395 img_container_format = CONF.scenario.img_container_format
396 img_disk_format = CONF.scenario.img_disk_format
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000397 img_properties = CONF.scenario.img_properties
PranaliD2aa523c2016-06-07 03:54:34 -0400398 LOG.debug("paths: img: %s, container_format: %s, disk_format: %s, "
Jordan Pittier525ec712016-12-07 17:51:26 +0100399 "properties: %s, ami: %s, ari: %s, aki: %s",
400 img_path, img_container_format, img_disk_format,
401 img_properties, ami_img_path, ari_img_path, aki_img_path)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100402 try:
Jordan Pittier1e443ec2015-11-20 16:15:58 +0100403 image = self._image_create('scenario-img',
404 img_container_format,
405 img_path,
406 disk_format=img_disk_format,
407 properties=img_properties)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100408 except IOError:
409 LOG.debug("A qcow2 image was not found. Try to get a uec image.")
410 kernel = self._image_create('scenario-aki', 'aki', aki_img_path)
411 ramdisk = self._image_create('scenario-ari', 'ari', ari_img_path)
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000412 properties = {'kernel_id': kernel, 'ramdisk_id': ramdisk}
Jordan Pittier1e443ec2015-11-20 16:15:58 +0100413 image = self._image_create('scenario-ami', 'ami',
414 path=ami_img_path,
415 properties=properties)
Jordan Pittier525ec712016-12-07 17:51:26 +0100416 LOG.debug("image:%s", image)
Jordan Pittier1e443ec2015-11-20 16:15:58 +0100417
418 return image
Andrea Frittoli247058f2014-07-16 16:09:22 +0100419
Ihar Hrachyshkaa9dca2b2017-04-04 14:17:11 -0700420 def _log_console_output(self, servers=None, client=None):
Matthew Treinish42a3f3a2014-09-04 15:04:53 -0400421 if not CONF.compute_feature_enabled.console_output:
422 LOG.debug('Console output not supported, cannot log')
423 return
Ihar Hrachyshkaa9dca2b2017-04-04 14:17:11 -0700424 client = client or self.servers_client
Andrea Frittoli247058f2014-07-16 16:09:22 +0100425 if not servers:
Ihar Hrachyshkaa9dca2b2017-04-04 14:17:11 -0700426 servers = client.list_servers()
Andrea Frittoli247058f2014-07-16 16:09:22 +0100427 servers = servers['servers']
428 for server in servers:
Attila Fazekas9a5a1122016-11-08 10:24:57 +0100429 try:
Ihar Hrachyshkaa9dca2b2017-04-04 14:17:11 -0700430 console_output = client.get_console_output(
Attila Fazekas9a5a1122016-11-08 10:24:57 +0100431 server['id'])['output']
432 LOG.debug('Console output for %s\nbody=\n%s',
433 server['id'], console_output)
434 except lib_exc.NotFound:
Attila Fazekase1360482016-11-10 11:28:08 +0100435 LOG.debug("Server %s disappeared(deleted) while looking "
Attila Fazekas9a5a1122016-11-08 10:24:57 +0100436 "for the console log", server['id'])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100437
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000438 def _log_net_info(self, exc):
439 # network debug is called as part of ssh init
Andrey Pavlov64723762015-04-29 06:24:58 +0300440 if not isinstance(exc, lib_exc.SSHTimeout):
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000441 LOG.debug('Network information on a devstack host')
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000442
nithya-ganesan882595e2014-07-29 18:51:07 +0000443 def create_server_snapshot(self, server, name=None):
444 # Glance client
445 _image_client = self.image_client
446 # Compute client
Ghanshyamae76c122015-12-22 13:41:35 +0900447 _images_client = self.compute_images_client
nithya-ganesan882595e2014-07-29 18:51:07 +0000448 if name is None:
zhuflf9d95722016-10-19 16:06:17 +0800449 name = data_utils.rand_name(self.__class__.__name__ + 'snapshot')
nithya-ganesan882595e2014-07-29 18:51:07 +0000450 LOG.debug("Creating a snapshot image for server: %s", server['name'])
Ken'ichi Ohmichi28f18672015-07-17 10:00:38 +0000451 image = _images_client.create_image(server['id'], name=name)
David Kranza5299eb2015-01-15 17:24:05 -0500452 image_id = image.response['location'].split('images/')[1]
Yaroslav Lobankov2fea4052016-04-19 15:05:57 +0300453 waiters.wait_for_image_status(_image_client, image_id, 'active')
Jordan Pittierf672b7d2016-06-20 18:50:40 +0200454
455 self.addCleanup(_image_client.wait_for_resource_deletion,
456 image_id)
457 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
458 _image_client.delete_image, image_id)
459
Matt Riedemann2aa19d42016-06-06 17:45:41 -0400460 if CONF.image_feature_enabled.api_v1:
461 # In glance v1 the additional properties are stored in the headers.
Ken'ichi Ohmichi01151e82016-06-10 11:19:52 -0700462 resp = _image_client.check_image(image_id)
463 snapshot_image = common_image.get_image_meta_from_headers(resp)
Matt Riedemann2aa19d42016-06-06 17:45:41 -0400464 image_props = snapshot_image.get('properties', {})
465 else:
466 # In glance v2 the additional properties are flattened.
467 snapshot_image = _image_client.show_image(image_id)
468 image_props = snapshot_image
Andrey Pavlovc8bd4b12015-08-17 10:20:17 +0300469
Matt Riedemann2aa19d42016-06-06 17:45:41 -0400470 bdm = image_props.get('block_device_mapping')
Andrey Pavlovc8bd4b12015-08-17 10:20:17 +0300471 if bdm:
472 bdm = json.loads(bdm)
473 if bdm and 'snapshot_id' in bdm[0]:
474 snapshot_id = bdm[0]['snapshot_id']
475 self.addCleanup(
476 self.snapshots_client.wait_for_resource_deletion,
477 snapshot_id)
Jordan Pittier9e227c52016-02-09 14:35:18 +0100478 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
479 self.snapshots_client.delete_snapshot,
480 snapshot_id)
lkuchlan52d7b0d2016-11-07 20:53:19 +0200481 waiters.wait_for_volume_resource_status(self.snapshots_client,
482 snapshot_id,
483 'available')
nithya-ganesan882595e2014-07-29 18:51:07 +0000484 image_name = snapshot_image['name']
485 self.assertEqual(name, image_name)
486 LOG.debug("Created snapshot image %s for server %s",
487 image_name, server['name'])
488 return snapshot_image
489
Jordan Pittier7cf64762015-10-14 15:01:12 +0200490 def nova_volume_attach(self, server, volume_to_attach):
Joseph Lanoux6809bab2014-12-18 14:57:18 +0000491 volume = self.servers_client.attach_volume(
Jordan Pittier7cf64762015-10-14 15:01:12 +0200492 server['id'], volumeId=volume_to_attach['id'], device='/dev/%s'
ghanshyam0f825252015-08-25 16:02:50 +0900493 % CONF.compute.volume_device_name)['volumeAttachment']
Jordan Pittier7cf64762015-10-14 15:01:12 +0200494 self.assertEqual(volume_to_attach['id'], volume['id'])
lkuchlan52d7b0d2016-11-07 20:53:19 +0200495 waiters.wait_for_volume_resource_status(self.volumes_client,
496 volume['id'], 'in-use')
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900497
Jordan Pittier7cf64762015-10-14 15:01:12 +0200498 # Return the updated volume after the attachment
499 return self.volumes_client.show_volume(volume['id'])['volume']
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900500
Jordan Pittier7cf64762015-10-14 15:01:12 +0200501 def nova_volume_detach(self, server, volume):
502 self.servers_client.detach_volume(server['id'], volume['id'])
lkuchlan52d7b0d2016-11-07 20:53:19 +0200503 waiters.wait_for_volume_resource_status(self.volumes_client,
504 volume['id'], 'available')
Jordan Pittier7cf64762015-10-14 15:01:12 +0200505
Steven Hardyda2a8352014-10-02 12:52:20 +0100506 def ping_ip_address(self, ip_address, should_succeed=True,
Ihar Hrachyshkaf9227c02016-09-15 11:16:47 +0000507 ping_timeout=None, mtu=None):
lanoux5fc14522015-09-21 08:17:35 +0000508 timeout = ping_timeout or CONF.validation.ping_timeout
Ihar Hrachyshkaf9227c02016-09-15 11:16:47 +0000509 cmd = ['ping', '-c1', '-w1']
510
511 if mtu:
512 cmd += [
513 # don't fragment
514 '-M', 'do',
515 # ping receives just the size of ICMP payload
516 '-s', str(net_utils.get_ping_payload_size(mtu, 4))
517 ]
518 cmd.append(ip_address)
Aaron Rosena7df13b2014-09-23 09:45:45 -0700519
520 def ping():
521 proc = subprocess.Popen(cmd,
522 stdout=subprocess.PIPE,
523 stderr=subprocess.PIPE)
524 proc.communicate()
Shuquan Huang753629e2015-07-20 08:52:29 +0000525
Aaron Rosena7df13b2014-09-23 09:45:45 -0700526 return (proc.returncode == 0) == should_succeed
527
Jordan Pittier9e227c52016-02-09 14:35:18 +0100528 caller = test_utils.find_test_caller()
Shuquan Huang753629e2015-07-20 08:52:29 +0000529 LOG.debug('%(caller)s begins to ping %(ip)s in %(timeout)s sec and the'
John L. Villalovosa898aec2017-01-13 14:46:46 -0800530 ' expected result is %(should_succeed)s', {
Shuquan Huang753629e2015-07-20 08:52:29 +0000531 'caller': caller, 'ip': ip_address, 'timeout': timeout,
532 'should_succeed':
533 'reachable' if should_succeed else 'unreachable'
534 })
Jordan Pittier35a63752016-08-30 13:09:12 +0200535 result = test_utils.call_until_true(ping, timeout, 1)
Shuquan Huang753629e2015-07-20 08:52:29 +0000536 LOG.debug('%(caller)s finishes ping %(ip)s in %(timeout)s sec and the '
John L. Villalovosa898aec2017-01-13 14:46:46 -0800537 'ping result is %(result)s', {
Shuquan Huang753629e2015-07-20 08:52:29 +0000538 'caller': caller, 'ip': ip_address, 'timeout': timeout,
539 'result': 'expected' if result else 'unexpected'
540 })
541 return result
Aaron Rosena7df13b2014-09-23 09:45:45 -0700542
Yair Friedae0e73d2014-11-24 11:56:26 +0200543 def check_vm_connectivity(self, ip_address,
544 username=None,
545 private_key=None,
Ihar Hrachyshkaf9227c02016-09-15 11:16:47 +0000546 should_connect=True,
547 mtu=None):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000548 """Check server connectivity
549
Yair Friedae0e73d2014-11-24 11:56:26 +0200550 :param ip_address: server to test against
551 :param username: server's ssh username
552 :param private_key: server's ssh private key to be used
553 :param should_connect: True/False indicates positive/negative test
554 positive - attempt ping and ssh
555 negative - attempt ping and fail if succeed
Ihar Hrachyshkaf9227c02016-09-15 11:16:47 +0000556 :param mtu: network MTU to use for connectivity validation
Yair Friedae0e73d2014-11-24 11:56:26 +0200557
558 :raises: AssertError if the result of the connectivity check does
559 not match the value of the should_connect param
560 """
561 if should_connect:
562 msg = "Timed out waiting for %s to become reachable" % ip_address
563 else:
564 msg = "ip address %s is reachable" % ip_address
565 self.assertTrue(self.ping_ip_address(ip_address,
Ihar Hrachyshkaf9227c02016-09-15 11:16:47 +0000566 should_succeed=should_connect,
567 mtu=mtu),
Yair Friedae0e73d2014-11-24 11:56:26 +0200568 msg=msg)
569 if should_connect:
570 # no need to check ssh for negative connectivity
571 self.get_remote_client(ip_address, username, private_key)
572
573 def check_public_network_connectivity(self, ip_address, username,
574 private_key, should_connect=True,
Ihar Hrachyshkaf9227c02016-09-15 11:16:47 +0000575 msg=None, servers=None, mtu=None):
Yair Friedae0e73d2014-11-24 11:56:26 +0200576 # The target login is assumed to have been configured for
577 # key-based authentication by cloud-init.
Jordan Pittier525ec712016-12-07 17:51:26 +0100578 LOG.debug('checking network connections to IP %s with user: %s',
579 ip_address, username)
Yair Friedae0e73d2014-11-24 11:56:26 +0200580 try:
581 self.check_vm_connectivity(ip_address,
582 username,
583 private_key,
Ihar Hrachyshkaf9227c02016-09-15 11:16:47 +0000584 should_connect=should_connect,
585 mtu=mtu)
Matthew Treinish53483132014-12-09 18:50:06 -0500586 except Exception:
Yair Friedae0e73d2014-11-24 11:56:26 +0200587 ex_msg = 'Public network connectivity check failed'
588 if msg:
589 ex_msg += ": " + msg
590 LOG.exception(ex_msg)
591 self._log_console_output(servers)
Yair Friedae0e73d2014-11-24 11:56:26 +0200592 raise
593
594 def create_floating_ip(self, thing, pool_name=None):
Ken'ichi Ohmichia112a592015-11-17 08:49:37 +0000595 """Create a floating IP and associates to a server on Nova"""
Yair Friedae0e73d2014-11-24 11:56:26 +0200596
Marc Koderer3b57d802016-03-22 15:23:31 +0100597 if not pool_name:
598 pool_name = CONF.network.floating_network_name
John Warrene74890a2015-11-11 15:18:01 -0500599 floating_ip = (self.compute_floating_ips_client.
Ken'ichi Ohmichie037a6f2015-12-03 06:41:49 +0000600 create_floating_ip(pool=pool_name)['floating_ip'])
Jordan Pittier9e227c52016-02-09 14:35:18 +0100601 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
John Warrene74890a2015-11-11 15:18:01 -0500602 self.compute_floating_ips_client.delete_floating_ip,
Yair Friedae0e73d2014-11-24 11:56:26 +0200603 floating_ip['id'])
John Warrene74890a2015-11-11 15:18:01 -0500604 self.compute_floating_ips_client.associate_floating_ip_to_server(
Yair Friedae0e73d2014-11-24 11:56:26 +0200605 floating_ip['ip'], thing['id'])
606 return floating_ip
607
Sean Dague20e98612016-01-06 14:33:28 -0500608 def create_timestamp(self, ip_address, dev_name=None, mount_path='/mnt',
Matt Riedemannfd5657d2015-09-30 14:47:07 -0700609 private_key=None):
Sean Dague20e98612016-01-06 14:33:28 -0500610 ssh_client = self.get_remote_client(ip_address,
Matt Riedemannfd5657d2015-09-30 14:47:07 -0700611 private_key=private_key)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300612 if dev_name is not None:
613 ssh_client.make_fs(dev_name)
Ken'ichi Ohmichi4e5a69e2017-03-01 18:15:29 -0800614 ssh_client.exec_command('sudo mount /dev/%s %s' % (dev_name,
615 mount_path))
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300616 cmd_timestamp = 'sudo sh -c "date > %s/timestamp; sync"' % mount_path
617 ssh_client.exec_command(cmd_timestamp)
618 timestamp = ssh_client.exec_command('sudo cat %s/timestamp'
619 % mount_path)
620 if dev_name is not None:
Ken'ichi Ohmichi4e5a69e2017-03-01 18:15:29 -0800621 ssh_client.exec_command('sudo umount %s' % mount_path)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300622 return timestamp
623
Sean Dague20e98612016-01-06 14:33:28 -0500624 def get_timestamp(self, ip_address, dev_name=None, mount_path='/mnt',
Matt Riedemannfd5657d2015-09-30 14:47:07 -0700625 private_key=None):
Sean Dague20e98612016-01-06 14:33:28 -0500626 ssh_client = self.get_remote_client(ip_address,
Matt Riedemannfd5657d2015-09-30 14:47:07 -0700627 private_key=private_key)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300628 if dev_name is not None:
Matt Riedemann076685a2015-09-30 14:38:16 -0700629 ssh_client.mount(dev_name, mount_path)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300630 timestamp = ssh_client.exec_command('sudo cat %s/timestamp'
631 % mount_path)
632 if dev_name is not None:
Ken'ichi Ohmichi4e5a69e2017-03-01 18:15:29 -0800633 ssh_client.exec_command('sudo umount %s' % mount_path)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300634 return timestamp
635
Sean Dague20e98612016-01-06 14:33:28 -0500636 def get_server_ip(self, server):
637 """Get the server fixed or floating IP.
638
639 Based on the configuration we're in, return a correct ip
640 address for validating that a guest is up.
641 """
Alexander Gubanovc8829f82015-11-12 10:35:13 +0200642 if CONF.validation.connect_method == 'floating':
Sean Dague20e98612016-01-06 14:33:28 -0500643 # The tests calling this method don't have a floating IP
zhufl0892cb22016-05-06 14:46:00 +0800644 # and can't make use of the validation resources. So the
Sean Dague20e98612016-01-06 14:33:28 -0500645 # method is creating the floating IP there.
646 return self.create_floating_ip(server)['ip']
647 elif CONF.validation.connect_method == 'fixed':
Matt Riedemanna7782552016-08-08 16:26:01 -0400648 # Determine the network name to look for based on config or creds
649 # provider network resources.
650 if CONF.validation.network_for_ssh:
651 addresses = server['addresses'][
652 CONF.validation.network_for_ssh]
653 else:
zhufl7b4a7202017-09-28 10:29:27 +0800654 network = self.get_tenant_network()
Matt Riedemanna7782552016-08-08 16:26:01 -0400655 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,
884 nic=None):
YAMAMOTO Takashi4c3ebb02017-01-25 16:04:30 +0900885 """assert ping server via source ssh connection
886
Yair Fried1fc32a12014-08-04 09:11:30 +0300887 :param source: RemoteClient: an ssh connection from which to ping
zhufle9877c62017-10-13 09:38:19 +0800888 :param dest: an IP to ping against
889 :param should_succeed: boolean: should ping succeed or not
Yair Friedbc46f592015-11-18 16:29:34 +0200890 :param nic: specific network interface to ping from
Yair Fried1fc32a12014-08-04 09:11:30 +0300891 """
892 def ping_remote():
893 try:
Yair Friedbc46f592015-11-18 16:29:34 +0200894 source.ping_host(dest, nic=nic)
Andrey Pavlov64723762015-04-29 06:24:58 +0300895 except lib_exc.SSHExecCommandFailed:
zhangguoqing6c096642016-01-04 06:17:21 +0000896 LOG.warning('Failed to ping IP: %s via a ssh connection '
Jordan Pittier525ec712016-12-07 17:51:26 +0100897 'from: %s.', dest, source.ssh_client.host)
Yair Fried1fc32a12014-08-04 09:11:30 +0300898 return not should_succeed
899 return should_succeed
900
zhufle9877c62017-10-13 09:38:19 +0800901 result = test_utils.call_until_true(ping_remote,
902 CONF.validation.ping_timeout, 1)
Ihar Hrachyshkaf9fda2d2017-11-06 13:16:09 -0800903 if result:
904 return
905
YAMAMOTO Takashi4c3ebb02017-01-25 16:04:30 +0900906 source_host = source.ssh_client.host
907 if should_succeed:
908 msg = "Timed out waiting for %s to become reachable from %s" \
909 % (dest, source_host)
910 else:
911 msg = "%s is reachable from %s" % (dest, source_host)
Ihar Hrachyshkaf9fda2d2017-11-06 13:16:09 -0800912 self._log_console_output()
913 self.fail(msg)
YAMAMOTO Takashi4c3ebb02017-01-25 16:04:30 +0900914
John Warren456d9ae2016-01-12 15:36:33 -0500915 def _create_security_group(self, security_group_rules_client=None,
916 tenant_id=None,
John Warrenf9606e92015-12-10 12:12:42 -0500917 namestart='secgroup-smoke',
918 security_groups_client=None):
John Warren456d9ae2016-01-12 15:36:33 -0500919 if security_group_rules_client is None:
920 security_group_rules_client = self.security_group_rules_client
John Warrenf9606e92015-12-10 12:12:42 -0500921 if security_groups_client is None:
922 security_groups_client = self.security_groups_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300923 if tenant_id is None:
John Warrenf9606e92015-12-10 12:12:42 -0500924 tenant_id = security_groups_client.tenant_id
925 secgroup = self._create_empty_security_group(
926 namestart=namestart, client=security_groups_client,
927 tenant_id=tenant_id)
Yair Fried1fc32a12014-08-04 09:11:30 +0300928
929 # Add rules to the security group
John Warrenf9606e92015-12-10 12:12:42 -0500930 rules = self._create_loginable_secgroup_rule(
John Warren456d9ae2016-01-12 15:36:33 -0500931 security_group_rules_client=security_group_rules_client,
932 secgroup=secgroup,
John Warrenf9606e92015-12-10 12:12:42 -0500933 security_groups_client=security_groups_client)
Yair Fried1fc32a12014-08-04 09:11:30 +0300934 for rule in rules:
Steve Heyman33735f22016-05-24 09:28:08 -0500935 self.assertEqual(tenant_id, rule['tenant_id'])
936 self.assertEqual(secgroup['id'], rule['security_group_id'])
Yair Fried1fc32a12014-08-04 09:11:30 +0300937 return secgroup
938
Yair Frieddb6c9e92014-08-06 08:53:13 +0300939 def _create_empty_security_group(self, client=None, tenant_id=None,
Yair Fried1fc32a12014-08-04 09:11:30 +0300940 namestart='secgroup-smoke'):
941 """Create a security group without rules.
942
943 Default rules will be created:
944 - IPv4 egress to any
945 - IPv6 egress to any
946
947 :param tenant_id: secgroup will be created in this tenant
Steve Heyman33735f22016-05-24 09:28:08 -0500948 :returns: the created security group
Yair Fried1fc32a12014-08-04 09:11:30 +0300949 """
950 if client is None:
John Warrenf9606e92015-12-10 12:12:42 -0500951 client = self.security_groups_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300952 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000953 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300954 sg_name = data_utils.rand_name(namestart)
955 sg_desc = sg_name + " description"
956 sg_dict = dict(name=sg_name,
957 description=sg_desc)
958 sg_dict['tenant_id'] = tenant_id
David Kranz34e88122014-12-11 15:24:05 -0500959 result = client.create_security_group(**sg_dict)
Steve Heyman33735f22016-05-24 09:28:08 -0500960
961 secgroup = result['security_group']
962 self.assertEqual(secgroup['name'], sg_name)
963 self.assertEqual(tenant_id, secgroup['tenant_id'])
964 self.assertEqual(secgroup['description'], sg_desc)
965
Jordan Pittier9e227c52016-02-09 14:35:18 +0100966 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
Steve Heyman33735f22016-05-24 09:28:08 -0500967 client.delete_security_group, secgroup['id'])
Yair Fried1fc32a12014-08-04 09:11:30 +0300968 return secgroup
969
John Warren456d9ae2016-01-12 15:36:33 -0500970 def _create_security_group_rule(self, secgroup=None,
971 sec_group_rules_client=None,
John Warrenf9606e92015-12-10 12:12:42 -0500972 tenant_id=None,
973 security_groups_client=None, **kwargs):
Yair Fried1fc32a12014-08-04 09:11:30 +0300974 """Create a rule from a dictionary of rule parameters.
975
976 Create a rule in a secgroup. if secgroup not defined will search for
977 default secgroup in tenant_id.
978
Steve Heyman33735f22016-05-24 09:28:08 -0500979 :param secgroup: the security group.
Yair Fried1fc32a12014-08-04 09:11:30 +0300980 :param tenant_id: if secgroup not passed -- the tenant in which to
981 search for default secgroup
982 :param kwargs: a dictionary containing rule parameters:
983 for example, to allow incoming ssh:
984 rule = {
985 direction: 'ingress'
986 protocol:'tcp',
987 port_range_min: 22,
988 port_range_max: 22
989 }
990 """
John Warren456d9ae2016-01-12 15:36:33 -0500991 if sec_group_rules_client is None:
992 sec_group_rules_client = self.security_group_rules_client
John Warrenf9606e92015-12-10 12:12:42 -0500993 if security_groups_client is None:
994 security_groups_client = self.security_groups_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300995 if not tenant_id:
John Warrenf9606e92015-12-10 12:12:42 -0500996 tenant_id = security_groups_client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300997 if secgroup is None:
zhuflb0b272e2017-09-22 16:01:46 +0800998 # Get default secgroup for tenant_id
999 default_secgroups = security_groups_client.list_security_groups(
1000 name='default', tenant_id=tenant_id)['security_groups']
1001 msg = "No default security group for tenant %s." % (tenant_id)
1002 self.assertNotEmpty(default_secgroups, msg)
1003 secgroup = default_secgroups[0]
Yair Fried1fc32a12014-08-04 09:11:30 +03001004
Steve Heyman33735f22016-05-24 09:28:08 -05001005 ruleset = dict(security_group_id=secgroup['id'],
1006 tenant_id=secgroup['tenant_id'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001007 ruleset.update(kwargs)
1008
John Warren456d9ae2016-01-12 15:36:33 -05001009 sg_rule = sec_group_rules_client.create_security_group_rule(**ruleset)
Steve Heyman33735f22016-05-24 09:28:08 -05001010 sg_rule = sg_rule['security_group_rule']
1011
1012 self.assertEqual(secgroup['tenant_id'], sg_rule['tenant_id'])
1013 self.assertEqual(secgroup['id'], sg_rule['security_group_id'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001014
1015 return sg_rule
1016
John Warren456d9ae2016-01-12 15:36:33 -05001017 def _create_loginable_secgroup_rule(self, security_group_rules_client=None,
1018 secgroup=None,
John Warrenf9606e92015-12-10 12:12:42 -05001019 security_groups_client=None):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001020 """Create loginable security group rule
1021
Alex Stafeyevdd5dde92016-05-08 14:35:04 +03001022 This function will create:
1023 1. egress and ingress tcp port 22 allow rule in order to allow ssh
1024 access for ipv4.
1025 2. egress and ingress ipv6 icmp allow rule, in order to allow icmpv6.
1026 3. egress and ingress ipv4 icmp allow rule, in order to allow icmpv4.
Yair Fried1fc32a12014-08-04 09:11:30 +03001027 """
1028
John Warren456d9ae2016-01-12 15:36:33 -05001029 if security_group_rules_client is None:
1030 security_group_rules_client = self.security_group_rules_client
John Warrenf9606e92015-12-10 12:12:42 -05001031 if security_groups_client is None:
1032 security_groups_client = self.security_groups_client
Yair Fried1fc32a12014-08-04 09:11:30 +03001033 rules = []
1034 rulesets = [
1035 dict(
1036 # ssh
1037 protocol='tcp',
1038 port_range_min=22,
1039 port_range_max=22,
1040 ),
1041 dict(
1042 # ping
1043 protocol='icmp',
Andreas Scheuring887ca8e2015-02-03 17:56:12 +01001044 ),
1045 dict(
1046 # ipv6-icmp for ping6
1047 protocol='icmp',
1048 ethertype='IPv6',
Yair Fried1fc32a12014-08-04 09:11:30 +03001049 )
1050 ]
John Warren456d9ae2016-01-12 15:36:33 -05001051 sec_group_rules_client = security_group_rules_client
Yair Fried1fc32a12014-08-04 09:11:30 +03001052 for ruleset in rulesets:
1053 for r_direction in ['ingress', 'egress']:
1054 ruleset['direction'] = r_direction
1055 try:
1056 sg_rule = self._create_security_group_rule(
John Warren456d9ae2016-01-12 15:36:33 -05001057 sec_group_rules_client=sec_group_rules_client,
1058 secgroup=secgroup,
John Warrenf9606e92015-12-10 12:12:42 -05001059 security_groups_client=security_groups_client,
1060 **ruleset)
Masayuki Igawad9388762015-01-20 14:56:42 +09001061 except lib_exc.Conflict as ex:
Yair Fried1fc32a12014-08-04 09:11:30 +03001062 # if rule already exist - skip rule and continue
1063 msg = 'Security group rule already exists'
1064 if msg not in ex._error_string:
1065 raise ex
1066 else:
Steve Heyman33735f22016-05-24 09:28:08 -05001067 self.assertEqual(r_direction, sg_rule['direction'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001068 rules.append(sg_rule)
1069
1070 return rules
1071
Yair Frieddb6c9e92014-08-06 08:53:13 +03001072 def _get_router(self, client=None, tenant_id=None):
Yair Fried1fc32a12014-08-04 09:11:30 +03001073 """Retrieve a router for the given tenant id.
1074
1075 If a public router has been configured, it will be returned.
1076
1077 If a public router has not been configured, but a public
1078 network has, a tenant router will be created and returned that
1079 routes traffic to the public network.
1080 """
Yair Frieddb6c9e92014-08-06 08:53:13 +03001081 if not client:
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +00001082 client = self.routers_client
Yair Frieddb6c9e92014-08-06 08:53:13 +03001083 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +00001084 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001085 router_id = CONF.network.public_router_id
1086 network_id = CONF.network.public_network_id
1087 if router_id:
David Kranzca4c7e72015-05-27 11:39:19 -04001088 body = client.show_router(router_id)
Steve Heyman33735f22016-05-24 09:28:08 -05001089 return body['router']
Yair Fried1fc32a12014-08-04 09:11:30 +03001090 elif network_id:
zhufl3484f992017-10-10 16:18:29 +08001091 router = client.create_router(
1092 name=data_utils.rand_name(self.__class__.__name__ + '-router'),
1093 admin_state_up=True,
1094 tenant_id=tenant_id,
1095 external_gateway_info=dict(network_id=network_id))['router']
1096 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
1097 client.delete_router, router['id'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001098 return router
1099 else:
1100 raise Exception("Neither of 'public_router_id' or "
1101 "'public_network_id' has been defined.")
1102
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -07001103 def create_networks(self, networks_client=None,
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +00001104 routers_client=None, subnets_client=None,
Markus Zoeller156b5da2016-07-11 18:10:31 +02001105 tenant_id=None, dns_nameservers=None,
1106 port_security_enabled=True):
Yair Fried1fc32a12014-08-04 09:11:30 +03001107 """Create a network with a subnet connected to a router.
1108
David Shrewsbury9bac3662014-08-07 15:07:01 -04001109 The baremetal driver is a special case since all nodes are
1110 on the same shared network.
1111
Yair Fried413bf2d2014-11-19 17:07:11 +02001112 :param tenant_id: id of tenant to create resources in.
1113 :param dns_nameservers: list of dns servers to send to subnet.
Yair Fried1fc32a12014-08-04 09:11:30 +03001114 :returns: network, subnet, router
1115 """
Thiago Paiva66cded22016-08-15 14:55:58 -03001116 if CONF.network.shared_physical_network:
David Shrewsbury9bac3662014-08-07 15:07:01 -04001117 # NOTE(Shrews): This exception is for environments where tenant
1118 # credential isolation is available, but network separation is
1119 # not (the current baremetal case). Likely can be removed when
1120 # test account mgmt is reworked:
1121 # https://blueprints.launchpad.net/tempest/+spec/test-accounts
Adam Gandelman878a5fd2015-03-30 14:33:36 -07001122 if not CONF.compute.fixed_network_name:
1123 m = 'fixed_network_name must be specified in config'
Matthew Treinish4217a702016-10-07 17:27:11 -04001124 raise lib_exc.InvalidConfiguration(m)
David Shrewsbury9bac3662014-08-07 15:07:01 -04001125 network = self._get_network_by_name(
1126 CONF.compute.fixed_network_name)
1127 router = None
1128 subnet = None
1129 else:
John Warren94d8faf2015-09-15 12:22:24 -04001130 network = self._create_network(
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -07001131 networks_client=networks_client,
Markus Zoeller156b5da2016-07-11 18:10:31 +02001132 tenant_id=tenant_id,
1133 port_security_enabled=port_security_enabled)
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +00001134 router = self._get_router(client=routers_client,
1135 tenant_id=tenant_id)
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -07001136 subnet_kwargs = dict(network=network,
zhufl5b0a52f2017-10-24 15:48:20 +08001137 subnets_client=subnets_client)
Yair Fried413bf2d2014-11-19 17:07:11 +02001138 # use explicit check because empty list is a valid option
1139 if dns_nameservers is not None:
1140 subnet_kwargs['dns_nameservers'] = dns_nameservers
zhufl5b0a52f2017-10-24 15:48:20 +08001141 subnet = self.create_subnet(**subnet_kwargs)
Steve Heyman33735f22016-05-24 09:28:08 -05001142 if not routers_client:
1143 routers_client = self.routers_client
1144 router_id = router['id']
1145 routers_client.add_router_interface(router_id,
1146 subnet_id=subnet['id'])
1147
1148 # save a cleanup job to remove this association between
1149 # router and subnet
1150 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
1151 routers_client.remove_router_interface, router_id,
1152 subnet_id=subnet['id'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001153 return network, subnet, router
1154
1155
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001156class EncryptionScenarioTest(ScenarioTest):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001157 """Base class for encryption scenario tests"""
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001158
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001159 credentials = ['primary', 'admin']
David Kranz4cc852b2015-03-09 14:57:11 -04001160
1161 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001162 def setup_clients(cls):
1163 super(EncryptionScenarioTest, cls).setup_clients()
Jordan Pittier8160d312017-04-18 11:52:23 +02001164 cls.admin_volume_types_client = cls.os_admin.volume_types_v2_client
ghanshyam3bd0d2b2017-03-23 01:57:28 +00001165 cls.admin_encryption_types_client =\
Jordan Pittier8160d312017-04-18 11:52:23 +02001166 cls.os_admin.encryption_types_v2_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001167
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001168 def create_encryption_type(self, client=None, type_id=None, provider=None,
1169 key_size=None, cipher=None,
1170 control_location=None):
1171 if not client:
Ken'ichi Ohmichia6ebf622016-08-25 11:52:27 -07001172 client = self.admin_encryption_types_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001173 if not type_id:
1174 volume_type = self.create_volume_type()
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001175 type_id = volume_type['id']
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001176 LOG.debug("Creating an encryption type for volume type: %s", type_id)
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001177 client.create_encryption_type(
1178 type_id, provider=provider, key_size=key_size, cipher=cipher,
John Warrend053ded2015-08-13 15:22:48 +00001179 control_location=control_location)['encryption']
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001180
lkuchlan3023e752017-06-08 12:53:13 +03001181 def create_encrypted_volume(self, encryption_provider, volume_type,
1182 key_size=256, cipher='aes-xts-plain64',
1183 control_location='front-end'):
1184 volume_type = self.create_volume_type(name=volume_type)
1185 self.create_encryption_type(type_id=volume_type['id'],
1186 provider=encryption_provider,
1187 key_size=key_size,
1188 cipher=cipher,
1189 control_location=control_location)
1190 return self.create_volume(volume_type=volume_type['name'])
1191
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001192
Masayuki Igawa0870db52015-09-18 21:08:36 +09001193class ObjectStorageScenarioTest(ScenarioTest):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001194 """Provide harness to do Object Storage scenario tests.
Chris Dent0d494112014-08-26 13:48:30 +01001195
1196 Subclasses implement the tests that use the methods provided by this
1197 class.
1198 """
1199
1200 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001201 def skip_checks(cls):
Masayuki Igawa0870db52015-09-18 21:08:36 +09001202 super(ObjectStorageScenarioTest, cls).skip_checks()
Chris Dent0d494112014-08-26 13:48:30 +01001203 if not CONF.service_available.swift:
1204 skip_msg = ("%s skipped as swift is not available" %
1205 cls.__name__)
1206 raise cls.skipException(skip_msg)
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001207
1208 @classmethod
1209 def setup_credentials(cls):
Masayuki Igawa60ea6c52014-10-15 17:32:14 +09001210 cls.set_network_resources()
Masayuki Igawa0870db52015-09-18 21:08:36 +09001211 super(ObjectStorageScenarioTest, cls).setup_credentials()
Matthew Treinish4a596932015-03-06 20:37:01 -05001212 operator_role = CONF.object_storage.operator_role
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +01001213 cls.os_operator = cls.get_client_manager(roles=[operator_role])
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001214
1215 @classmethod
1216 def setup_clients(cls):
Masayuki Igawa0870db52015-09-18 21:08:36 +09001217 super(ObjectStorageScenarioTest, cls).setup_clients()
Chris Dent0d494112014-08-26 13:48:30 +01001218 # Clients for Swift
Matthew Treinish8f268292015-02-24 20:01:36 -05001219 cls.account_client = cls.os_operator.account_client
1220 cls.container_client = cls.os_operator.container_client
1221 cls.object_client = cls.os_operator.object_client
Chris Dent0d494112014-08-26 13:48:30 +01001222
Chris Dentde456a12014-09-10 12:41:15 +01001223 def get_swift_stat(self):
Chris Dent0d494112014-08-26 13:48:30 +01001224 """get swift status for our user account."""
1225 self.account_client.list_account_containers()
1226 LOG.debug('Swift status information obtained successfully')
1227
Chris Dentde456a12014-09-10 12:41:15 +01001228 def create_container(self, container_name=None):
Chris Dent0d494112014-08-26 13:48:30 +01001229 name = container_name or data_utils.rand_name(
1230 'swift-scenario-container')
ghanshyameed40312017-09-15 18:30:04 +03001231 self.container_client.update_container(name)
Chris Dent0d494112014-08-26 13:48:30 +01001232 # look for the container to assure it is created
Chris Dentde456a12014-09-10 12:41:15 +01001233 self.list_and_check_container_objects(name)
Jordan Pittier525ec712016-12-07 17:51:26 +01001234 LOG.debug('Container %s created', name)
Jordan Pittier9e227c52016-02-09 14:35:18 +01001235 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
Chris Dent1d4313a2014-10-28 12:16:48 +00001236 self.container_client.delete_container,
1237 name)
Chris Dent0d494112014-08-26 13:48:30 +01001238 return name
1239
Chris Dentde456a12014-09-10 12:41:15 +01001240 def delete_container(self, container_name):
Chris Dent0d494112014-08-26 13:48:30 +01001241 self.container_client.delete_container(container_name)
Jordan Pittier525ec712016-12-07 17:51:26 +01001242 LOG.debug('Container %s deleted', container_name)
Chris Dent0d494112014-08-26 13:48:30 +01001243
Chris Dentde456a12014-09-10 12:41:15 +01001244 def upload_object_to_container(self, container_name, obj_name=None):
Chris Dent0d494112014-08-26 13:48:30 +01001245 obj_name = obj_name or data_utils.rand_name('swift-scenario-object')
Jordan Pittierb84f2d42016-12-21 19:02:15 +01001246 obj_data = data_utils.random_bytes()
Chris Dent0d494112014-08-26 13:48:30 +01001247 self.object_client.create_object(container_name, obj_name, obj_data)
Jordan Pittier9e227c52016-02-09 14:35:18 +01001248 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
Chris Dent1d4313a2014-10-28 12:16:48 +00001249 self.object_client.delete_object,
1250 container_name,
1251 obj_name)
Chris Dent0d494112014-08-26 13:48:30 +01001252 return obj_name, obj_data
1253
Chris Dentde456a12014-09-10 12:41:15 +01001254 def delete_object(self, container_name, filename):
Chris Dent0d494112014-08-26 13:48:30 +01001255 self.object_client.delete_object(container_name, filename)
Chris Dentde456a12014-09-10 12:41:15 +01001256 self.list_and_check_container_objects(container_name,
1257 not_present_obj=[filename])
Chris Dent0d494112014-08-26 13:48:30 +01001258
Chris Dentde456a12014-09-10 12:41:15 +01001259 def list_and_check_container_objects(self, container_name,
1260 present_obj=None,
1261 not_present_obj=None):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001262 # List objects for a given container and assert which are present and
1263 # which are not.
Ghanshyam2a180b82014-06-16 13:54:22 +09001264 if present_obj is None:
1265 present_obj = []
1266 if not_present_obj is None:
1267 not_present_obj = []
ghanshyam871b1a82017-09-14 02:56:16 +03001268 _, object_list = self.container_client.list_container_objects(
Chris Dent0d494112014-08-26 13:48:30 +01001269 container_name)
1270 if present_obj:
1271 for obj in present_obj:
1272 self.assertIn(obj, object_list)
1273 if not_present_obj:
1274 for obj in not_present_obj:
1275 self.assertNotIn(obj, object_list)
1276
Chris Dentde456a12014-09-10 12:41:15 +01001277 def download_and_verify(self, container_name, obj_name, expected_data):
Chris Dent0d494112014-08-26 13:48:30 +01001278 _, obj = self.object_client.get_object(container_name, obj_name)
1279 self.assertEqual(obj, expected_data)