blob: f25ab1d66adf5f72e652d7c13a605ec5066d1984 [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)
82 cls.volumes_client = cls.os_primary.volumes_v2_client
83 cls.snapshots_client = cls.os_primary.snapshots_v2_client
Ivan Kolodyazhnybcfc32e2015-08-06 13:31:36 +030084
Jordan Pittierf672b7d2016-06-20 18:50:40 +020085 # ## Test functions library
86 #
87 # The create_[resource] functions only return body and discard the
88 # resp part which is not used in scenario tests
Andrea Frittoli247058f2014-07-16 16:09:22 +010089
Lenny Verkhovsky136376f2016-06-29 14:33:34 +030090 def _create_port(self, network_id, client=None, namestart='port-quotatest',
91 **kwargs):
92 if not client:
93 client = self.ports_client
94 name = data_utils.rand_name(namestart)
95 result = client.create_port(
96 name=name,
97 network_id=network_id,
98 **kwargs)
99 self.assertIsNotNone(result, 'Unable to allocate port')
100 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
lanoux5fc14522015-09-21 08:17:35 +0000148 create_port_body = {'binding:vnic_type': vnic_type,
149 'namestart': 'port-smoke'}
150 if kwargs:
151 # Convert security group names to security group ids
152 # to pass to create_port
153 if 'security_groups' in kwargs:
Thiago Paiva66cded22016-08-15 14:55:58 -0300154 security_groups = \
John Warrenf9606e92015-12-10 12:12:42 -0500155 clients.security_groups_client.list_security_groups(
lanoux5fc14522015-09-21 08:17:35 +0000156 ).get('security_groups')
157 sec_dict = dict([(s['name'], s['id'])
158 for s in security_groups])
159
160 sec_groups_names = [s['name'] for s in kwargs.pop(
161 'security_groups')]
162 security_groups_ids = [sec_dict[s]
163 for s in sec_groups_names]
164
165 if security_groups_ids:
166 create_port_body[
167 'security_groups'] = security_groups_ids
Lenny Verkhovsky69363502016-07-17 16:33:33 +0300168 networks = kwargs.pop('networks', [])
169 else:
170 networks = []
lanoux5fc14522015-09-21 08:17:35 +0000171
172 # If there are no networks passed to us we look up
Lenny Verkhovsky136376f2016-06-29 14:33:34 +0300173 # for the project's private networks and create a port.
174 # The same behaviour as we would expect when passing
175 # the call to the clients with no networks
lanoux5fc14522015-09-21 08:17:35 +0000176 if not networks:
177 networks = clients.networks_client.list_networks(
Lenny Verkhovsky136376f2016-06-29 14:33:34 +0300178 **{'router:external': False, 'fields': 'id'})['networks']
179
180 # It's net['uuid'] if networks come from kwargs
181 # and net['id'] if they come from
182 # clients.networks_client.list_networks
lanoux5fc14522015-09-21 08:17:35 +0000183 for net in networks:
Lenny Verkhovsky97f7cea2016-08-15 13:29:48 +0000184 net_id = net.get('uuid', net.get('id'))
Lenny Verkhovsky69363502016-07-17 16:33:33 +0300185 if 'port' not in net:
186 port = self._create_port(network_id=net_id,
187 client=clients.ports_client,
188 **create_port_body)
189 ports.append({'port': port['id']})
190 else:
191 ports.append({'port': net['port']})
lanoux5fc14522015-09-21 08:17:35 +0000192 if ports:
193 kwargs['networks'] = ports
194 self.ports = ports
195
196 tenant_network = self.get_tenant_network()
197
Ferenc Horváthbce1fcf2017-06-07 11:19:51 +0200198 body, _ = compute.create_test_server(
lanoux5fc14522015-09-21 08:17:35 +0000199 clients,
200 tenant_network=tenant_network,
201 wait_until=wait_until,
Anusha Ramineni9aaef8b2016-01-19 10:56:40 +0530202 name=name, flavor=flavor,
203 image_id=image_id, **kwargs)
lanoux5fc14522015-09-21 08:17:35 +0000204
Jordan Pittierf672b7d2016-06-20 18:50:40 +0200205 self.addCleanup(waiters.wait_for_server_termination,
206 clients.servers_client, body['id'])
207 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
208 clients.servers_client.delete_server, body['id'])
lanoux5fc14522015-09-21 08:17:35 +0000209 server = clients.servers_client.show_server(body['id'])['server']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100210 return server
211
Markus Zoeller3d2a21c2015-02-27 12:04:22 +0100212 def create_volume(self, size=None, name=None, snapshot_id=None,
Jordan Pittier5e1741c2016-03-02 18:25:51 +0100213 imageRef=None, volume_type=None):
Ken'ichi Ohmichiadb905e2016-08-26 15:16:23 -0700214 if size is None:
215 size = CONF.volume.volume_size
Nuno Santosb746d992016-11-17 15:41:55 -0500216 if imageRef:
217 image = self.compute_images_client.show_image(imageRef)['image']
218 min_disk = image.get('minDisk')
219 size = max(size, min_disk)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100220 if name is None:
zhuflf9d95722016-10-19 16:06:17 +0800221 name = data_utils.rand_name(self.__class__.__name__ + "-volume")
Ghanshyam8fc0ed22015-12-18 10:25:14 +0900222 kwargs = {'display_name': name,
223 'snapshot_id': snapshot_id,
224 'imageRef': imageRef,
Ken'ichi Ohmichiadb905e2016-08-26 15:16:23 -0700225 'volume_type': volume_type,
226 'size': size}
Ghanshyam8fc0ed22015-12-18 10:25:14 +0900227 volume = self.volumes_client.create_volume(**kwargs)['volume']
Matt Riedemanne85c2702014-09-10 11:50:13 -0700228
Jordan Pittier5e1741c2016-03-02 18:25:51 +0100229 self.addCleanup(self.volumes_client.wait_for_resource_deletion,
230 volume['id'])
Jordan Pittier9e227c52016-02-09 14:35:18 +0100231 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
Jordan Pittier5e1741c2016-03-02 18:25:51 +0100232 self.volumes_client.delete_volume, volume['id'])
lkuchlan5cbc00a2017-03-26 11:49:54 +0300233 self.assertEqual(name, volume['name'])
lkuchlan52d7b0d2016-11-07 20:53:19 +0200234 waiters.wait_for_volume_resource_status(self.volumes_client,
235 volume['id'], 'available')
Andrea Frittoli247058f2014-07-16 16:09:22 +0100236 # The volume retrieved on creation has a non-up-to-date status.
237 # Retrieval after it becomes active ensures correct details.
John Warren6177c9e2015-08-19 20:00:17 +0000238 volume = self.volumes_client.show_volume(volume['id'])['volume']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100239 return volume
240
scottda61f68ac2016-06-07 12:07:55 -0600241 def create_volume_type(self, client=None, name=None, backend_name=None):
242 if not client:
243 client = self.admin_volume_types_client
244 if not name:
245 class_name = self.__class__.__name__
246 name = data_utils.rand_name(class_name + '-volume-type')
247 randomized_name = data_utils.rand_name('scenario-type-' + name)
248
249 LOG.debug("Creating a volume type: %s on backend %s",
250 randomized_name, backend_name)
251 extra_specs = {}
252 if backend_name:
253 extra_specs = {"volume_backend_name": backend_name}
254
255 body = client.create_volume_type(name=randomized_name,
256 extra_specs=extra_specs)
257 volume_type = body['volume_type']
258 self.assertIn('id', volume_type)
259 self.addCleanup(client.delete_volume_type, volume_type['id'])
260 return volume_type
261
Yair Fried1fc32a12014-08-04 09:11:30 +0300262 def _create_loginable_secgroup_rule(self, secgroup_id=None):
John Warrenf2345512015-12-10 13:39:30 -0500263 _client = self.compute_security_groups_client
John Warren5cdbf422016-01-05 12:42:43 -0500264 _client_rules = self.compute_security_group_rules_client
Andrea Frittoli247058f2014-07-16 16:09:22 +0100265 if secgroup_id is None:
ghanshyamb610b772015-08-24 17:29:38 +0900266 sgs = _client.list_security_groups()['security_groups']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100267 for sg in sgs:
268 if sg['name'] == 'default':
269 secgroup_id = sg['id']
270
271 # These rules are intended to permit inbound ssh and icmp
272 # traffic from all sources, so no group_id is provided.
273 # Setting a group_id would only permit traffic from ports
274 # belonging to the same security group.
275 rulesets = [
276 {
277 # ssh
Ken'ichi Ohmichieb7eeec2015-07-21 01:00:06 +0000278 'ip_protocol': 'tcp',
Andrea Frittoli247058f2014-07-16 16:09:22 +0100279 'from_port': 22,
280 'to_port': 22,
281 'cidr': '0.0.0.0/0',
282 },
283 {
284 # ping
Ken'ichi Ohmichieb7eeec2015-07-21 01:00:06 +0000285 'ip_protocol': 'icmp',
Andrea Frittoli247058f2014-07-16 16:09:22 +0100286 'from_port': -1,
287 'to_port': -1,
288 'cidr': '0.0.0.0/0',
289 }
290 ]
291 rules = list()
292 for ruleset in rulesets:
Ken'ichi Ohmichieb7eeec2015-07-21 01:00:06 +0000293 sg_rule = _client_rules.create_security_group_rule(
ghanshyam0a5e1232015-08-24 16:59:59 +0900294 parent_group_id=secgroup_id, **ruleset)['security_group_rule']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100295 rules.append(sg_rule)
296 return rules
297
Yair Fried1fc32a12014-08-04 09:11:30 +0300298 def _create_security_group(self):
Andrea Frittoli247058f2014-07-16 16:09:22 +0100299 # Create security group
300 sg_name = data_utils.rand_name(self.__class__.__name__)
301 sg_desc = sg_name + " description"
John Warrenf2345512015-12-10 13:39:30 -0500302 secgroup = self.compute_security_groups_client.create_security_group(
ghanshyamb610b772015-08-24 17:29:38 +0900303 name=sg_name, description=sg_desc)['security_group']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100304 self.assertEqual(secgroup['name'], sg_name)
305 self.assertEqual(secgroup['description'], sg_desc)
John Warrenf2345512015-12-10 13:39:30 -0500306 self.addCleanup(
Jordan Pittier9e227c52016-02-09 14:35:18 +0100307 test_utils.call_and_ignore_notfound_exc,
John Warrenf2345512015-12-10 13:39:30 -0500308 self.compute_security_groups_client.delete_security_group,
309 secgroup['id'])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100310
311 # Add rules to the security group
Yair Fried1fc32a12014-08-04 09:11:30 +0300312 self._create_loginable_secgroup_rule(secgroup['id'])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100313
314 return secgroup
315
Sean Dague20e98612016-01-06 14:33:28 -0500316 def get_remote_client(self, ip_address, username=None, private_key=None):
JordanP3fe2dc32014-11-17 13:06:01 +0100317 """Get a SSH client to a remote server
318
Sean Dague20e98612016-01-06 14:33:28 -0500319 @param ip_address the server floating or fixed IP address to use
320 for ssh validation
JordanP3fe2dc32014-11-17 13:06:01 +0100321 @param username name of the Linux account on the remote server
322 @param private_key the SSH private key to use
JordanP3fe2dc32014-11-17 13:06:01 +0100323 @return a RemoteClient object
324 """
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700325
Andrea Frittoli247058f2014-07-16 16:09:22 +0100326 if username is None:
lanoux283273b2015-12-04 03:01:54 -0800327 username = CONF.validation.image_ssh_user
wantwatering896300c2015-03-27 15:17:42 +0800328 # Set this with 'keypair' or others to log in with keypair or
329 # username/password.
lanoux5fc14522015-09-21 08:17:35 +0000330 if CONF.validation.auth_method == 'keypair':
wantwatering896300c2015-03-27 15:17:42 +0800331 password = None
332 if private_key is None:
333 private_key = self.keypair['private_key']
334 else:
lanoux283273b2015-12-04 03:01:54 -0800335 password = CONF.validation.image_ssh_password
wantwatering896300c2015-03-27 15:17:42 +0800336 private_key = None
Sean Dague20e98612016-01-06 14:33:28 -0500337 linux_client = remote_client.RemoteClient(ip_address, username,
wantwatering896300c2015-03-27 15:17:42 +0800338 pkey=private_key,
339 password=password)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100340 try:
341 linux_client.validate_authentication()
Matt Riedemann5f0ac522015-05-21 09:16:24 -0700342 except Exception as e:
343 message = ('Initializing SSH connection to %(ip)s failed. '
Eric Brown0911af62016-02-08 17:15:40 -0800344 'Error: %(error)s' % {'ip': ip_address,
Sean Dague20e98612016-01-06 14:33:28 -0500345 'error': e})
Jordan Pittier9e227c52016-02-09 14:35:18 +0100346 caller = test_utils.find_test_caller()
Matt Riedemann5f0ac522015-05-21 09:16:24 -0700347 if caller:
348 message = '(%s) %s' % (caller, message)
349 LOG.exception(message)
Sean Dague2c98a162016-01-06 14:11:13 -0500350 self._log_console_output()
Andrea Frittoli247058f2014-07-16 16:09:22 +0100351 raise
352
353 return linux_client
354
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000355 def _image_create(self, name, fmt, path,
356 disk_format=None, properties=None):
Ghanshyam2a180b82014-06-16 13:54:22 +0900357 if properties is None:
358 properties = {}
Andrea Frittoli247058f2014-07-16 16:09:22 +0100359 name = data_utils.rand_name('%s-' % name)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100360 params = {
361 'name': name,
362 'container_format': fmt,
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000363 'disk_format': disk_format or fmt,
Andrea Frittoli247058f2014-07-16 16:09:22 +0100364 }
Matt Riedemann2aa19d42016-06-06 17:45:41 -0400365 if CONF.image_feature_enabled.api_v1:
366 params['is_public'] = 'False'
367 params['properties'] = properties
Ken'ichi Ohmichi02bcdf32016-06-17 16:41:26 -0700368 params = {'headers': common_image.image_meta_to_headers(**params)}
Matt Riedemann2aa19d42016-06-06 17:45:41 -0400369 else:
370 params['visibility'] = 'private'
371 # Additional properties are flattened out in the v2 API.
372 params.update(properties)
373 body = self.image_client.create_image(**params)
374 image = body['image'] if 'image' in body else body
Andrea Frittoli247058f2014-07-16 16:09:22 +0100375 self.addCleanup(self.image_client.delete_image, image['id'])
376 self.assertEqual("queued", image['status'])
zhang.leia4b1cef2016-03-01 10:50:01 +0800377 with open(path, 'rb') as image_file:
Matt Riedemann2aa19d42016-06-06 17:45:41 -0400378 if CONF.image_feature_enabled.api_v1:
379 self.image_client.update_image(image['id'], data=image_file)
380 else:
381 self.image_client.store_image_file(image['id'], image_file)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100382 return image['id']
383
384 def glance_image_create(self):
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300385 img_path = CONF.scenario.img_dir + "/" + CONF.scenario.img_file
Andrea Frittoli247058f2014-07-16 16:09:22 +0100386 aki_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.aki_img_file
387 ari_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.ari_img_file
388 ami_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.ami_img_file
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300389 img_container_format = CONF.scenario.img_container_format
390 img_disk_format = CONF.scenario.img_disk_format
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000391 img_properties = CONF.scenario.img_properties
PranaliD2aa523c2016-06-07 03:54:34 -0400392 LOG.debug("paths: img: %s, container_format: %s, disk_format: %s, "
Jordan Pittier525ec712016-12-07 17:51:26 +0100393 "properties: %s, ami: %s, ari: %s, aki: %s",
394 img_path, img_container_format, img_disk_format,
395 img_properties, ami_img_path, ari_img_path, aki_img_path)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100396 try:
Jordan Pittier1e443ec2015-11-20 16:15:58 +0100397 image = self._image_create('scenario-img',
398 img_container_format,
399 img_path,
400 disk_format=img_disk_format,
401 properties=img_properties)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100402 except IOError:
403 LOG.debug("A qcow2 image was not found. Try to get a uec image.")
404 kernel = self._image_create('scenario-aki', 'aki', aki_img_path)
405 ramdisk = self._image_create('scenario-ari', 'ari', ari_img_path)
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000406 properties = {'kernel_id': kernel, 'ramdisk_id': ramdisk}
Jordan Pittier1e443ec2015-11-20 16:15:58 +0100407 image = self._image_create('scenario-ami', 'ami',
408 path=ami_img_path,
409 properties=properties)
Jordan Pittier525ec712016-12-07 17:51:26 +0100410 LOG.debug("image:%s", image)
Jordan Pittier1e443ec2015-11-20 16:15:58 +0100411
412 return image
Andrea Frittoli247058f2014-07-16 16:09:22 +0100413
Ihar Hrachyshkaa9dca2b2017-04-04 14:17:11 -0700414 def _log_console_output(self, servers=None, client=None):
Matthew Treinish42a3f3a2014-09-04 15:04:53 -0400415 if not CONF.compute_feature_enabled.console_output:
416 LOG.debug('Console output not supported, cannot log')
417 return
Ihar Hrachyshkaa9dca2b2017-04-04 14:17:11 -0700418 client = client or self.servers_client
Andrea Frittoli247058f2014-07-16 16:09:22 +0100419 if not servers:
Ihar Hrachyshkaa9dca2b2017-04-04 14:17:11 -0700420 servers = client.list_servers()
Andrea Frittoli247058f2014-07-16 16:09:22 +0100421 servers = servers['servers']
422 for server in servers:
Attila Fazekas9a5a1122016-11-08 10:24:57 +0100423 try:
Ihar Hrachyshkaa9dca2b2017-04-04 14:17:11 -0700424 console_output = client.get_console_output(
Attila Fazekas9a5a1122016-11-08 10:24:57 +0100425 server['id'])['output']
426 LOG.debug('Console output for %s\nbody=\n%s',
427 server['id'], console_output)
428 except lib_exc.NotFound:
Attila Fazekase1360482016-11-10 11:28:08 +0100429 LOG.debug("Server %s disappeared(deleted) while looking "
Attila Fazekas9a5a1122016-11-08 10:24:57 +0100430 "for the console log", server['id'])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100431
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000432 def _log_net_info(self, exc):
433 # network debug is called as part of ssh init
Andrey Pavlov64723762015-04-29 06:24:58 +0300434 if not isinstance(exc, lib_exc.SSHTimeout):
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000435 LOG.debug('Network information on a devstack host')
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000436
nithya-ganesan882595e2014-07-29 18:51:07 +0000437 def create_server_snapshot(self, server, name=None):
438 # Glance client
439 _image_client = self.image_client
440 # Compute client
Ghanshyamae76c122015-12-22 13:41:35 +0900441 _images_client = self.compute_images_client
nithya-ganesan882595e2014-07-29 18:51:07 +0000442 if name is None:
zhuflf9d95722016-10-19 16:06:17 +0800443 name = data_utils.rand_name(self.__class__.__name__ + 'snapshot')
nithya-ganesan882595e2014-07-29 18:51:07 +0000444 LOG.debug("Creating a snapshot image for server: %s", server['name'])
Ken'ichi Ohmichi28f18672015-07-17 10:00:38 +0000445 image = _images_client.create_image(server['id'], name=name)
David Kranza5299eb2015-01-15 17:24:05 -0500446 image_id = image.response['location'].split('images/')[1]
Yaroslav Lobankov2fea4052016-04-19 15:05:57 +0300447 waiters.wait_for_image_status(_image_client, image_id, 'active')
Jordan Pittierf672b7d2016-06-20 18:50:40 +0200448
449 self.addCleanup(_image_client.wait_for_resource_deletion,
450 image_id)
451 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
452 _image_client.delete_image, image_id)
453
Matt Riedemann2aa19d42016-06-06 17:45:41 -0400454 if CONF.image_feature_enabled.api_v1:
455 # In glance v1 the additional properties are stored in the headers.
Ken'ichi Ohmichi01151e82016-06-10 11:19:52 -0700456 resp = _image_client.check_image(image_id)
457 snapshot_image = common_image.get_image_meta_from_headers(resp)
Matt Riedemann2aa19d42016-06-06 17:45:41 -0400458 image_props = snapshot_image.get('properties', {})
459 else:
460 # In glance v2 the additional properties are flattened.
461 snapshot_image = _image_client.show_image(image_id)
462 image_props = snapshot_image
Andrey Pavlovc8bd4b12015-08-17 10:20:17 +0300463
Matt Riedemann2aa19d42016-06-06 17:45:41 -0400464 bdm = image_props.get('block_device_mapping')
Andrey Pavlovc8bd4b12015-08-17 10:20:17 +0300465 if bdm:
466 bdm = json.loads(bdm)
467 if bdm and 'snapshot_id' in bdm[0]:
468 snapshot_id = bdm[0]['snapshot_id']
469 self.addCleanup(
470 self.snapshots_client.wait_for_resource_deletion,
471 snapshot_id)
Jordan Pittier9e227c52016-02-09 14:35:18 +0100472 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
473 self.snapshots_client.delete_snapshot,
474 snapshot_id)
lkuchlan52d7b0d2016-11-07 20:53:19 +0200475 waiters.wait_for_volume_resource_status(self.snapshots_client,
476 snapshot_id,
477 'available')
nithya-ganesan882595e2014-07-29 18:51:07 +0000478 image_name = snapshot_image['name']
479 self.assertEqual(name, image_name)
480 LOG.debug("Created snapshot image %s for server %s",
481 image_name, server['name'])
482 return snapshot_image
483
Jordan Pittier7cf64762015-10-14 15:01:12 +0200484 def nova_volume_attach(self, server, volume_to_attach):
Joseph Lanoux6809bab2014-12-18 14:57:18 +0000485 volume = self.servers_client.attach_volume(
Jordan Pittier7cf64762015-10-14 15:01:12 +0200486 server['id'], volumeId=volume_to_attach['id'], device='/dev/%s'
ghanshyam0f825252015-08-25 16:02:50 +0900487 % CONF.compute.volume_device_name)['volumeAttachment']
Jordan Pittier7cf64762015-10-14 15:01:12 +0200488 self.assertEqual(volume_to_attach['id'], volume['id'])
lkuchlan52d7b0d2016-11-07 20:53:19 +0200489 waiters.wait_for_volume_resource_status(self.volumes_client,
490 volume['id'], 'in-use')
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900491
Jordan Pittier7cf64762015-10-14 15:01:12 +0200492 # Return the updated volume after the attachment
493 return self.volumes_client.show_volume(volume['id'])['volume']
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900494
Jordan Pittier7cf64762015-10-14 15:01:12 +0200495 def nova_volume_detach(self, server, volume):
496 self.servers_client.detach_volume(server['id'], volume['id'])
lkuchlan52d7b0d2016-11-07 20:53:19 +0200497 waiters.wait_for_volume_resource_status(self.volumes_client,
498 volume['id'], 'available')
Jordan Pittier7cf64762015-10-14 15:01:12 +0200499
500 volume = self.volumes_client.show_volume(volume['id'])['volume']
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900501 self.assertEqual('available', volume['status'])
502
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700503 def rebuild_server(self, server_id, image=None,
504 preserve_ephemeral=False, wait=True,
505 rebuild_kwargs=None):
506 if image is None:
507 image = CONF.compute.image_ref
508
509 rebuild_kwargs = rebuild_kwargs or {}
510
511 LOG.debug("Rebuilding server (id: %s, image: %s, preserve eph: %s)",
512 server_id, image, preserve_ephemeral)
Ken'ichi Ohmichi5271b0f2015-08-10 07:53:27 +0000513 self.servers_client.rebuild_server(
514 server_id=server_id, image_ref=image,
515 preserve_ephemeral=preserve_ephemeral,
516 **rebuild_kwargs)
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700517 if wait:
Ken'ichi Ohmichi0eb153c2015-07-13 02:18:25 +0000518 waiters.wait_for_server_status(self.servers_client,
519 server_id, 'ACTIVE')
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700520
Steven Hardyda2a8352014-10-02 12:52:20 +0100521 def ping_ip_address(self, ip_address, should_succeed=True,
Ihar Hrachyshkaf9227c02016-09-15 11:16:47 +0000522 ping_timeout=None, mtu=None):
lanoux5fc14522015-09-21 08:17:35 +0000523 timeout = ping_timeout or CONF.validation.ping_timeout
Ihar Hrachyshkaf9227c02016-09-15 11:16:47 +0000524 cmd = ['ping', '-c1', '-w1']
525
526 if mtu:
527 cmd += [
528 # don't fragment
529 '-M', 'do',
530 # ping receives just the size of ICMP payload
531 '-s', str(net_utils.get_ping_payload_size(mtu, 4))
532 ]
533 cmd.append(ip_address)
Aaron Rosena7df13b2014-09-23 09:45:45 -0700534
535 def ping():
536 proc = subprocess.Popen(cmd,
537 stdout=subprocess.PIPE,
538 stderr=subprocess.PIPE)
539 proc.communicate()
Shuquan Huang753629e2015-07-20 08:52:29 +0000540
Aaron Rosena7df13b2014-09-23 09:45:45 -0700541 return (proc.returncode == 0) == should_succeed
542
Jordan Pittier9e227c52016-02-09 14:35:18 +0100543 caller = test_utils.find_test_caller()
Shuquan Huang753629e2015-07-20 08:52:29 +0000544 LOG.debug('%(caller)s begins to ping %(ip)s in %(timeout)s sec and the'
John L. Villalovosa898aec2017-01-13 14:46:46 -0800545 ' expected result is %(should_succeed)s', {
Shuquan Huang753629e2015-07-20 08:52:29 +0000546 'caller': caller, 'ip': ip_address, 'timeout': timeout,
547 'should_succeed':
548 'reachable' if should_succeed else 'unreachable'
549 })
Jordan Pittier35a63752016-08-30 13:09:12 +0200550 result = test_utils.call_until_true(ping, timeout, 1)
Shuquan Huang753629e2015-07-20 08:52:29 +0000551 LOG.debug('%(caller)s finishes ping %(ip)s in %(timeout)s sec and the '
John L. Villalovosa898aec2017-01-13 14:46:46 -0800552 'ping result is %(result)s', {
Shuquan Huang753629e2015-07-20 08:52:29 +0000553 'caller': caller, 'ip': ip_address, 'timeout': timeout,
554 'result': 'expected' if result else 'unexpected'
555 })
556 return result
Aaron Rosena7df13b2014-09-23 09:45:45 -0700557
Yair Friedae0e73d2014-11-24 11:56:26 +0200558 def check_vm_connectivity(self, ip_address,
559 username=None,
560 private_key=None,
Ihar Hrachyshkaf9227c02016-09-15 11:16:47 +0000561 should_connect=True,
562 mtu=None):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000563 """Check server connectivity
564
Yair Friedae0e73d2014-11-24 11:56:26 +0200565 :param ip_address: server to test against
566 :param username: server's ssh username
567 :param private_key: server's ssh private key to be used
568 :param should_connect: True/False indicates positive/negative test
569 positive - attempt ping and ssh
570 negative - attempt ping and fail if succeed
Ihar Hrachyshkaf9227c02016-09-15 11:16:47 +0000571 :param mtu: network MTU to use for connectivity validation
Yair Friedae0e73d2014-11-24 11:56:26 +0200572
573 :raises: AssertError if the result of the connectivity check does
574 not match the value of the should_connect param
575 """
576 if should_connect:
577 msg = "Timed out waiting for %s to become reachable" % ip_address
578 else:
579 msg = "ip address %s is reachable" % ip_address
580 self.assertTrue(self.ping_ip_address(ip_address,
Ihar Hrachyshkaf9227c02016-09-15 11:16:47 +0000581 should_succeed=should_connect,
582 mtu=mtu),
Yair Friedae0e73d2014-11-24 11:56:26 +0200583 msg=msg)
584 if should_connect:
585 # no need to check ssh for negative connectivity
586 self.get_remote_client(ip_address, username, private_key)
587
588 def check_public_network_connectivity(self, ip_address, username,
589 private_key, should_connect=True,
Ihar Hrachyshkaf9227c02016-09-15 11:16:47 +0000590 msg=None, servers=None, mtu=None):
Yair Friedae0e73d2014-11-24 11:56:26 +0200591 # The target login is assumed to have been configured for
592 # key-based authentication by cloud-init.
Jordan Pittier525ec712016-12-07 17:51:26 +0100593 LOG.debug('checking network connections to IP %s with user: %s',
594 ip_address, username)
Yair Friedae0e73d2014-11-24 11:56:26 +0200595 try:
596 self.check_vm_connectivity(ip_address,
597 username,
598 private_key,
Ihar Hrachyshkaf9227c02016-09-15 11:16:47 +0000599 should_connect=should_connect,
600 mtu=mtu)
Matthew Treinish53483132014-12-09 18:50:06 -0500601 except Exception:
Yair Friedae0e73d2014-11-24 11:56:26 +0200602 ex_msg = 'Public network connectivity check failed'
603 if msg:
604 ex_msg += ": " + msg
605 LOG.exception(ex_msg)
606 self._log_console_output(servers)
Yair Friedae0e73d2014-11-24 11:56:26 +0200607 raise
608
609 def create_floating_ip(self, thing, pool_name=None):
Ken'ichi Ohmichia112a592015-11-17 08:49:37 +0000610 """Create a floating IP and associates to a server on Nova"""
Yair Friedae0e73d2014-11-24 11:56:26 +0200611
Marc Koderer3b57d802016-03-22 15:23:31 +0100612 if not pool_name:
613 pool_name = CONF.network.floating_network_name
John Warrene74890a2015-11-11 15:18:01 -0500614 floating_ip = (self.compute_floating_ips_client.
Ken'ichi Ohmichie037a6f2015-12-03 06:41:49 +0000615 create_floating_ip(pool=pool_name)['floating_ip'])
Jordan Pittier9e227c52016-02-09 14:35:18 +0100616 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
John Warrene74890a2015-11-11 15:18:01 -0500617 self.compute_floating_ips_client.delete_floating_ip,
Yair Friedae0e73d2014-11-24 11:56:26 +0200618 floating_ip['id'])
John Warrene74890a2015-11-11 15:18:01 -0500619 self.compute_floating_ips_client.associate_floating_ip_to_server(
Yair Friedae0e73d2014-11-24 11:56:26 +0200620 floating_ip['ip'], thing['id'])
621 return floating_ip
622
Sean Dague20e98612016-01-06 14:33:28 -0500623 def create_timestamp(self, ip_address, dev_name=None, mount_path='/mnt',
Matt Riedemannfd5657d2015-09-30 14:47:07 -0700624 private_key=None):
Sean Dague20e98612016-01-06 14:33:28 -0500625 ssh_client = self.get_remote_client(ip_address,
Matt Riedemannfd5657d2015-09-30 14:47:07 -0700626 private_key=private_key)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300627 if dev_name is not None:
628 ssh_client.make_fs(dev_name)
Ken'ichi Ohmichi4e5a69e2017-03-01 18:15:29 -0800629 ssh_client.exec_command('sudo mount /dev/%s %s' % (dev_name,
630 mount_path))
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300631 cmd_timestamp = 'sudo sh -c "date > %s/timestamp; sync"' % mount_path
632 ssh_client.exec_command(cmd_timestamp)
633 timestamp = ssh_client.exec_command('sudo cat %s/timestamp'
634 % mount_path)
635 if dev_name is not None:
Ken'ichi Ohmichi4e5a69e2017-03-01 18:15:29 -0800636 ssh_client.exec_command('sudo umount %s' % mount_path)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300637 return timestamp
638
Sean Dague20e98612016-01-06 14:33:28 -0500639 def get_timestamp(self, ip_address, dev_name=None, mount_path='/mnt',
Matt Riedemannfd5657d2015-09-30 14:47:07 -0700640 private_key=None):
Sean Dague20e98612016-01-06 14:33:28 -0500641 ssh_client = self.get_remote_client(ip_address,
Matt Riedemannfd5657d2015-09-30 14:47:07 -0700642 private_key=private_key)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300643 if dev_name is not None:
Matt Riedemann076685a2015-09-30 14:38:16 -0700644 ssh_client.mount(dev_name, mount_path)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300645 timestamp = ssh_client.exec_command('sudo cat %s/timestamp'
646 % mount_path)
647 if dev_name is not None:
Ken'ichi Ohmichi4e5a69e2017-03-01 18:15:29 -0800648 ssh_client.exec_command('sudo umount %s' % mount_path)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300649 return timestamp
650
Sean Dague20e98612016-01-06 14:33:28 -0500651 def get_server_ip(self, server):
652 """Get the server fixed or floating IP.
653
654 Based on the configuration we're in, return a correct ip
655 address for validating that a guest is up.
656 """
Alexander Gubanovc8829f82015-11-12 10:35:13 +0200657 if CONF.validation.connect_method == 'floating':
Sean Dague20e98612016-01-06 14:33:28 -0500658 # The tests calling this method don't have a floating IP
zhufl0892cb22016-05-06 14:46:00 +0800659 # and can't make use of the validation resources. So the
Sean Dague20e98612016-01-06 14:33:28 -0500660 # method is creating the floating IP there.
661 return self.create_floating_ip(server)['ip']
662 elif CONF.validation.connect_method == 'fixed':
Matt Riedemanna7782552016-08-08 16:26:01 -0400663 # Determine the network name to look for based on config or creds
664 # provider network resources.
665 if CONF.validation.network_for_ssh:
666 addresses = server['addresses'][
667 CONF.validation.network_for_ssh]
668 else:
669 creds_provider = self._get_credentials_provider()
670 net_creds = creds_provider.get_primary_creds()
671 network = getattr(net_creds, 'network', None)
672 addresses = (server['addresses'][network['name']]
673 if network else [])
Sean Dague20e98612016-01-06 14:33:28 -0500674 for address in addresses:
Matt Riedemanna7782552016-08-08 16:26:01 -0400675 if (address['version'] == CONF.validation.ip_version_for_ssh
676 and address['OS-EXT-IPS:type'] == 'fixed'):
Sean Dague20e98612016-01-06 14:33:28 -0500677 return address['addr']
zhufl955f82b2016-07-22 11:14:34 +0800678 raise exceptions.ServerUnreachable(server_id=server['id'])
Alexander Gubanovc8829f82015-11-12 10:35:13 +0200679 else:
Matthew Treinish4217a702016-10-07 17:27:11 -0400680 raise lib_exc.InvalidConfiguration()
Alexander Gubanovc8829f82015-11-12 10:35:13 +0200681
Andrea Frittoli2e733b52014-07-16 14:12:11 +0100682
Andrea Frittoli4971fc82014-09-25 10:22:20 +0100683class NetworkScenarioTest(ScenarioTest):
Yair Fried1fc32a12014-08-04 09:11:30 +0300684 """Base class for network scenario tests.
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000685
Yair Fried1fc32a12014-08-04 09:11:30 +0300686 This class provide helpers for network scenario tests, using the neutron
687 API. Helpers from ancestor which use the nova network API are overridden
688 with the neutron API.
689
690 This Class also enforces using Neutron instead of novanetwork.
691 Subclassed tests will be skipped if Neutron is not enabled
692
693 """
694
Andrea Frittolib21de6c2015-02-06 20:12:38 +0000695 credentials = ['primary', 'admin']
696
Yair Fried1fc32a12014-08-04 09:11:30 +0300697 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +0000698 def skip_checks(cls):
699 super(NetworkScenarioTest, cls).skip_checks()
Andrea Frittoli2ddc2632014-09-25 11:03:00 +0100700 if not CONF.service_available.neutron:
701 raise cls.skipException('Neutron not available')
Yair Fried1fc32a12014-08-04 09:11:30 +0300702
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -0700703 def _create_network(self, networks_client=None,
zhoubin5058bead72017-02-04 18:01:15 +0800704 tenant_id=None,
Markus Zoeller156b5da2016-07-11 18:10:31 +0200705 namestart='network-smoke-',
706 port_security_enabled=True):
John Warren94d8faf2015-09-15 12:22:24 -0400707 if not networks_client:
708 networks_client = self.networks_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300709 if not tenant_id:
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -0700710 tenant_id = networks_client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300711 name = data_utils.rand_name(namestart)
Matt Riedemann039b2fe2016-09-15 16:12:24 -0400712 network_kwargs = dict(name=name, tenant_id=tenant_id)
713 # Neutron disables port security by default so we have to check the
714 # config before trying to create the network with port_security_enabled
715 if CONF.network_feature_enabled.port_security:
716 network_kwargs['port_security_enabled'] = port_security_enabled
Markus Zoeller156b5da2016-07-11 18:10:31 +0200717 result = networks_client.create_network(**network_kwargs)
Steve Heyman33735f22016-05-24 09:28:08 -0500718 network = result['network']
719
720 self.assertEqual(network['name'], name)
Jordan Pittier9e227c52016-02-09 14:35:18 +0100721 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
zhoubin508bf20b32017-02-03 09:39:14 +0800722 networks_client.delete_network,
Steve Heyman33735f22016-05-24 09:28:08 -0500723 network['id'])
Yair Fried1fc32a12014-08-04 09:11:30 +0300724 return network
725
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -0700726 def _create_subnet(self, network, subnets_client=None,
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000727 routers_client=None, namestart='subnet-smoke',
728 **kwargs):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000729 """Create a subnet for the given network
730
731 within the cidr block configured for tenant networks.
Yair Fried1fc32a12014-08-04 09:11:30 +0300732 """
John Warren3961acd2015-10-02 14:38:53 -0400733 if not subnets_client:
734 subnets_client = self.subnets_client
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000735 if not routers_client:
736 routers_client = self.routers_client
Yair Fried1fc32a12014-08-04 09:11:30 +0300737
738 def cidr_in_use(cidr, tenant_id):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000739 """Check cidr existence
740
lei zhangdd552b22015-11-25 20:41:48 +0800741 :returns: True if subnet with cidr already exist in tenant
742 False else
Yair Fried1fc32a12014-08-04 09:11:30 +0300743 """
jeremy.zhang5870ff12017-05-25 11:24:23 +0800744 cidr_in_use = self.os_admin.subnets_client.list_subnets(
Jordan Pittier64e6b442017-02-20 19:29:02 +0100745 tenant_id=tenant_id, cidr=cidr)['subnets']
Yair Fried1fc32a12014-08-04 09:11:30 +0300746 return len(cidr_in_use) != 0
747
Kirill Shileev14113572014-11-21 16:58:02 +0300748 ip_version = kwargs.pop('ip_version', 4)
749
750 if ip_version == 6:
751 tenant_cidr = netaddr.IPNetwork(
Sean Dagueed6e5862016-04-04 10:49:13 -0400752 CONF.network.project_network_v6_cidr)
753 num_bits = CONF.network.project_network_v6_mask_bits
Kirill Shileev14113572014-11-21 16:58:02 +0300754 else:
Sean Dagueed6e5862016-04-04 10:49:13 -0400755 tenant_cidr = netaddr.IPNetwork(CONF.network.project_network_cidr)
756 num_bits = CONF.network.project_network_mask_bits
Kirill Shileev14113572014-11-21 16:58:02 +0300757
Yair Fried1fc32a12014-08-04 09:11:30 +0300758 result = None
Kirill Shileev14113572014-11-21 16:58:02 +0300759 str_cidr = None
Yair Fried1fc32a12014-08-04 09:11:30 +0300760 # Repeatedly attempt subnet creation with sequential cidr
761 # blocks until an unallocated block is found.
Kirill Shileev14113572014-11-21 16:58:02 +0300762 for subnet_cidr in tenant_cidr.subnet(num_bits):
Yair Fried1fc32a12014-08-04 09:11:30 +0300763 str_cidr = str(subnet_cidr)
Steve Heyman33735f22016-05-24 09:28:08 -0500764 if cidr_in_use(str_cidr, tenant_id=network['tenant_id']):
Yair Fried1fc32a12014-08-04 09:11:30 +0300765 continue
766
767 subnet = dict(
768 name=data_utils.rand_name(namestart),
Steve Heyman33735f22016-05-24 09:28:08 -0500769 network_id=network['id'],
770 tenant_id=network['tenant_id'],
Yair Fried1fc32a12014-08-04 09:11:30 +0300771 cidr=str_cidr,
Kirill Shileev14113572014-11-21 16:58:02 +0300772 ip_version=ip_version,
Yair Fried1fc32a12014-08-04 09:11:30 +0300773 **kwargs
774 )
775 try:
John Warren3961acd2015-10-02 14:38:53 -0400776 result = subnets_client.create_subnet(**subnet)
Yair Fried1fc32a12014-08-04 09:11:30 +0300777 break
Masayuki Igawad9388762015-01-20 14:56:42 +0900778 except lib_exc.Conflict as e:
Yair Fried1fc32a12014-08-04 09:11:30 +0300779 is_overlapping_cidr = 'overlaps with another subnet' in str(e)
780 if not is_overlapping_cidr:
781 raise
782 self.assertIsNotNone(result, 'Unable to allocate tenant network')
Steve Heyman33735f22016-05-24 09:28:08 -0500783
784 subnet = result['subnet']
785 self.assertEqual(subnet['cidr'], str_cidr)
786
787 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
788 subnets_client.delete_subnet, subnet['id'])
789
Yair Fried1fc32a12014-08-04 09:11:30 +0300790 return subnet
791
Kirill Shileev14113572014-11-21 16:58:02 +0300792 def _get_server_port_id_and_ip4(self, server, ip_addr=None):
jeremy.zhang5870ff12017-05-25 11:24:23 +0800793 ports = self.os_admin.ports_client.list_ports(
Jordan Pittier64e6b442017-02-20 19:29:02 +0100794 device_id=server['id'], fixed_ip=ip_addr)['ports']
Kobi Samoray166500a2016-10-09 14:42:48 +0300795 # A port can have more than one IP address in some cases.
Sean M. Collins2e896832015-12-15 13:58:47 -0500796 # If the network is dual-stack (IPv4 + IPv6), this port is associated
797 # with 2 subnets
Vasyl Saienko8fd517c2016-05-30 09:52:54 +0300798 p_status = ['ACTIVE']
799 # NOTE(vsaienko) With Ironic, instances live on separate hardware
800 # servers. Neutron does not bind ports for Ironic instances, as a
801 # result the port remains in the DOWN state.
Vasyl Saienkoc8aa34b2016-08-01 14:18:37 +0300802 # TODO(vsaienko) remove once bug: #1599836 is resolved.
Thiago Paiva66cded22016-08-15 14:55:58 -0300803 if getattr(CONF.service_available, 'ironic', False):
Vasyl Saienko8fd517c2016-05-30 09:52:54 +0300804 p_status.append('DOWN')
Daniel Mellado9e3e1062015-08-06 18:07:05 +0200805 port_map = [(p["id"], fxip["ip_address"])
806 for p in ports
807 for fxip in p["fixed_ips"]
Yatin Kumbhareee4924c2016-06-09 15:12:06 +0530808 if netutils.is_valid_ipv4(fxip["ip_address"])
Vasyl Saienko8fd517c2016-05-30 09:52:54 +0300809 and p['status'] in p_status]
Kevin Benton1d0c1dc2016-02-04 14:30:08 -0800810 inactive = [p for p in ports if p['status'] != 'ACTIVE']
811 if inactive:
812 LOG.warning("Instance has ports that are not ACTIVE: %s", inactive)
Daniel Mellado9e3e1062015-08-06 18:07:05 +0200813
Masayuki Igawaf9009b42017-04-10 14:49:29 +0900814 self.assertNotEmpty(port_map,
John L. Villalovosb83286f2015-11-04 14:46:57 -0800815 "No IPv4 addresses found in: %s" % ports)
Daniel Mellado9e3e1062015-08-06 18:07:05 +0200816 self.assertEqual(len(port_map), 1,
817 "Found multiple IPv4 addresses: %s. "
818 "Unable to determine which port to target."
819 % port_map)
820 return port_map[0]
Yair Fried1fc32a12014-08-04 09:11:30 +0300821
David Shrewsbury9bac3662014-08-07 15:07:01 -0400822 def _get_network_by_name(self, network_name):
jeremy.zhang5870ff12017-05-25 11:24:23 +0800823 net = self.os_admin.networks_client.list_networks(
Jordan Pittier64e6b442017-02-20 19:29:02 +0100824 name=network_name)['networks']
Ferenc Horváth268ccce2017-06-08 12:39:02 +0200825 self.assertNotEmpty(net,
Adam Gandelman878a5fd2015-03-30 14:33:36 -0700826 "Unable to get network by name: %s" % network_name)
Steve Heyman33735f22016-05-24 09:28:08 -0500827 return net[0]
David Shrewsbury9bac3662014-08-07 15:07:01 -0400828
Yair Friedae0e73d2014-11-24 11:56:26 +0200829 def create_floating_ip(self, thing, external_network_id=None,
830 port_id=None, client=None):
Ken'ichi Ohmichia112a592015-11-17 08:49:37 +0000831 """Create a floating IP and associates to a resource/port on Neutron"""
Yair Friedae0e73d2014-11-24 11:56:26 +0200832 if not external_network_id:
833 external_network_id = CONF.network.public_network_id
Yair Frieddb6c9e92014-08-06 08:53:13 +0300834 if not client:
John Warrenfbf2a892015-11-17 12:36:14 -0500835 client = self.floating_ips_client
Yair Fried1fc32a12014-08-04 09:11:30 +0300836 if not port_id:
Kirill Shileev14113572014-11-21 16:58:02 +0300837 port_id, ip4 = self._get_server_port_id_and_ip4(thing)
838 else:
839 ip4 = None
David Kranz34e88122014-12-11 15:24:05 -0500840 result = client.create_floatingip(
Yair Fried1fc32a12014-08-04 09:11:30 +0300841 floating_network_id=external_network_id,
842 port_id=port_id,
Kirill Shileev14113572014-11-21 16:58:02 +0300843 tenant_id=thing['tenant_id'],
844 fixed_ip_address=ip4
Yair Fried1fc32a12014-08-04 09:11:30 +0300845 )
Steve Heyman33735f22016-05-24 09:28:08 -0500846 floating_ip = result['floatingip']
Jordan Pittier9e227c52016-02-09 14:35:18 +0100847 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
zhoubin508bf20b32017-02-03 09:39:14 +0800848 client.delete_floatingip,
Steve Heyman33735f22016-05-24 09:28:08 -0500849 floating_ip['id'])
Yair Fried1fc32a12014-08-04 09:11:30 +0300850 return floating_ip
851
852 def _associate_floating_ip(self, floating_ip, server):
Kirill Shileev14113572014-11-21 16:58:02 +0300853 port_id, _ = self._get_server_port_id_and_ip4(server)
Steve Heyman33735f22016-05-24 09:28:08 -0500854 kwargs = dict(port_id=port_id)
855 floating_ip = self.floating_ips_client.update_floatingip(
856 floating_ip['id'], **kwargs)['floatingip']
857 self.assertEqual(port_id, floating_ip['port_id'])
Yair Fried1fc32a12014-08-04 09:11:30 +0300858 return floating_ip
859
860 def _disassociate_floating_ip(self, floating_ip):
Steve Heyman33735f22016-05-24 09:28:08 -0500861 """:param floating_ip: floating_ips_client.create_floatingip"""
862 kwargs = dict(port_id=None)
863 floating_ip = self.floating_ips_client.update_floatingip(
864 floating_ip['id'], **kwargs)['floatingip']
865 self.assertIsNone(floating_ip['port_id'])
Yair Fried1fc32a12014-08-04 09:11:30 +0300866 return floating_ip
867
Yair Fried45f92952014-06-26 05:19:19 +0300868 def check_floating_ip_status(self, floating_ip, status):
Carl Baldwina754e2d2014-10-23 22:47:41 +0000869 """Verifies floatingip reaches the given status
Yair Fried45f92952014-06-26 05:19:19 +0300870
Steve Heyman33735f22016-05-24 09:28:08 -0500871 :param dict floating_ip: floating IP dict to check status
Yair Fried45f92952014-06-26 05:19:19 +0300872 :param status: target status
873 :raises: AssertionError if status doesn't match
874 """
Steve Heyman33735f22016-05-24 09:28:08 -0500875 floatingip_id = floating_ip['id']
876
Carl Baldwina754e2d2014-10-23 22:47:41 +0000877 def refresh():
Steve Heyman33735f22016-05-24 09:28:08 -0500878 result = (self.floating_ips_client.
879 show_floatingip(floatingip_id)['floatingip'])
880 return status == result['status']
Carl Baldwina754e2d2014-10-23 22:47:41 +0000881
zhufl4dda94e2017-03-14 16:14:46 +0800882 if not test_utils.call_until_true(refresh,
883 CONF.network.build_timeout,
884 CONF.network.build_interval):
885 floating_ip = self.floating_ips_client.show_floatingip(
886 floatingip_id)['floatingip']
887 self.assertEqual(status, floating_ip['status'],
888 message="FloatingIP: {fp} is at status: {cst}. "
889 "failed to reach status: {st}"
890 .format(fp=floating_ip, cst=floating_ip['status'],
891 st=status))
Yair Fried45f92952014-06-26 05:19:19 +0300892 LOG.info("FloatingIP: {fp} is at status: {st}"
893 .format(fp=floating_ip, st=status))
894
Yair Fried1fc32a12014-08-04 09:11:30 +0300895 def _check_tenant_network_connectivity(self, server,
896 username,
897 private_key,
898 should_connect=True,
899 servers_for_debug=None):
Sean Dagueed6e5862016-04-04 10:49:13 -0400900 if not CONF.network.project_networks_reachable:
Yair Fried1fc32a12014-08-04 09:11:30 +0300901 msg = 'Tenant networks not configured to be reachable.'
902 LOG.info(msg)
903 return
904 # The target login is assumed to have been configured for
905 # key-based authentication by cloud-init.
906 try:
Béla Vancsicsb6dfa082017-03-01 10:44:58 +0100907 for ip_addresses in server['addresses'].values():
Yair Fried1fc32a12014-08-04 09:11:30 +0300908 for ip_address in ip_addresses:
ghanshyam807211c2014-12-18 13:21:22 +0900909 self.check_vm_connectivity(ip_address['addr'],
Yair Friedae0e73d2014-11-24 11:56:26 +0200910 username,
911 private_key,
912 should_connect=should_connect)
Yair Fried1fc32a12014-08-04 09:11:30 +0300913 except Exception as e:
914 LOG.exception('Tenant network connectivity check failed')
915 self._log_console_output(servers_for_debug)
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000916 self._log_net_info(e)
Yair Fried1fc32a12014-08-04 09:11:30 +0300917 raise
918
Yair Friedbc46f592015-11-18 16:29:34 +0200919 def _check_remote_connectivity(self, source, dest, should_succeed=True,
920 nic=None):
YAMAMOTO Takashi4c3ebb02017-01-25 16:04:30 +0900921 """assert ping server via source ssh connection
922
923 Note: This is an internal method. Use check_remote_connectivity
924 instead.
Yair Fried1fc32a12014-08-04 09:11:30 +0300925
926 :param source: RemoteClient: an ssh connection from which to ping
927 :param dest: and IP to ping against
928 :param should_succeed: boolean should ping succeed or not
Yair Friedbc46f592015-11-18 16:29:34 +0200929 :param nic: specific network interface to ping from
Yair Fried1fc32a12014-08-04 09:11:30 +0300930 """
931 def ping_remote():
932 try:
Yair Friedbc46f592015-11-18 16:29:34 +0200933 source.ping_host(dest, nic=nic)
Andrey Pavlov64723762015-04-29 06:24:58 +0300934 except lib_exc.SSHExecCommandFailed:
zhangguoqing6c096642016-01-04 06:17:21 +0000935 LOG.warning('Failed to ping IP: %s via a ssh connection '
Jordan Pittier525ec712016-12-07 17:51:26 +0100936 'from: %s.', dest, source.ssh_client.host)
Yair Fried1fc32a12014-08-04 09:11:30 +0300937 return not should_succeed
938 return should_succeed
939
Jordan Pittier35a63752016-08-30 13:09:12 +0200940 return test_utils.call_until_true(ping_remote,
941 CONF.validation.ping_timeout,
942 1)
Yair Fried1fc32a12014-08-04 09:11:30 +0300943
YAMAMOTO Takashi4c3ebb02017-01-25 16:04:30 +0900944 def check_remote_connectivity(self, source, dest, should_succeed=True,
945 nic=None):
946 """assert ping server via source ssh connection
947
948 :param source: RemoteClient: an ssh connection from which to ping
949 :param dest: and IP to ping against
950 :param should_succeed: boolean should ping succeed or not
951 :param nic: specific network interface to ping from
952 """
953 result = self._check_remote_connectivity(source, dest, should_succeed,
954 nic)
955 source_host = source.ssh_client.host
956 if should_succeed:
957 msg = "Timed out waiting for %s to become reachable from %s" \
958 % (dest, source_host)
959 else:
960 msg = "%s is reachable from %s" % (dest, source_host)
961 self.assertTrue(result, msg)
962
John Warren456d9ae2016-01-12 15:36:33 -0500963 def _create_security_group(self, security_group_rules_client=None,
964 tenant_id=None,
John Warrenf9606e92015-12-10 12:12:42 -0500965 namestart='secgroup-smoke',
966 security_groups_client=None):
John Warren456d9ae2016-01-12 15:36:33 -0500967 if security_group_rules_client is None:
968 security_group_rules_client = self.security_group_rules_client
John Warrenf9606e92015-12-10 12:12:42 -0500969 if security_groups_client is None:
970 security_groups_client = self.security_groups_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300971 if tenant_id is None:
John Warrenf9606e92015-12-10 12:12:42 -0500972 tenant_id = security_groups_client.tenant_id
973 secgroup = self._create_empty_security_group(
974 namestart=namestart, client=security_groups_client,
975 tenant_id=tenant_id)
Yair Fried1fc32a12014-08-04 09:11:30 +0300976
977 # Add rules to the security group
John Warrenf9606e92015-12-10 12:12:42 -0500978 rules = self._create_loginable_secgroup_rule(
John Warren456d9ae2016-01-12 15:36:33 -0500979 security_group_rules_client=security_group_rules_client,
980 secgroup=secgroup,
John Warrenf9606e92015-12-10 12:12:42 -0500981 security_groups_client=security_groups_client)
Yair Fried1fc32a12014-08-04 09:11:30 +0300982 for rule in rules:
Steve Heyman33735f22016-05-24 09:28:08 -0500983 self.assertEqual(tenant_id, rule['tenant_id'])
984 self.assertEqual(secgroup['id'], rule['security_group_id'])
Yair Fried1fc32a12014-08-04 09:11:30 +0300985 return secgroup
986
Yair Frieddb6c9e92014-08-06 08:53:13 +0300987 def _create_empty_security_group(self, client=None, tenant_id=None,
Yair Fried1fc32a12014-08-04 09:11:30 +0300988 namestart='secgroup-smoke'):
989 """Create a security group without rules.
990
991 Default rules will be created:
992 - IPv4 egress to any
993 - IPv6 egress to any
994
995 :param tenant_id: secgroup will be created in this tenant
Steve Heyman33735f22016-05-24 09:28:08 -0500996 :returns: the created security group
Yair Fried1fc32a12014-08-04 09:11:30 +0300997 """
998 if client is None:
John Warrenf9606e92015-12-10 12:12:42 -0500999 client = self.security_groups_client
Yair Frieddb6c9e92014-08-06 08:53:13 +03001000 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +00001001 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001002 sg_name = data_utils.rand_name(namestart)
1003 sg_desc = sg_name + " description"
1004 sg_dict = dict(name=sg_name,
1005 description=sg_desc)
1006 sg_dict['tenant_id'] = tenant_id
David Kranz34e88122014-12-11 15:24:05 -05001007 result = client.create_security_group(**sg_dict)
Steve Heyman33735f22016-05-24 09:28:08 -05001008
1009 secgroup = result['security_group']
1010 self.assertEqual(secgroup['name'], sg_name)
1011 self.assertEqual(tenant_id, secgroup['tenant_id'])
1012 self.assertEqual(secgroup['description'], sg_desc)
1013
Jordan Pittier9e227c52016-02-09 14:35:18 +01001014 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
Steve Heyman33735f22016-05-24 09:28:08 -05001015 client.delete_security_group, secgroup['id'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001016 return secgroup
1017
Yair Frieddb6c9e92014-08-06 08:53:13 +03001018 def _default_security_group(self, client=None, tenant_id=None):
Yair Fried1fc32a12014-08-04 09:11:30 +03001019 """Get default secgroup for given tenant_id.
1020
Ken'ichi Ohmichid67c8da2016-09-13 16:18:11 -07001021 :returns: default secgroup for given tenant
Yair Fried1fc32a12014-08-04 09:11:30 +03001022 """
1023 if client is None:
John Warrenf9606e92015-12-10 12:12:42 -05001024 client = self.security_groups_client
Yair Frieddb6c9e92014-08-06 08:53:13 +03001025 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +00001026 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001027 sgs = [
Jordan Pittier8ad86172016-04-25 16:20:53 +02001028 sg for sg in list(client.list_security_groups().values())[0]
Yair Fried1fc32a12014-08-04 09:11:30 +03001029 if sg['tenant_id'] == tenant_id and sg['name'] == 'default'
1030 ]
1031 msg = "No default security group for tenant %s." % (tenant_id)
Masayuki Igawaf9009b42017-04-10 14:49:29 +09001032 self.assertNotEmpty(sgs, msg)
Steve Heyman33735f22016-05-24 09:28:08 -05001033 return sgs[0]
Yair Fried1fc32a12014-08-04 09:11:30 +03001034
John Warren456d9ae2016-01-12 15:36:33 -05001035 def _create_security_group_rule(self, secgroup=None,
1036 sec_group_rules_client=None,
John Warrenf9606e92015-12-10 12:12:42 -05001037 tenant_id=None,
1038 security_groups_client=None, **kwargs):
Yair Fried1fc32a12014-08-04 09:11:30 +03001039 """Create a rule from a dictionary of rule parameters.
1040
1041 Create a rule in a secgroup. if secgroup not defined will search for
1042 default secgroup in tenant_id.
1043
Steve Heyman33735f22016-05-24 09:28:08 -05001044 :param secgroup: the security group.
Yair Fried1fc32a12014-08-04 09:11:30 +03001045 :param tenant_id: if secgroup not passed -- the tenant in which to
1046 search for default secgroup
1047 :param kwargs: a dictionary containing rule parameters:
1048 for example, to allow incoming ssh:
1049 rule = {
1050 direction: 'ingress'
1051 protocol:'tcp',
1052 port_range_min: 22,
1053 port_range_max: 22
1054 }
1055 """
John Warren456d9ae2016-01-12 15:36:33 -05001056 if sec_group_rules_client is None:
1057 sec_group_rules_client = self.security_group_rules_client
John Warrenf9606e92015-12-10 12:12:42 -05001058 if security_groups_client is None:
1059 security_groups_client = self.security_groups_client
Yair Frieddb6c9e92014-08-06 08:53:13 +03001060 if not tenant_id:
John Warrenf9606e92015-12-10 12:12:42 -05001061 tenant_id = security_groups_client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001062 if secgroup is None:
John Warrenf9606e92015-12-10 12:12:42 -05001063 secgroup = self._default_security_group(
1064 client=security_groups_client, tenant_id=tenant_id)
Yair Fried1fc32a12014-08-04 09:11:30 +03001065
Steve Heyman33735f22016-05-24 09:28:08 -05001066 ruleset = dict(security_group_id=secgroup['id'],
1067 tenant_id=secgroup['tenant_id'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001068 ruleset.update(kwargs)
1069
John Warren456d9ae2016-01-12 15:36:33 -05001070 sg_rule = sec_group_rules_client.create_security_group_rule(**ruleset)
Steve Heyman33735f22016-05-24 09:28:08 -05001071 sg_rule = sg_rule['security_group_rule']
1072
1073 self.assertEqual(secgroup['tenant_id'], sg_rule['tenant_id'])
1074 self.assertEqual(secgroup['id'], sg_rule['security_group_id'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001075
1076 return sg_rule
1077
John Warren456d9ae2016-01-12 15:36:33 -05001078 def _create_loginable_secgroup_rule(self, security_group_rules_client=None,
1079 secgroup=None,
John Warrenf9606e92015-12-10 12:12:42 -05001080 security_groups_client=None):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001081 """Create loginable security group rule
1082
Alex Stafeyevdd5dde92016-05-08 14:35:04 +03001083 This function will create:
1084 1. egress and ingress tcp port 22 allow rule in order to allow ssh
1085 access for ipv4.
1086 2. egress and ingress ipv6 icmp allow rule, in order to allow icmpv6.
1087 3. egress and ingress ipv4 icmp allow rule, in order to allow icmpv4.
Yair Fried1fc32a12014-08-04 09:11:30 +03001088 """
1089
John Warren456d9ae2016-01-12 15:36:33 -05001090 if security_group_rules_client is None:
1091 security_group_rules_client = self.security_group_rules_client
John Warrenf9606e92015-12-10 12:12:42 -05001092 if security_groups_client is None:
1093 security_groups_client = self.security_groups_client
Yair Fried1fc32a12014-08-04 09:11:30 +03001094 rules = []
1095 rulesets = [
1096 dict(
1097 # ssh
1098 protocol='tcp',
1099 port_range_min=22,
1100 port_range_max=22,
1101 ),
1102 dict(
1103 # ping
1104 protocol='icmp',
Andreas Scheuring887ca8e2015-02-03 17:56:12 +01001105 ),
1106 dict(
1107 # ipv6-icmp for ping6
1108 protocol='icmp',
1109 ethertype='IPv6',
Yair Fried1fc32a12014-08-04 09:11:30 +03001110 )
1111 ]
John Warren456d9ae2016-01-12 15:36:33 -05001112 sec_group_rules_client = security_group_rules_client
Yair Fried1fc32a12014-08-04 09:11:30 +03001113 for ruleset in rulesets:
1114 for r_direction in ['ingress', 'egress']:
1115 ruleset['direction'] = r_direction
1116 try:
1117 sg_rule = self._create_security_group_rule(
John Warren456d9ae2016-01-12 15:36:33 -05001118 sec_group_rules_client=sec_group_rules_client,
1119 secgroup=secgroup,
John Warrenf9606e92015-12-10 12:12:42 -05001120 security_groups_client=security_groups_client,
1121 **ruleset)
Masayuki Igawad9388762015-01-20 14:56:42 +09001122 except lib_exc.Conflict as ex:
Yair Fried1fc32a12014-08-04 09:11:30 +03001123 # if rule already exist - skip rule and continue
1124 msg = 'Security group rule already exists'
1125 if msg not in ex._error_string:
1126 raise ex
1127 else:
Steve Heyman33735f22016-05-24 09:28:08 -05001128 self.assertEqual(r_direction, sg_rule['direction'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001129 rules.append(sg_rule)
1130
1131 return rules
1132
Yair Frieddb6c9e92014-08-06 08:53:13 +03001133 def _get_router(self, client=None, tenant_id=None):
Yair Fried1fc32a12014-08-04 09:11:30 +03001134 """Retrieve a router for the given tenant id.
1135
1136 If a public router has been configured, it will be returned.
1137
1138 If a public router has not been configured, but a public
1139 network has, a tenant router will be created and returned that
1140 routes traffic to the public network.
1141 """
Yair Frieddb6c9e92014-08-06 08:53:13 +03001142 if not client:
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +00001143 client = self.routers_client
Yair Frieddb6c9e92014-08-06 08:53:13 +03001144 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +00001145 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001146 router_id = CONF.network.public_router_id
1147 network_id = CONF.network.public_network_id
1148 if router_id:
David Kranzca4c7e72015-05-27 11:39:19 -04001149 body = client.show_router(router_id)
Steve Heyman33735f22016-05-24 09:28:08 -05001150 return body['router']
Yair Fried1fc32a12014-08-04 09:11:30 +03001151 elif network_id:
Yair Frieddb6c9e92014-08-06 08:53:13 +03001152 router = self._create_router(client, tenant_id)
Steve Heyman33735f22016-05-24 09:28:08 -05001153 kwargs = {'external_gateway_info': dict(network_id=network_id)}
1154 router = client.update_router(router['id'], **kwargs)['router']
Yair Fried1fc32a12014-08-04 09:11:30 +03001155 return router
1156 else:
1157 raise Exception("Neither of 'public_router_id' or "
1158 "'public_network_id' has been defined.")
1159
Yair Frieddb6c9e92014-08-06 08:53:13 +03001160 def _create_router(self, client=None, tenant_id=None,
1161 namestart='router-smoke'):
1162 if not client:
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +00001163 client = self.routers_client
Yair Frieddb6c9e92014-08-06 08:53:13 +03001164 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +00001165 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001166 name = data_utils.rand_name(namestart)
David Kranz34e88122014-12-11 15:24:05 -05001167 result = client.create_router(name=name,
1168 admin_state_up=True,
1169 tenant_id=tenant_id)
Steve Heyman33735f22016-05-24 09:28:08 -05001170 router = result['router']
1171 self.assertEqual(router['name'], name)
1172 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
1173 client.delete_router,
1174 router['id'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001175 return router
1176
Alok Maurya6384bbb2014-07-13 06:44:29 -07001177 def _update_router_admin_state(self, router, admin_state_up):
Steve Heyman33735f22016-05-24 09:28:08 -05001178 kwargs = dict(admin_state_up=admin_state_up)
1179 router = self.routers_client.update_router(
1180 router['id'], **kwargs)['router']
1181 self.assertEqual(admin_state_up, router['admin_state_up'])
Alok Maurya6384bbb2014-07-13 06:44:29 -07001182
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -07001183 def create_networks(self, networks_client=None,
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +00001184 routers_client=None, subnets_client=None,
Markus Zoeller156b5da2016-07-11 18:10:31 +02001185 tenant_id=None, dns_nameservers=None,
1186 port_security_enabled=True):
Yair Fried1fc32a12014-08-04 09:11:30 +03001187 """Create a network with a subnet connected to a router.
1188
David Shrewsbury9bac3662014-08-07 15:07:01 -04001189 The baremetal driver is a special case since all nodes are
1190 on the same shared network.
1191
Yair Fried413bf2d2014-11-19 17:07:11 +02001192 :param tenant_id: id of tenant to create resources in.
1193 :param dns_nameservers: list of dns servers to send to subnet.
Yair Fried1fc32a12014-08-04 09:11:30 +03001194 :returns: network, subnet, router
1195 """
Thiago Paiva66cded22016-08-15 14:55:58 -03001196 if CONF.network.shared_physical_network:
David Shrewsbury9bac3662014-08-07 15:07:01 -04001197 # NOTE(Shrews): This exception is for environments where tenant
1198 # credential isolation is available, but network separation is
1199 # not (the current baremetal case). Likely can be removed when
1200 # test account mgmt is reworked:
1201 # https://blueprints.launchpad.net/tempest/+spec/test-accounts
Adam Gandelman878a5fd2015-03-30 14:33:36 -07001202 if not CONF.compute.fixed_network_name:
1203 m = 'fixed_network_name must be specified in config'
Matthew Treinish4217a702016-10-07 17:27:11 -04001204 raise lib_exc.InvalidConfiguration(m)
David Shrewsbury9bac3662014-08-07 15:07:01 -04001205 network = self._get_network_by_name(
1206 CONF.compute.fixed_network_name)
1207 router = None
1208 subnet = None
1209 else:
John Warren94d8faf2015-09-15 12:22:24 -04001210 network = self._create_network(
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -07001211 networks_client=networks_client,
Markus Zoeller156b5da2016-07-11 18:10:31 +02001212 tenant_id=tenant_id,
1213 port_security_enabled=port_security_enabled)
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +00001214 router = self._get_router(client=routers_client,
1215 tenant_id=tenant_id)
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -07001216 subnet_kwargs = dict(network=network,
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +00001217 subnets_client=subnets_client,
1218 routers_client=routers_client)
Yair Fried413bf2d2014-11-19 17:07:11 +02001219 # use explicit check because empty list is a valid option
1220 if dns_nameservers is not None:
1221 subnet_kwargs['dns_nameservers'] = dns_nameservers
1222 subnet = self._create_subnet(**subnet_kwargs)
Steve Heyman33735f22016-05-24 09:28:08 -05001223 if not routers_client:
1224 routers_client = self.routers_client
1225 router_id = router['id']
1226 routers_client.add_router_interface(router_id,
1227 subnet_id=subnet['id'])
1228
1229 # save a cleanup job to remove this association between
1230 # router and subnet
1231 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
1232 routers_client.remove_router_interface, router_id,
1233 subnet_id=subnet['id'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001234 return network, subnet, router
1235
1236
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001237class EncryptionScenarioTest(ScenarioTest):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001238 """Base class for encryption scenario tests"""
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001239
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001240 credentials = ['primary', 'admin']
David Kranz4cc852b2015-03-09 14:57:11 -04001241
1242 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001243 def setup_clients(cls):
1244 super(EncryptionScenarioTest, cls).setup_clients()
Jordan Pittier8160d312017-04-18 11:52:23 +02001245 cls.admin_volume_types_client = cls.os_admin.volume_types_v2_client
ghanshyam3bd0d2b2017-03-23 01:57:28 +00001246 cls.admin_encryption_types_client =\
Jordan Pittier8160d312017-04-18 11:52:23 +02001247 cls.os_admin.encryption_types_v2_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001248
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001249 def create_encryption_type(self, client=None, type_id=None, provider=None,
1250 key_size=None, cipher=None,
1251 control_location=None):
1252 if not client:
Ken'ichi Ohmichia6ebf622016-08-25 11:52:27 -07001253 client = self.admin_encryption_types_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001254 if not type_id:
1255 volume_type = self.create_volume_type()
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001256 type_id = volume_type['id']
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001257 LOG.debug("Creating an encryption type for volume type: %s", type_id)
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001258 client.create_encryption_type(
1259 type_id, provider=provider, key_size=key_size, cipher=cipher,
John Warrend053ded2015-08-13 15:22:48 +00001260 control_location=control_location)['encryption']
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001261
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001262
Masayuki Igawa0870db52015-09-18 21:08:36 +09001263class ObjectStorageScenarioTest(ScenarioTest):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001264 """Provide harness to do Object Storage scenario tests.
Chris Dent0d494112014-08-26 13:48:30 +01001265
1266 Subclasses implement the tests that use the methods provided by this
1267 class.
1268 """
1269
1270 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001271 def skip_checks(cls):
Masayuki Igawa0870db52015-09-18 21:08:36 +09001272 super(ObjectStorageScenarioTest, cls).skip_checks()
Chris Dent0d494112014-08-26 13:48:30 +01001273 if not CONF.service_available.swift:
1274 skip_msg = ("%s skipped as swift is not available" %
1275 cls.__name__)
1276 raise cls.skipException(skip_msg)
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001277
1278 @classmethod
1279 def setup_credentials(cls):
Masayuki Igawa60ea6c52014-10-15 17:32:14 +09001280 cls.set_network_resources()
Masayuki Igawa0870db52015-09-18 21:08:36 +09001281 super(ObjectStorageScenarioTest, cls).setup_credentials()
Matthew Treinish4a596932015-03-06 20:37:01 -05001282 operator_role = CONF.object_storage.operator_role
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +01001283 cls.os_operator = cls.get_client_manager(roles=[operator_role])
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001284
1285 @classmethod
1286 def setup_clients(cls):
Masayuki Igawa0870db52015-09-18 21:08:36 +09001287 super(ObjectStorageScenarioTest, cls).setup_clients()
Chris Dent0d494112014-08-26 13:48:30 +01001288 # Clients for Swift
Matthew Treinish8f268292015-02-24 20:01:36 -05001289 cls.account_client = cls.os_operator.account_client
1290 cls.container_client = cls.os_operator.container_client
1291 cls.object_client = cls.os_operator.object_client
Chris Dent0d494112014-08-26 13:48:30 +01001292
Chris Dentde456a12014-09-10 12:41:15 +01001293 def get_swift_stat(self):
Chris Dent0d494112014-08-26 13:48:30 +01001294 """get swift status for our user account."""
1295 self.account_client.list_account_containers()
1296 LOG.debug('Swift status information obtained successfully')
1297
Chris Dentde456a12014-09-10 12:41:15 +01001298 def create_container(self, container_name=None):
Chris Dent0d494112014-08-26 13:48:30 +01001299 name = container_name or data_utils.rand_name(
1300 'swift-scenario-container')
1301 self.container_client.create_container(name)
1302 # look for the container to assure it is created
Chris Dentde456a12014-09-10 12:41:15 +01001303 self.list_and_check_container_objects(name)
Jordan Pittier525ec712016-12-07 17:51:26 +01001304 LOG.debug('Container %s created', name)
Jordan Pittier9e227c52016-02-09 14:35:18 +01001305 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
Chris Dent1d4313a2014-10-28 12:16:48 +00001306 self.container_client.delete_container,
1307 name)
Chris Dent0d494112014-08-26 13:48:30 +01001308 return name
1309
Chris Dentde456a12014-09-10 12:41:15 +01001310 def delete_container(self, container_name):
Chris Dent0d494112014-08-26 13:48:30 +01001311 self.container_client.delete_container(container_name)
Jordan Pittier525ec712016-12-07 17:51:26 +01001312 LOG.debug('Container %s deleted', container_name)
Chris Dent0d494112014-08-26 13:48:30 +01001313
Chris Dentde456a12014-09-10 12:41:15 +01001314 def upload_object_to_container(self, container_name, obj_name=None):
Chris Dent0d494112014-08-26 13:48:30 +01001315 obj_name = obj_name or data_utils.rand_name('swift-scenario-object')
Jordan Pittierb84f2d42016-12-21 19:02:15 +01001316 obj_data = data_utils.random_bytes()
Chris Dent0d494112014-08-26 13:48:30 +01001317 self.object_client.create_object(container_name, obj_name, obj_data)
Jordan Pittier9e227c52016-02-09 14:35:18 +01001318 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
Chris Dent1d4313a2014-10-28 12:16:48 +00001319 self.object_client.delete_object,
1320 container_name,
1321 obj_name)
Chris Dent0d494112014-08-26 13:48:30 +01001322 return obj_name, obj_data
1323
Chris Dentde456a12014-09-10 12:41:15 +01001324 def delete_object(self, container_name, filename):
Chris Dent0d494112014-08-26 13:48:30 +01001325 self.object_client.delete_object(container_name, filename)
Chris Dentde456a12014-09-10 12:41:15 +01001326 self.list_and_check_container_objects(container_name,
1327 not_present_obj=[filename])
Chris Dent0d494112014-08-26 13:48:30 +01001328
Chris Dentde456a12014-09-10 12:41:15 +01001329 def list_and_check_container_objects(self, container_name,
1330 present_obj=None,
1331 not_present_obj=None):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001332 # List objects for a given container and assert which are present and
1333 # which are not.
Ghanshyam2a180b82014-06-16 13:54:22 +09001334 if present_obj is None:
1335 present_obj = []
1336 if not_present_obj is None:
1337 not_present_obj = []
Chris Dent0d494112014-08-26 13:48:30 +01001338 _, object_list = self.container_client.list_container_contents(
1339 container_name)
1340 if present_obj:
1341 for obj in present_obj:
1342 self.assertIn(obj, object_list)
1343 if not_present_obj:
1344 for obj in not_present_obj:
1345 self.assertNotIn(obj, object_list)
1346
Chris Dentde456a12014-09-10 12:41:15 +01001347 def change_container_acl(self, container_name, acl):
Chris Dent0d494112014-08-26 13:48:30 +01001348 metadata_param = {'metadata_prefix': 'x-container-',
1349 'metadata': {'read': acl}}
1350 self.container_client.update_container_metadata(container_name,
1351 **metadata_param)
1352 resp, _ = self.container_client.list_container_metadata(container_name)
1353 self.assertEqual(resp['x-container-read'], acl)
1354
Chris Dentde456a12014-09-10 12:41:15 +01001355 def download_and_verify(self, container_name, obj_name, expected_data):
Chris Dent0d494112014-08-26 13:48:30 +01001356 _, obj = self.object_client.get_object(container_name, obj_name)
1357 self.assertEqual(obj, expected_data)