blob: 4d7cee4441003ae3ce6c09f0b551d8a136760947 [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
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700504 def rebuild_server(self, server_id, image=None,
505 preserve_ephemeral=False, wait=True,
506 rebuild_kwargs=None):
507 if image is None:
508 image = CONF.compute.image_ref
509
510 rebuild_kwargs = rebuild_kwargs or {}
511
512 LOG.debug("Rebuilding server (id: %s, image: %s, preserve eph: %s)",
513 server_id, image, preserve_ephemeral)
Ken'ichi Ohmichi5271b0f2015-08-10 07:53:27 +0000514 self.servers_client.rebuild_server(
515 server_id=server_id, image_ref=image,
516 preserve_ephemeral=preserve_ephemeral,
517 **rebuild_kwargs)
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700518 if wait:
Ken'ichi Ohmichi0eb153c2015-07-13 02:18:25 +0000519 waiters.wait_for_server_status(self.servers_client,
520 server_id, 'ACTIVE')
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700521
Steven Hardyda2a8352014-10-02 12:52:20 +0100522 def ping_ip_address(self, ip_address, should_succeed=True,
Ihar Hrachyshkaf9227c02016-09-15 11:16:47 +0000523 ping_timeout=None, mtu=None):
lanoux5fc14522015-09-21 08:17:35 +0000524 timeout = ping_timeout or CONF.validation.ping_timeout
Ihar Hrachyshkaf9227c02016-09-15 11:16:47 +0000525 cmd = ['ping', '-c1', '-w1']
526
527 if mtu:
528 cmd += [
529 # don't fragment
530 '-M', 'do',
531 # ping receives just the size of ICMP payload
532 '-s', str(net_utils.get_ping_payload_size(mtu, 4))
533 ]
534 cmd.append(ip_address)
Aaron Rosena7df13b2014-09-23 09:45:45 -0700535
536 def ping():
537 proc = subprocess.Popen(cmd,
538 stdout=subprocess.PIPE,
539 stderr=subprocess.PIPE)
540 proc.communicate()
Shuquan Huang753629e2015-07-20 08:52:29 +0000541
Aaron Rosena7df13b2014-09-23 09:45:45 -0700542 return (proc.returncode == 0) == should_succeed
543
Jordan Pittier9e227c52016-02-09 14:35:18 +0100544 caller = test_utils.find_test_caller()
Shuquan Huang753629e2015-07-20 08:52:29 +0000545 LOG.debug('%(caller)s begins to ping %(ip)s in %(timeout)s sec and the'
John L. Villalovosa898aec2017-01-13 14:46:46 -0800546 ' expected result is %(should_succeed)s', {
Shuquan Huang753629e2015-07-20 08:52:29 +0000547 'caller': caller, 'ip': ip_address, 'timeout': timeout,
548 'should_succeed':
549 'reachable' if should_succeed else 'unreachable'
550 })
Jordan Pittier35a63752016-08-30 13:09:12 +0200551 result = test_utils.call_until_true(ping, timeout, 1)
Shuquan Huang753629e2015-07-20 08:52:29 +0000552 LOG.debug('%(caller)s finishes ping %(ip)s in %(timeout)s sec and the '
John L. Villalovosa898aec2017-01-13 14:46:46 -0800553 'ping result is %(result)s', {
Shuquan Huang753629e2015-07-20 08:52:29 +0000554 'caller': caller, 'ip': ip_address, 'timeout': timeout,
555 'result': 'expected' if result else 'unexpected'
556 })
557 return result
Aaron Rosena7df13b2014-09-23 09:45:45 -0700558
Yair Friedae0e73d2014-11-24 11:56:26 +0200559 def check_vm_connectivity(self, ip_address,
560 username=None,
561 private_key=None,
Ihar Hrachyshkaf9227c02016-09-15 11:16:47 +0000562 should_connect=True,
563 mtu=None):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000564 """Check server connectivity
565
Yair Friedae0e73d2014-11-24 11:56:26 +0200566 :param ip_address: server to test against
567 :param username: server's ssh username
568 :param private_key: server's ssh private key to be used
569 :param should_connect: True/False indicates positive/negative test
570 positive - attempt ping and ssh
571 negative - attempt ping and fail if succeed
Ihar Hrachyshkaf9227c02016-09-15 11:16:47 +0000572 :param mtu: network MTU to use for connectivity validation
Yair Friedae0e73d2014-11-24 11:56:26 +0200573
574 :raises: AssertError if the result of the connectivity check does
575 not match the value of the should_connect param
576 """
577 if should_connect:
578 msg = "Timed out waiting for %s to become reachable" % ip_address
579 else:
580 msg = "ip address %s is reachable" % ip_address
581 self.assertTrue(self.ping_ip_address(ip_address,
Ihar Hrachyshkaf9227c02016-09-15 11:16:47 +0000582 should_succeed=should_connect,
583 mtu=mtu),
Yair Friedae0e73d2014-11-24 11:56:26 +0200584 msg=msg)
585 if should_connect:
586 # no need to check ssh for negative connectivity
587 self.get_remote_client(ip_address, username, private_key)
588
589 def check_public_network_connectivity(self, ip_address, username,
590 private_key, should_connect=True,
Ihar Hrachyshkaf9227c02016-09-15 11:16:47 +0000591 msg=None, servers=None, mtu=None):
Yair Friedae0e73d2014-11-24 11:56:26 +0200592 # The target login is assumed to have been configured for
593 # key-based authentication by cloud-init.
Jordan Pittier525ec712016-12-07 17:51:26 +0100594 LOG.debug('checking network connections to IP %s with user: %s',
595 ip_address, username)
Yair Friedae0e73d2014-11-24 11:56:26 +0200596 try:
597 self.check_vm_connectivity(ip_address,
598 username,
599 private_key,
Ihar Hrachyshkaf9227c02016-09-15 11:16:47 +0000600 should_connect=should_connect,
601 mtu=mtu)
Matthew Treinish53483132014-12-09 18:50:06 -0500602 except Exception:
Yair Friedae0e73d2014-11-24 11:56:26 +0200603 ex_msg = 'Public network connectivity check failed'
604 if msg:
605 ex_msg += ": " + msg
606 LOG.exception(ex_msg)
607 self._log_console_output(servers)
Yair Friedae0e73d2014-11-24 11:56:26 +0200608 raise
609
610 def create_floating_ip(self, thing, pool_name=None):
Ken'ichi Ohmichia112a592015-11-17 08:49:37 +0000611 """Create a floating IP and associates to a server on Nova"""
Yair Friedae0e73d2014-11-24 11:56:26 +0200612
Marc Koderer3b57d802016-03-22 15:23:31 +0100613 if not pool_name:
614 pool_name = CONF.network.floating_network_name
John Warrene74890a2015-11-11 15:18:01 -0500615 floating_ip = (self.compute_floating_ips_client.
Ken'ichi Ohmichie037a6f2015-12-03 06:41:49 +0000616 create_floating_ip(pool=pool_name)['floating_ip'])
Jordan Pittier9e227c52016-02-09 14:35:18 +0100617 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
John Warrene74890a2015-11-11 15:18:01 -0500618 self.compute_floating_ips_client.delete_floating_ip,
Yair Friedae0e73d2014-11-24 11:56:26 +0200619 floating_ip['id'])
John Warrene74890a2015-11-11 15:18:01 -0500620 self.compute_floating_ips_client.associate_floating_ip_to_server(
Yair Friedae0e73d2014-11-24 11:56:26 +0200621 floating_ip['ip'], thing['id'])
622 return floating_ip
623
Sean Dague20e98612016-01-06 14:33:28 -0500624 def create_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:
629 ssh_client.make_fs(dev_name)
Ken'ichi Ohmichi4e5a69e2017-03-01 18:15:29 -0800630 ssh_client.exec_command('sudo mount /dev/%s %s' % (dev_name,
631 mount_path))
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300632 cmd_timestamp = 'sudo sh -c "date > %s/timestamp; sync"' % mount_path
633 ssh_client.exec_command(cmd_timestamp)
634 timestamp = ssh_client.exec_command('sudo cat %s/timestamp'
635 % mount_path)
636 if dev_name is not None:
Ken'ichi Ohmichi4e5a69e2017-03-01 18:15:29 -0800637 ssh_client.exec_command('sudo umount %s' % mount_path)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300638 return timestamp
639
Sean Dague20e98612016-01-06 14:33:28 -0500640 def get_timestamp(self, ip_address, dev_name=None, mount_path='/mnt',
Matt Riedemannfd5657d2015-09-30 14:47:07 -0700641 private_key=None):
Sean Dague20e98612016-01-06 14:33:28 -0500642 ssh_client = self.get_remote_client(ip_address,
Matt Riedemannfd5657d2015-09-30 14:47:07 -0700643 private_key=private_key)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300644 if dev_name is not None:
Matt Riedemann076685a2015-09-30 14:38:16 -0700645 ssh_client.mount(dev_name, mount_path)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300646 timestamp = ssh_client.exec_command('sudo cat %s/timestamp'
647 % mount_path)
648 if dev_name is not None:
Ken'ichi Ohmichi4e5a69e2017-03-01 18:15:29 -0800649 ssh_client.exec_command('sudo umount %s' % mount_path)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300650 return timestamp
651
Sean Dague20e98612016-01-06 14:33:28 -0500652 def get_server_ip(self, server):
653 """Get the server fixed or floating IP.
654
655 Based on the configuration we're in, return a correct ip
656 address for validating that a guest is up.
657 """
Alexander Gubanovc8829f82015-11-12 10:35:13 +0200658 if CONF.validation.connect_method == 'floating':
Sean Dague20e98612016-01-06 14:33:28 -0500659 # The tests calling this method don't have a floating IP
zhufl0892cb22016-05-06 14:46:00 +0800660 # and can't make use of the validation resources. So the
Sean Dague20e98612016-01-06 14:33:28 -0500661 # method is creating the floating IP there.
662 return self.create_floating_ip(server)['ip']
663 elif CONF.validation.connect_method == 'fixed':
Matt Riedemanna7782552016-08-08 16:26:01 -0400664 # Determine the network name to look for based on config or creds
665 # provider network resources.
666 if CONF.validation.network_for_ssh:
667 addresses = server['addresses'][
668 CONF.validation.network_for_ssh]
669 else:
670 creds_provider = self._get_credentials_provider()
671 net_creds = creds_provider.get_primary_creds()
672 network = getattr(net_creds, 'network', None)
673 addresses = (server['addresses'][network['name']]
674 if network else [])
Sean Dague20e98612016-01-06 14:33:28 -0500675 for address in addresses:
Matt Riedemanna7782552016-08-08 16:26:01 -0400676 if (address['version'] == CONF.validation.ip_version_for_ssh
677 and address['OS-EXT-IPS:type'] == 'fixed'):
Sean Dague20e98612016-01-06 14:33:28 -0500678 return address['addr']
zhufl955f82b2016-07-22 11:14:34 +0800679 raise exceptions.ServerUnreachable(server_id=server['id'])
Alexander Gubanovc8829f82015-11-12 10:35:13 +0200680 else:
Matthew Treinish4217a702016-10-07 17:27:11 -0400681 raise lib_exc.InvalidConfiguration()
Alexander Gubanovc8829f82015-11-12 10:35:13 +0200682
Andrea Frittoli2e733b52014-07-16 14:12:11 +0100683
Andrea Frittoli4971fc82014-09-25 10:22:20 +0100684class NetworkScenarioTest(ScenarioTest):
Yair Fried1fc32a12014-08-04 09:11:30 +0300685 """Base class for network scenario tests.
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000686
Yair Fried1fc32a12014-08-04 09:11:30 +0300687 This class provide helpers for network scenario tests, using the neutron
688 API. Helpers from ancestor which use the nova network API are overridden
689 with the neutron API.
690
691 This Class also enforces using Neutron instead of novanetwork.
692 Subclassed tests will be skipped if Neutron is not enabled
693
694 """
695
Andrea Frittolib21de6c2015-02-06 20:12:38 +0000696 credentials = ['primary', 'admin']
697
Yair Fried1fc32a12014-08-04 09:11:30 +0300698 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +0000699 def skip_checks(cls):
700 super(NetworkScenarioTest, cls).skip_checks()
Andrea Frittoli2ddc2632014-09-25 11:03:00 +0100701 if not CONF.service_available.neutron:
702 raise cls.skipException('Neutron not available')
Yair Fried1fc32a12014-08-04 09:11:30 +0300703
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -0700704 def _create_network(self, networks_client=None,
zhoubin5058bead72017-02-04 18:01:15 +0800705 tenant_id=None,
Markus Zoeller156b5da2016-07-11 18:10:31 +0200706 namestart='network-smoke-',
707 port_security_enabled=True):
John Warren94d8faf2015-09-15 12:22:24 -0400708 if not networks_client:
709 networks_client = self.networks_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300710 if not tenant_id:
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -0700711 tenant_id = networks_client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300712 name = data_utils.rand_name(namestart)
Matt Riedemann039b2fe2016-09-15 16:12:24 -0400713 network_kwargs = dict(name=name, tenant_id=tenant_id)
714 # Neutron disables port security by default so we have to check the
715 # config before trying to create the network with port_security_enabled
716 if CONF.network_feature_enabled.port_security:
717 network_kwargs['port_security_enabled'] = port_security_enabled
Markus Zoeller156b5da2016-07-11 18:10:31 +0200718 result = networks_client.create_network(**network_kwargs)
Steve Heyman33735f22016-05-24 09:28:08 -0500719 network = result['network']
720
721 self.assertEqual(network['name'], name)
Jordan Pittier9e227c52016-02-09 14:35:18 +0100722 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
zhoubin508bf20b32017-02-03 09:39:14 +0800723 networks_client.delete_network,
Steve Heyman33735f22016-05-24 09:28:08 -0500724 network['id'])
Yair Fried1fc32a12014-08-04 09:11:30 +0300725 return network
726
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -0700727 def _create_subnet(self, network, subnets_client=None,
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000728 routers_client=None, namestart='subnet-smoke',
729 **kwargs):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000730 """Create a subnet for the given network
731
732 within the cidr block configured for tenant networks.
Yair Fried1fc32a12014-08-04 09:11:30 +0300733 """
John Warren3961acd2015-10-02 14:38:53 -0400734 if not subnets_client:
735 subnets_client = self.subnets_client
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000736 if not routers_client:
737 routers_client = self.routers_client
Yair Fried1fc32a12014-08-04 09:11:30 +0300738
739 def cidr_in_use(cidr, tenant_id):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000740 """Check cidr existence
741
lei zhangdd552b22015-11-25 20:41:48 +0800742 :returns: True if subnet with cidr already exist in tenant
743 False else
Yair Fried1fc32a12014-08-04 09:11:30 +0300744 """
jeremy.zhang5870ff12017-05-25 11:24:23 +0800745 cidr_in_use = self.os_admin.subnets_client.list_subnets(
Jordan Pittier64e6b442017-02-20 19:29:02 +0100746 tenant_id=tenant_id, cidr=cidr)['subnets']
Yair Fried1fc32a12014-08-04 09:11:30 +0300747 return len(cidr_in_use) != 0
748
Kirill Shileev14113572014-11-21 16:58:02 +0300749 ip_version = kwargs.pop('ip_version', 4)
750
751 if ip_version == 6:
752 tenant_cidr = netaddr.IPNetwork(
Sean Dagueed6e5862016-04-04 10:49:13 -0400753 CONF.network.project_network_v6_cidr)
754 num_bits = CONF.network.project_network_v6_mask_bits
Kirill Shileev14113572014-11-21 16:58:02 +0300755 else:
Sean Dagueed6e5862016-04-04 10:49:13 -0400756 tenant_cidr = netaddr.IPNetwork(CONF.network.project_network_cidr)
757 num_bits = CONF.network.project_network_mask_bits
Kirill Shileev14113572014-11-21 16:58:02 +0300758
Yair Fried1fc32a12014-08-04 09:11:30 +0300759 result = None
Kirill Shileev14113572014-11-21 16:58:02 +0300760 str_cidr = None
Yair Fried1fc32a12014-08-04 09:11:30 +0300761 # Repeatedly attempt subnet creation with sequential cidr
762 # blocks until an unallocated block is found.
Kirill Shileev14113572014-11-21 16:58:02 +0300763 for subnet_cidr in tenant_cidr.subnet(num_bits):
Yair Fried1fc32a12014-08-04 09:11:30 +0300764 str_cidr = str(subnet_cidr)
Steve Heyman33735f22016-05-24 09:28:08 -0500765 if cidr_in_use(str_cidr, tenant_id=network['tenant_id']):
Yair Fried1fc32a12014-08-04 09:11:30 +0300766 continue
767
768 subnet = dict(
769 name=data_utils.rand_name(namestart),
Steve Heyman33735f22016-05-24 09:28:08 -0500770 network_id=network['id'],
771 tenant_id=network['tenant_id'],
Yair Fried1fc32a12014-08-04 09:11:30 +0300772 cidr=str_cidr,
Kirill Shileev14113572014-11-21 16:58:02 +0300773 ip_version=ip_version,
Yair Fried1fc32a12014-08-04 09:11:30 +0300774 **kwargs
775 )
776 try:
John Warren3961acd2015-10-02 14:38:53 -0400777 result = subnets_client.create_subnet(**subnet)
Yair Fried1fc32a12014-08-04 09:11:30 +0300778 break
Masayuki Igawad9388762015-01-20 14:56:42 +0900779 except lib_exc.Conflict as e:
Yair Fried1fc32a12014-08-04 09:11:30 +0300780 is_overlapping_cidr = 'overlaps with another subnet' in str(e)
781 if not is_overlapping_cidr:
782 raise
783 self.assertIsNotNone(result, 'Unable to allocate tenant network')
Steve Heyman33735f22016-05-24 09:28:08 -0500784
785 subnet = result['subnet']
786 self.assertEqual(subnet['cidr'], str_cidr)
787
788 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
789 subnets_client.delete_subnet, subnet['id'])
790
Yair Fried1fc32a12014-08-04 09:11:30 +0300791 return subnet
792
Kirill Shileev14113572014-11-21 16:58:02 +0300793 def _get_server_port_id_and_ip4(self, server, ip_addr=None):
jeremy.zhang5870ff12017-05-25 11:24:23 +0800794 ports = self.os_admin.ports_client.list_ports(
Jordan Pittier64e6b442017-02-20 19:29:02 +0100795 device_id=server['id'], fixed_ip=ip_addr)['ports']
Kobi Samoray166500a2016-10-09 14:42:48 +0300796 # A port can have more than one IP address in some cases.
Sean M. Collins2e896832015-12-15 13:58:47 -0500797 # If the network is dual-stack (IPv4 + IPv6), this port is associated
798 # with 2 subnets
Vasyl Saienko8fd517c2016-05-30 09:52:54 +0300799 p_status = ['ACTIVE']
800 # NOTE(vsaienko) With Ironic, instances live on separate hardware
801 # servers. Neutron does not bind ports for Ironic instances, as a
802 # result the port remains in the DOWN state.
Vasyl Saienkoc8aa34b2016-08-01 14:18:37 +0300803 # TODO(vsaienko) remove once bug: #1599836 is resolved.
Thiago Paiva66cded22016-08-15 14:55:58 -0300804 if getattr(CONF.service_available, 'ironic', False):
Vasyl Saienko8fd517c2016-05-30 09:52:54 +0300805 p_status.append('DOWN')
Daniel Mellado9e3e1062015-08-06 18:07:05 +0200806 port_map = [(p["id"], fxip["ip_address"])
807 for p in ports
808 for fxip in p["fixed_ips"]
Yatin Kumbhareee4924c2016-06-09 15:12:06 +0530809 if netutils.is_valid_ipv4(fxip["ip_address"])
Vasyl Saienko8fd517c2016-05-30 09:52:54 +0300810 and p['status'] in p_status]
Kevin Benton1d0c1dc2016-02-04 14:30:08 -0800811 inactive = [p for p in ports if p['status'] != 'ACTIVE']
812 if inactive:
813 LOG.warning("Instance has ports that are not ACTIVE: %s", inactive)
Daniel Mellado9e3e1062015-08-06 18:07:05 +0200814
Masayuki Igawaf9009b42017-04-10 14:49:29 +0900815 self.assertNotEmpty(port_map,
John L. Villalovosb83286f2015-11-04 14:46:57 -0800816 "No IPv4 addresses found in: %s" % ports)
Daniel Mellado9e3e1062015-08-06 18:07:05 +0200817 self.assertEqual(len(port_map), 1,
818 "Found multiple IPv4 addresses: %s. "
819 "Unable to determine which port to target."
820 % port_map)
821 return port_map[0]
Yair Fried1fc32a12014-08-04 09:11:30 +0300822
David Shrewsbury9bac3662014-08-07 15:07:01 -0400823 def _get_network_by_name(self, network_name):
jeremy.zhang5870ff12017-05-25 11:24:23 +0800824 net = self.os_admin.networks_client.list_networks(
Jordan Pittier64e6b442017-02-20 19:29:02 +0100825 name=network_name)['networks']
Ferenc Horváth268ccce2017-06-08 12:39:02 +0200826 self.assertNotEmpty(net,
Adam Gandelman878a5fd2015-03-30 14:33:36 -0700827 "Unable to get network by name: %s" % network_name)
Steve Heyman33735f22016-05-24 09:28:08 -0500828 return net[0]
David Shrewsbury9bac3662014-08-07 15:07:01 -0400829
Yair Friedae0e73d2014-11-24 11:56:26 +0200830 def create_floating_ip(self, thing, external_network_id=None,
831 port_id=None, client=None):
Ken'ichi Ohmichia112a592015-11-17 08:49:37 +0000832 """Create a floating IP and associates to a resource/port on Neutron"""
Yair Friedae0e73d2014-11-24 11:56:26 +0200833 if not external_network_id:
834 external_network_id = CONF.network.public_network_id
Yair Frieddb6c9e92014-08-06 08:53:13 +0300835 if not client:
John Warrenfbf2a892015-11-17 12:36:14 -0500836 client = self.floating_ips_client
Yair Fried1fc32a12014-08-04 09:11:30 +0300837 if not port_id:
Kirill Shileev14113572014-11-21 16:58:02 +0300838 port_id, ip4 = self._get_server_port_id_and_ip4(thing)
839 else:
840 ip4 = None
David Kranz34e88122014-12-11 15:24:05 -0500841 result = client.create_floatingip(
Yair Fried1fc32a12014-08-04 09:11:30 +0300842 floating_network_id=external_network_id,
843 port_id=port_id,
Kirill Shileev14113572014-11-21 16:58:02 +0300844 tenant_id=thing['tenant_id'],
845 fixed_ip_address=ip4
Yair Fried1fc32a12014-08-04 09:11:30 +0300846 )
Steve Heyman33735f22016-05-24 09:28:08 -0500847 floating_ip = result['floatingip']
Jordan Pittier9e227c52016-02-09 14:35:18 +0100848 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
zhoubin508bf20b32017-02-03 09:39:14 +0800849 client.delete_floatingip,
Steve Heyman33735f22016-05-24 09:28:08 -0500850 floating_ip['id'])
Yair Fried1fc32a12014-08-04 09:11:30 +0300851 return floating_ip
852
Yair Fried45f92952014-06-26 05:19:19 +0300853 def check_floating_ip_status(self, floating_ip, status):
Carl Baldwina754e2d2014-10-23 22:47:41 +0000854 """Verifies floatingip reaches the given status
Yair Fried45f92952014-06-26 05:19:19 +0300855
Steve Heyman33735f22016-05-24 09:28:08 -0500856 :param dict floating_ip: floating IP dict to check status
Yair Fried45f92952014-06-26 05:19:19 +0300857 :param status: target status
858 :raises: AssertionError if status doesn't match
859 """
Steve Heyman33735f22016-05-24 09:28:08 -0500860 floatingip_id = floating_ip['id']
861
Carl Baldwina754e2d2014-10-23 22:47:41 +0000862 def refresh():
Steve Heyman33735f22016-05-24 09:28:08 -0500863 result = (self.floating_ips_client.
864 show_floatingip(floatingip_id)['floatingip'])
865 return status == result['status']
Carl Baldwina754e2d2014-10-23 22:47:41 +0000866
zhufl4dda94e2017-03-14 16:14:46 +0800867 if not test_utils.call_until_true(refresh,
868 CONF.network.build_timeout,
869 CONF.network.build_interval):
870 floating_ip = self.floating_ips_client.show_floatingip(
871 floatingip_id)['floatingip']
872 self.assertEqual(status, floating_ip['status'],
873 message="FloatingIP: {fp} is at status: {cst}. "
874 "failed to reach status: {st}"
875 .format(fp=floating_ip, cst=floating_ip['status'],
876 st=status))
Yair Fried45f92952014-06-26 05:19:19 +0300877 LOG.info("FloatingIP: {fp} is at status: {st}"
878 .format(fp=floating_ip, st=status))
879
Yair Fried1fc32a12014-08-04 09:11:30 +0300880 def _check_tenant_network_connectivity(self, server,
881 username,
882 private_key,
883 should_connect=True,
884 servers_for_debug=None):
Sean Dagueed6e5862016-04-04 10:49:13 -0400885 if not CONF.network.project_networks_reachable:
Yair Fried1fc32a12014-08-04 09:11:30 +0300886 msg = 'Tenant networks not configured to be reachable.'
887 LOG.info(msg)
888 return
889 # The target login is assumed to have been configured for
890 # key-based authentication by cloud-init.
891 try:
Béla Vancsicsb6dfa082017-03-01 10:44:58 +0100892 for ip_addresses in server['addresses'].values():
Yair Fried1fc32a12014-08-04 09:11:30 +0300893 for ip_address in ip_addresses:
ghanshyam807211c2014-12-18 13:21:22 +0900894 self.check_vm_connectivity(ip_address['addr'],
Yair Friedae0e73d2014-11-24 11:56:26 +0200895 username,
896 private_key,
897 should_connect=should_connect)
Yair Fried1fc32a12014-08-04 09:11:30 +0300898 except Exception as e:
899 LOG.exception('Tenant network connectivity check failed')
900 self._log_console_output(servers_for_debug)
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000901 self._log_net_info(e)
Yair Fried1fc32a12014-08-04 09:11:30 +0300902 raise
903
zhufle9877c62017-10-13 09:38:19 +0800904 def check_remote_connectivity(self, source, dest, should_succeed=True,
905 nic=None):
YAMAMOTO Takashi4c3ebb02017-01-25 16:04:30 +0900906 """assert ping server via source ssh connection
907
Yair Fried1fc32a12014-08-04 09:11:30 +0300908 :param source: RemoteClient: an ssh connection from which to ping
zhufle9877c62017-10-13 09:38:19 +0800909 :param dest: an IP to ping against
910 :param should_succeed: boolean: should ping succeed or not
Yair Friedbc46f592015-11-18 16:29:34 +0200911 :param nic: specific network interface to ping from
Yair Fried1fc32a12014-08-04 09:11:30 +0300912 """
913 def ping_remote():
914 try:
Yair Friedbc46f592015-11-18 16:29:34 +0200915 source.ping_host(dest, nic=nic)
Andrey Pavlov64723762015-04-29 06:24:58 +0300916 except lib_exc.SSHExecCommandFailed:
zhangguoqing6c096642016-01-04 06:17:21 +0000917 LOG.warning('Failed to ping IP: %s via a ssh connection '
Jordan Pittier525ec712016-12-07 17:51:26 +0100918 'from: %s.', dest, source.ssh_client.host)
Yair Fried1fc32a12014-08-04 09:11:30 +0300919 return not should_succeed
920 return should_succeed
921
zhufle9877c62017-10-13 09:38:19 +0800922 result = test_utils.call_until_true(ping_remote,
923 CONF.validation.ping_timeout, 1)
YAMAMOTO Takashi4c3ebb02017-01-25 16:04:30 +0900924 source_host = source.ssh_client.host
925 if should_succeed:
926 msg = "Timed out waiting for %s to become reachable from %s" \
927 % (dest, source_host)
928 else:
929 msg = "%s is reachable from %s" % (dest, source_host)
930 self.assertTrue(result, msg)
931
John Warren456d9ae2016-01-12 15:36:33 -0500932 def _create_security_group(self, security_group_rules_client=None,
933 tenant_id=None,
John Warrenf9606e92015-12-10 12:12:42 -0500934 namestart='secgroup-smoke',
935 security_groups_client=None):
John Warren456d9ae2016-01-12 15:36:33 -0500936 if security_group_rules_client is None:
937 security_group_rules_client = self.security_group_rules_client
John Warrenf9606e92015-12-10 12:12:42 -0500938 if security_groups_client is None:
939 security_groups_client = self.security_groups_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300940 if tenant_id is None:
John Warrenf9606e92015-12-10 12:12:42 -0500941 tenant_id = security_groups_client.tenant_id
942 secgroup = self._create_empty_security_group(
943 namestart=namestart, client=security_groups_client,
944 tenant_id=tenant_id)
Yair Fried1fc32a12014-08-04 09:11:30 +0300945
946 # Add rules to the security group
John Warrenf9606e92015-12-10 12:12:42 -0500947 rules = self._create_loginable_secgroup_rule(
John Warren456d9ae2016-01-12 15:36:33 -0500948 security_group_rules_client=security_group_rules_client,
949 secgroup=secgroup,
John Warrenf9606e92015-12-10 12:12:42 -0500950 security_groups_client=security_groups_client)
Yair Fried1fc32a12014-08-04 09:11:30 +0300951 for rule in rules:
Steve Heyman33735f22016-05-24 09:28:08 -0500952 self.assertEqual(tenant_id, rule['tenant_id'])
953 self.assertEqual(secgroup['id'], rule['security_group_id'])
Yair Fried1fc32a12014-08-04 09:11:30 +0300954 return secgroup
955
Yair Frieddb6c9e92014-08-06 08:53:13 +0300956 def _create_empty_security_group(self, client=None, tenant_id=None,
Yair Fried1fc32a12014-08-04 09:11:30 +0300957 namestart='secgroup-smoke'):
958 """Create a security group without rules.
959
960 Default rules will be created:
961 - IPv4 egress to any
962 - IPv6 egress to any
963
964 :param tenant_id: secgroup will be created in this tenant
Steve Heyman33735f22016-05-24 09:28:08 -0500965 :returns: the created security group
Yair Fried1fc32a12014-08-04 09:11:30 +0300966 """
967 if client is None:
John Warrenf9606e92015-12-10 12:12:42 -0500968 client = self.security_groups_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300969 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000970 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300971 sg_name = data_utils.rand_name(namestart)
972 sg_desc = sg_name + " description"
973 sg_dict = dict(name=sg_name,
974 description=sg_desc)
975 sg_dict['tenant_id'] = tenant_id
David Kranz34e88122014-12-11 15:24:05 -0500976 result = client.create_security_group(**sg_dict)
Steve Heyman33735f22016-05-24 09:28:08 -0500977
978 secgroup = result['security_group']
979 self.assertEqual(secgroup['name'], sg_name)
980 self.assertEqual(tenant_id, secgroup['tenant_id'])
981 self.assertEqual(secgroup['description'], sg_desc)
982
Jordan Pittier9e227c52016-02-09 14:35:18 +0100983 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
Steve Heyman33735f22016-05-24 09:28:08 -0500984 client.delete_security_group, secgroup['id'])
Yair Fried1fc32a12014-08-04 09:11:30 +0300985 return secgroup
986
John Warren456d9ae2016-01-12 15:36:33 -0500987 def _create_security_group_rule(self, secgroup=None,
988 sec_group_rules_client=None,
John Warrenf9606e92015-12-10 12:12:42 -0500989 tenant_id=None,
990 security_groups_client=None, **kwargs):
Yair Fried1fc32a12014-08-04 09:11:30 +0300991 """Create a rule from a dictionary of rule parameters.
992
993 Create a rule in a secgroup. if secgroup not defined will search for
994 default secgroup in tenant_id.
995
Steve Heyman33735f22016-05-24 09:28:08 -0500996 :param secgroup: the security group.
Yair Fried1fc32a12014-08-04 09:11:30 +0300997 :param tenant_id: if secgroup not passed -- the tenant in which to
998 search for default secgroup
999 :param kwargs: a dictionary containing rule parameters:
1000 for example, to allow incoming ssh:
1001 rule = {
1002 direction: 'ingress'
1003 protocol:'tcp',
1004 port_range_min: 22,
1005 port_range_max: 22
1006 }
1007 """
John Warren456d9ae2016-01-12 15:36:33 -05001008 if sec_group_rules_client is None:
1009 sec_group_rules_client = self.security_group_rules_client
John Warrenf9606e92015-12-10 12:12:42 -05001010 if security_groups_client is None:
1011 security_groups_client = self.security_groups_client
Yair Frieddb6c9e92014-08-06 08:53:13 +03001012 if not tenant_id:
John Warrenf9606e92015-12-10 12:12:42 -05001013 tenant_id = security_groups_client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001014 if secgroup is None:
zhuflb0b272e2017-09-22 16:01:46 +08001015 # Get default secgroup for tenant_id
1016 default_secgroups = security_groups_client.list_security_groups(
1017 name='default', tenant_id=tenant_id)['security_groups']
1018 msg = "No default security group for tenant %s." % (tenant_id)
1019 self.assertNotEmpty(default_secgroups, msg)
1020 secgroup = default_secgroups[0]
Yair Fried1fc32a12014-08-04 09:11:30 +03001021
Steve Heyman33735f22016-05-24 09:28:08 -05001022 ruleset = dict(security_group_id=secgroup['id'],
1023 tenant_id=secgroup['tenant_id'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001024 ruleset.update(kwargs)
1025
John Warren456d9ae2016-01-12 15:36:33 -05001026 sg_rule = sec_group_rules_client.create_security_group_rule(**ruleset)
Steve Heyman33735f22016-05-24 09:28:08 -05001027 sg_rule = sg_rule['security_group_rule']
1028
1029 self.assertEqual(secgroup['tenant_id'], sg_rule['tenant_id'])
1030 self.assertEqual(secgroup['id'], sg_rule['security_group_id'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001031
1032 return sg_rule
1033
John Warren456d9ae2016-01-12 15:36:33 -05001034 def _create_loginable_secgroup_rule(self, security_group_rules_client=None,
1035 secgroup=None,
John Warrenf9606e92015-12-10 12:12:42 -05001036 security_groups_client=None):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001037 """Create loginable security group rule
1038
Alex Stafeyevdd5dde92016-05-08 14:35:04 +03001039 This function will create:
1040 1. egress and ingress tcp port 22 allow rule in order to allow ssh
1041 access for ipv4.
1042 2. egress and ingress ipv6 icmp allow rule, in order to allow icmpv6.
1043 3. egress and ingress ipv4 icmp allow rule, in order to allow icmpv4.
Yair Fried1fc32a12014-08-04 09:11:30 +03001044 """
1045
John Warren456d9ae2016-01-12 15:36:33 -05001046 if security_group_rules_client is None:
1047 security_group_rules_client = self.security_group_rules_client
John Warrenf9606e92015-12-10 12:12:42 -05001048 if security_groups_client is None:
1049 security_groups_client = self.security_groups_client
Yair Fried1fc32a12014-08-04 09:11:30 +03001050 rules = []
1051 rulesets = [
1052 dict(
1053 # ssh
1054 protocol='tcp',
1055 port_range_min=22,
1056 port_range_max=22,
1057 ),
1058 dict(
1059 # ping
1060 protocol='icmp',
Andreas Scheuring887ca8e2015-02-03 17:56:12 +01001061 ),
1062 dict(
1063 # ipv6-icmp for ping6
1064 protocol='icmp',
1065 ethertype='IPv6',
Yair Fried1fc32a12014-08-04 09:11:30 +03001066 )
1067 ]
John Warren456d9ae2016-01-12 15:36:33 -05001068 sec_group_rules_client = security_group_rules_client
Yair Fried1fc32a12014-08-04 09:11:30 +03001069 for ruleset in rulesets:
1070 for r_direction in ['ingress', 'egress']:
1071 ruleset['direction'] = r_direction
1072 try:
1073 sg_rule = self._create_security_group_rule(
John Warren456d9ae2016-01-12 15:36:33 -05001074 sec_group_rules_client=sec_group_rules_client,
1075 secgroup=secgroup,
John Warrenf9606e92015-12-10 12:12:42 -05001076 security_groups_client=security_groups_client,
1077 **ruleset)
Masayuki Igawad9388762015-01-20 14:56:42 +09001078 except lib_exc.Conflict as ex:
Yair Fried1fc32a12014-08-04 09:11:30 +03001079 # if rule already exist - skip rule and continue
1080 msg = 'Security group rule already exists'
1081 if msg not in ex._error_string:
1082 raise ex
1083 else:
Steve Heyman33735f22016-05-24 09:28:08 -05001084 self.assertEqual(r_direction, sg_rule['direction'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001085 rules.append(sg_rule)
1086
1087 return rules
1088
Yair Frieddb6c9e92014-08-06 08:53:13 +03001089 def _get_router(self, client=None, tenant_id=None):
Yair Fried1fc32a12014-08-04 09:11:30 +03001090 """Retrieve a router for the given tenant id.
1091
1092 If a public router has been configured, it will be returned.
1093
1094 If a public router has not been configured, but a public
1095 network has, a tenant router will be created and returned that
1096 routes traffic to the public network.
1097 """
Yair Frieddb6c9e92014-08-06 08:53:13 +03001098 if not client:
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +00001099 client = self.routers_client
Yair Frieddb6c9e92014-08-06 08:53:13 +03001100 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +00001101 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001102 router_id = CONF.network.public_router_id
1103 network_id = CONF.network.public_network_id
1104 if router_id:
David Kranzca4c7e72015-05-27 11:39:19 -04001105 body = client.show_router(router_id)
Steve Heyman33735f22016-05-24 09:28:08 -05001106 return body['router']
Yair Fried1fc32a12014-08-04 09:11:30 +03001107 elif network_id:
Yair Frieddb6c9e92014-08-06 08:53:13 +03001108 router = self._create_router(client, tenant_id)
Steve Heyman33735f22016-05-24 09:28:08 -05001109 kwargs = {'external_gateway_info': dict(network_id=network_id)}
1110 router = client.update_router(router['id'], **kwargs)['router']
Yair Fried1fc32a12014-08-04 09:11:30 +03001111 return router
1112 else:
1113 raise Exception("Neither of 'public_router_id' or "
1114 "'public_network_id' has been defined.")
1115
Yair Frieddb6c9e92014-08-06 08:53:13 +03001116 def _create_router(self, client=None, tenant_id=None,
1117 namestart='router-smoke'):
1118 if not client:
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +00001119 client = self.routers_client
Yair Frieddb6c9e92014-08-06 08:53:13 +03001120 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +00001121 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001122 name = data_utils.rand_name(namestart)
David Kranz34e88122014-12-11 15:24:05 -05001123 result = client.create_router(name=name,
1124 admin_state_up=True,
1125 tenant_id=tenant_id)
Steve Heyman33735f22016-05-24 09:28:08 -05001126 router = result['router']
1127 self.assertEqual(router['name'], name)
1128 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
1129 client.delete_router,
1130 router['id'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001131 return router
1132
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -07001133 def create_networks(self, networks_client=None,
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +00001134 routers_client=None, subnets_client=None,
Markus Zoeller156b5da2016-07-11 18:10:31 +02001135 tenant_id=None, dns_nameservers=None,
1136 port_security_enabled=True):
Yair Fried1fc32a12014-08-04 09:11:30 +03001137 """Create a network with a subnet connected to a router.
1138
David Shrewsbury9bac3662014-08-07 15:07:01 -04001139 The baremetal driver is a special case since all nodes are
1140 on the same shared network.
1141
Yair Fried413bf2d2014-11-19 17:07:11 +02001142 :param tenant_id: id of tenant to create resources in.
1143 :param dns_nameservers: list of dns servers to send to subnet.
Yair Fried1fc32a12014-08-04 09:11:30 +03001144 :returns: network, subnet, router
1145 """
Thiago Paiva66cded22016-08-15 14:55:58 -03001146 if CONF.network.shared_physical_network:
David Shrewsbury9bac3662014-08-07 15:07:01 -04001147 # NOTE(Shrews): This exception is for environments where tenant
1148 # credential isolation is available, but network separation is
1149 # not (the current baremetal case). Likely can be removed when
1150 # test account mgmt is reworked:
1151 # https://blueprints.launchpad.net/tempest/+spec/test-accounts
Adam Gandelman878a5fd2015-03-30 14:33:36 -07001152 if not CONF.compute.fixed_network_name:
1153 m = 'fixed_network_name must be specified in config'
Matthew Treinish4217a702016-10-07 17:27:11 -04001154 raise lib_exc.InvalidConfiguration(m)
David Shrewsbury9bac3662014-08-07 15:07:01 -04001155 network = self._get_network_by_name(
1156 CONF.compute.fixed_network_name)
1157 router = None
1158 subnet = None
1159 else:
John Warren94d8faf2015-09-15 12:22:24 -04001160 network = self._create_network(
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -07001161 networks_client=networks_client,
Markus Zoeller156b5da2016-07-11 18:10:31 +02001162 tenant_id=tenant_id,
1163 port_security_enabled=port_security_enabled)
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +00001164 router = self._get_router(client=routers_client,
1165 tenant_id=tenant_id)
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -07001166 subnet_kwargs = dict(network=network,
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +00001167 subnets_client=subnets_client,
1168 routers_client=routers_client)
Yair Fried413bf2d2014-11-19 17:07:11 +02001169 # use explicit check because empty list is a valid option
1170 if dns_nameservers is not None:
1171 subnet_kwargs['dns_nameservers'] = dns_nameservers
1172 subnet = self._create_subnet(**subnet_kwargs)
Steve Heyman33735f22016-05-24 09:28:08 -05001173 if not routers_client:
1174 routers_client = self.routers_client
1175 router_id = router['id']
1176 routers_client.add_router_interface(router_id,
1177 subnet_id=subnet['id'])
1178
1179 # save a cleanup job to remove this association between
1180 # router and subnet
1181 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
1182 routers_client.remove_router_interface, router_id,
1183 subnet_id=subnet['id'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001184 return network, subnet, router
1185
1186
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001187class EncryptionScenarioTest(ScenarioTest):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001188 """Base class for encryption scenario tests"""
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001189
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001190 credentials = ['primary', 'admin']
David Kranz4cc852b2015-03-09 14:57:11 -04001191
1192 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001193 def setup_clients(cls):
1194 super(EncryptionScenarioTest, cls).setup_clients()
Jordan Pittier8160d312017-04-18 11:52:23 +02001195 cls.admin_volume_types_client = cls.os_admin.volume_types_v2_client
ghanshyam3bd0d2b2017-03-23 01:57:28 +00001196 cls.admin_encryption_types_client =\
Jordan Pittier8160d312017-04-18 11:52:23 +02001197 cls.os_admin.encryption_types_v2_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001198
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001199 def create_encryption_type(self, client=None, type_id=None, provider=None,
1200 key_size=None, cipher=None,
1201 control_location=None):
1202 if not client:
Ken'ichi Ohmichia6ebf622016-08-25 11:52:27 -07001203 client = self.admin_encryption_types_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001204 if not type_id:
1205 volume_type = self.create_volume_type()
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001206 type_id = volume_type['id']
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001207 LOG.debug("Creating an encryption type for volume type: %s", type_id)
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001208 client.create_encryption_type(
1209 type_id, provider=provider, key_size=key_size, cipher=cipher,
John Warrend053ded2015-08-13 15:22:48 +00001210 control_location=control_location)['encryption']
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001211
lkuchlan3023e752017-06-08 12:53:13 +03001212 def create_encrypted_volume(self, encryption_provider, volume_type,
1213 key_size=256, cipher='aes-xts-plain64',
1214 control_location='front-end'):
1215 volume_type = self.create_volume_type(name=volume_type)
1216 self.create_encryption_type(type_id=volume_type['id'],
1217 provider=encryption_provider,
1218 key_size=key_size,
1219 cipher=cipher,
1220 control_location=control_location)
1221 return self.create_volume(volume_type=volume_type['name'])
1222
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001223
Masayuki Igawa0870db52015-09-18 21:08:36 +09001224class ObjectStorageScenarioTest(ScenarioTest):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001225 """Provide harness to do Object Storage scenario tests.
Chris Dent0d494112014-08-26 13:48:30 +01001226
1227 Subclasses implement the tests that use the methods provided by this
1228 class.
1229 """
1230
1231 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001232 def skip_checks(cls):
Masayuki Igawa0870db52015-09-18 21:08:36 +09001233 super(ObjectStorageScenarioTest, cls).skip_checks()
Chris Dent0d494112014-08-26 13:48:30 +01001234 if not CONF.service_available.swift:
1235 skip_msg = ("%s skipped as swift is not available" %
1236 cls.__name__)
1237 raise cls.skipException(skip_msg)
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001238
1239 @classmethod
1240 def setup_credentials(cls):
Masayuki Igawa60ea6c52014-10-15 17:32:14 +09001241 cls.set_network_resources()
Masayuki Igawa0870db52015-09-18 21:08:36 +09001242 super(ObjectStorageScenarioTest, cls).setup_credentials()
Matthew Treinish4a596932015-03-06 20:37:01 -05001243 operator_role = CONF.object_storage.operator_role
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +01001244 cls.os_operator = cls.get_client_manager(roles=[operator_role])
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001245
1246 @classmethod
1247 def setup_clients(cls):
Masayuki Igawa0870db52015-09-18 21:08:36 +09001248 super(ObjectStorageScenarioTest, cls).setup_clients()
Chris Dent0d494112014-08-26 13:48:30 +01001249 # Clients for Swift
Matthew Treinish8f268292015-02-24 20:01:36 -05001250 cls.account_client = cls.os_operator.account_client
1251 cls.container_client = cls.os_operator.container_client
1252 cls.object_client = cls.os_operator.object_client
Chris Dent0d494112014-08-26 13:48:30 +01001253
Chris Dentde456a12014-09-10 12:41:15 +01001254 def get_swift_stat(self):
Chris Dent0d494112014-08-26 13:48:30 +01001255 """get swift status for our user account."""
1256 self.account_client.list_account_containers()
1257 LOG.debug('Swift status information obtained successfully')
1258
Chris Dentde456a12014-09-10 12:41:15 +01001259 def create_container(self, container_name=None):
Chris Dent0d494112014-08-26 13:48:30 +01001260 name = container_name or data_utils.rand_name(
1261 'swift-scenario-container')
ghanshyameed40312017-09-15 18:30:04 +03001262 self.container_client.update_container(name)
Chris Dent0d494112014-08-26 13:48:30 +01001263 # look for the container to assure it is created
Chris Dentde456a12014-09-10 12:41:15 +01001264 self.list_and_check_container_objects(name)
Jordan Pittier525ec712016-12-07 17:51:26 +01001265 LOG.debug('Container %s created', name)
Jordan Pittier9e227c52016-02-09 14:35:18 +01001266 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
Chris Dent1d4313a2014-10-28 12:16:48 +00001267 self.container_client.delete_container,
1268 name)
Chris Dent0d494112014-08-26 13:48:30 +01001269 return name
1270
Chris Dentde456a12014-09-10 12:41:15 +01001271 def delete_container(self, container_name):
Chris Dent0d494112014-08-26 13:48:30 +01001272 self.container_client.delete_container(container_name)
Jordan Pittier525ec712016-12-07 17:51:26 +01001273 LOG.debug('Container %s deleted', container_name)
Chris Dent0d494112014-08-26 13:48:30 +01001274
Chris Dentde456a12014-09-10 12:41:15 +01001275 def upload_object_to_container(self, container_name, obj_name=None):
Chris Dent0d494112014-08-26 13:48:30 +01001276 obj_name = obj_name or data_utils.rand_name('swift-scenario-object')
Jordan Pittierb84f2d42016-12-21 19:02:15 +01001277 obj_data = data_utils.random_bytes()
Chris Dent0d494112014-08-26 13:48:30 +01001278 self.object_client.create_object(container_name, obj_name, obj_data)
Jordan Pittier9e227c52016-02-09 14:35:18 +01001279 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
Chris Dent1d4313a2014-10-28 12:16:48 +00001280 self.object_client.delete_object,
1281 container_name,
1282 obj_name)
Chris Dent0d494112014-08-26 13:48:30 +01001283 return obj_name, obj_data
1284
Chris Dentde456a12014-09-10 12:41:15 +01001285 def delete_object(self, container_name, filename):
Chris Dent0d494112014-08-26 13:48:30 +01001286 self.object_client.delete_object(container_name, filename)
Chris Dentde456a12014-09-10 12:41:15 +01001287 self.list_and_check_container_objects(container_name,
1288 not_present_obj=[filename])
Chris Dent0d494112014-08-26 13:48:30 +01001289
Chris Dentde456a12014-09-10 12:41:15 +01001290 def list_and_check_container_objects(self, container_name,
1291 present_obj=None,
1292 not_present_obj=None):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001293 # List objects for a given container and assert which are present and
1294 # which are not.
Ghanshyam2a180b82014-06-16 13:54:22 +09001295 if present_obj is None:
1296 present_obj = []
1297 if not_present_obj is None:
1298 not_present_obj = []
ghanshyam871b1a82017-09-14 02:56:16 +03001299 _, object_list = self.container_client.list_container_objects(
Chris Dent0d494112014-08-26 13:48:30 +01001300 container_name)
1301 if present_obj:
1302 for obj in present_obj:
1303 self.assertIn(obj, object_list)
1304 if not_present_obj:
1305 for obj in not_present_obj:
1306 self.assertNotIn(obj, object_list)
1307
Chris Dentde456a12014-09-10 12:41:15 +01001308 def download_and_verify(self, container_name, obj_name, expected_data):
Chris Dent0d494112014-08-26 13:48:30 +01001309 _, obj = self.object_client.get_object(container_name, obj_name)
1310 self.assertEqual(obj, expected_data)