blob: 6ec30b8451a6ddbdb114fb35c8b22ef2f0097aa9 [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
Matthew Treinish96e9e882014-06-09 18:37:19 -040023import six
Sean Dague6dbc6da2013-05-08 17:49:46 -040024
lanoux5fc14522015-09-21 08:17:35 +000025from tempest.common import compute
Ken'ichi Ohmichi01151e82016-06-10 11:19:52 -070026from tempest.common import image as common_image
Fei Long Wangd39431f2015-05-14 11:30:48 +120027from tempest.common.utils import data_utils
Masayuki Igawa4ded9f02014-02-17 15:05:59 +090028from tempest.common.utils.linux import remote_client
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
143 vnic_type = CONF.network.port_vnic_type
144
145 # If vnic_type is configured create port for
146 # every network
147 if vnic_type:
148 ports = []
Lenny Verkhovsky69363502016-07-17 16:33:33 +0300149
lanoux5fc14522015-09-21 08:17:35 +0000150 create_port_body = {'binding:vnic_type': vnic_type,
151 'namestart': 'port-smoke'}
152 if kwargs:
153 # Convert security group names to security group ids
154 # to pass to create_port
155 if 'security_groups' in kwargs:
156 security_groups =\
John Warrenf9606e92015-12-10 12:12:42 -0500157 clients.security_groups_client.list_security_groups(
lanoux5fc14522015-09-21 08:17:35 +0000158 ).get('security_groups')
159 sec_dict = dict([(s['name'], s['id'])
160 for s in security_groups])
161
162 sec_groups_names = [s['name'] for s in kwargs.pop(
163 'security_groups')]
164 security_groups_ids = [sec_dict[s]
165 for s in sec_groups_names]
166
167 if security_groups_ids:
168 create_port_body[
169 'security_groups'] = security_groups_ids
Lenny Verkhovsky69363502016-07-17 16:33:33 +0300170 networks = kwargs.pop('networks', [])
171 else:
172 networks = []
lanoux5fc14522015-09-21 08:17:35 +0000173
174 # If there are no networks passed to us we look up
Lenny Verkhovsky136376f2016-06-29 14:33:34 +0300175 # for the project's private networks and create a port.
176 # The same behaviour as we would expect when passing
177 # the call to the clients with no networks
lanoux5fc14522015-09-21 08:17:35 +0000178 if not networks:
179 networks = clients.networks_client.list_networks(
Lenny Verkhovsky136376f2016-06-29 14:33:34 +0300180 **{'router:external': False, 'fields': 'id'})['networks']
181
182 # It's net['uuid'] if networks come from kwargs
183 # and net['id'] if they come from
184 # clients.networks_client.list_networks
lanoux5fc14522015-09-21 08:17:35 +0000185 for net in networks:
Lenny Verkhovsky97f7cea2016-08-15 13:29:48 +0000186 net_id = net.get('uuid', net.get('id'))
Lenny Verkhovsky69363502016-07-17 16:33:33 +0300187 if 'port' not in net:
188 port = self._create_port(network_id=net_id,
189 client=clients.ports_client,
190 **create_port_body)
191 ports.append({'port': port['id']})
192 else:
193 ports.append({'port': net['port']})
lanoux5fc14522015-09-21 08:17:35 +0000194 if ports:
195 kwargs['networks'] = ports
196 self.ports = ports
197
198 tenant_network = self.get_tenant_network()
199
200 body, servers = compute.create_test_server(
201 clients,
202 tenant_network=tenant_network,
203 wait_until=wait_until,
Anusha Ramineni9aaef8b2016-01-19 10:56:40 +0530204 name=name, flavor=flavor,
205 image_id=image_id, **kwargs)
lanoux5fc14522015-09-21 08:17:35 +0000206
Jordan Pittierf672b7d2016-06-20 18:50:40 +0200207 self.addCleanup(waiters.wait_for_server_termination,
208 clients.servers_client, body['id'])
209 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
210 clients.servers_client.delete_server, body['id'])
lanoux5fc14522015-09-21 08:17:35 +0000211 server = clients.servers_client.show_server(body['id'])['server']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100212 return server
213
Markus Zoeller3d2a21c2015-02-27 12:04:22 +0100214 def create_volume(self, size=None, name=None, snapshot_id=None,
Jordan Pittier5e1741c2016-03-02 18:25:51 +0100215 imageRef=None, volume_type=None):
Ken'ichi Ohmichiadb905e2016-08-26 15:16:23 -0700216 if size is None:
217 size = CONF.volume.volume_size
Andrea Frittoli247058f2014-07-16 16:09:22 +0100218 if name is None:
zhuflf9d95722016-10-19 16:06:17 +0800219 name = data_utils.rand_name(self.__class__.__name__ + "-volume")
Ghanshyam8fc0ed22015-12-18 10:25:14 +0900220 kwargs = {'display_name': name,
221 'snapshot_id': snapshot_id,
222 'imageRef': imageRef,
Ken'ichi Ohmichiadb905e2016-08-26 15:16:23 -0700223 'volume_type': volume_type,
224 'size': size}
Ghanshyam8fc0ed22015-12-18 10:25:14 +0900225 volume = self.volumes_client.create_volume(**kwargs)['volume']
Matt Riedemanne85c2702014-09-10 11:50:13 -0700226
Jordan Pittier5e1741c2016-03-02 18:25:51 +0100227 self.addCleanup(self.volumes_client.wait_for_resource_deletion,
228 volume['id'])
Jordan Pittier9e227c52016-02-09 14:35:18 +0100229 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
Jordan Pittier5e1741c2016-03-02 18:25:51 +0100230 self.volumes_client.delete_volume, volume['id'])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100231
Ivan Kolodyazhnybcfc32e2015-08-06 13:31:36 +0300232 # NOTE(e0ne): Cinder API v2 uses name instead of display_name
233 if 'display_name' in volume:
234 self.assertEqual(name, volume['display_name'])
235 else:
236 self.assertEqual(name, volume['name'])
Yaroslav Lobankoved3a35b2016-03-24 22:41:30 -0500237 waiters.wait_for_volume_status(self.volumes_client,
238 volume['id'], 'available')
Andrea Frittoli247058f2014-07-16 16:09:22 +0100239 # The volume retrieved on creation has a non-up-to-date status.
240 # Retrieval after it becomes active ensures correct details.
John Warren6177c9e2015-08-19 20:00:17 +0000241 volume = self.volumes_client.show_volume(volume['id'])['volume']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100242 return volume
243
Yair Fried1fc32a12014-08-04 09:11:30 +0300244 def _create_loginable_secgroup_rule(self, secgroup_id=None):
John Warrenf2345512015-12-10 13:39:30 -0500245 _client = self.compute_security_groups_client
John Warren5cdbf422016-01-05 12:42:43 -0500246 _client_rules = self.compute_security_group_rules_client
Andrea Frittoli247058f2014-07-16 16:09:22 +0100247 if secgroup_id is None:
ghanshyamb610b772015-08-24 17:29:38 +0900248 sgs = _client.list_security_groups()['security_groups']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100249 for sg in sgs:
250 if sg['name'] == 'default':
251 secgroup_id = sg['id']
252
253 # These rules are intended to permit inbound ssh and icmp
254 # traffic from all sources, so no group_id is provided.
255 # Setting a group_id would only permit traffic from ports
256 # belonging to the same security group.
257 rulesets = [
258 {
259 # ssh
Ken'ichi Ohmichieb7eeec2015-07-21 01:00:06 +0000260 'ip_protocol': 'tcp',
Andrea Frittoli247058f2014-07-16 16:09:22 +0100261 'from_port': 22,
262 'to_port': 22,
263 'cidr': '0.0.0.0/0',
264 },
265 {
266 # ping
Ken'ichi Ohmichieb7eeec2015-07-21 01:00:06 +0000267 'ip_protocol': 'icmp',
Andrea Frittoli247058f2014-07-16 16:09:22 +0100268 'from_port': -1,
269 'to_port': -1,
270 'cidr': '0.0.0.0/0',
271 }
272 ]
273 rules = list()
274 for ruleset in rulesets:
Ken'ichi Ohmichieb7eeec2015-07-21 01:00:06 +0000275 sg_rule = _client_rules.create_security_group_rule(
ghanshyam0a5e1232015-08-24 16:59:59 +0900276 parent_group_id=secgroup_id, **ruleset)['security_group_rule']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100277 rules.append(sg_rule)
278 return rules
279
Yair Fried1fc32a12014-08-04 09:11:30 +0300280 def _create_security_group(self):
Andrea Frittoli247058f2014-07-16 16:09:22 +0100281 # Create security group
282 sg_name = data_utils.rand_name(self.__class__.__name__)
283 sg_desc = sg_name + " description"
John Warrenf2345512015-12-10 13:39:30 -0500284 secgroup = self.compute_security_groups_client.create_security_group(
ghanshyamb610b772015-08-24 17:29:38 +0900285 name=sg_name, description=sg_desc)['security_group']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100286 self.assertEqual(secgroup['name'], sg_name)
287 self.assertEqual(secgroup['description'], sg_desc)
John Warrenf2345512015-12-10 13:39:30 -0500288 self.addCleanup(
Jordan Pittier9e227c52016-02-09 14:35:18 +0100289 test_utils.call_and_ignore_notfound_exc,
John Warrenf2345512015-12-10 13:39:30 -0500290 self.compute_security_groups_client.delete_security_group,
291 secgroup['id'])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100292
293 # Add rules to the security group
Yair Fried1fc32a12014-08-04 09:11:30 +0300294 self._create_loginable_secgroup_rule(secgroup['id'])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100295
296 return secgroup
297
Sean Dague20e98612016-01-06 14:33:28 -0500298 def get_remote_client(self, ip_address, username=None, private_key=None):
JordanP3fe2dc32014-11-17 13:06:01 +0100299 """Get a SSH client to a remote server
300
Sean Dague20e98612016-01-06 14:33:28 -0500301 @param ip_address the server floating or fixed IP address to use
302 for ssh validation
JordanP3fe2dc32014-11-17 13:06:01 +0100303 @param username name of the Linux account on the remote server
304 @param private_key the SSH private key to use
JordanP3fe2dc32014-11-17 13:06:01 +0100305 @return a RemoteClient object
306 """
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700307
Andrea Frittoli247058f2014-07-16 16:09:22 +0100308 if username is None:
lanoux283273b2015-12-04 03:01:54 -0800309 username = CONF.validation.image_ssh_user
wantwatering896300c2015-03-27 15:17:42 +0800310 # Set this with 'keypair' or others to log in with keypair or
311 # username/password.
lanoux5fc14522015-09-21 08:17:35 +0000312 if CONF.validation.auth_method == 'keypair':
wantwatering896300c2015-03-27 15:17:42 +0800313 password = None
314 if private_key is None:
315 private_key = self.keypair['private_key']
316 else:
lanoux283273b2015-12-04 03:01:54 -0800317 password = CONF.validation.image_ssh_password
wantwatering896300c2015-03-27 15:17:42 +0800318 private_key = None
Sean Dague20e98612016-01-06 14:33:28 -0500319 linux_client = remote_client.RemoteClient(ip_address, username,
wantwatering896300c2015-03-27 15:17:42 +0800320 pkey=private_key,
321 password=password)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100322 try:
323 linux_client.validate_authentication()
Matt Riedemann5f0ac522015-05-21 09:16:24 -0700324 except Exception as e:
325 message = ('Initializing SSH connection to %(ip)s failed. '
Eric Brown0911af62016-02-08 17:15:40 -0800326 'Error: %(error)s' % {'ip': ip_address,
Sean Dague20e98612016-01-06 14:33:28 -0500327 'error': e})
Jordan Pittier9e227c52016-02-09 14:35:18 +0100328 caller = test_utils.find_test_caller()
Matt Riedemann5f0ac522015-05-21 09:16:24 -0700329 if caller:
330 message = '(%s) %s' % (caller, message)
331 LOG.exception(message)
Sean Dague2c98a162016-01-06 14:11:13 -0500332 self._log_console_output()
Andrea Frittoli247058f2014-07-16 16:09:22 +0100333 raise
334
335 return linux_client
336
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000337 def _image_create(self, name, fmt, path,
338 disk_format=None, properties=None):
Ghanshyam2a180b82014-06-16 13:54:22 +0900339 if properties is None:
340 properties = {}
Andrea Frittoli247058f2014-07-16 16:09:22 +0100341 name = data_utils.rand_name('%s-' % name)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100342 params = {
343 'name': name,
344 'container_format': fmt,
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000345 'disk_format': disk_format or fmt,
Andrea Frittoli247058f2014-07-16 16:09:22 +0100346 }
Matt Riedemann2aa19d42016-06-06 17:45:41 -0400347 if CONF.image_feature_enabled.api_v1:
348 params['is_public'] = 'False'
349 params['properties'] = properties
Ken'ichi Ohmichi02bcdf32016-06-17 16:41:26 -0700350 params = {'headers': common_image.image_meta_to_headers(**params)}
Matt Riedemann2aa19d42016-06-06 17:45:41 -0400351 else:
352 params['visibility'] = 'private'
353 # Additional properties are flattened out in the v2 API.
354 params.update(properties)
355 body = self.image_client.create_image(**params)
356 image = body['image'] if 'image' in body else body
Andrea Frittoli247058f2014-07-16 16:09:22 +0100357 self.addCleanup(self.image_client.delete_image, image['id'])
358 self.assertEqual("queued", image['status'])
zhang.leia4b1cef2016-03-01 10:50:01 +0800359 with open(path, 'rb') as image_file:
Matt Riedemann2aa19d42016-06-06 17:45:41 -0400360 if CONF.image_feature_enabled.api_v1:
361 self.image_client.update_image(image['id'], data=image_file)
362 else:
363 self.image_client.store_image_file(image['id'], image_file)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100364 return image['id']
365
366 def glance_image_create(self):
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300367 img_path = CONF.scenario.img_dir + "/" + CONF.scenario.img_file
Andrea Frittoli247058f2014-07-16 16:09:22 +0100368 aki_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.aki_img_file
369 ari_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.ari_img_file
370 ami_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.ami_img_file
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300371 img_container_format = CONF.scenario.img_container_format
372 img_disk_format = CONF.scenario.img_disk_format
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000373 img_properties = CONF.scenario.img_properties
PranaliD2aa523c2016-06-07 03:54:34 -0400374 LOG.debug("paths: img: %s, container_format: %s, disk_format: %s, "
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000375 "properties: %s, ami: %s, ari: %s, aki: %s" %
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300376 (img_path, img_container_format, img_disk_format,
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000377 img_properties, ami_img_path, ari_img_path, aki_img_path))
Andrea Frittoli247058f2014-07-16 16:09:22 +0100378 try:
Jordan Pittier1e443ec2015-11-20 16:15:58 +0100379 image = self._image_create('scenario-img',
380 img_container_format,
381 img_path,
382 disk_format=img_disk_format,
383 properties=img_properties)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100384 except IOError:
385 LOG.debug("A qcow2 image was not found. Try to get a uec image.")
386 kernel = self._image_create('scenario-aki', 'aki', aki_img_path)
387 ramdisk = self._image_create('scenario-ari', 'ari', ari_img_path)
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000388 properties = {'kernel_id': kernel, 'ramdisk_id': ramdisk}
Jordan Pittier1e443ec2015-11-20 16:15:58 +0100389 image = self._image_create('scenario-ami', 'ami',
390 path=ami_img_path,
391 properties=properties)
392 LOG.debug("image:%s" % image)
393
394 return image
Andrea Frittoli247058f2014-07-16 16:09:22 +0100395
396 def _log_console_output(self, servers=None):
Matthew Treinish42a3f3a2014-09-04 15:04:53 -0400397 if not CONF.compute_feature_enabled.console_output:
398 LOG.debug('Console output not supported, cannot log')
399 return
Andrea Frittoli247058f2014-07-16 16:09:22 +0100400 if not servers:
David Kranzae99b9a2015-02-16 13:37:01 -0500401 servers = self.servers_client.list_servers()
Andrea Frittoli247058f2014-07-16 16:09:22 +0100402 servers = servers['servers']
403 for server in servers:
Brant Knudson566c5712014-09-24 20:04:50 -0500404 console_output = self.servers_client.get_console_output(
Ken'ichi Ohmichibf4766a2015-12-09 07:48:43 +0000405 server['id'])['output']
David Kranzae99b9a2015-02-16 13:37:01 -0500406 LOG.debug('Console output for %s\nbody=\n%s',
407 server['id'], console_output)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100408
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000409 def _log_net_info(self, exc):
410 # network debug is called as part of ssh init
Andrey Pavlov64723762015-04-29 06:24:58 +0300411 if not isinstance(exc, lib_exc.SSHTimeout):
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000412 LOG.debug('Network information on a devstack host')
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000413
nithya-ganesan882595e2014-07-29 18:51:07 +0000414 def create_server_snapshot(self, server, name=None):
415 # Glance client
416 _image_client = self.image_client
417 # Compute client
Ghanshyamae76c122015-12-22 13:41:35 +0900418 _images_client = self.compute_images_client
nithya-ganesan882595e2014-07-29 18:51:07 +0000419 if name is None:
zhuflf9d95722016-10-19 16:06:17 +0800420 name = data_utils.rand_name(self.__class__.__name__ + 'snapshot')
nithya-ganesan882595e2014-07-29 18:51:07 +0000421 LOG.debug("Creating a snapshot image for server: %s", server['name'])
Ken'ichi Ohmichi28f18672015-07-17 10:00:38 +0000422 image = _images_client.create_image(server['id'], name=name)
David Kranza5299eb2015-01-15 17:24:05 -0500423 image_id = image.response['location'].split('images/')[1]
Yaroslav Lobankov2fea4052016-04-19 15:05:57 +0300424 waiters.wait_for_image_status(_image_client, image_id, 'active')
Jordan Pittierf672b7d2016-06-20 18:50:40 +0200425
426 self.addCleanup(_image_client.wait_for_resource_deletion,
427 image_id)
428 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
429 _image_client.delete_image, image_id)
430
Matt Riedemann2aa19d42016-06-06 17:45:41 -0400431 if CONF.image_feature_enabled.api_v1:
432 # In glance v1 the additional properties are stored in the headers.
Ken'ichi Ohmichi01151e82016-06-10 11:19:52 -0700433 resp = _image_client.check_image(image_id)
434 snapshot_image = common_image.get_image_meta_from_headers(resp)
Matt Riedemann2aa19d42016-06-06 17:45:41 -0400435 image_props = snapshot_image.get('properties', {})
436 else:
437 # In glance v2 the additional properties are flattened.
438 snapshot_image = _image_client.show_image(image_id)
439 image_props = snapshot_image
Andrey Pavlovc8bd4b12015-08-17 10:20:17 +0300440
Matt Riedemann2aa19d42016-06-06 17:45:41 -0400441 bdm = image_props.get('block_device_mapping')
Andrey Pavlovc8bd4b12015-08-17 10:20:17 +0300442 if bdm:
443 bdm = json.loads(bdm)
444 if bdm and 'snapshot_id' in bdm[0]:
445 snapshot_id = bdm[0]['snapshot_id']
446 self.addCleanup(
447 self.snapshots_client.wait_for_resource_deletion,
448 snapshot_id)
Jordan Pittier9e227c52016-02-09 14:35:18 +0100449 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
450 self.snapshots_client.delete_snapshot,
451 snapshot_id)
Yaroslav Lobankov667aaa22016-03-24 23:13:28 -0500452 waiters.wait_for_snapshot_status(self.snapshots_client,
453 snapshot_id, 'available')
nithya-ganesan882595e2014-07-29 18:51:07 +0000454 image_name = snapshot_image['name']
455 self.assertEqual(name, image_name)
456 LOG.debug("Created snapshot image %s for server %s",
457 image_name, server['name'])
458 return snapshot_image
459
Jordan Pittier7cf64762015-10-14 15:01:12 +0200460 def nova_volume_attach(self, server, volume_to_attach):
Joseph Lanoux6809bab2014-12-18 14:57:18 +0000461 volume = self.servers_client.attach_volume(
Jordan Pittier7cf64762015-10-14 15:01:12 +0200462 server['id'], volumeId=volume_to_attach['id'], device='/dev/%s'
ghanshyam0f825252015-08-25 16:02:50 +0900463 % CONF.compute.volume_device_name)['volumeAttachment']
Jordan Pittier7cf64762015-10-14 15:01:12 +0200464 self.assertEqual(volume_to_attach['id'], volume['id'])
Yaroslav Lobankoved3a35b2016-03-24 22:41:30 -0500465 waiters.wait_for_volume_status(self.volumes_client,
466 volume['id'], 'in-use')
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900467
Jordan Pittier7cf64762015-10-14 15:01:12 +0200468 # Return the updated volume after the attachment
469 return self.volumes_client.show_volume(volume['id'])['volume']
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900470
Jordan Pittier7cf64762015-10-14 15:01:12 +0200471 def nova_volume_detach(self, server, volume):
472 self.servers_client.detach_volume(server['id'], volume['id'])
Yaroslav Lobankoved3a35b2016-03-24 22:41:30 -0500473 waiters.wait_for_volume_status(self.volumes_client,
474 volume['id'], 'available')
Jordan Pittier7cf64762015-10-14 15:01:12 +0200475
476 volume = self.volumes_client.show_volume(volume['id'])['volume']
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900477 self.assertEqual('available', volume['status'])
478
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700479 def rebuild_server(self, server_id, image=None,
480 preserve_ephemeral=False, wait=True,
481 rebuild_kwargs=None):
482 if image is None:
483 image = CONF.compute.image_ref
484
485 rebuild_kwargs = rebuild_kwargs or {}
486
487 LOG.debug("Rebuilding server (id: %s, image: %s, preserve eph: %s)",
488 server_id, image, preserve_ephemeral)
Ken'ichi Ohmichi5271b0f2015-08-10 07:53:27 +0000489 self.servers_client.rebuild_server(
490 server_id=server_id, image_ref=image,
491 preserve_ephemeral=preserve_ephemeral,
492 **rebuild_kwargs)
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700493 if wait:
Ken'ichi Ohmichi0eb153c2015-07-13 02:18:25 +0000494 waiters.wait_for_server_status(self.servers_client,
495 server_id, 'ACTIVE')
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700496
Steven Hardyda2a8352014-10-02 12:52:20 +0100497 def ping_ip_address(self, ip_address, should_succeed=True,
498 ping_timeout=None):
lanoux5fc14522015-09-21 08:17:35 +0000499 timeout = ping_timeout or CONF.validation.ping_timeout
Aaron Rosena7df13b2014-09-23 09:45:45 -0700500 cmd = ['ping', '-c1', '-w1', ip_address]
501
502 def ping():
503 proc = subprocess.Popen(cmd,
504 stdout=subprocess.PIPE,
505 stderr=subprocess.PIPE)
506 proc.communicate()
Shuquan Huang753629e2015-07-20 08:52:29 +0000507
Aaron Rosena7df13b2014-09-23 09:45:45 -0700508 return (proc.returncode == 0) == should_succeed
509
Jordan Pittier9e227c52016-02-09 14:35:18 +0100510 caller = test_utils.find_test_caller()
Shuquan Huang753629e2015-07-20 08:52:29 +0000511 LOG.debug('%(caller)s begins to ping %(ip)s in %(timeout)s sec and the'
512 ' expected result is %(should_succeed)s' % {
513 'caller': caller, 'ip': ip_address, 'timeout': timeout,
514 'should_succeed':
515 'reachable' if should_succeed else 'unreachable'
516 })
Jordan Pittier35a63752016-08-30 13:09:12 +0200517 result = test_utils.call_until_true(ping, timeout, 1)
Shuquan Huang753629e2015-07-20 08:52:29 +0000518 LOG.debug('%(caller)s finishes ping %(ip)s in %(timeout)s sec and the '
519 'ping result is %(result)s' % {
520 'caller': caller, 'ip': ip_address, 'timeout': timeout,
521 'result': 'expected' if result else 'unexpected'
522 })
523 return result
Aaron Rosena7df13b2014-09-23 09:45:45 -0700524
Yair Friedae0e73d2014-11-24 11:56:26 +0200525 def check_vm_connectivity(self, ip_address,
526 username=None,
527 private_key=None,
528 should_connect=True):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000529 """Check server connectivity
530
Yair Friedae0e73d2014-11-24 11:56:26 +0200531 :param ip_address: server to test against
532 :param username: server's ssh username
533 :param private_key: server's ssh private key to be used
534 :param should_connect: True/False indicates positive/negative test
535 positive - attempt ping and ssh
536 negative - attempt ping and fail if succeed
537
538 :raises: AssertError if the result of the connectivity check does
539 not match the value of the should_connect param
540 """
541 if should_connect:
542 msg = "Timed out waiting for %s to become reachable" % ip_address
543 else:
544 msg = "ip address %s is reachable" % ip_address
545 self.assertTrue(self.ping_ip_address(ip_address,
546 should_succeed=should_connect),
547 msg=msg)
548 if should_connect:
549 # no need to check ssh for negative connectivity
550 self.get_remote_client(ip_address, username, private_key)
551
552 def check_public_network_connectivity(self, ip_address, username,
553 private_key, should_connect=True,
554 msg=None, servers=None):
555 # The target login is assumed to have been configured for
556 # key-based authentication by cloud-init.
557 LOG.debug('checking network connections to IP %s with user: %s' %
558 (ip_address, username))
559 try:
560 self.check_vm_connectivity(ip_address,
561 username,
562 private_key,
563 should_connect=should_connect)
Matthew Treinish53483132014-12-09 18:50:06 -0500564 except Exception:
Yair Friedae0e73d2014-11-24 11:56:26 +0200565 ex_msg = 'Public network connectivity check failed'
566 if msg:
567 ex_msg += ": " + msg
568 LOG.exception(ex_msg)
569 self._log_console_output(servers)
Yair Friedae0e73d2014-11-24 11:56:26 +0200570 raise
571
572 def create_floating_ip(self, thing, pool_name=None):
Ken'ichi Ohmichia112a592015-11-17 08:49:37 +0000573 """Create a floating IP and associates to a server on Nova"""
Yair Friedae0e73d2014-11-24 11:56:26 +0200574
Marc Koderer3b57d802016-03-22 15:23:31 +0100575 if not pool_name:
576 pool_name = CONF.network.floating_network_name
John Warrene74890a2015-11-11 15:18:01 -0500577 floating_ip = (self.compute_floating_ips_client.
Ken'ichi Ohmichie037a6f2015-12-03 06:41:49 +0000578 create_floating_ip(pool=pool_name)['floating_ip'])
Jordan Pittier9e227c52016-02-09 14:35:18 +0100579 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
John Warrene74890a2015-11-11 15:18:01 -0500580 self.compute_floating_ips_client.delete_floating_ip,
Yair Friedae0e73d2014-11-24 11:56:26 +0200581 floating_ip['id'])
John Warrene74890a2015-11-11 15:18:01 -0500582 self.compute_floating_ips_client.associate_floating_ip_to_server(
Yair Friedae0e73d2014-11-24 11:56:26 +0200583 floating_ip['ip'], thing['id'])
584 return floating_ip
585
Sean Dague20e98612016-01-06 14:33:28 -0500586 def create_timestamp(self, ip_address, dev_name=None, mount_path='/mnt',
Matt Riedemannfd5657d2015-09-30 14:47:07 -0700587 private_key=None):
Sean Dague20e98612016-01-06 14:33:28 -0500588 ssh_client = self.get_remote_client(ip_address,
Matt Riedemannfd5657d2015-09-30 14:47:07 -0700589 private_key=private_key)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300590 if dev_name is not None:
591 ssh_client.make_fs(dev_name)
Matt Riedemann076685a2015-09-30 14:38:16 -0700592 ssh_client.mount(dev_name, mount_path)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300593 cmd_timestamp = 'sudo sh -c "date > %s/timestamp; sync"' % mount_path
594 ssh_client.exec_command(cmd_timestamp)
595 timestamp = ssh_client.exec_command('sudo cat %s/timestamp'
596 % mount_path)
597 if dev_name is not None:
598 ssh_client.umount(mount_path)
599 return timestamp
600
Sean Dague20e98612016-01-06 14:33:28 -0500601 def get_timestamp(self, ip_address, dev_name=None, mount_path='/mnt',
Matt Riedemannfd5657d2015-09-30 14:47:07 -0700602 private_key=None):
Sean Dague20e98612016-01-06 14:33:28 -0500603 ssh_client = self.get_remote_client(ip_address,
Matt Riedemannfd5657d2015-09-30 14:47:07 -0700604 private_key=private_key)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300605 if dev_name is not None:
Matt Riedemann076685a2015-09-30 14:38:16 -0700606 ssh_client.mount(dev_name, mount_path)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300607 timestamp = ssh_client.exec_command('sudo cat %s/timestamp'
608 % mount_path)
609 if dev_name is not None:
610 ssh_client.umount(mount_path)
611 return timestamp
612
Sean Dague20e98612016-01-06 14:33:28 -0500613 def get_server_ip(self, server):
614 """Get the server fixed or floating IP.
615
616 Based on the configuration we're in, return a correct ip
617 address for validating that a guest is up.
618 """
Alexander Gubanovc8829f82015-11-12 10:35:13 +0200619 if CONF.validation.connect_method == 'floating':
Sean Dague20e98612016-01-06 14:33:28 -0500620 # The tests calling this method don't have a floating IP
zhufl0892cb22016-05-06 14:46:00 +0800621 # and can't make use of the validation resources. So the
Sean Dague20e98612016-01-06 14:33:28 -0500622 # method is creating the floating IP there.
623 return self.create_floating_ip(server)['ip']
624 elif CONF.validation.connect_method == 'fixed':
Matt Riedemanna7782552016-08-08 16:26:01 -0400625 # Determine the network name to look for based on config or creds
626 # provider network resources.
627 if CONF.validation.network_for_ssh:
628 addresses = server['addresses'][
629 CONF.validation.network_for_ssh]
630 else:
631 creds_provider = self._get_credentials_provider()
632 net_creds = creds_provider.get_primary_creds()
633 network = getattr(net_creds, 'network', None)
634 addresses = (server['addresses'][network['name']]
635 if network else [])
Sean Dague20e98612016-01-06 14:33:28 -0500636 for address in addresses:
Matt Riedemanna7782552016-08-08 16:26:01 -0400637 if (address['version'] == CONF.validation.ip_version_for_ssh
638 and address['OS-EXT-IPS:type'] == 'fixed'):
Sean Dague20e98612016-01-06 14:33:28 -0500639 return address['addr']
zhufl955f82b2016-07-22 11:14:34 +0800640 raise exceptions.ServerUnreachable(server_id=server['id'])
Alexander Gubanovc8829f82015-11-12 10:35:13 +0200641 else:
Matthew Treinish4217a702016-10-07 17:27:11 -0400642 raise lib_exc.InvalidConfiguration()
Alexander Gubanovc8829f82015-11-12 10:35:13 +0200643
Andrea Frittoli2e733b52014-07-16 14:12:11 +0100644
Andrea Frittoli4971fc82014-09-25 10:22:20 +0100645class NetworkScenarioTest(ScenarioTest):
Yair Fried1fc32a12014-08-04 09:11:30 +0300646 """Base class for network scenario tests.
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000647
Yair Fried1fc32a12014-08-04 09:11:30 +0300648 This class provide helpers for network scenario tests, using the neutron
649 API. Helpers from ancestor which use the nova network API are overridden
650 with the neutron API.
651
652 This Class also enforces using Neutron instead of novanetwork.
653 Subclassed tests will be skipped if Neutron is not enabled
654
655 """
656
Andrea Frittolib21de6c2015-02-06 20:12:38 +0000657 credentials = ['primary', 'admin']
658
Yair Fried1fc32a12014-08-04 09:11:30 +0300659 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +0000660 def skip_checks(cls):
661 super(NetworkScenarioTest, cls).skip_checks()
Andrea Frittoli2ddc2632014-09-25 11:03:00 +0100662 if not CONF.service_available.neutron:
663 raise cls.skipException('Neutron not available')
Yair Fried1fc32a12014-08-04 09:11:30 +0300664
665 @classmethod
Andrea Frittoliac20b5e2014-09-15 13:31:14 +0100666 def resource_setup(cls):
667 super(NetworkScenarioTest, cls).resource_setup()
Yair Fried1fc32a12014-08-04 09:11:30 +0300668 cls.tenant_id = cls.manager.identity_client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300669
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -0700670 def _create_network(self, networks_client=None,
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000671 routers_client=None, tenant_id=None,
Markus Zoeller156b5da2016-07-11 18:10:31 +0200672 namestart='network-smoke-',
673 port_security_enabled=True):
John Warren94d8faf2015-09-15 12:22:24 -0400674 if not networks_client:
675 networks_client = self.networks_client
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000676 if not routers_client:
677 routers_client = self.routers_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300678 if not tenant_id:
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -0700679 tenant_id = networks_client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300680 name = data_utils.rand_name(namestart)
Matt Riedemann039b2fe2016-09-15 16:12:24 -0400681 network_kwargs = dict(name=name, tenant_id=tenant_id)
682 # Neutron disables port security by default so we have to check the
683 # config before trying to create the network with port_security_enabled
684 if CONF.network_feature_enabled.port_security:
685 network_kwargs['port_security_enabled'] = port_security_enabled
Markus Zoeller156b5da2016-07-11 18:10:31 +0200686 result = networks_client.create_network(**network_kwargs)
Steve Heyman33735f22016-05-24 09:28:08 -0500687 network = result['network']
688
689 self.assertEqual(network['name'], name)
Jordan Pittier9e227c52016-02-09 14:35:18 +0100690 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
Steve Heyman33735f22016-05-24 09:28:08 -0500691 self.networks_client.delete_network,
692 network['id'])
Yair Fried1fc32a12014-08-04 09:11:30 +0300693 return network
694
695 def _list_networks(self, *args, **kwargs):
696 """List networks using admin creds """
John Warren94d8faf2015-09-15 12:22:24 -0400697 networks_list = self.admin_manager.networks_client.list_networks(
ghanshyam2f7cc022015-06-26 18:18:11 +0900698 *args, **kwargs)
699 return networks_list['networks']
Yair Fried1fc32a12014-08-04 09:11:30 +0300700
701 def _list_subnets(self, *args, **kwargs):
702 """List subnets using admin creds """
John Warren3961acd2015-10-02 14:38:53 -0400703 subnets_list = self.admin_manager.subnets_client.list_subnets(
ghanshyam2f7cc022015-06-26 18:18:11 +0900704 *args, **kwargs)
705 return subnets_list['subnets']
Yair Fried1fc32a12014-08-04 09:11:30 +0300706
707 def _list_routers(self, *args, **kwargs):
708 """List routers using admin creds """
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000709 routers_list = self.admin_manager.routers_client.list_routers(
ghanshyam2f7cc022015-06-26 18:18:11 +0900710 *args, **kwargs)
711 return routers_list['routers']
Yair Fried1fc32a12014-08-04 09:11:30 +0300712
713 def _list_ports(self, *args, **kwargs):
714 """List ports using admin creds """
John Warren49c0fe52015-10-22 12:35:54 -0400715 ports_list = self.admin_manager.ports_client.list_ports(
ghanshyam2f7cc022015-06-26 18:18:11 +0900716 *args, **kwargs)
717 return ports_list['ports']
Yair Fried1fc32a12014-08-04 09:11:30 +0300718
Yair Fried564d89d2015-08-06 17:02:12 +0300719 def _list_agents(self, *args, **kwargs):
720 """List agents using admin creds """
Ken'ichi Ohmichi71860062015-12-15 08:20:13 +0000721 agents_list = self.admin_manager.network_agents_client.list_agents(
Yair Fried564d89d2015-08-06 17:02:12 +0300722 *args, **kwargs)
723 return agents_list['agents']
724
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -0700725 def _create_subnet(self, network, subnets_client=None,
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000726 routers_client=None, namestart='subnet-smoke',
727 **kwargs):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000728 """Create a subnet for the given network
729
730 within the cidr block configured for tenant networks.
Yair Fried1fc32a12014-08-04 09:11:30 +0300731 """
John Warren3961acd2015-10-02 14:38:53 -0400732 if not subnets_client:
733 subnets_client = self.subnets_client
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000734 if not routers_client:
735 routers_client = self.routers_client
Yair Fried1fc32a12014-08-04 09:11:30 +0300736
737 def cidr_in_use(cidr, tenant_id):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000738 """Check cidr existence
739
lei zhangdd552b22015-11-25 20:41:48 +0800740 :returns: True if subnet with cidr already exist in tenant
741 False else
Yair Fried1fc32a12014-08-04 09:11:30 +0300742 """
743 cidr_in_use = self._list_subnets(tenant_id=tenant_id, cidr=cidr)
744 return len(cidr_in_use) != 0
745
Kirill Shileev14113572014-11-21 16:58:02 +0300746 ip_version = kwargs.pop('ip_version', 4)
747
748 if ip_version == 6:
749 tenant_cidr = netaddr.IPNetwork(
Sean Dagueed6e5862016-04-04 10:49:13 -0400750 CONF.network.project_network_v6_cidr)
751 num_bits = CONF.network.project_network_v6_mask_bits
Kirill Shileev14113572014-11-21 16:58:02 +0300752 else:
Sean Dagueed6e5862016-04-04 10:49:13 -0400753 tenant_cidr = netaddr.IPNetwork(CONF.network.project_network_cidr)
754 num_bits = CONF.network.project_network_mask_bits
Kirill Shileev14113572014-11-21 16:58:02 +0300755
Yair Fried1fc32a12014-08-04 09:11:30 +0300756 result = None
Kirill Shileev14113572014-11-21 16:58:02 +0300757 str_cidr = None
Yair Fried1fc32a12014-08-04 09:11:30 +0300758 # Repeatedly attempt subnet creation with sequential cidr
759 # blocks until an unallocated block is found.
Kirill Shileev14113572014-11-21 16:58:02 +0300760 for subnet_cidr in tenant_cidr.subnet(num_bits):
Yair Fried1fc32a12014-08-04 09:11:30 +0300761 str_cidr = str(subnet_cidr)
Steve Heyman33735f22016-05-24 09:28:08 -0500762 if cidr_in_use(str_cidr, tenant_id=network['tenant_id']):
Yair Fried1fc32a12014-08-04 09:11:30 +0300763 continue
764
765 subnet = dict(
766 name=data_utils.rand_name(namestart),
Steve Heyman33735f22016-05-24 09:28:08 -0500767 network_id=network['id'],
768 tenant_id=network['tenant_id'],
Yair Fried1fc32a12014-08-04 09:11:30 +0300769 cidr=str_cidr,
Kirill Shileev14113572014-11-21 16:58:02 +0300770 ip_version=ip_version,
Yair Fried1fc32a12014-08-04 09:11:30 +0300771 **kwargs
772 )
773 try:
John Warren3961acd2015-10-02 14:38:53 -0400774 result = subnets_client.create_subnet(**subnet)
Yair Fried1fc32a12014-08-04 09:11:30 +0300775 break
Masayuki Igawad9388762015-01-20 14:56:42 +0900776 except lib_exc.Conflict as e:
Yair Fried1fc32a12014-08-04 09:11:30 +0300777 is_overlapping_cidr = 'overlaps with another subnet' in str(e)
778 if not is_overlapping_cidr:
779 raise
780 self.assertIsNotNone(result, 'Unable to allocate tenant network')
Steve Heyman33735f22016-05-24 09:28:08 -0500781
782 subnet = result['subnet']
783 self.assertEqual(subnet['cidr'], str_cidr)
784
785 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
786 subnets_client.delete_subnet, subnet['id'])
787
Yair Fried1fc32a12014-08-04 09:11:30 +0300788 return subnet
789
Kirill Shileev14113572014-11-21 16:58:02 +0300790 def _get_server_port_id_and_ip4(self, server, ip_addr=None):
Kevin Benton1d0c1dc2016-02-04 14:30:08 -0800791 ports = self._list_ports(device_id=server['id'], fixed_ip=ip_addr)
Sean M. Collins2e896832015-12-15 13:58:47 -0500792 # A port can have more then one IP address in some cases.
793 # If the network is dual-stack (IPv4 + IPv6), this port is associated
794 # with 2 subnets
Vasyl Saienko8fd517c2016-05-30 09:52:54 +0300795 p_status = ['ACTIVE']
796 # NOTE(vsaienko) With Ironic, instances live on separate hardware
797 # servers. Neutron does not bind ports for Ironic instances, as a
798 # result the port remains in the DOWN state.
Vasyl Saienkoc8aa34b2016-08-01 14:18:37 +0300799 # TODO(vsaienko) remove once bug: #1599836 is resolved.
Vasyl Saienko8fd517c2016-05-30 09:52:54 +0300800 if CONF.service_available.ironic:
801 p_status.append('DOWN')
Daniel Mellado9e3e1062015-08-06 18:07:05 +0200802 port_map = [(p["id"], fxip["ip_address"])
803 for p in ports
804 for fxip in p["fixed_ips"]
Yatin Kumbhareee4924c2016-06-09 15:12:06 +0530805 if netutils.is_valid_ipv4(fxip["ip_address"])
Vasyl Saienko8fd517c2016-05-30 09:52:54 +0300806 and p['status'] in p_status]
Kevin Benton1d0c1dc2016-02-04 14:30:08 -0800807 inactive = [p for p in ports if p['status'] != 'ACTIVE']
808 if inactive:
809 LOG.warning("Instance has ports that are not ACTIVE: %s", inactive)
Daniel Mellado9e3e1062015-08-06 18:07:05 +0200810
John L. Villalovosb83286f2015-11-04 14:46:57 -0800811 self.assertNotEqual(0, len(port_map),
812 "No IPv4 addresses found in: %s" % ports)
Daniel Mellado9e3e1062015-08-06 18:07:05 +0200813 self.assertEqual(len(port_map), 1,
814 "Found multiple IPv4 addresses: %s. "
815 "Unable to determine which port to target."
816 % port_map)
817 return port_map[0]
Yair Fried1fc32a12014-08-04 09:11:30 +0300818
David Shrewsbury9bac3662014-08-07 15:07:01 -0400819 def _get_network_by_name(self, network_name):
820 net = self._list_networks(name=network_name)
Adam Gandelman878a5fd2015-03-30 14:33:36 -0700821 self.assertNotEqual(len(net), 0,
822 "Unable to get network by name: %s" % network_name)
Steve Heyman33735f22016-05-24 09:28:08 -0500823 return net[0]
David Shrewsbury9bac3662014-08-07 15:07:01 -0400824
Yair Friedae0e73d2014-11-24 11:56:26 +0200825 def create_floating_ip(self, thing, external_network_id=None,
826 port_id=None, client=None):
Ken'ichi Ohmichia112a592015-11-17 08:49:37 +0000827 """Create a floating IP and associates to a resource/port on Neutron"""
Yair Friedae0e73d2014-11-24 11:56:26 +0200828 if not external_network_id:
829 external_network_id = CONF.network.public_network_id
Yair Frieddb6c9e92014-08-06 08:53:13 +0300830 if not client:
John Warrenfbf2a892015-11-17 12:36:14 -0500831 client = self.floating_ips_client
Yair Fried1fc32a12014-08-04 09:11:30 +0300832 if not port_id:
Kirill Shileev14113572014-11-21 16:58:02 +0300833 port_id, ip4 = self._get_server_port_id_and_ip4(thing)
834 else:
835 ip4 = None
David Kranz34e88122014-12-11 15:24:05 -0500836 result = client.create_floatingip(
Yair Fried1fc32a12014-08-04 09:11:30 +0300837 floating_network_id=external_network_id,
838 port_id=port_id,
Kirill Shileev14113572014-11-21 16:58:02 +0300839 tenant_id=thing['tenant_id'],
840 fixed_ip_address=ip4
Yair Fried1fc32a12014-08-04 09:11:30 +0300841 )
Steve Heyman33735f22016-05-24 09:28:08 -0500842 floating_ip = result['floatingip']
Jordan Pittier9e227c52016-02-09 14:35:18 +0100843 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
Steve Heyman33735f22016-05-24 09:28:08 -0500844 self.floating_ips_client.delete_floatingip,
845 floating_ip['id'])
Yair Fried1fc32a12014-08-04 09:11:30 +0300846 return floating_ip
847
848 def _associate_floating_ip(self, floating_ip, server):
Kirill Shileev14113572014-11-21 16:58:02 +0300849 port_id, _ = self._get_server_port_id_and_ip4(server)
Steve Heyman33735f22016-05-24 09:28:08 -0500850 kwargs = dict(port_id=port_id)
851 floating_ip = self.floating_ips_client.update_floatingip(
852 floating_ip['id'], **kwargs)['floatingip']
853 self.assertEqual(port_id, floating_ip['port_id'])
Yair Fried1fc32a12014-08-04 09:11:30 +0300854 return floating_ip
855
856 def _disassociate_floating_ip(self, floating_ip):
Steve Heyman33735f22016-05-24 09:28:08 -0500857 """:param floating_ip: floating_ips_client.create_floatingip"""
858 kwargs = dict(port_id=None)
859 floating_ip = self.floating_ips_client.update_floatingip(
860 floating_ip['id'], **kwargs)['floatingip']
861 self.assertIsNone(floating_ip['port_id'])
Yair Fried1fc32a12014-08-04 09:11:30 +0300862 return floating_ip
863
Yair Fried45f92952014-06-26 05:19:19 +0300864 def check_floating_ip_status(self, floating_ip, status):
Carl Baldwina754e2d2014-10-23 22:47:41 +0000865 """Verifies floatingip reaches the given status
Yair Fried45f92952014-06-26 05:19:19 +0300866
Steve Heyman33735f22016-05-24 09:28:08 -0500867 :param dict floating_ip: floating IP dict to check status
Yair Fried45f92952014-06-26 05:19:19 +0300868 :param status: target status
869 :raises: AssertionError if status doesn't match
870 """
Steve Heyman33735f22016-05-24 09:28:08 -0500871 floatingip_id = floating_ip['id']
872
Carl Baldwina754e2d2014-10-23 22:47:41 +0000873 def refresh():
Steve Heyman33735f22016-05-24 09:28:08 -0500874 result = (self.floating_ips_client.
875 show_floatingip(floatingip_id)['floatingip'])
876 return status == result['status']
Carl Baldwina754e2d2014-10-23 22:47:41 +0000877
Jordan Pittier35a63752016-08-30 13:09:12 +0200878 test_utils.call_until_true(refresh,
879 CONF.network.build_timeout,
880 CONF.network.build_interval)
Steve Heyman33735f22016-05-24 09:28:08 -0500881 floating_ip = self.floating_ips_client.show_floatingip(
882 floatingip_id)['floatingip']
883 self.assertEqual(status, floating_ip['status'],
Yair Fried45f92952014-06-26 05:19:19 +0300884 message="FloatingIP: {fp} is at status: {cst}. "
885 "failed to reach status: {st}"
Steve Heyman33735f22016-05-24 09:28:08 -0500886 .format(fp=floating_ip, cst=floating_ip['status'],
Yair Fried45f92952014-06-26 05:19:19 +0300887 st=status))
888 LOG.info("FloatingIP: {fp} is at status: {st}"
889 .format(fp=floating_ip, st=status))
890
Yair Fried1fc32a12014-08-04 09:11:30 +0300891 def _check_tenant_network_connectivity(self, server,
892 username,
893 private_key,
894 should_connect=True,
895 servers_for_debug=None):
Sean Dagueed6e5862016-04-04 10:49:13 -0400896 if not CONF.network.project_networks_reachable:
Yair Fried1fc32a12014-08-04 09:11:30 +0300897 msg = 'Tenant networks not configured to be reachable.'
898 LOG.info(msg)
899 return
900 # The target login is assumed to have been configured for
901 # key-based authentication by cloud-init.
902 try:
Matthew Treinish71426682015-04-23 11:19:38 -0400903 for net_name, ip_addresses in six.iteritems(server['addresses']):
Yair Fried1fc32a12014-08-04 09:11:30 +0300904 for ip_address in ip_addresses:
ghanshyam807211c2014-12-18 13:21:22 +0900905 self.check_vm_connectivity(ip_address['addr'],
Yair Friedae0e73d2014-11-24 11:56:26 +0200906 username,
907 private_key,
908 should_connect=should_connect)
Yair Fried1fc32a12014-08-04 09:11:30 +0300909 except Exception as e:
910 LOG.exception('Tenant network connectivity check failed')
911 self._log_console_output(servers_for_debug)
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000912 self._log_net_info(e)
Yair Fried1fc32a12014-08-04 09:11:30 +0300913 raise
914
Yair Friedbc46f592015-11-18 16:29:34 +0200915 def _check_remote_connectivity(self, source, dest, should_succeed=True,
916 nic=None):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000917 """check ping server via source ssh connection
Yair Fried1fc32a12014-08-04 09:11:30 +0300918
919 :param source: RemoteClient: an ssh connection from which to ping
920 :param dest: and IP to ping against
921 :param should_succeed: boolean should ping succeed or not
Yair Friedbc46f592015-11-18 16:29:34 +0200922 :param nic: specific network interface to ping from
Yair Fried1fc32a12014-08-04 09:11:30 +0300923 :returns: boolean -- should_succeed == ping
924 :returns: ping is false if ping failed
925 """
926 def ping_remote():
927 try:
Yair Friedbc46f592015-11-18 16:29:34 +0200928 source.ping_host(dest, nic=nic)
Andrey Pavlov64723762015-04-29 06:24:58 +0300929 except lib_exc.SSHExecCommandFailed:
zhangguoqing6c096642016-01-04 06:17:21 +0000930 LOG.warning('Failed to ping IP: %s via a ssh connection '
931 'from: %s.' % (dest, source.ssh_client.host))
Yair Fried1fc32a12014-08-04 09:11:30 +0300932 return not should_succeed
933 return should_succeed
934
Jordan Pittier35a63752016-08-30 13:09:12 +0200935 return test_utils.call_until_true(ping_remote,
936 CONF.validation.ping_timeout,
937 1)
Yair Fried1fc32a12014-08-04 09:11:30 +0300938
John Warren456d9ae2016-01-12 15:36:33 -0500939 def _create_security_group(self, security_group_rules_client=None,
940 tenant_id=None,
John Warrenf9606e92015-12-10 12:12:42 -0500941 namestart='secgroup-smoke',
942 security_groups_client=None):
John Warren456d9ae2016-01-12 15:36:33 -0500943 if security_group_rules_client is None:
944 security_group_rules_client = self.security_group_rules_client
John Warrenf9606e92015-12-10 12:12:42 -0500945 if security_groups_client is None:
946 security_groups_client = self.security_groups_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300947 if tenant_id is None:
John Warrenf9606e92015-12-10 12:12:42 -0500948 tenant_id = security_groups_client.tenant_id
949 secgroup = self._create_empty_security_group(
950 namestart=namestart, client=security_groups_client,
951 tenant_id=tenant_id)
Yair Fried1fc32a12014-08-04 09:11:30 +0300952
953 # Add rules to the security group
John Warrenf9606e92015-12-10 12:12:42 -0500954 rules = self._create_loginable_secgroup_rule(
John Warren456d9ae2016-01-12 15:36:33 -0500955 security_group_rules_client=security_group_rules_client,
956 secgroup=secgroup,
John Warrenf9606e92015-12-10 12:12:42 -0500957 security_groups_client=security_groups_client)
Yair Fried1fc32a12014-08-04 09:11:30 +0300958 for rule in rules:
Steve Heyman33735f22016-05-24 09:28:08 -0500959 self.assertEqual(tenant_id, rule['tenant_id'])
960 self.assertEqual(secgroup['id'], rule['security_group_id'])
Yair Fried1fc32a12014-08-04 09:11:30 +0300961 return secgroup
962
Yair Frieddb6c9e92014-08-06 08:53:13 +0300963 def _create_empty_security_group(self, client=None, tenant_id=None,
Yair Fried1fc32a12014-08-04 09:11:30 +0300964 namestart='secgroup-smoke'):
965 """Create a security group without rules.
966
967 Default rules will be created:
968 - IPv4 egress to any
969 - IPv6 egress to any
970
971 :param tenant_id: secgroup will be created in this tenant
Steve Heyman33735f22016-05-24 09:28:08 -0500972 :returns: the created security group
Yair Fried1fc32a12014-08-04 09:11:30 +0300973 """
974 if client is None:
John Warrenf9606e92015-12-10 12:12:42 -0500975 client = self.security_groups_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300976 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000977 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300978 sg_name = data_utils.rand_name(namestart)
979 sg_desc = sg_name + " description"
980 sg_dict = dict(name=sg_name,
981 description=sg_desc)
982 sg_dict['tenant_id'] = tenant_id
David Kranz34e88122014-12-11 15:24:05 -0500983 result = client.create_security_group(**sg_dict)
Steve Heyman33735f22016-05-24 09:28:08 -0500984
985 secgroup = result['security_group']
986 self.assertEqual(secgroup['name'], sg_name)
987 self.assertEqual(tenant_id, secgroup['tenant_id'])
988 self.assertEqual(secgroup['description'], sg_desc)
989
Jordan Pittier9e227c52016-02-09 14:35:18 +0100990 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
Steve Heyman33735f22016-05-24 09:28:08 -0500991 client.delete_security_group, secgroup['id'])
Yair Fried1fc32a12014-08-04 09:11:30 +0300992 return secgroup
993
Yair Frieddb6c9e92014-08-06 08:53:13 +0300994 def _default_security_group(self, client=None, tenant_id=None):
Yair Fried1fc32a12014-08-04 09:11:30 +0300995 """Get default secgroup for given tenant_id.
996
Ken'ichi Ohmichid67c8da2016-09-13 16:18:11 -0700997 :returns: default secgroup for given tenant
Yair Fried1fc32a12014-08-04 09:11:30 +0300998 """
999 if client is None:
John Warrenf9606e92015-12-10 12:12:42 -05001000 client = self.security_groups_client
Yair Frieddb6c9e92014-08-06 08:53:13 +03001001 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +00001002 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001003 sgs = [
Jordan Pittier8ad86172016-04-25 16:20:53 +02001004 sg for sg in list(client.list_security_groups().values())[0]
Yair Fried1fc32a12014-08-04 09:11:30 +03001005 if sg['tenant_id'] == tenant_id and sg['name'] == 'default'
1006 ]
1007 msg = "No default security group for tenant %s." % (tenant_id)
1008 self.assertTrue(len(sgs) > 0, msg)
Steve Heyman33735f22016-05-24 09:28:08 -05001009 return sgs[0]
Yair Fried1fc32a12014-08-04 09:11:30 +03001010
John Warren456d9ae2016-01-12 15:36:33 -05001011 def _create_security_group_rule(self, secgroup=None,
1012 sec_group_rules_client=None,
John Warrenf9606e92015-12-10 12:12:42 -05001013 tenant_id=None,
1014 security_groups_client=None, **kwargs):
Yair Fried1fc32a12014-08-04 09:11:30 +03001015 """Create a rule from a dictionary of rule parameters.
1016
1017 Create a rule in a secgroup. if secgroup not defined will search for
1018 default secgroup in tenant_id.
1019
Steve Heyman33735f22016-05-24 09:28:08 -05001020 :param secgroup: the security group.
Yair Fried1fc32a12014-08-04 09:11:30 +03001021 :param tenant_id: if secgroup not passed -- the tenant in which to
1022 search for default secgroup
1023 :param kwargs: a dictionary containing rule parameters:
1024 for example, to allow incoming ssh:
1025 rule = {
1026 direction: 'ingress'
1027 protocol:'tcp',
1028 port_range_min: 22,
1029 port_range_max: 22
1030 }
1031 """
John Warren456d9ae2016-01-12 15:36:33 -05001032 if sec_group_rules_client is None:
1033 sec_group_rules_client = self.security_group_rules_client
John Warrenf9606e92015-12-10 12:12:42 -05001034 if security_groups_client is None:
1035 security_groups_client = self.security_groups_client
Yair Frieddb6c9e92014-08-06 08:53:13 +03001036 if not tenant_id:
John Warrenf9606e92015-12-10 12:12:42 -05001037 tenant_id = security_groups_client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001038 if secgroup is None:
John Warrenf9606e92015-12-10 12:12:42 -05001039 secgroup = self._default_security_group(
1040 client=security_groups_client, tenant_id=tenant_id)
Yair Fried1fc32a12014-08-04 09:11:30 +03001041
Steve Heyman33735f22016-05-24 09:28:08 -05001042 ruleset = dict(security_group_id=secgroup['id'],
1043 tenant_id=secgroup['tenant_id'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001044 ruleset.update(kwargs)
1045
John Warren456d9ae2016-01-12 15:36:33 -05001046 sg_rule = sec_group_rules_client.create_security_group_rule(**ruleset)
Steve Heyman33735f22016-05-24 09:28:08 -05001047 sg_rule = sg_rule['security_group_rule']
1048
1049 self.assertEqual(secgroup['tenant_id'], sg_rule['tenant_id'])
1050 self.assertEqual(secgroup['id'], sg_rule['security_group_id'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001051
1052 return sg_rule
1053
John Warren456d9ae2016-01-12 15:36:33 -05001054 def _create_loginable_secgroup_rule(self, security_group_rules_client=None,
1055 secgroup=None,
John Warrenf9606e92015-12-10 12:12:42 -05001056 security_groups_client=None):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001057 """Create loginable security group rule
1058
Alex Stafeyevdd5dde92016-05-08 14:35:04 +03001059 This function will create:
1060 1. egress and ingress tcp port 22 allow rule in order to allow ssh
1061 access for ipv4.
1062 2. egress and ingress ipv6 icmp allow rule, in order to allow icmpv6.
1063 3. egress and ingress ipv4 icmp allow rule, in order to allow icmpv4.
Yair Fried1fc32a12014-08-04 09:11:30 +03001064 """
1065
John Warren456d9ae2016-01-12 15:36:33 -05001066 if security_group_rules_client is None:
1067 security_group_rules_client = self.security_group_rules_client
John Warrenf9606e92015-12-10 12:12:42 -05001068 if security_groups_client is None:
1069 security_groups_client = self.security_groups_client
Yair Fried1fc32a12014-08-04 09:11:30 +03001070 rules = []
1071 rulesets = [
1072 dict(
1073 # ssh
1074 protocol='tcp',
1075 port_range_min=22,
1076 port_range_max=22,
1077 ),
1078 dict(
1079 # ping
1080 protocol='icmp',
Andreas Scheuring887ca8e2015-02-03 17:56:12 +01001081 ),
1082 dict(
1083 # ipv6-icmp for ping6
1084 protocol='icmp',
1085 ethertype='IPv6',
Yair Fried1fc32a12014-08-04 09:11:30 +03001086 )
1087 ]
John Warren456d9ae2016-01-12 15:36:33 -05001088 sec_group_rules_client = security_group_rules_client
Yair Fried1fc32a12014-08-04 09:11:30 +03001089 for ruleset in rulesets:
1090 for r_direction in ['ingress', 'egress']:
1091 ruleset['direction'] = r_direction
1092 try:
1093 sg_rule = self._create_security_group_rule(
John Warren456d9ae2016-01-12 15:36:33 -05001094 sec_group_rules_client=sec_group_rules_client,
1095 secgroup=secgroup,
John Warrenf9606e92015-12-10 12:12:42 -05001096 security_groups_client=security_groups_client,
1097 **ruleset)
Masayuki Igawad9388762015-01-20 14:56:42 +09001098 except lib_exc.Conflict as ex:
Yair Fried1fc32a12014-08-04 09:11:30 +03001099 # if rule already exist - skip rule and continue
1100 msg = 'Security group rule already exists'
1101 if msg not in ex._error_string:
1102 raise ex
1103 else:
Steve Heyman33735f22016-05-24 09:28:08 -05001104 self.assertEqual(r_direction, sg_rule['direction'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001105 rules.append(sg_rule)
1106
1107 return rules
1108
Yair Frieddb6c9e92014-08-06 08:53:13 +03001109 def _get_router(self, client=None, tenant_id=None):
Yair Fried1fc32a12014-08-04 09:11:30 +03001110 """Retrieve a router for the given tenant id.
1111
1112 If a public router has been configured, it will be returned.
1113
1114 If a public router has not been configured, but a public
1115 network has, a tenant router will be created and returned that
1116 routes traffic to the public network.
1117 """
Yair Frieddb6c9e92014-08-06 08:53:13 +03001118 if not client:
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +00001119 client = self.routers_client
Yair Frieddb6c9e92014-08-06 08:53:13 +03001120 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +00001121 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001122 router_id = CONF.network.public_router_id
1123 network_id = CONF.network.public_network_id
1124 if router_id:
David Kranzca4c7e72015-05-27 11:39:19 -04001125 body = client.show_router(router_id)
Steve Heyman33735f22016-05-24 09:28:08 -05001126 return body['router']
Yair Fried1fc32a12014-08-04 09:11:30 +03001127 elif network_id:
Yair Frieddb6c9e92014-08-06 08:53:13 +03001128 router = self._create_router(client, tenant_id)
Steve Heyman33735f22016-05-24 09:28:08 -05001129 kwargs = {'external_gateway_info': dict(network_id=network_id)}
1130 router = client.update_router(router['id'], **kwargs)['router']
Yair Fried1fc32a12014-08-04 09:11:30 +03001131 return router
1132 else:
1133 raise Exception("Neither of 'public_router_id' or "
1134 "'public_network_id' has been defined.")
1135
Yair Frieddb6c9e92014-08-06 08:53:13 +03001136 def _create_router(self, client=None, tenant_id=None,
1137 namestart='router-smoke'):
1138 if not client:
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +00001139 client = self.routers_client
Yair Frieddb6c9e92014-08-06 08:53:13 +03001140 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +00001141 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001142 name = data_utils.rand_name(namestart)
David Kranz34e88122014-12-11 15:24:05 -05001143 result = client.create_router(name=name,
1144 admin_state_up=True,
1145 tenant_id=tenant_id)
Steve Heyman33735f22016-05-24 09:28:08 -05001146 router = result['router']
1147 self.assertEqual(router['name'], name)
1148 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
1149 client.delete_router,
1150 router['id'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001151 return router
1152
Alok Maurya6384bbb2014-07-13 06:44:29 -07001153 def _update_router_admin_state(self, router, admin_state_up):
Steve Heyman33735f22016-05-24 09:28:08 -05001154 kwargs = dict(admin_state_up=admin_state_up)
1155 router = self.routers_client.update_router(
1156 router['id'], **kwargs)['router']
1157 self.assertEqual(admin_state_up, router['admin_state_up'])
Alok Maurya6384bbb2014-07-13 06:44:29 -07001158
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -07001159 def create_networks(self, networks_client=None,
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +00001160 routers_client=None, subnets_client=None,
Markus Zoeller156b5da2016-07-11 18:10:31 +02001161 tenant_id=None, dns_nameservers=None,
1162 port_security_enabled=True):
Yair Fried1fc32a12014-08-04 09:11:30 +03001163 """Create a network with a subnet connected to a router.
1164
David Shrewsbury9bac3662014-08-07 15:07:01 -04001165 The baremetal driver is a special case since all nodes are
1166 on the same shared network.
1167
Yair Fried413bf2d2014-11-19 17:07:11 +02001168 :param tenant_id: id of tenant to create resources in.
1169 :param dns_nameservers: list of dns servers to send to subnet.
Yair Fried1fc32a12014-08-04 09:11:30 +03001170 :returns: network, subnet, router
1171 """
David Shrewsbury9bac3662014-08-07 15:07:01 -04001172 if CONF.baremetal.driver_enabled:
1173 # NOTE(Shrews): This exception is for environments where tenant
1174 # credential isolation is available, but network separation is
1175 # not (the current baremetal case). Likely can be removed when
1176 # test account mgmt is reworked:
1177 # https://blueprints.launchpad.net/tempest/+spec/test-accounts
Adam Gandelman878a5fd2015-03-30 14:33:36 -07001178 if not CONF.compute.fixed_network_name:
1179 m = 'fixed_network_name must be specified in config'
Matthew Treinish4217a702016-10-07 17:27:11 -04001180 raise lib_exc.InvalidConfiguration(m)
David Shrewsbury9bac3662014-08-07 15:07:01 -04001181 network = self._get_network_by_name(
1182 CONF.compute.fixed_network_name)
1183 router = None
1184 subnet = None
1185 else:
John Warren94d8faf2015-09-15 12:22:24 -04001186 network = self._create_network(
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -07001187 networks_client=networks_client,
Markus Zoeller156b5da2016-07-11 18:10:31 +02001188 tenant_id=tenant_id,
1189 port_security_enabled=port_security_enabled)
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +00001190 router = self._get_router(client=routers_client,
1191 tenant_id=tenant_id)
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -07001192 subnet_kwargs = dict(network=network,
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +00001193 subnets_client=subnets_client,
1194 routers_client=routers_client)
Yair Fried413bf2d2014-11-19 17:07:11 +02001195 # use explicit check because empty list is a valid option
1196 if dns_nameservers is not None:
1197 subnet_kwargs['dns_nameservers'] = dns_nameservers
1198 subnet = self._create_subnet(**subnet_kwargs)
Steve Heyman33735f22016-05-24 09:28:08 -05001199 if not routers_client:
1200 routers_client = self.routers_client
1201 router_id = router['id']
1202 routers_client.add_router_interface(router_id,
1203 subnet_id=subnet['id'])
1204
1205 # save a cleanup job to remove this association between
1206 # router and subnet
1207 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
1208 routers_client.remove_router_interface, router_id,
1209 subnet_id=subnet['id'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001210 return network, subnet, router
1211
1212
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001213# power/provision states as of icehouse
1214class BaremetalPowerStates(object):
1215 """Possible power states of an Ironic node."""
1216 POWER_ON = 'power on'
1217 POWER_OFF = 'power off'
1218 REBOOT = 'rebooting'
1219 SUSPEND = 'suspended'
1220
1221
1222class BaremetalProvisionStates(object):
1223 """Possible provision states of an Ironic node."""
1224 NOSTATE = None
1225 INIT = 'initializing'
1226 ACTIVE = 'active'
1227 BUILDING = 'building'
1228 DEPLOYWAIT = 'wait call-back'
1229 DEPLOYING = 'deploying'
1230 DEPLOYFAIL = 'deploy failed'
1231 DEPLOYDONE = 'deploy complete'
1232 DELETING = 'deleting'
1233 DELETED = 'deleted'
1234 ERROR = 'error'
1235
1236
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001237class BaremetalScenarioTest(ScenarioTest):
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001238
1239 credentials = ['primary', 'admin']
1240
Adam Gandelman4a48a602014-03-20 18:23:18 -07001241 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001242 def skip_checks(cls):
1243 super(BaremetalScenarioTest, cls).skip_checks()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001244 if (not CONF.service_available.ironic or
1245 not CONF.baremetal.driver_enabled):
1246 msg = 'Ironic not available or Ironic compute driver not enabled'
1247 raise cls.skipException(msg)
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001248
1249 @classmethod
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001250 def setup_clients(cls):
1251 super(BaremetalScenarioTest, cls).setup_clients()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001252
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001253 cls.baremetal_client = cls.admin_manager.baremetal_client
Adam Gandelman4a48a602014-03-20 18:23:18 -07001254
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001255 @classmethod
1256 def resource_setup(cls):
1257 super(BaremetalScenarioTest, cls).resource_setup()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001258 # allow any issues obtaining the node list to raise early
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001259 cls.baremetal_client.list_nodes()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001260
1261 def _node_state_timeout(self, node_id, state_attr,
1262 target_states, timeout=10, interval=1):
1263 if not isinstance(target_states, list):
1264 target_states = [target_states]
1265
1266 def check_state():
1267 node = self.get_node(node_id=node_id)
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001268 if node.get(state_attr) in target_states:
Adam Gandelman4a48a602014-03-20 18:23:18 -07001269 return True
1270 return False
1271
Jordan Pittier35a63752016-08-30 13:09:12 +02001272 if not test_utils.call_until_true(
Adam Gandelman4a48a602014-03-20 18:23:18 -07001273 check_state, timeout, interval):
1274 msg = ("Timed out waiting for node %s to reach %s state(s) %s" %
1275 (node_id, state_attr, target_states))
guo yunxianebb15f22016-11-01 21:03:35 +08001276 raise lib_exc.TimeoutException(msg)
Adam Gandelman4a48a602014-03-20 18:23:18 -07001277
1278 def wait_provisioning_state(self, node_id, state, timeout):
1279 self._node_state_timeout(
1280 node_id=node_id, state_attr='provision_state',
1281 target_states=state, timeout=timeout)
1282
1283 def wait_power_state(self, node_id, state):
1284 self._node_state_timeout(
1285 node_id=node_id, state_attr='power_state',
1286 target_states=state, timeout=CONF.baremetal.power_timeout)
1287
1288 def wait_node(self, instance_id):
1289 """Waits for a node to be associated with instance_id."""
Zhi Kun Liu4a8d1ea2014-04-15 22:08:21 -05001290
Adam Gandelman4a48a602014-03-20 18:23:18 -07001291 def _get_node():
Jordan Pittier9e227c52016-02-09 14:35:18 +01001292 node = test_utils.call_and_ignore_notfound_exc(
1293 self.get_node, instance_id=instance_id)
Adam Gandelman4a48a602014-03-20 18:23:18 -07001294 return node is not None
1295
Jordan Pittier35a63752016-08-30 13:09:12 +02001296 if not test_utils.call_until_true(
Adam Gandelman4a48a602014-03-20 18:23:18 -07001297 _get_node, CONF.baremetal.association_timeout, 1):
1298 msg = ('Timed out waiting to get Ironic node by instance id %s'
1299 % instance_id)
guo yunxianebb15f22016-11-01 21:03:35 +08001300 raise lib_exc.TimeoutException(msg)
Adam Gandelman4a48a602014-03-20 18:23:18 -07001301
1302 def get_node(self, node_id=None, instance_id=None):
1303 if node_id:
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001304 _, body = self.baremetal_client.show_node(node_id)
1305 return body
Adam Gandelman4a48a602014-03-20 18:23:18 -07001306 elif instance_id:
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001307 _, body = self.baremetal_client.show_node_by_instance_uuid(
1308 instance_id)
1309 if body['nodes']:
1310 return body['nodes'][0]
Adam Gandelman4a48a602014-03-20 18:23:18 -07001311
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001312 def get_ports(self, node_uuid):
Adam Gandelman4a48a602014-03-20 18:23:18 -07001313 ports = []
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001314 _, body = self.baremetal_client.list_node_ports(node_uuid)
1315 for port in body['ports']:
1316 _, p = self.baremetal_client.show_port(port['uuid'])
1317 ports.append(p)
Adam Gandelman4a48a602014-03-20 18:23:18 -07001318 return ports
1319
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001320 def add_keypair(self):
1321 self.keypair = self.create_keypair()
1322
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001323 def boot_instance(self):
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001324 self.instance = self.create_server(
lanoux5fc14522015-09-21 08:17:35 +00001325 key_name=self.keypair['name'])
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001326
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001327 self.wait_node(self.instance['id'])
1328 self.node = self.get_node(instance_id=self.instance['id'])
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001329
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001330 self.wait_power_state(self.node['uuid'], BaremetalPowerStates.POWER_ON)
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001331
1332 self.wait_provisioning_state(
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001333 self.node['uuid'],
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001334 [BaremetalProvisionStates.DEPLOYWAIT,
1335 BaremetalProvisionStates.ACTIVE],
1336 timeout=15)
1337
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001338 self.wait_provisioning_state(self.node['uuid'],
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001339 BaremetalProvisionStates.ACTIVE,
1340 timeout=CONF.baremetal.active_timeout)
1341
Ken'ichi Ohmichi0eb153c2015-07-13 02:18:25 +00001342 waiters.wait_for_server_status(self.servers_client,
1343 self.instance['id'], 'ACTIVE')
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001344 self.node = self.get_node(instance_id=self.instance['id'])
ghanshyam0f825252015-08-25 16:02:50 +09001345 self.instance = (self.servers_client.show_server(self.instance['id'])
1346 ['server'])
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001347
1348 def terminate_instance(self):
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001349 self.servers_client.delete_server(self.instance['id'])
1350 self.wait_power_state(self.node['uuid'],
1351 BaremetalPowerStates.POWER_OFF)
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001352 self.wait_provisioning_state(
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001353 self.node['uuid'],
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001354 BaremetalProvisionStates.NOSTATE,
1355 timeout=CONF.baremetal.unprovision_timeout)
1356
Adam Gandelman4a48a602014-03-20 18:23:18 -07001357
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001358class EncryptionScenarioTest(ScenarioTest):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001359 """Base class for encryption scenario tests"""
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001360
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001361 credentials = ['primary', 'admin']
David Kranz4cc852b2015-03-09 14:57:11 -04001362
1363 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001364 def setup_clients(cls):
1365 super(EncryptionScenarioTest, cls).setup_clients()
Jordan Pittierc3f76be2016-10-11 17:06:21 +02001366 if CONF.volume_feature_enabled.api_v2:
Ivan Kolodyazhnybcfc32e2015-08-06 13:31:36 +03001367 cls.admin_volume_types_client = cls.os_adm.volume_types_v2_client
Ken'ichi Ohmichia6ebf622016-08-25 11:52:27 -07001368 cls.admin_encryption_types_client =\
1369 cls.os_adm.encryption_types_v2_client
Jordan Pittierc3f76be2016-10-11 17:06:21 +02001370 else:
1371 cls.admin_volume_types_client = cls.os_adm.volume_types_client
1372 cls.admin_encryption_types_client =\
1373 cls.os_adm.encryption_types_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001374
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001375 def create_volume_type(self, client=None, name=None):
1376 if not client:
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001377 client = self.admin_volume_types_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001378 if not name:
1379 name = 'generic'
Ken'ichi Ohmichi6ded8df2015-03-23 02:00:19 +00001380 randomized_name = data_utils.rand_name('scenario-type-' + name)
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001381 LOG.debug("Creating a volume type: %s", randomized_name)
Joseph Lanoux6809bab2014-12-18 14:57:18 +00001382 body = client.create_volume_type(
lei zhang83c4bbd2015-11-27 00:35:21 +08001383 name=randomized_name)['volume_type']
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001384 self.assertIn('id', body)
1385 self.addCleanup(client.delete_volume_type, body['id'])
1386 return body
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001387
1388 def create_encryption_type(self, client=None, type_id=None, provider=None,
1389 key_size=None, cipher=None,
1390 control_location=None):
1391 if not client:
Ken'ichi Ohmichia6ebf622016-08-25 11:52:27 -07001392 client = self.admin_encryption_types_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001393 if not type_id:
1394 volume_type = self.create_volume_type()
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001395 type_id = volume_type['id']
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001396 LOG.debug("Creating an encryption type for volume type: %s", type_id)
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001397 client.create_encryption_type(
1398 type_id, provider=provider, key_size=key_size, cipher=cipher,
John Warrend053ded2015-08-13 15:22:48 +00001399 control_location=control_location)['encryption']
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001400
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001401
Masayuki Igawa0870db52015-09-18 21:08:36 +09001402class ObjectStorageScenarioTest(ScenarioTest):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001403 """Provide harness to do Object Storage scenario tests.
Chris Dent0d494112014-08-26 13:48:30 +01001404
1405 Subclasses implement the tests that use the methods provided by this
1406 class.
1407 """
1408
1409 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001410 def skip_checks(cls):
Masayuki Igawa0870db52015-09-18 21:08:36 +09001411 super(ObjectStorageScenarioTest, cls).skip_checks()
Chris Dent0d494112014-08-26 13:48:30 +01001412 if not CONF.service_available.swift:
1413 skip_msg = ("%s skipped as swift is not available" %
1414 cls.__name__)
1415 raise cls.skipException(skip_msg)
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001416
1417 @classmethod
1418 def setup_credentials(cls):
Masayuki Igawa60ea6c52014-10-15 17:32:14 +09001419 cls.set_network_resources()
Masayuki Igawa0870db52015-09-18 21:08:36 +09001420 super(ObjectStorageScenarioTest, cls).setup_credentials()
Matthew Treinish4a596932015-03-06 20:37:01 -05001421 operator_role = CONF.object_storage.operator_role
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +01001422 cls.os_operator = cls.get_client_manager(roles=[operator_role])
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001423
1424 @classmethod
1425 def setup_clients(cls):
Masayuki Igawa0870db52015-09-18 21:08:36 +09001426 super(ObjectStorageScenarioTest, cls).setup_clients()
Chris Dent0d494112014-08-26 13:48:30 +01001427 # Clients for Swift
Matthew Treinish8f268292015-02-24 20:01:36 -05001428 cls.account_client = cls.os_operator.account_client
1429 cls.container_client = cls.os_operator.container_client
1430 cls.object_client = cls.os_operator.object_client
Chris Dent0d494112014-08-26 13:48:30 +01001431
Chris Dentde456a12014-09-10 12:41:15 +01001432 def get_swift_stat(self):
Chris Dent0d494112014-08-26 13:48:30 +01001433 """get swift status for our user account."""
1434 self.account_client.list_account_containers()
1435 LOG.debug('Swift status information obtained successfully')
1436
Chris Dentde456a12014-09-10 12:41:15 +01001437 def create_container(self, container_name=None):
Chris Dent0d494112014-08-26 13:48:30 +01001438 name = container_name or data_utils.rand_name(
1439 'swift-scenario-container')
1440 self.container_client.create_container(name)
1441 # look for the container to assure it is created
Chris Dentde456a12014-09-10 12:41:15 +01001442 self.list_and_check_container_objects(name)
Chris Dent0d494112014-08-26 13:48:30 +01001443 LOG.debug('Container %s created' % (name))
Jordan Pittier9e227c52016-02-09 14:35:18 +01001444 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
Chris Dent1d4313a2014-10-28 12:16:48 +00001445 self.container_client.delete_container,
1446 name)
Chris Dent0d494112014-08-26 13:48:30 +01001447 return name
1448
Chris Dentde456a12014-09-10 12:41:15 +01001449 def delete_container(self, container_name):
Chris Dent0d494112014-08-26 13:48:30 +01001450 self.container_client.delete_container(container_name)
1451 LOG.debug('Container %s deleted' % (container_name))
1452
Chris Dentde456a12014-09-10 12:41:15 +01001453 def upload_object_to_container(self, container_name, obj_name=None):
Chris Dent0d494112014-08-26 13:48:30 +01001454 obj_name = obj_name or data_utils.rand_name('swift-scenario-object')
1455 obj_data = data_utils.arbitrary_string()
1456 self.object_client.create_object(container_name, obj_name, obj_data)
Jordan Pittier9e227c52016-02-09 14:35:18 +01001457 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
Chris Dent1d4313a2014-10-28 12:16:48 +00001458 self.object_client.delete_object,
1459 container_name,
1460 obj_name)
Chris Dent0d494112014-08-26 13:48:30 +01001461 return obj_name, obj_data
1462
Chris Dentde456a12014-09-10 12:41:15 +01001463 def delete_object(self, container_name, filename):
Chris Dent0d494112014-08-26 13:48:30 +01001464 self.object_client.delete_object(container_name, filename)
Chris Dentde456a12014-09-10 12:41:15 +01001465 self.list_and_check_container_objects(container_name,
1466 not_present_obj=[filename])
Chris Dent0d494112014-08-26 13:48:30 +01001467
Chris Dentde456a12014-09-10 12:41:15 +01001468 def list_and_check_container_objects(self, container_name,
1469 present_obj=None,
1470 not_present_obj=None):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001471 # List objects for a given container and assert which are present and
1472 # which are not.
Ghanshyam2a180b82014-06-16 13:54:22 +09001473 if present_obj is None:
1474 present_obj = []
1475 if not_present_obj is None:
1476 not_present_obj = []
Chris Dent0d494112014-08-26 13:48:30 +01001477 _, object_list = self.container_client.list_container_contents(
1478 container_name)
1479 if present_obj:
1480 for obj in present_obj:
1481 self.assertIn(obj, object_list)
1482 if not_present_obj:
1483 for obj in not_present_obj:
1484 self.assertNotIn(obj, object_list)
1485
Chris Dentde456a12014-09-10 12:41:15 +01001486 def change_container_acl(self, container_name, acl):
Chris Dent0d494112014-08-26 13:48:30 +01001487 metadata_param = {'metadata_prefix': 'x-container-',
1488 'metadata': {'read': acl}}
1489 self.container_client.update_container_metadata(container_name,
1490 **metadata_param)
1491 resp, _ = self.container_client.list_container_metadata(container_name)
1492 self.assertEqual(resp['x-container-read'], acl)
1493
Chris Dentde456a12014-09-10 12:41:15 +01001494 def download_and_verify(self, container_name, obj_name, expected_data):
Chris Dent0d494112014-08-26 13:48:30 +01001495 _, obj = self.object_client.get_object(container_name, obj_name)
1496 self.assertEqual(obj, expected_data)