blob: 8c930c32eeb482dac413aec0c029c4b10eb204a2 [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
Fei Long Wangd39431f2015-05-14 11:30:48 +120026from tempest.common.utils import data_utils
Masayuki Igawa4ded9f02014-02-17 15:05:59 +090027from tempest.common.utils.linux import remote_client
Ihar Hrachyshkaf9227c02016-09-15 11:16:47 +000028from tempest.common.utils import net_utils
Ken'ichi Ohmichi0eb153c2015-07-13 02:18:25 +000029from tempest.common import waiters
Matthew Treinish6c072292014-01-29 19:15:52 +000030from tempest import config
Giulio Fidente92f77192013-08-26 17:13:28 +020031from tempest import exceptions
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)
Adam Gandelmanc78c7572014-08-28 18:38:55 -070050 cls.flavors_client = cls.manager.flavors_client
John Warrene74890a2015-11-11 15:18:01 -050051 cls.compute_floating_ips_client = (
52 cls.manager.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:
56 cls.image_client = cls.manager.image_client
57 elif CONF.image_feature_enabled.api_v2:
58 cls.image_client = cls.manager.image_client_v2
59 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
Ghanshyamae76c122015-12-22 13:41:35 +090064 cls.compute_images_client = cls.manager.compute_images_client
Andrea Frittoli247058f2014-07-16 16:09:22 +010065 cls.keypairs_client = cls.manager.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 = (
68 cls.manager.compute_security_groups_client)
John Warren5cdbf422016-01-05 12:42:43 -050069 cls.compute_security_group_rules_client = (
70 cls.manager.compute_security_group_rules_client)
Andrea Frittoli247058f2014-07-16 16:09:22 +010071 cls.servers_client = cls.manager.servers_client
Yair Fried1fc32a12014-08-04 09:11:30 +030072 cls.interface_client = cls.manager.interfaces_client
73 # Neutron network client
John Warren94d8faf2015-09-15 12:22:24 -040074 cls.networks_client = cls.manager.networks_client
John Warren49c0fe52015-10-22 12:35:54 -040075 cls.ports_client = cls.manager.ports_client
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +000076 cls.routers_client = cls.manager.routers_client
John Warren3961acd2015-10-02 14:38:53 -040077 cls.subnets_client = cls.manager.subnets_client
John Warrenfbf2a892015-11-17 12:36:14 -050078 cls.floating_ips_client = cls.manager.floating_ips_client
John Warrenf9606e92015-12-10 12:12:42 -050079 cls.security_groups_client = cls.manager.security_groups_client
John Warren456d9ae2016-01-12 15:36:33 -050080 cls.security_group_rules_client = (
81 cls.manager.security_group_rules_client)
Andrea Frittoli2e733b52014-07-16 14:12:11 +010082
Jordan Pittierc3f76be2016-10-11 17:06:21 +020083 if CONF.volume_feature_enabled.api_v2:
Ivan Kolodyazhnybcfc32e2015-08-06 13:31:36 +030084 cls.volumes_client = cls.manager.volumes_v2_client
85 cls.snapshots_client = cls.manager.snapshots_v2_client
Jordan Pittierc3f76be2016-10-11 17:06:21 +020086 else:
87 cls.volumes_client = cls.manager.volumes_client
88 cls.snapshots_client = cls.manager.snapshots_client
Ivan Kolodyazhnybcfc32e2015-08-06 13:31:36 +030089
Jordan Pittierf672b7d2016-06-20 18:50:40 +020090 # ## Test functions library
91 #
92 # The create_[resource] functions only return body and discard the
93 # resp part which is not used in scenario tests
Andrea Frittoli247058f2014-07-16 16:09:22 +010094
Lenny Verkhovsky136376f2016-06-29 14:33:34 +030095 def _create_port(self, network_id, client=None, namestart='port-quotatest',
96 **kwargs):
97 if not client:
98 client = self.ports_client
99 name = data_utils.rand_name(namestart)
100 result = client.create_port(
101 name=name,
102 network_id=network_id,
103 **kwargs)
104 self.assertIsNotNone(result, 'Unable to allocate port')
105 port = result['port']
106 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
107 client.delete_port, port['id'])
108 return port
109
Yair Frieddb6c9e92014-08-06 08:53:13 +0300110 def create_keypair(self, client=None):
111 if not client:
112 client = self.keypairs_client
Andrea Frittoli247058f2014-07-16 16:09:22 +0100113 name = data_utils.rand_name(self.__class__.__name__)
114 # We don't need to create a keypair by pubkey in scenario
Ken'ichi Ohmichie364bce2015-07-17 10:27:59 +0000115 body = client.create_keypair(name=name)
Yair Frieddb6c9e92014-08-06 08:53:13 +0300116 self.addCleanup(client.delete_keypair, name)
ghanshyamdee01f22015-08-17 11:41:47 +0900117 return body['keypair']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100118
Anusha Ramineni9aaef8b2016-01-19 10:56:40 +0530119 def create_server(self, name=None, image_id=None, flavor=None,
lanoux5fc14522015-09-21 08:17:35 +0000120 validatable=False, wait_until=None,
Jordan Pittierf672b7d2016-06-20 18:50:40 +0200121 clients=None, **kwargs):
lanoux5fc14522015-09-21 08:17:35 +0000122 """Wrapper utility that returns a test server.
Andrea Frittoli247058f2014-07-16 16:09:22 +0100123
lanoux5fc14522015-09-21 08:17:35 +0000124 This wrapper utility calls the common create test server and
125 returns a test server. The purpose of this wrapper is to minimize
126 the impact on the code of the tests already using this
127 function.
Andrea Frittoli247058f2014-07-16 16:09:22 +0100128 """
Andrea Frittoli247058f2014-07-16 16:09:22 +0100129
lanoux5fc14522015-09-21 08:17:35 +0000130 # NOTE(jlanoux): As a first step, ssh checks in the scenario
131 # tests need to be run regardless of the run_validation and
132 # validatable parameters and thus until the ssh validation job
133 # becomes voting in CI. The test resources management and IP
134 # association are taken care of in the scenario tests.
135 # Therefore, the validatable parameter is set to false in all
136 # those tests. In this way create_server just return a standard
137 # server and the scenario tests always perform ssh checks.
138
139 # Needed for the cross_tenant_traffic test:
140 if clients is None:
141 clients = self.manager
142
zhufl24208c22016-10-25 15:23:48 +0800143 if name is None:
144 name = data_utils.rand_name(self.__class__.__name__ + "-server")
145
lanoux5fc14522015-09-21 08:17:35 +0000146 vnic_type = CONF.network.port_vnic_type
147
148 # If vnic_type is configured create port for
149 # every network
150 if vnic_type:
151 ports = []
Lenny Verkhovsky69363502016-07-17 16:33:33 +0300152
lanoux5fc14522015-09-21 08:17:35 +0000153 create_port_body = {'binding:vnic_type': vnic_type,
154 'namestart': 'port-smoke'}
155 if kwargs:
156 # Convert security group names to security group ids
157 # to pass to create_port
158 if 'security_groups' in kwargs:
Thiago Paiva66cded22016-08-15 14:55:58 -0300159 security_groups = \
John Warrenf9606e92015-12-10 12:12:42 -0500160 clients.security_groups_client.list_security_groups(
lanoux5fc14522015-09-21 08:17:35 +0000161 ).get('security_groups')
162 sec_dict = dict([(s['name'], s['id'])
163 for s in security_groups])
164
165 sec_groups_names = [s['name'] for s in kwargs.pop(
166 'security_groups')]
167 security_groups_ids = [sec_dict[s]
168 for s in sec_groups_names]
169
170 if security_groups_ids:
171 create_port_body[
172 'security_groups'] = security_groups_ids
Lenny Verkhovsky69363502016-07-17 16:33:33 +0300173 networks = kwargs.pop('networks', [])
174 else:
175 networks = []
lanoux5fc14522015-09-21 08:17:35 +0000176
177 # If there are no networks passed to us we look up
Lenny Verkhovsky136376f2016-06-29 14:33:34 +0300178 # for the project's private networks and create a port.
179 # The same behaviour as we would expect when passing
180 # the call to the clients with no networks
lanoux5fc14522015-09-21 08:17:35 +0000181 if not networks:
182 networks = clients.networks_client.list_networks(
Lenny Verkhovsky136376f2016-06-29 14:33:34 +0300183 **{'router:external': False, 'fields': 'id'})['networks']
184
185 # It's net['uuid'] if networks come from kwargs
186 # and net['id'] if they come from
187 # clients.networks_client.list_networks
lanoux5fc14522015-09-21 08:17:35 +0000188 for net in networks:
Lenny Verkhovsky97f7cea2016-08-15 13:29:48 +0000189 net_id = net.get('uuid', net.get('id'))
Lenny Verkhovsky69363502016-07-17 16:33:33 +0300190 if 'port' not in net:
191 port = self._create_port(network_id=net_id,
192 client=clients.ports_client,
193 **create_port_body)
194 ports.append({'port': port['id']})
195 else:
196 ports.append({'port': net['port']})
lanoux5fc14522015-09-21 08:17:35 +0000197 if ports:
198 kwargs['networks'] = ports
199 self.ports = ports
200
201 tenant_network = self.get_tenant_network()
202
203 body, servers = compute.create_test_server(
204 clients,
205 tenant_network=tenant_network,
206 wait_until=wait_until,
Anusha Ramineni9aaef8b2016-01-19 10:56:40 +0530207 name=name, flavor=flavor,
208 image_id=image_id, **kwargs)
lanoux5fc14522015-09-21 08:17:35 +0000209
Jordan Pittierf672b7d2016-06-20 18:50:40 +0200210 self.addCleanup(waiters.wait_for_server_termination,
211 clients.servers_client, body['id'])
212 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
213 clients.servers_client.delete_server, body['id'])
lanoux5fc14522015-09-21 08:17:35 +0000214 server = clients.servers_client.show_server(body['id'])['server']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100215 return server
216
Markus Zoeller3d2a21c2015-02-27 12:04:22 +0100217 def create_volume(self, size=None, name=None, snapshot_id=None,
Jordan Pittier5e1741c2016-03-02 18:25:51 +0100218 imageRef=None, volume_type=None):
Ken'ichi Ohmichiadb905e2016-08-26 15:16:23 -0700219 if size is None:
220 size = CONF.volume.volume_size
Nuno Santosb746d992016-11-17 15:41:55 -0500221 if imageRef:
222 image = self.compute_images_client.show_image(imageRef)['image']
223 min_disk = image.get('minDisk')
224 size = max(size, min_disk)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100225 if name is None:
zhuflf9d95722016-10-19 16:06:17 +0800226 name = data_utils.rand_name(self.__class__.__name__ + "-volume")
Ghanshyam8fc0ed22015-12-18 10:25:14 +0900227 kwargs = {'display_name': name,
228 'snapshot_id': snapshot_id,
229 'imageRef': imageRef,
Ken'ichi Ohmichiadb905e2016-08-26 15:16:23 -0700230 'volume_type': volume_type,
231 'size': size}
Ghanshyam8fc0ed22015-12-18 10:25:14 +0900232 volume = self.volumes_client.create_volume(**kwargs)['volume']
Matt Riedemanne85c2702014-09-10 11:50:13 -0700233
Jordan Pittier5e1741c2016-03-02 18:25:51 +0100234 self.addCleanup(self.volumes_client.wait_for_resource_deletion,
235 volume['id'])
Jordan Pittier9e227c52016-02-09 14:35:18 +0100236 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
Jordan Pittier5e1741c2016-03-02 18:25:51 +0100237 self.volumes_client.delete_volume, volume['id'])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100238
Ivan Kolodyazhnybcfc32e2015-08-06 13:31:36 +0300239 # NOTE(e0ne): Cinder API v2 uses name instead of display_name
240 if 'display_name' in volume:
241 self.assertEqual(name, volume['display_name'])
242 else:
243 self.assertEqual(name, volume['name'])
Yaroslav Lobankoved3a35b2016-03-24 22:41:30 -0500244 waiters.wait_for_volume_status(self.volumes_client,
245 volume['id'], 'available')
Andrea Frittoli247058f2014-07-16 16:09:22 +0100246 # The volume retrieved on creation has a non-up-to-date status.
247 # Retrieval after it becomes active ensures correct details.
John Warren6177c9e2015-08-19 20:00:17 +0000248 volume = self.volumes_client.show_volume(volume['id'])['volume']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100249 return volume
250
scottda61f68ac2016-06-07 12:07:55 -0600251 def create_volume_type(self, client=None, name=None, backend_name=None):
252 if not client:
253 client = self.admin_volume_types_client
254 if not name:
255 class_name = self.__class__.__name__
256 name = data_utils.rand_name(class_name + '-volume-type')
257 randomized_name = data_utils.rand_name('scenario-type-' + name)
258
259 LOG.debug("Creating a volume type: %s on backend %s",
260 randomized_name, backend_name)
261 extra_specs = {}
262 if backend_name:
263 extra_specs = {"volume_backend_name": backend_name}
264
265 body = client.create_volume_type(name=randomized_name,
266 extra_specs=extra_specs)
267 volume_type = body['volume_type']
268 self.assertIn('id', volume_type)
269 self.addCleanup(client.delete_volume_type, volume_type['id'])
270 return volume_type
271
Yair Fried1fc32a12014-08-04 09:11:30 +0300272 def _create_loginable_secgroup_rule(self, secgroup_id=None):
John Warrenf2345512015-12-10 13:39:30 -0500273 _client = self.compute_security_groups_client
John Warren5cdbf422016-01-05 12:42:43 -0500274 _client_rules = self.compute_security_group_rules_client
Andrea Frittoli247058f2014-07-16 16:09:22 +0100275 if secgroup_id is None:
ghanshyamb610b772015-08-24 17:29:38 +0900276 sgs = _client.list_security_groups()['security_groups']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100277 for sg in sgs:
278 if sg['name'] == 'default':
279 secgroup_id = sg['id']
280
281 # These rules are intended to permit inbound ssh and icmp
282 # traffic from all sources, so no group_id is provided.
283 # Setting a group_id would only permit traffic from ports
284 # belonging to the same security group.
285 rulesets = [
286 {
287 # ssh
Ken'ichi Ohmichieb7eeec2015-07-21 01:00:06 +0000288 'ip_protocol': 'tcp',
Andrea Frittoli247058f2014-07-16 16:09:22 +0100289 'from_port': 22,
290 'to_port': 22,
291 'cidr': '0.0.0.0/0',
292 },
293 {
294 # ping
Ken'ichi Ohmichieb7eeec2015-07-21 01:00:06 +0000295 'ip_protocol': 'icmp',
Andrea Frittoli247058f2014-07-16 16:09:22 +0100296 'from_port': -1,
297 'to_port': -1,
298 'cidr': '0.0.0.0/0',
299 }
300 ]
301 rules = list()
302 for ruleset in rulesets:
Ken'ichi Ohmichieb7eeec2015-07-21 01:00:06 +0000303 sg_rule = _client_rules.create_security_group_rule(
ghanshyam0a5e1232015-08-24 16:59:59 +0900304 parent_group_id=secgroup_id, **ruleset)['security_group_rule']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100305 rules.append(sg_rule)
306 return rules
307
Yair Fried1fc32a12014-08-04 09:11:30 +0300308 def _create_security_group(self):
Andrea Frittoli247058f2014-07-16 16:09:22 +0100309 # Create security group
310 sg_name = data_utils.rand_name(self.__class__.__name__)
311 sg_desc = sg_name + " description"
John Warrenf2345512015-12-10 13:39:30 -0500312 secgroup = self.compute_security_groups_client.create_security_group(
ghanshyamb610b772015-08-24 17:29:38 +0900313 name=sg_name, description=sg_desc)['security_group']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100314 self.assertEqual(secgroup['name'], sg_name)
315 self.assertEqual(secgroup['description'], sg_desc)
John Warrenf2345512015-12-10 13:39:30 -0500316 self.addCleanup(
Jordan Pittier9e227c52016-02-09 14:35:18 +0100317 test_utils.call_and_ignore_notfound_exc,
John Warrenf2345512015-12-10 13:39:30 -0500318 self.compute_security_groups_client.delete_security_group,
319 secgroup['id'])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100320
321 # Add rules to the security group
Yair Fried1fc32a12014-08-04 09:11:30 +0300322 self._create_loginable_secgroup_rule(secgroup['id'])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100323
324 return secgroup
325
Sean Dague20e98612016-01-06 14:33:28 -0500326 def get_remote_client(self, ip_address, username=None, private_key=None):
JordanP3fe2dc32014-11-17 13:06:01 +0100327 """Get a SSH client to a remote server
328
Sean Dague20e98612016-01-06 14:33:28 -0500329 @param ip_address the server floating or fixed IP address to use
330 for ssh validation
JordanP3fe2dc32014-11-17 13:06:01 +0100331 @param username name of the Linux account on the remote server
332 @param private_key the SSH private key to use
JordanP3fe2dc32014-11-17 13:06:01 +0100333 @return a RemoteClient object
334 """
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700335
Andrea Frittoli247058f2014-07-16 16:09:22 +0100336 if username is None:
lanoux283273b2015-12-04 03:01:54 -0800337 username = CONF.validation.image_ssh_user
wantwatering896300c2015-03-27 15:17:42 +0800338 # Set this with 'keypair' or others to log in with keypair or
339 # username/password.
lanoux5fc14522015-09-21 08:17:35 +0000340 if CONF.validation.auth_method == 'keypair':
wantwatering896300c2015-03-27 15:17:42 +0800341 password = None
342 if private_key is None:
343 private_key = self.keypair['private_key']
344 else:
lanoux283273b2015-12-04 03:01:54 -0800345 password = CONF.validation.image_ssh_password
wantwatering896300c2015-03-27 15:17:42 +0800346 private_key = None
Sean Dague20e98612016-01-06 14:33:28 -0500347 linux_client = remote_client.RemoteClient(ip_address, username,
wantwatering896300c2015-03-27 15:17:42 +0800348 pkey=private_key,
349 password=password)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100350 try:
351 linux_client.validate_authentication()
Matt Riedemann5f0ac522015-05-21 09:16:24 -0700352 except Exception as e:
353 message = ('Initializing SSH connection to %(ip)s failed. '
Eric Brown0911af62016-02-08 17:15:40 -0800354 'Error: %(error)s' % {'ip': ip_address,
Sean Dague20e98612016-01-06 14:33:28 -0500355 'error': e})
Jordan Pittier9e227c52016-02-09 14:35:18 +0100356 caller = test_utils.find_test_caller()
Matt Riedemann5f0ac522015-05-21 09:16:24 -0700357 if caller:
358 message = '(%s) %s' % (caller, message)
359 LOG.exception(message)
Sean Dague2c98a162016-01-06 14:11:13 -0500360 self._log_console_output()
Andrea Frittoli247058f2014-07-16 16:09:22 +0100361 raise
362
363 return linux_client
364
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000365 def _image_create(self, name, fmt, path,
366 disk_format=None, properties=None):
Ghanshyam2a180b82014-06-16 13:54:22 +0900367 if properties is None:
368 properties = {}
Andrea Frittoli247058f2014-07-16 16:09:22 +0100369 name = data_utils.rand_name('%s-' % name)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100370 params = {
371 'name': name,
372 'container_format': fmt,
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000373 'disk_format': disk_format or fmt,
Andrea Frittoli247058f2014-07-16 16:09:22 +0100374 }
Matt Riedemann2aa19d42016-06-06 17:45:41 -0400375 if CONF.image_feature_enabled.api_v1:
376 params['is_public'] = 'False'
377 params['properties'] = properties
Ken'ichi Ohmichi02bcdf32016-06-17 16:41:26 -0700378 params = {'headers': common_image.image_meta_to_headers(**params)}
Matt Riedemann2aa19d42016-06-06 17:45:41 -0400379 else:
380 params['visibility'] = 'private'
381 # Additional properties are flattened out in the v2 API.
382 params.update(properties)
383 body = self.image_client.create_image(**params)
384 image = body['image'] if 'image' in body else body
Andrea Frittoli247058f2014-07-16 16:09:22 +0100385 self.addCleanup(self.image_client.delete_image, image['id'])
386 self.assertEqual("queued", image['status'])
zhang.leia4b1cef2016-03-01 10:50:01 +0800387 with open(path, 'rb') as image_file:
Matt Riedemann2aa19d42016-06-06 17:45:41 -0400388 if CONF.image_feature_enabled.api_v1:
389 self.image_client.update_image(image['id'], data=image_file)
390 else:
391 self.image_client.store_image_file(image['id'], image_file)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100392 return image['id']
393
394 def glance_image_create(self):
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300395 img_path = CONF.scenario.img_dir + "/" + CONF.scenario.img_file
Andrea Frittoli247058f2014-07-16 16:09:22 +0100396 aki_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.aki_img_file
397 ari_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.ari_img_file
398 ami_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.ami_img_file
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300399 img_container_format = CONF.scenario.img_container_format
400 img_disk_format = CONF.scenario.img_disk_format
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000401 img_properties = CONF.scenario.img_properties
PranaliD2aa523c2016-06-07 03:54:34 -0400402 LOG.debug("paths: img: %s, container_format: %s, disk_format: %s, "
Jordan Pittier525ec712016-12-07 17:51:26 +0100403 "properties: %s, ami: %s, ari: %s, aki: %s",
404 img_path, img_container_format, img_disk_format,
405 img_properties, ami_img_path, ari_img_path, aki_img_path)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100406 try:
Jordan Pittier1e443ec2015-11-20 16:15:58 +0100407 image = self._image_create('scenario-img',
408 img_container_format,
409 img_path,
410 disk_format=img_disk_format,
411 properties=img_properties)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100412 except IOError:
413 LOG.debug("A qcow2 image was not found. Try to get a uec image.")
414 kernel = self._image_create('scenario-aki', 'aki', aki_img_path)
415 ramdisk = self._image_create('scenario-ari', 'ari', ari_img_path)
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000416 properties = {'kernel_id': kernel, 'ramdisk_id': ramdisk}
Jordan Pittier1e443ec2015-11-20 16:15:58 +0100417 image = self._image_create('scenario-ami', 'ami',
418 path=ami_img_path,
419 properties=properties)
Jordan Pittier525ec712016-12-07 17:51:26 +0100420 LOG.debug("image:%s", image)
Jordan Pittier1e443ec2015-11-20 16:15:58 +0100421
422 return image
Andrea Frittoli247058f2014-07-16 16:09:22 +0100423
424 def _log_console_output(self, servers=None):
Matthew Treinish42a3f3a2014-09-04 15:04:53 -0400425 if not CONF.compute_feature_enabled.console_output:
426 LOG.debug('Console output not supported, cannot log')
427 return
Andrea Frittoli247058f2014-07-16 16:09:22 +0100428 if not servers:
David Kranzae99b9a2015-02-16 13:37:01 -0500429 servers = self.servers_client.list_servers()
Andrea Frittoli247058f2014-07-16 16:09:22 +0100430 servers = servers['servers']
431 for server in servers:
Attila Fazekas9a5a1122016-11-08 10:24:57 +0100432 try:
433 console_output = self.servers_client.get_console_output(
434 server['id'])['output']
435 LOG.debug('Console output for %s\nbody=\n%s',
436 server['id'], console_output)
437 except lib_exc.NotFound:
Attila Fazekase1360482016-11-10 11:28:08 +0100438 LOG.debug("Server %s disappeared(deleted) while looking "
Attila Fazekas9a5a1122016-11-08 10:24:57 +0100439 "for the console log", server['id'])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100440
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000441 def _log_net_info(self, exc):
442 # network debug is called as part of ssh init
Andrey Pavlov64723762015-04-29 06:24:58 +0300443 if not isinstance(exc, lib_exc.SSHTimeout):
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000444 LOG.debug('Network information on a devstack host')
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000445
nithya-ganesan882595e2014-07-29 18:51:07 +0000446 def create_server_snapshot(self, server, name=None):
447 # Glance client
448 _image_client = self.image_client
449 # Compute client
Ghanshyamae76c122015-12-22 13:41:35 +0900450 _images_client = self.compute_images_client
nithya-ganesan882595e2014-07-29 18:51:07 +0000451 if name is None:
zhuflf9d95722016-10-19 16:06:17 +0800452 name = data_utils.rand_name(self.__class__.__name__ + 'snapshot')
nithya-ganesan882595e2014-07-29 18:51:07 +0000453 LOG.debug("Creating a snapshot image for server: %s", server['name'])
Ken'ichi Ohmichi28f18672015-07-17 10:00:38 +0000454 image = _images_client.create_image(server['id'], name=name)
David Kranza5299eb2015-01-15 17:24:05 -0500455 image_id = image.response['location'].split('images/')[1]
Yaroslav Lobankov2fea4052016-04-19 15:05:57 +0300456 waiters.wait_for_image_status(_image_client, image_id, 'active')
Jordan Pittierf672b7d2016-06-20 18:50:40 +0200457
458 self.addCleanup(_image_client.wait_for_resource_deletion,
459 image_id)
460 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
461 _image_client.delete_image, image_id)
462
Matt Riedemann2aa19d42016-06-06 17:45:41 -0400463 if CONF.image_feature_enabled.api_v1:
464 # In glance v1 the additional properties are stored in the headers.
Ken'ichi Ohmichi01151e82016-06-10 11:19:52 -0700465 resp = _image_client.check_image(image_id)
466 snapshot_image = common_image.get_image_meta_from_headers(resp)
Matt Riedemann2aa19d42016-06-06 17:45:41 -0400467 image_props = snapshot_image.get('properties', {})
468 else:
469 # In glance v2 the additional properties are flattened.
470 snapshot_image = _image_client.show_image(image_id)
471 image_props = snapshot_image
Andrey Pavlovc8bd4b12015-08-17 10:20:17 +0300472
Matt Riedemann2aa19d42016-06-06 17:45:41 -0400473 bdm = image_props.get('block_device_mapping')
Andrey Pavlovc8bd4b12015-08-17 10:20:17 +0300474 if bdm:
475 bdm = json.loads(bdm)
476 if bdm and 'snapshot_id' in bdm[0]:
477 snapshot_id = bdm[0]['snapshot_id']
478 self.addCleanup(
479 self.snapshots_client.wait_for_resource_deletion,
480 snapshot_id)
Jordan Pittier9e227c52016-02-09 14:35:18 +0100481 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
482 self.snapshots_client.delete_snapshot,
483 snapshot_id)
Yaroslav Lobankov667aaa22016-03-24 23:13:28 -0500484 waiters.wait_for_snapshot_status(self.snapshots_client,
485 snapshot_id, 'available')
nithya-ganesan882595e2014-07-29 18:51:07 +0000486 image_name = snapshot_image['name']
487 self.assertEqual(name, image_name)
488 LOG.debug("Created snapshot image %s for server %s",
489 image_name, server['name'])
490 return snapshot_image
491
Jordan Pittier7cf64762015-10-14 15:01:12 +0200492 def nova_volume_attach(self, server, volume_to_attach):
Joseph Lanoux6809bab2014-12-18 14:57:18 +0000493 volume = self.servers_client.attach_volume(
Jordan Pittier7cf64762015-10-14 15:01:12 +0200494 server['id'], volumeId=volume_to_attach['id'], device='/dev/%s'
ghanshyam0f825252015-08-25 16:02:50 +0900495 % CONF.compute.volume_device_name)['volumeAttachment']
Jordan Pittier7cf64762015-10-14 15:01:12 +0200496 self.assertEqual(volume_to_attach['id'], volume['id'])
Yaroslav Lobankoved3a35b2016-03-24 22:41:30 -0500497 waiters.wait_for_volume_status(self.volumes_client,
498 volume['id'], 'in-use')
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900499
Jordan Pittier7cf64762015-10-14 15:01:12 +0200500 # Return the updated volume after the attachment
501 return self.volumes_client.show_volume(volume['id'])['volume']
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900502
Jordan Pittier7cf64762015-10-14 15:01:12 +0200503 def nova_volume_detach(self, server, volume):
504 self.servers_client.detach_volume(server['id'], volume['id'])
Yaroslav Lobankoved3a35b2016-03-24 22:41:30 -0500505 waiters.wait_for_volume_status(self.volumes_client,
506 volume['id'], 'available')
Jordan Pittier7cf64762015-10-14 15:01:12 +0200507
508 volume = self.volumes_client.show_volume(volume['id'])['volume']
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900509 self.assertEqual('available', volume['status'])
510
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700511 def rebuild_server(self, server_id, image=None,
512 preserve_ephemeral=False, wait=True,
513 rebuild_kwargs=None):
514 if image is None:
515 image = CONF.compute.image_ref
516
517 rebuild_kwargs = rebuild_kwargs or {}
518
519 LOG.debug("Rebuilding server (id: %s, image: %s, preserve eph: %s)",
520 server_id, image, preserve_ephemeral)
Ken'ichi Ohmichi5271b0f2015-08-10 07:53:27 +0000521 self.servers_client.rebuild_server(
522 server_id=server_id, image_ref=image,
523 preserve_ephemeral=preserve_ephemeral,
524 **rebuild_kwargs)
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700525 if wait:
Ken'ichi Ohmichi0eb153c2015-07-13 02:18:25 +0000526 waiters.wait_for_server_status(self.servers_client,
527 server_id, 'ACTIVE')
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700528
Steven Hardyda2a8352014-10-02 12:52:20 +0100529 def ping_ip_address(self, ip_address, should_succeed=True,
Ihar Hrachyshkaf9227c02016-09-15 11:16:47 +0000530 ping_timeout=None, mtu=None):
lanoux5fc14522015-09-21 08:17:35 +0000531 timeout = ping_timeout or CONF.validation.ping_timeout
Ihar Hrachyshkaf9227c02016-09-15 11:16:47 +0000532 cmd = ['ping', '-c1', '-w1']
533
534 if mtu:
535 cmd += [
536 # don't fragment
537 '-M', 'do',
538 # ping receives just the size of ICMP payload
539 '-s', str(net_utils.get_ping_payload_size(mtu, 4))
540 ]
541 cmd.append(ip_address)
Aaron Rosena7df13b2014-09-23 09:45:45 -0700542
543 def ping():
544 proc = subprocess.Popen(cmd,
545 stdout=subprocess.PIPE,
546 stderr=subprocess.PIPE)
547 proc.communicate()
Shuquan Huang753629e2015-07-20 08:52:29 +0000548
Aaron Rosena7df13b2014-09-23 09:45:45 -0700549 return (proc.returncode == 0) == should_succeed
550
Jordan Pittier9e227c52016-02-09 14:35:18 +0100551 caller = test_utils.find_test_caller()
Shuquan Huang753629e2015-07-20 08:52:29 +0000552 LOG.debug('%(caller)s begins to ping %(ip)s in %(timeout)s sec and the'
John L. Villalovosa898aec2017-01-13 14:46:46 -0800553 ' expected result is %(should_succeed)s', {
Shuquan Huang753629e2015-07-20 08:52:29 +0000554 'caller': caller, 'ip': ip_address, 'timeout': timeout,
555 'should_succeed':
556 'reachable' if should_succeed else 'unreachable'
557 })
Jordan Pittier35a63752016-08-30 13:09:12 +0200558 result = test_utils.call_until_true(ping, timeout, 1)
Shuquan Huang753629e2015-07-20 08:52:29 +0000559 LOG.debug('%(caller)s finishes ping %(ip)s in %(timeout)s sec and the '
John L. Villalovosa898aec2017-01-13 14:46:46 -0800560 'ping result is %(result)s', {
Shuquan Huang753629e2015-07-20 08:52:29 +0000561 'caller': caller, 'ip': ip_address, 'timeout': timeout,
562 'result': 'expected' if result else 'unexpected'
563 })
564 return result
Aaron Rosena7df13b2014-09-23 09:45:45 -0700565
Yair Friedae0e73d2014-11-24 11:56:26 +0200566 def check_vm_connectivity(self, ip_address,
567 username=None,
568 private_key=None,
Ihar Hrachyshkaf9227c02016-09-15 11:16:47 +0000569 should_connect=True,
570 mtu=None):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000571 """Check server connectivity
572
Yair Friedae0e73d2014-11-24 11:56:26 +0200573 :param ip_address: server to test against
574 :param username: server's ssh username
575 :param private_key: server's ssh private key to be used
576 :param should_connect: True/False indicates positive/negative test
577 positive - attempt ping and ssh
578 negative - attempt ping and fail if succeed
Ihar Hrachyshkaf9227c02016-09-15 11:16:47 +0000579 :param mtu: network MTU to use for connectivity validation
Yair Friedae0e73d2014-11-24 11:56:26 +0200580
581 :raises: AssertError if the result of the connectivity check does
582 not match the value of the should_connect param
583 """
584 if should_connect:
585 msg = "Timed out waiting for %s to become reachable" % ip_address
586 else:
587 msg = "ip address %s is reachable" % ip_address
588 self.assertTrue(self.ping_ip_address(ip_address,
Ihar Hrachyshkaf9227c02016-09-15 11:16:47 +0000589 should_succeed=should_connect,
590 mtu=mtu),
Yair Friedae0e73d2014-11-24 11:56:26 +0200591 msg=msg)
592 if should_connect:
593 # no need to check ssh for negative connectivity
594 self.get_remote_client(ip_address, username, private_key)
595
596 def check_public_network_connectivity(self, ip_address, username,
597 private_key, should_connect=True,
Ihar Hrachyshkaf9227c02016-09-15 11:16:47 +0000598 msg=None, servers=None, mtu=None):
Yair Friedae0e73d2014-11-24 11:56:26 +0200599 # The target login is assumed to have been configured for
600 # key-based authentication by cloud-init.
Jordan Pittier525ec712016-12-07 17:51:26 +0100601 LOG.debug('checking network connections to IP %s with user: %s',
602 ip_address, username)
Yair Friedae0e73d2014-11-24 11:56:26 +0200603 try:
604 self.check_vm_connectivity(ip_address,
605 username,
606 private_key,
Ihar Hrachyshkaf9227c02016-09-15 11:16:47 +0000607 should_connect=should_connect,
608 mtu=mtu)
Matthew Treinish53483132014-12-09 18:50:06 -0500609 except Exception:
Yair Friedae0e73d2014-11-24 11:56:26 +0200610 ex_msg = 'Public network connectivity check failed'
611 if msg:
612 ex_msg += ": " + msg
613 LOG.exception(ex_msg)
614 self._log_console_output(servers)
Yair Friedae0e73d2014-11-24 11:56:26 +0200615 raise
616
617 def create_floating_ip(self, thing, pool_name=None):
Ken'ichi Ohmichia112a592015-11-17 08:49:37 +0000618 """Create a floating IP and associates to a server on Nova"""
Yair Friedae0e73d2014-11-24 11:56:26 +0200619
Marc Koderer3b57d802016-03-22 15:23:31 +0100620 if not pool_name:
621 pool_name = CONF.network.floating_network_name
John Warrene74890a2015-11-11 15:18:01 -0500622 floating_ip = (self.compute_floating_ips_client.
Ken'ichi Ohmichie037a6f2015-12-03 06:41:49 +0000623 create_floating_ip(pool=pool_name)['floating_ip'])
Jordan Pittier9e227c52016-02-09 14:35:18 +0100624 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
John Warrene74890a2015-11-11 15:18:01 -0500625 self.compute_floating_ips_client.delete_floating_ip,
Yair Friedae0e73d2014-11-24 11:56:26 +0200626 floating_ip['id'])
John Warrene74890a2015-11-11 15:18:01 -0500627 self.compute_floating_ips_client.associate_floating_ip_to_server(
Yair Friedae0e73d2014-11-24 11:56:26 +0200628 floating_ip['ip'], thing['id'])
629 return floating_ip
630
Sean Dague20e98612016-01-06 14:33:28 -0500631 def create_timestamp(self, ip_address, dev_name=None, mount_path='/mnt',
Matt Riedemannfd5657d2015-09-30 14:47:07 -0700632 private_key=None):
Sean Dague20e98612016-01-06 14:33:28 -0500633 ssh_client = self.get_remote_client(ip_address,
Matt Riedemannfd5657d2015-09-30 14:47:07 -0700634 private_key=private_key)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300635 if dev_name is not None:
636 ssh_client.make_fs(dev_name)
Matt Riedemann076685a2015-09-30 14:38:16 -0700637 ssh_client.mount(dev_name, mount_path)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300638 cmd_timestamp = 'sudo sh -c "date > %s/timestamp; sync"' % mount_path
639 ssh_client.exec_command(cmd_timestamp)
640 timestamp = ssh_client.exec_command('sudo cat %s/timestamp'
641 % mount_path)
642 if dev_name is not None:
643 ssh_client.umount(mount_path)
644 return timestamp
645
Sean Dague20e98612016-01-06 14:33:28 -0500646 def get_timestamp(self, ip_address, dev_name=None, mount_path='/mnt',
Matt Riedemannfd5657d2015-09-30 14:47:07 -0700647 private_key=None):
Sean Dague20e98612016-01-06 14:33:28 -0500648 ssh_client = self.get_remote_client(ip_address,
Matt Riedemannfd5657d2015-09-30 14:47:07 -0700649 private_key=private_key)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300650 if dev_name is not None:
Matt Riedemann076685a2015-09-30 14:38:16 -0700651 ssh_client.mount(dev_name, mount_path)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300652 timestamp = ssh_client.exec_command('sudo cat %s/timestamp'
653 % mount_path)
654 if dev_name is not None:
655 ssh_client.umount(mount_path)
656 return timestamp
657
Sean Dague20e98612016-01-06 14:33:28 -0500658 def get_server_ip(self, server):
659 """Get the server fixed or floating IP.
660
661 Based on the configuration we're in, return a correct ip
662 address for validating that a guest is up.
663 """
Alexander Gubanovc8829f82015-11-12 10:35:13 +0200664 if CONF.validation.connect_method == 'floating':
Sean Dague20e98612016-01-06 14:33:28 -0500665 # The tests calling this method don't have a floating IP
zhufl0892cb22016-05-06 14:46:00 +0800666 # and can't make use of the validation resources. So the
Sean Dague20e98612016-01-06 14:33:28 -0500667 # method is creating the floating IP there.
668 return self.create_floating_ip(server)['ip']
669 elif CONF.validation.connect_method == 'fixed':
Matt Riedemanna7782552016-08-08 16:26:01 -0400670 # Determine the network name to look for based on config or creds
671 # provider network resources.
672 if CONF.validation.network_for_ssh:
673 addresses = server['addresses'][
674 CONF.validation.network_for_ssh]
675 else:
676 creds_provider = self._get_credentials_provider()
677 net_creds = creds_provider.get_primary_creds()
678 network = getattr(net_creds, 'network', None)
679 addresses = (server['addresses'][network['name']]
680 if network else [])
Sean Dague20e98612016-01-06 14:33:28 -0500681 for address in addresses:
Matt Riedemanna7782552016-08-08 16:26:01 -0400682 if (address['version'] == CONF.validation.ip_version_for_ssh
683 and address['OS-EXT-IPS:type'] == 'fixed'):
Sean Dague20e98612016-01-06 14:33:28 -0500684 return address['addr']
zhufl955f82b2016-07-22 11:14:34 +0800685 raise exceptions.ServerUnreachable(server_id=server['id'])
Alexander Gubanovc8829f82015-11-12 10:35:13 +0200686 else:
Matthew Treinish4217a702016-10-07 17:27:11 -0400687 raise lib_exc.InvalidConfiguration()
Alexander Gubanovc8829f82015-11-12 10:35:13 +0200688
Andrea Frittoli2e733b52014-07-16 14:12:11 +0100689
Andrea Frittoli4971fc82014-09-25 10:22:20 +0100690class NetworkScenarioTest(ScenarioTest):
Yair Fried1fc32a12014-08-04 09:11:30 +0300691 """Base class for network scenario tests.
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000692
Yair Fried1fc32a12014-08-04 09:11:30 +0300693 This class provide helpers for network scenario tests, using the neutron
694 API. Helpers from ancestor which use the nova network API are overridden
695 with the neutron API.
696
697 This Class also enforces using Neutron instead of novanetwork.
698 Subclassed tests will be skipped if Neutron is not enabled
699
700 """
701
Andrea Frittolib21de6c2015-02-06 20:12:38 +0000702 credentials = ['primary', 'admin']
703
Yair Fried1fc32a12014-08-04 09:11:30 +0300704 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +0000705 def skip_checks(cls):
706 super(NetworkScenarioTest, cls).skip_checks()
Andrea Frittoli2ddc2632014-09-25 11:03:00 +0100707 if not CONF.service_available.neutron:
708 raise cls.skipException('Neutron not available')
Yair Fried1fc32a12014-08-04 09:11:30 +0300709
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -0700710 def _create_network(self, networks_client=None,
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000711 routers_client=None, tenant_id=None,
Markus Zoeller156b5da2016-07-11 18:10:31 +0200712 namestart='network-smoke-',
713 port_security_enabled=True):
John Warren94d8faf2015-09-15 12:22:24 -0400714 if not networks_client:
715 networks_client = self.networks_client
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000716 if not routers_client:
717 routers_client = self.routers_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300718 if not tenant_id:
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -0700719 tenant_id = networks_client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300720 name = data_utils.rand_name(namestart)
Matt Riedemann039b2fe2016-09-15 16:12:24 -0400721 network_kwargs = dict(name=name, tenant_id=tenant_id)
722 # Neutron disables port security by default so we have to check the
723 # config before trying to create the network with port_security_enabled
724 if CONF.network_feature_enabled.port_security:
725 network_kwargs['port_security_enabled'] = port_security_enabled
Markus Zoeller156b5da2016-07-11 18:10:31 +0200726 result = networks_client.create_network(**network_kwargs)
Steve Heyman33735f22016-05-24 09:28:08 -0500727 network = result['network']
728
729 self.assertEqual(network['name'], name)
Jordan Pittier9e227c52016-02-09 14:35:18 +0100730 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
Steve Heyman33735f22016-05-24 09:28:08 -0500731 self.networks_client.delete_network,
732 network['id'])
Yair Fried1fc32a12014-08-04 09:11:30 +0300733 return network
734
735 def _list_networks(self, *args, **kwargs):
736 """List networks using admin creds """
John Warren94d8faf2015-09-15 12:22:24 -0400737 networks_list = self.admin_manager.networks_client.list_networks(
ghanshyam2f7cc022015-06-26 18:18:11 +0900738 *args, **kwargs)
739 return networks_list['networks']
Yair Fried1fc32a12014-08-04 09:11:30 +0300740
741 def _list_subnets(self, *args, **kwargs):
742 """List subnets using admin creds """
John Warren3961acd2015-10-02 14:38:53 -0400743 subnets_list = self.admin_manager.subnets_client.list_subnets(
ghanshyam2f7cc022015-06-26 18:18:11 +0900744 *args, **kwargs)
745 return subnets_list['subnets']
Yair Fried1fc32a12014-08-04 09:11:30 +0300746
747 def _list_routers(self, *args, **kwargs):
748 """List routers using admin creds """
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000749 routers_list = self.admin_manager.routers_client.list_routers(
ghanshyam2f7cc022015-06-26 18:18:11 +0900750 *args, **kwargs)
751 return routers_list['routers']
Yair Fried1fc32a12014-08-04 09:11:30 +0300752
753 def _list_ports(self, *args, **kwargs):
754 """List ports using admin creds """
John Warren49c0fe52015-10-22 12:35:54 -0400755 ports_list = self.admin_manager.ports_client.list_ports(
ghanshyam2f7cc022015-06-26 18:18:11 +0900756 *args, **kwargs)
757 return ports_list['ports']
Yair Fried1fc32a12014-08-04 09:11:30 +0300758
Yair Fried564d89d2015-08-06 17:02:12 +0300759 def _list_agents(self, *args, **kwargs):
760 """List agents using admin creds """
Ken'ichi Ohmichi71860062015-12-15 08:20:13 +0000761 agents_list = self.admin_manager.network_agents_client.list_agents(
Yair Fried564d89d2015-08-06 17:02:12 +0300762 *args, **kwargs)
763 return agents_list['agents']
764
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -0700765 def _create_subnet(self, network, subnets_client=None,
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000766 routers_client=None, namestart='subnet-smoke',
767 **kwargs):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000768 """Create a subnet for the given network
769
770 within the cidr block configured for tenant networks.
Yair Fried1fc32a12014-08-04 09:11:30 +0300771 """
John Warren3961acd2015-10-02 14:38:53 -0400772 if not subnets_client:
773 subnets_client = self.subnets_client
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000774 if not routers_client:
775 routers_client = self.routers_client
Yair Fried1fc32a12014-08-04 09:11:30 +0300776
777 def cidr_in_use(cidr, tenant_id):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000778 """Check cidr existence
779
lei zhangdd552b22015-11-25 20:41:48 +0800780 :returns: True if subnet with cidr already exist in tenant
781 False else
Yair Fried1fc32a12014-08-04 09:11:30 +0300782 """
783 cidr_in_use = self._list_subnets(tenant_id=tenant_id, cidr=cidr)
784 return len(cidr_in_use) != 0
785
Kirill Shileev14113572014-11-21 16:58:02 +0300786 ip_version = kwargs.pop('ip_version', 4)
787
788 if ip_version == 6:
789 tenant_cidr = netaddr.IPNetwork(
Sean Dagueed6e5862016-04-04 10:49:13 -0400790 CONF.network.project_network_v6_cidr)
791 num_bits = CONF.network.project_network_v6_mask_bits
Kirill Shileev14113572014-11-21 16:58:02 +0300792 else:
Sean Dagueed6e5862016-04-04 10:49:13 -0400793 tenant_cidr = netaddr.IPNetwork(CONF.network.project_network_cidr)
794 num_bits = CONF.network.project_network_mask_bits
Kirill Shileev14113572014-11-21 16:58:02 +0300795
Yair Fried1fc32a12014-08-04 09:11:30 +0300796 result = None
Kirill Shileev14113572014-11-21 16:58:02 +0300797 str_cidr = None
Yair Fried1fc32a12014-08-04 09:11:30 +0300798 # Repeatedly attempt subnet creation with sequential cidr
799 # blocks until an unallocated block is found.
Kirill Shileev14113572014-11-21 16:58:02 +0300800 for subnet_cidr in tenant_cidr.subnet(num_bits):
Yair Fried1fc32a12014-08-04 09:11:30 +0300801 str_cidr = str(subnet_cidr)
Steve Heyman33735f22016-05-24 09:28:08 -0500802 if cidr_in_use(str_cidr, tenant_id=network['tenant_id']):
Yair Fried1fc32a12014-08-04 09:11:30 +0300803 continue
804
805 subnet = dict(
806 name=data_utils.rand_name(namestart),
Steve Heyman33735f22016-05-24 09:28:08 -0500807 network_id=network['id'],
808 tenant_id=network['tenant_id'],
Yair Fried1fc32a12014-08-04 09:11:30 +0300809 cidr=str_cidr,
Kirill Shileev14113572014-11-21 16:58:02 +0300810 ip_version=ip_version,
Yair Fried1fc32a12014-08-04 09:11:30 +0300811 **kwargs
812 )
813 try:
John Warren3961acd2015-10-02 14:38:53 -0400814 result = subnets_client.create_subnet(**subnet)
Yair Fried1fc32a12014-08-04 09:11:30 +0300815 break
Masayuki Igawad9388762015-01-20 14:56:42 +0900816 except lib_exc.Conflict as e:
Yair Fried1fc32a12014-08-04 09:11:30 +0300817 is_overlapping_cidr = 'overlaps with another subnet' in str(e)
818 if not is_overlapping_cidr:
819 raise
820 self.assertIsNotNone(result, 'Unable to allocate tenant network')
Steve Heyman33735f22016-05-24 09:28:08 -0500821
822 subnet = result['subnet']
823 self.assertEqual(subnet['cidr'], str_cidr)
824
825 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
826 subnets_client.delete_subnet, subnet['id'])
827
Yair Fried1fc32a12014-08-04 09:11:30 +0300828 return subnet
829
Kirill Shileev14113572014-11-21 16:58:02 +0300830 def _get_server_port_id_and_ip4(self, server, ip_addr=None):
Kevin Benton1d0c1dc2016-02-04 14:30:08 -0800831 ports = self._list_ports(device_id=server['id'], fixed_ip=ip_addr)
Kobi Samoray166500a2016-10-09 14:42:48 +0300832 # A port can have more than one IP address in some cases.
Sean M. Collins2e896832015-12-15 13:58:47 -0500833 # If the network is dual-stack (IPv4 + IPv6), this port is associated
834 # with 2 subnets
Vasyl Saienko8fd517c2016-05-30 09:52:54 +0300835 p_status = ['ACTIVE']
836 # NOTE(vsaienko) With Ironic, instances live on separate hardware
837 # servers. Neutron does not bind ports for Ironic instances, as a
838 # result the port remains in the DOWN state.
Vasyl Saienkoc8aa34b2016-08-01 14:18:37 +0300839 # TODO(vsaienko) remove once bug: #1599836 is resolved.
Thiago Paiva66cded22016-08-15 14:55:58 -0300840 if getattr(CONF.service_available, 'ironic', False):
Vasyl Saienko8fd517c2016-05-30 09:52:54 +0300841 p_status.append('DOWN')
Daniel Mellado9e3e1062015-08-06 18:07:05 +0200842 port_map = [(p["id"], fxip["ip_address"])
843 for p in ports
844 for fxip in p["fixed_ips"]
Yatin Kumbhareee4924c2016-06-09 15:12:06 +0530845 if netutils.is_valid_ipv4(fxip["ip_address"])
Vasyl Saienko8fd517c2016-05-30 09:52:54 +0300846 and p['status'] in p_status]
Kevin Benton1d0c1dc2016-02-04 14:30:08 -0800847 inactive = [p for p in ports if p['status'] != 'ACTIVE']
848 if inactive:
849 LOG.warning("Instance has ports that are not ACTIVE: %s", inactive)
Daniel Mellado9e3e1062015-08-06 18:07:05 +0200850
John L. Villalovosb83286f2015-11-04 14:46:57 -0800851 self.assertNotEqual(0, len(port_map),
852 "No IPv4 addresses found in: %s" % ports)
Daniel Mellado9e3e1062015-08-06 18:07:05 +0200853 self.assertEqual(len(port_map), 1,
854 "Found multiple IPv4 addresses: %s. "
855 "Unable to determine which port to target."
856 % port_map)
857 return port_map[0]
Yair Fried1fc32a12014-08-04 09:11:30 +0300858
David Shrewsbury9bac3662014-08-07 15:07:01 -0400859 def _get_network_by_name(self, network_name):
860 net = self._list_networks(name=network_name)
Adam Gandelman878a5fd2015-03-30 14:33:36 -0700861 self.assertNotEqual(len(net), 0,
862 "Unable to get network by name: %s" % network_name)
Steve Heyman33735f22016-05-24 09:28:08 -0500863 return net[0]
David Shrewsbury9bac3662014-08-07 15:07:01 -0400864
Yair Friedae0e73d2014-11-24 11:56:26 +0200865 def create_floating_ip(self, thing, external_network_id=None,
866 port_id=None, client=None):
Ken'ichi Ohmichia112a592015-11-17 08:49:37 +0000867 """Create a floating IP and associates to a resource/port on Neutron"""
Yair Friedae0e73d2014-11-24 11:56:26 +0200868 if not external_network_id:
869 external_network_id = CONF.network.public_network_id
Yair Frieddb6c9e92014-08-06 08:53:13 +0300870 if not client:
John Warrenfbf2a892015-11-17 12:36:14 -0500871 client = self.floating_ips_client
Yair Fried1fc32a12014-08-04 09:11:30 +0300872 if not port_id:
Kirill Shileev14113572014-11-21 16:58:02 +0300873 port_id, ip4 = self._get_server_port_id_and_ip4(thing)
874 else:
875 ip4 = None
David Kranz34e88122014-12-11 15:24:05 -0500876 result = client.create_floatingip(
Yair Fried1fc32a12014-08-04 09:11:30 +0300877 floating_network_id=external_network_id,
878 port_id=port_id,
Kirill Shileev14113572014-11-21 16:58:02 +0300879 tenant_id=thing['tenant_id'],
880 fixed_ip_address=ip4
Yair Fried1fc32a12014-08-04 09:11:30 +0300881 )
Steve Heyman33735f22016-05-24 09:28:08 -0500882 floating_ip = result['floatingip']
Jordan Pittier9e227c52016-02-09 14:35:18 +0100883 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
Steve Heyman33735f22016-05-24 09:28:08 -0500884 self.floating_ips_client.delete_floatingip,
885 floating_ip['id'])
Yair Fried1fc32a12014-08-04 09:11:30 +0300886 return floating_ip
887
888 def _associate_floating_ip(self, floating_ip, server):
Kirill Shileev14113572014-11-21 16:58:02 +0300889 port_id, _ = self._get_server_port_id_and_ip4(server)
Steve Heyman33735f22016-05-24 09:28:08 -0500890 kwargs = dict(port_id=port_id)
891 floating_ip = self.floating_ips_client.update_floatingip(
892 floating_ip['id'], **kwargs)['floatingip']
893 self.assertEqual(port_id, floating_ip['port_id'])
Yair Fried1fc32a12014-08-04 09:11:30 +0300894 return floating_ip
895
896 def _disassociate_floating_ip(self, floating_ip):
Steve Heyman33735f22016-05-24 09:28:08 -0500897 """:param floating_ip: floating_ips_client.create_floatingip"""
898 kwargs = dict(port_id=None)
899 floating_ip = self.floating_ips_client.update_floatingip(
900 floating_ip['id'], **kwargs)['floatingip']
901 self.assertIsNone(floating_ip['port_id'])
Yair Fried1fc32a12014-08-04 09:11:30 +0300902 return floating_ip
903
Yair Fried45f92952014-06-26 05:19:19 +0300904 def check_floating_ip_status(self, floating_ip, status):
Carl Baldwina754e2d2014-10-23 22:47:41 +0000905 """Verifies floatingip reaches the given status
Yair Fried45f92952014-06-26 05:19:19 +0300906
Steve Heyman33735f22016-05-24 09:28:08 -0500907 :param dict floating_ip: floating IP dict to check status
Yair Fried45f92952014-06-26 05:19:19 +0300908 :param status: target status
909 :raises: AssertionError if status doesn't match
910 """
Steve Heyman33735f22016-05-24 09:28:08 -0500911 floatingip_id = floating_ip['id']
912
Carl Baldwina754e2d2014-10-23 22:47:41 +0000913 def refresh():
Steve Heyman33735f22016-05-24 09:28:08 -0500914 result = (self.floating_ips_client.
915 show_floatingip(floatingip_id)['floatingip'])
916 return status == result['status']
Carl Baldwina754e2d2014-10-23 22:47:41 +0000917
Jordan Pittier35a63752016-08-30 13:09:12 +0200918 test_utils.call_until_true(refresh,
919 CONF.network.build_timeout,
920 CONF.network.build_interval)
Steve Heyman33735f22016-05-24 09:28:08 -0500921 floating_ip = self.floating_ips_client.show_floatingip(
922 floatingip_id)['floatingip']
923 self.assertEqual(status, floating_ip['status'],
Yair Fried45f92952014-06-26 05:19:19 +0300924 message="FloatingIP: {fp} is at status: {cst}. "
925 "failed to reach status: {st}"
Steve Heyman33735f22016-05-24 09:28:08 -0500926 .format(fp=floating_ip, cst=floating_ip['status'],
Yair Fried45f92952014-06-26 05:19:19 +0300927 st=status))
928 LOG.info("FloatingIP: {fp} is at status: {st}"
929 .format(fp=floating_ip, st=status))
930
Yair Fried1fc32a12014-08-04 09:11:30 +0300931 def _check_tenant_network_connectivity(self, server,
932 username,
933 private_key,
934 should_connect=True,
935 servers_for_debug=None):
Sean Dagueed6e5862016-04-04 10:49:13 -0400936 if not CONF.network.project_networks_reachable:
Yair Fried1fc32a12014-08-04 09:11:30 +0300937 msg = 'Tenant networks not configured to be reachable.'
938 LOG.info(msg)
939 return
940 # The target login is assumed to have been configured for
941 # key-based authentication by cloud-init.
942 try:
guo yunxian7bbbec12016-08-21 20:03:10 +0800943 for net_name, ip_addresses in server['addresses'].items():
Yair Fried1fc32a12014-08-04 09:11:30 +0300944 for ip_address in ip_addresses:
ghanshyam807211c2014-12-18 13:21:22 +0900945 self.check_vm_connectivity(ip_address['addr'],
Yair Friedae0e73d2014-11-24 11:56:26 +0200946 username,
947 private_key,
948 should_connect=should_connect)
Yair Fried1fc32a12014-08-04 09:11:30 +0300949 except Exception as e:
950 LOG.exception('Tenant network connectivity check failed')
951 self._log_console_output(servers_for_debug)
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000952 self._log_net_info(e)
Yair Fried1fc32a12014-08-04 09:11:30 +0300953 raise
954
Yair Friedbc46f592015-11-18 16:29:34 +0200955 def _check_remote_connectivity(self, source, dest, should_succeed=True,
956 nic=None):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000957 """check ping server via source ssh connection
Yair Fried1fc32a12014-08-04 09:11:30 +0300958
959 :param source: RemoteClient: an ssh connection from which to ping
960 :param dest: and IP to ping against
961 :param should_succeed: boolean should ping succeed or not
Yair Friedbc46f592015-11-18 16:29:34 +0200962 :param nic: specific network interface to ping from
Yair Fried1fc32a12014-08-04 09:11:30 +0300963 :returns: boolean -- should_succeed == ping
964 :returns: ping is false if ping failed
965 """
966 def ping_remote():
967 try:
Yair Friedbc46f592015-11-18 16:29:34 +0200968 source.ping_host(dest, nic=nic)
Andrey Pavlov64723762015-04-29 06:24:58 +0300969 except lib_exc.SSHExecCommandFailed:
zhangguoqing6c096642016-01-04 06:17:21 +0000970 LOG.warning('Failed to ping IP: %s via a ssh connection '
Jordan Pittier525ec712016-12-07 17:51:26 +0100971 'from: %s.', dest, source.ssh_client.host)
Yair Fried1fc32a12014-08-04 09:11:30 +0300972 return not should_succeed
973 return should_succeed
974
Jordan Pittier35a63752016-08-30 13:09:12 +0200975 return test_utils.call_until_true(ping_remote,
976 CONF.validation.ping_timeout,
977 1)
Yair Fried1fc32a12014-08-04 09:11:30 +0300978
John Warren456d9ae2016-01-12 15:36:33 -0500979 def _create_security_group(self, security_group_rules_client=None,
980 tenant_id=None,
John Warrenf9606e92015-12-10 12:12:42 -0500981 namestart='secgroup-smoke',
982 security_groups_client=None):
John Warren456d9ae2016-01-12 15:36:33 -0500983 if security_group_rules_client is None:
984 security_group_rules_client = self.security_group_rules_client
John Warrenf9606e92015-12-10 12:12:42 -0500985 if security_groups_client is None:
986 security_groups_client = self.security_groups_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300987 if tenant_id is None:
John Warrenf9606e92015-12-10 12:12:42 -0500988 tenant_id = security_groups_client.tenant_id
989 secgroup = self._create_empty_security_group(
990 namestart=namestart, client=security_groups_client,
991 tenant_id=tenant_id)
Yair Fried1fc32a12014-08-04 09:11:30 +0300992
993 # Add rules to the security group
John Warrenf9606e92015-12-10 12:12:42 -0500994 rules = self._create_loginable_secgroup_rule(
John Warren456d9ae2016-01-12 15:36:33 -0500995 security_group_rules_client=security_group_rules_client,
996 secgroup=secgroup,
John Warrenf9606e92015-12-10 12:12:42 -0500997 security_groups_client=security_groups_client)
Yair Fried1fc32a12014-08-04 09:11:30 +0300998 for rule in rules:
Steve Heyman33735f22016-05-24 09:28:08 -0500999 self.assertEqual(tenant_id, rule['tenant_id'])
1000 self.assertEqual(secgroup['id'], rule['security_group_id'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001001 return secgroup
1002
Yair Frieddb6c9e92014-08-06 08:53:13 +03001003 def _create_empty_security_group(self, client=None, tenant_id=None,
Yair Fried1fc32a12014-08-04 09:11:30 +03001004 namestart='secgroup-smoke'):
1005 """Create a security group without rules.
1006
1007 Default rules will be created:
1008 - IPv4 egress to any
1009 - IPv6 egress to any
1010
1011 :param tenant_id: secgroup will be created in this tenant
Steve Heyman33735f22016-05-24 09:28:08 -05001012 :returns: the created security group
Yair Fried1fc32a12014-08-04 09:11:30 +03001013 """
1014 if client is None:
John Warrenf9606e92015-12-10 12:12:42 -05001015 client = self.security_groups_client
Yair Frieddb6c9e92014-08-06 08:53:13 +03001016 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +00001017 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001018 sg_name = data_utils.rand_name(namestart)
1019 sg_desc = sg_name + " description"
1020 sg_dict = dict(name=sg_name,
1021 description=sg_desc)
1022 sg_dict['tenant_id'] = tenant_id
David Kranz34e88122014-12-11 15:24:05 -05001023 result = client.create_security_group(**sg_dict)
Steve Heyman33735f22016-05-24 09:28:08 -05001024
1025 secgroup = result['security_group']
1026 self.assertEqual(secgroup['name'], sg_name)
1027 self.assertEqual(tenant_id, secgroup['tenant_id'])
1028 self.assertEqual(secgroup['description'], sg_desc)
1029
Jordan Pittier9e227c52016-02-09 14:35:18 +01001030 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
Steve Heyman33735f22016-05-24 09:28:08 -05001031 client.delete_security_group, secgroup['id'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001032 return secgroup
1033
Yair Frieddb6c9e92014-08-06 08:53:13 +03001034 def _default_security_group(self, client=None, tenant_id=None):
Yair Fried1fc32a12014-08-04 09:11:30 +03001035 """Get default secgroup for given tenant_id.
1036
Ken'ichi Ohmichid67c8da2016-09-13 16:18:11 -07001037 :returns: default secgroup for given tenant
Yair Fried1fc32a12014-08-04 09:11:30 +03001038 """
1039 if client is None:
John Warrenf9606e92015-12-10 12:12:42 -05001040 client = self.security_groups_client
Yair Frieddb6c9e92014-08-06 08:53:13 +03001041 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +00001042 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001043 sgs = [
Jordan Pittier8ad86172016-04-25 16:20:53 +02001044 sg for sg in list(client.list_security_groups().values())[0]
Yair Fried1fc32a12014-08-04 09:11:30 +03001045 if sg['tenant_id'] == tenant_id and sg['name'] == 'default'
1046 ]
1047 msg = "No default security group for tenant %s." % (tenant_id)
Béla Vancsics64862f72016-11-08 09:12:31 +01001048 self.assertGreater(len(sgs), 0, msg)
Steve Heyman33735f22016-05-24 09:28:08 -05001049 return sgs[0]
Yair Fried1fc32a12014-08-04 09:11:30 +03001050
John Warren456d9ae2016-01-12 15:36:33 -05001051 def _create_security_group_rule(self, secgroup=None,
1052 sec_group_rules_client=None,
John Warrenf9606e92015-12-10 12:12:42 -05001053 tenant_id=None,
1054 security_groups_client=None, **kwargs):
Yair Fried1fc32a12014-08-04 09:11:30 +03001055 """Create a rule from a dictionary of rule parameters.
1056
1057 Create a rule in a secgroup. if secgroup not defined will search for
1058 default secgroup in tenant_id.
1059
Steve Heyman33735f22016-05-24 09:28:08 -05001060 :param secgroup: the security group.
Yair Fried1fc32a12014-08-04 09:11:30 +03001061 :param tenant_id: if secgroup not passed -- the tenant in which to
1062 search for default secgroup
1063 :param kwargs: a dictionary containing rule parameters:
1064 for example, to allow incoming ssh:
1065 rule = {
1066 direction: 'ingress'
1067 protocol:'tcp',
1068 port_range_min: 22,
1069 port_range_max: 22
1070 }
1071 """
John Warren456d9ae2016-01-12 15:36:33 -05001072 if sec_group_rules_client is None:
1073 sec_group_rules_client = self.security_group_rules_client
John Warrenf9606e92015-12-10 12:12:42 -05001074 if security_groups_client is None:
1075 security_groups_client = self.security_groups_client
Yair Frieddb6c9e92014-08-06 08:53:13 +03001076 if not tenant_id:
John Warrenf9606e92015-12-10 12:12:42 -05001077 tenant_id = security_groups_client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001078 if secgroup is None:
John Warrenf9606e92015-12-10 12:12:42 -05001079 secgroup = self._default_security_group(
1080 client=security_groups_client, tenant_id=tenant_id)
Yair Fried1fc32a12014-08-04 09:11:30 +03001081
Steve Heyman33735f22016-05-24 09:28:08 -05001082 ruleset = dict(security_group_id=secgroup['id'],
1083 tenant_id=secgroup['tenant_id'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001084 ruleset.update(kwargs)
1085
John Warren456d9ae2016-01-12 15:36:33 -05001086 sg_rule = sec_group_rules_client.create_security_group_rule(**ruleset)
Steve Heyman33735f22016-05-24 09:28:08 -05001087 sg_rule = sg_rule['security_group_rule']
1088
1089 self.assertEqual(secgroup['tenant_id'], sg_rule['tenant_id'])
1090 self.assertEqual(secgroup['id'], sg_rule['security_group_id'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001091
1092 return sg_rule
1093
John Warren456d9ae2016-01-12 15:36:33 -05001094 def _create_loginable_secgroup_rule(self, security_group_rules_client=None,
1095 secgroup=None,
John Warrenf9606e92015-12-10 12:12:42 -05001096 security_groups_client=None):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001097 """Create loginable security group rule
1098
Alex Stafeyevdd5dde92016-05-08 14:35:04 +03001099 This function will create:
1100 1. egress and ingress tcp port 22 allow rule in order to allow ssh
1101 access for ipv4.
1102 2. egress and ingress ipv6 icmp allow rule, in order to allow icmpv6.
1103 3. egress and ingress ipv4 icmp allow rule, in order to allow icmpv4.
Yair Fried1fc32a12014-08-04 09:11:30 +03001104 """
1105
John Warren456d9ae2016-01-12 15:36:33 -05001106 if security_group_rules_client is None:
1107 security_group_rules_client = self.security_group_rules_client
John Warrenf9606e92015-12-10 12:12:42 -05001108 if security_groups_client is None:
1109 security_groups_client = self.security_groups_client
Yair Fried1fc32a12014-08-04 09:11:30 +03001110 rules = []
1111 rulesets = [
1112 dict(
1113 # ssh
1114 protocol='tcp',
1115 port_range_min=22,
1116 port_range_max=22,
1117 ),
1118 dict(
1119 # ping
1120 protocol='icmp',
Andreas Scheuring887ca8e2015-02-03 17:56:12 +01001121 ),
1122 dict(
1123 # ipv6-icmp for ping6
1124 protocol='icmp',
1125 ethertype='IPv6',
Yair Fried1fc32a12014-08-04 09:11:30 +03001126 )
1127 ]
John Warren456d9ae2016-01-12 15:36:33 -05001128 sec_group_rules_client = security_group_rules_client
Yair Fried1fc32a12014-08-04 09:11:30 +03001129 for ruleset in rulesets:
1130 for r_direction in ['ingress', 'egress']:
1131 ruleset['direction'] = r_direction
1132 try:
1133 sg_rule = self._create_security_group_rule(
John Warren456d9ae2016-01-12 15:36:33 -05001134 sec_group_rules_client=sec_group_rules_client,
1135 secgroup=secgroup,
John Warrenf9606e92015-12-10 12:12:42 -05001136 security_groups_client=security_groups_client,
1137 **ruleset)
Masayuki Igawad9388762015-01-20 14:56:42 +09001138 except lib_exc.Conflict as ex:
Yair Fried1fc32a12014-08-04 09:11:30 +03001139 # if rule already exist - skip rule and continue
1140 msg = 'Security group rule already exists'
1141 if msg not in ex._error_string:
1142 raise ex
1143 else:
Steve Heyman33735f22016-05-24 09:28:08 -05001144 self.assertEqual(r_direction, sg_rule['direction'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001145 rules.append(sg_rule)
1146
1147 return rules
1148
Yair Frieddb6c9e92014-08-06 08:53:13 +03001149 def _get_router(self, client=None, tenant_id=None):
Yair Fried1fc32a12014-08-04 09:11:30 +03001150 """Retrieve a router for the given tenant id.
1151
1152 If a public router has been configured, it will be returned.
1153
1154 If a public router has not been configured, but a public
1155 network has, a tenant router will be created and returned that
1156 routes traffic to the public network.
1157 """
Yair Frieddb6c9e92014-08-06 08:53:13 +03001158 if not client:
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +00001159 client = self.routers_client
Yair Frieddb6c9e92014-08-06 08:53:13 +03001160 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +00001161 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001162 router_id = CONF.network.public_router_id
1163 network_id = CONF.network.public_network_id
1164 if router_id:
David Kranzca4c7e72015-05-27 11:39:19 -04001165 body = client.show_router(router_id)
Steve Heyman33735f22016-05-24 09:28:08 -05001166 return body['router']
Yair Fried1fc32a12014-08-04 09:11:30 +03001167 elif network_id:
Yair Frieddb6c9e92014-08-06 08:53:13 +03001168 router = self._create_router(client, tenant_id)
Steve Heyman33735f22016-05-24 09:28:08 -05001169 kwargs = {'external_gateway_info': dict(network_id=network_id)}
1170 router = client.update_router(router['id'], **kwargs)['router']
Yair Fried1fc32a12014-08-04 09:11:30 +03001171 return router
1172 else:
1173 raise Exception("Neither of 'public_router_id' or "
1174 "'public_network_id' has been defined.")
1175
Yair Frieddb6c9e92014-08-06 08:53:13 +03001176 def _create_router(self, client=None, tenant_id=None,
1177 namestart='router-smoke'):
1178 if not client:
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +00001179 client = self.routers_client
Yair Frieddb6c9e92014-08-06 08:53:13 +03001180 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +00001181 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001182 name = data_utils.rand_name(namestart)
David Kranz34e88122014-12-11 15:24:05 -05001183 result = client.create_router(name=name,
1184 admin_state_up=True,
1185 tenant_id=tenant_id)
Steve Heyman33735f22016-05-24 09:28:08 -05001186 router = result['router']
1187 self.assertEqual(router['name'], name)
1188 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
1189 client.delete_router,
1190 router['id'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001191 return router
1192
Alok Maurya6384bbb2014-07-13 06:44:29 -07001193 def _update_router_admin_state(self, router, admin_state_up):
Steve Heyman33735f22016-05-24 09:28:08 -05001194 kwargs = dict(admin_state_up=admin_state_up)
1195 router = self.routers_client.update_router(
1196 router['id'], **kwargs)['router']
1197 self.assertEqual(admin_state_up, router['admin_state_up'])
Alok Maurya6384bbb2014-07-13 06:44:29 -07001198
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -07001199 def create_networks(self, networks_client=None,
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +00001200 routers_client=None, subnets_client=None,
Markus Zoeller156b5da2016-07-11 18:10:31 +02001201 tenant_id=None, dns_nameservers=None,
1202 port_security_enabled=True):
Yair Fried1fc32a12014-08-04 09:11:30 +03001203 """Create a network with a subnet connected to a router.
1204
David Shrewsbury9bac3662014-08-07 15:07:01 -04001205 The baremetal driver is a special case since all nodes are
1206 on the same shared network.
1207
Yair Fried413bf2d2014-11-19 17:07:11 +02001208 :param tenant_id: id of tenant to create resources in.
1209 :param dns_nameservers: list of dns servers to send to subnet.
Yair Fried1fc32a12014-08-04 09:11:30 +03001210 :returns: network, subnet, router
1211 """
Thiago Paiva66cded22016-08-15 14:55:58 -03001212 if CONF.network.shared_physical_network:
David Shrewsbury9bac3662014-08-07 15:07:01 -04001213 # NOTE(Shrews): This exception is for environments where tenant
1214 # credential isolation is available, but network separation is
1215 # not (the current baremetal case). Likely can be removed when
1216 # test account mgmt is reworked:
1217 # https://blueprints.launchpad.net/tempest/+spec/test-accounts
Adam Gandelman878a5fd2015-03-30 14:33:36 -07001218 if not CONF.compute.fixed_network_name:
1219 m = 'fixed_network_name must be specified in config'
Matthew Treinish4217a702016-10-07 17:27:11 -04001220 raise lib_exc.InvalidConfiguration(m)
David Shrewsbury9bac3662014-08-07 15:07:01 -04001221 network = self._get_network_by_name(
1222 CONF.compute.fixed_network_name)
1223 router = None
1224 subnet = None
1225 else:
John Warren94d8faf2015-09-15 12:22:24 -04001226 network = self._create_network(
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -07001227 networks_client=networks_client,
Markus Zoeller156b5da2016-07-11 18:10:31 +02001228 tenant_id=tenant_id,
1229 port_security_enabled=port_security_enabled)
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +00001230 router = self._get_router(client=routers_client,
1231 tenant_id=tenant_id)
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -07001232 subnet_kwargs = dict(network=network,
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +00001233 subnets_client=subnets_client,
1234 routers_client=routers_client)
Yair Fried413bf2d2014-11-19 17:07:11 +02001235 # use explicit check because empty list is a valid option
1236 if dns_nameservers is not None:
1237 subnet_kwargs['dns_nameservers'] = dns_nameservers
1238 subnet = self._create_subnet(**subnet_kwargs)
Steve Heyman33735f22016-05-24 09:28:08 -05001239 if not routers_client:
1240 routers_client = self.routers_client
1241 router_id = router['id']
1242 routers_client.add_router_interface(router_id,
1243 subnet_id=subnet['id'])
1244
1245 # save a cleanup job to remove this association between
1246 # router and subnet
1247 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
1248 routers_client.remove_router_interface, router_id,
1249 subnet_id=subnet['id'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001250 return network, subnet, router
1251
1252
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001253class EncryptionScenarioTest(ScenarioTest):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001254 """Base class for encryption scenario tests"""
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001255
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001256 credentials = ['primary', 'admin']
David Kranz4cc852b2015-03-09 14:57:11 -04001257
1258 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001259 def setup_clients(cls):
1260 super(EncryptionScenarioTest, cls).setup_clients()
Jordan Pittierc3f76be2016-10-11 17:06:21 +02001261 if CONF.volume_feature_enabled.api_v2:
Ivan Kolodyazhnybcfc32e2015-08-06 13:31:36 +03001262 cls.admin_volume_types_client = cls.os_adm.volume_types_v2_client
Ken'ichi Ohmichia6ebf622016-08-25 11:52:27 -07001263 cls.admin_encryption_types_client =\
1264 cls.os_adm.encryption_types_v2_client
Jordan Pittierc3f76be2016-10-11 17:06:21 +02001265 else:
1266 cls.admin_volume_types_client = cls.os_adm.volume_types_client
1267 cls.admin_encryption_types_client =\
1268 cls.os_adm.encryption_types_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001269
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001270 def create_encryption_type(self, client=None, type_id=None, provider=None,
1271 key_size=None, cipher=None,
1272 control_location=None):
1273 if not client:
Ken'ichi Ohmichia6ebf622016-08-25 11:52:27 -07001274 client = self.admin_encryption_types_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001275 if not type_id:
1276 volume_type = self.create_volume_type()
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001277 type_id = volume_type['id']
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001278 LOG.debug("Creating an encryption type for volume type: %s", type_id)
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001279 client.create_encryption_type(
1280 type_id, provider=provider, key_size=key_size, cipher=cipher,
John Warrend053ded2015-08-13 15:22:48 +00001281 control_location=control_location)['encryption']
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001282
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001283
Masayuki Igawa0870db52015-09-18 21:08:36 +09001284class ObjectStorageScenarioTest(ScenarioTest):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001285 """Provide harness to do Object Storage scenario tests.
Chris Dent0d494112014-08-26 13:48:30 +01001286
1287 Subclasses implement the tests that use the methods provided by this
1288 class.
1289 """
1290
1291 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001292 def skip_checks(cls):
Masayuki Igawa0870db52015-09-18 21:08:36 +09001293 super(ObjectStorageScenarioTest, cls).skip_checks()
Chris Dent0d494112014-08-26 13:48:30 +01001294 if not CONF.service_available.swift:
1295 skip_msg = ("%s skipped as swift is not available" %
1296 cls.__name__)
1297 raise cls.skipException(skip_msg)
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001298
1299 @classmethod
1300 def setup_credentials(cls):
Masayuki Igawa60ea6c52014-10-15 17:32:14 +09001301 cls.set_network_resources()
Masayuki Igawa0870db52015-09-18 21:08:36 +09001302 super(ObjectStorageScenarioTest, cls).setup_credentials()
Matthew Treinish4a596932015-03-06 20:37:01 -05001303 operator_role = CONF.object_storage.operator_role
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +01001304 cls.os_operator = cls.get_client_manager(roles=[operator_role])
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001305
1306 @classmethod
1307 def setup_clients(cls):
Masayuki Igawa0870db52015-09-18 21:08:36 +09001308 super(ObjectStorageScenarioTest, cls).setup_clients()
Chris Dent0d494112014-08-26 13:48:30 +01001309 # Clients for Swift
Matthew Treinish8f268292015-02-24 20:01:36 -05001310 cls.account_client = cls.os_operator.account_client
1311 cls.container_client = cls.os_operator.container_client
1312 cls.object_client = cls.os_operator.object_client
Chris Dent0d494112014-08-26 13:48:30 +01001313
Chris Dentde456a12014-09-10 12:41:15 +01001314 def get_swift_stat(self):
Chris Dent0d494112014-08-26 13:48:30 +01001315 """get swift status for our user account."""
1316 self.account_client.list_account_containers()
1317 LOG.debug('Swift status information obtained successfully')
1318
Chris Dentde456a12014-09-10 12:41:15 +01001319 def create_container(self, container_name=None):
Chris Dent0d494112014-08-26 13:48:30 +01001320 name = container_name or data_utils.rand_name(
1321 'swift-scenario-container')
1322 self.container_client.create_container(name)
1323 # look for the container to assure it is created
Chris Dentde456a12014-09-10 12:41:15 +01001324 self.list_and_check_container_objects(name)
Jordan Pittier525ec712016-12-07 17:51:26 +01001325 LOG.debug('Container %s created', name)
Jordan Pittier9e227c52016-02-09 14:35:18 +01001326 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
Chris Dent1d4313a2014-10-28 12:16:48 +00001327 self.container_client.delete_container,
1328 name)
Chris Dent0d494112014-08-26 13:48:30 +01001329 return name
1330
Chris Dentde456a12014-09-10 12:41:15 +01001331 def delete_container(self, container_name):
Chris Dent0d494112014-08-26 13:48:30 +01001332 self.container_client.delete_container(container_name)
Jordan Pittier525ec712016-12-07 17:51:26 +01001333 LOG.debug('Container %s deleted', container_name)
Chris Dent0d494112014-08-26 13:48:30 +01001334
Chris Dentde456a12014-09-10 12:41:15 +01001335 def upload_object_to_container(self, container_name, obj_name=None):
Chris Dent0d494112014-08-26 13:48:30 +01001336 obj_name = obj_name or data_utils.rand_name('swift-scenario-object')
Jordan Pittierb84f2d42016-12-21 19:02:15 +01001337 obj_data = data_utils.random_bytes()
Chris Dent0d494112014-08-26 13:48:30 +01001338 self.object_client.create_object(container_name, obj_name, obj_data)
Jordan Pittier9e227c52016-02-09 14:35:18 +01001339 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
Chris Dent1d4313a2014-10-28 12:16:48 +00001340 self.object_client.delete_object,
1341 container_name,
1342 obj_name)
Chris Dent0d494112014-08-26 13:48:30 +01001343 return obj_name, obj_data
1344
Chris Dentde456a12014-09-10 12:41:15 +01001345 def delete_object(self, container_name, filename):
Chris Dent0d494112014-08-26 13:48:30 +01001346 self.object_client.delete_object(container_name, filename)
Chris Dentde456a12014-09-10 12:41:15 +01001347 self.list_and_check_container_objects(container_name,
1348 not_present_obj=[filename])
Chris Dent0d494112014-08-26 13:48:30 +01001349
Chris Dentde456a12014-09-10 12:41:15 +01001350 def list_and_check_container_objects(self, container_name,
1351 present_obj=None,
1352 not_present_obj=None):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001353 # List objects for a given container and assert which are present and
1354 # which are not.
Ghanshyam2a180b82014-06-16 13:54:22 +09001355 if present_obj is None:
1356 present_obj = []
1357 if not_present_obj is None:
1358 not_present_obj = []
Chris Dent0d494112014-08-26 13:48:30 +01001359 _, object_list = self.container_client.list_container_contents(
1360 container_name)
1361 if present_obj:
1362 for obj in present_obj:
1363 self.assertIn(obj, object_list)
1364 if not_present_obj:
1365 for obj in not_present_obj:
1366 self.assertNotIn(obj, object_list)
1367
Chris Dentde456a12014-09-10 12:41:15 +01001368 def change_container_acl(self, container_name, acl):
Chris Dent0d494112014-08-26 13:48:30 +01001369 metadata_param = {'metadata_prefix': 'x-container-',
1370 'metadata': {'read': acl}}
1371 self.container_client.update_container_metadata(container_name,
1372 **metadata_param)
1373 resp, _ = self.container_client.list_container_metadata(container_name)
1374 self.assertEqual(resp['x-container-read'], acl)
1375
Chris Dentde456a12014-09-10 12:41:15 +01001376 def download_and_verify(self, container_name, obj_name, expected_data):
Chris Dent0d494112014-08-26 13:48:30 +01001377 _, obj = self.object_client.get_object(container_name, obj_name)
1378 self.assertEqual(obj, expected_data)