blob: 48ed89cdc5a4f7ce932ee62f4722779921519039 [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
Ihar Hrachyshkaf9227c02016-09-15 11:16:47 +000029from tempest.common.utils import net_utils
Ken'ichi Ohmichi0eb153c2015-07-13 02:18:25 +000030from tempest.common import waiters
Matthew Treinish6c072292014-01-29 19:15:52 +000031from tempest import config
Giulio Fidente92f77192013-08-26 17:13:28 +020032from tempest import exceptions
Jordan Pittier9e227c52016-02-09 14:35:18 +010033from tempest.lib.common.utils import test_utils
Andrea Frittoli (andreaf)db9672e2016-02-23 14:07:24 -050034from tempest.lib import exceptions as lib_exc
Sean Dague6dbc6da2013-05-08 17:49:46 -040035import tempest.test
Sean Dague6dbc6da2013-05-08 17:49:46 -040036
Matthew Treinish6c072292014-01-29 19:15:52 +000037CONF = config.CONF
Sean Dague6dbc6da2013-05-08 17:49:46 -040038
Attila Fazekasfb7552a2013-08-27 13:02:26 +020039LOG = log.getLogger(__name__)
40
Sean Dague6dbc6da2013-05-08 17:49:46 -040041
Andrea Frittoli2e733b52014-07-16 14:12:11 +010042class ScenarioTest(tempest.test.BaseTestCase):
Andrea Frittoli486ede72014-09-25 11:50:05 +010043 """Base class for scenario tests. Uses tempest own clients. """
Andrea Frittoli2e733b52014-07-16 14:12:11 +010044
Andrea Frittolib21de6c2015-02-06 20:12:38 +000045 credentials = ['primary']
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +000046
47 @classmethod
48 def setup_clients(cls):
49 super(ScenarioTest, cls).setup_clients()
Andrea Frittoli247058f2014-07-16 16:09:22 +010050 # Clients (in alphabetical order)
Adam Gandelmanc78c7572014-08-28 18:38:55 -070051 cls.flavors_client = cls.manager.flavors_client
John Warrene74890a2015-11-11 15:18:01 -050052 cls.compute_floating_ips_client = (
53 cls.manager.compute_floating_ips_client)
Jordan Pittier1d2e40f2016-01-05 18:49:14 +010054 if CONF.service_available.glance:
Matt Riedemann2aa19d42016-06-06 17:45:41 -040055 # Check if glance v1 is available to determine which client to use.
56 if CONF.image_feature_enabled.api_v1:
57 cls.image_client = cls.manager.image_client
58 elif CONF.image_feature_enabled.api_v2:
59 cls.image_client = cls.manager.image_client_v2
60 else:
Matthew Treinish4217a702016-10-07 17:27:11 -040061 raise lib_exc.InvalidConfiguration(
Matt Riedemann2aa19d42016-06-06 17:45:41 -040062 'Either api_v1 or api_v2 must be True in '
63 '[image-feature-enabled].')
nithya-ganesan882595e2014-07-29 18:51:07 +000064 # Compute image client
Ghanshyamae76c122015-12-22 13:41:35 +090065 cls.compute_images_client = cls.manager.compute_images_client
Andrea Frittoli247058f2014-07-16 16:09:22 +010066 cls.keypairs_client = cls.manager.keypairs_client
Andrea Frittoli247058f2014-07-16 16:09:22 +010067 # Nova security groups client
John Warrenf2345512015-12-10 13:39:30 -050068 cls.compute_security_groups_client = (
69 cls.manager.compute_security_groups_client)
John Warren5cdbf422016-01-05 12:42:43 -050070 cls.compute_security_group_rules_client = (
71 cls.manager.compute_security_group_rules_client)
Andrea Frittoli247058f2014-07-16 16:09:22 +010072 cls.servers_client = cls.manager.servers_client
Yair Fried1fc32a12014-08-04 09:11:30 +030073 cls.interface_client = cls.manager.interfaces_client
74 # Neutron network client
John Warren94d8faf2015-09-15 12:22:24 -040075 cls.networks_client = cls.manager.networks_client
John Warren49c0fe52015-10-22 12:35:54 -040076 cls.ports_client = cls.manager.ports_client
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +000077 cls.routers_client = cls.manager.routers_client
John Warren3961acd2015-10-02 14:38:53 -040078 cls.subnets_client = cls.manager.subnets_client
John Warrenfbf2a892015-11-17 12:36:14 -050079 cls.floating_ips_client = cls.manager.floating_ips_client
John Warrenf9606e92015-12-10 12:12:42 -050080 cls.security_groups_client = cls.manager.security_groups_client
John Warren456d9ae2016-01-12 15:36:33 -050081 cls.security_group_rules_client = (
82 cls.manager.security_group_rules_client)
Andrea Frittoli2e733b52014-07-16 14:12:11 +010083
Jordan Pittierc3f76be2016-10-11 17:06:21 +020084 if CONF.volume_feature_enabled.api_v2:
Ivan Kolodyazhnybcfc32e2015-08-06 13:31:36 +030085 cls.volumes_client = cls.manager.volumes_v2_client
86 cls.snapshots_client = cls.manager.snapshots_v2_client
Jordan Pittierc3f76be2016-10-11 17:06:21 +020087 else:
88 cls.volumes_client = cls.manager.volumes_client
89 cls.snapshots_client = cls.manager.snapshots_client
Ivan Kolodyazhnybcfc32e2015-08-06 13:31:36 +030090
Jordan Pittierf672b7d2016-06-20 18:50:40 +020091 # ## Test functions library
92 #
93 # The create_[resource] functions only return body and discard the
94 # resp part which is not used in scenario tests
Andrea Frittoli247058f2014-07-16 16:09:22 +010095
Lenny Verkhovsky136376f2016-06-29 14:33:34 +030096 def _create_port(self, network_id, client=None, namestart='port-quotatest',
97 **kwargs):
98 if not client:
99 client = self.ports_client
100 name = data_utils.rand_name(namestart)
101 result = client.create_port(
102 name=name,
103 network_id=network_id,
104 **kwargs)
105 self.assertIsNotNone(result, 'Unable to allocate port')
106 port = result['port']
107 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
108 client.delete_port, port['id'])
109 return port
110
Yair Frieddb6c9e92014-08-06 08:53:13 +0300111 def create_keypair(self, client=None):
112 if not client:
113 client = self.keypairs_client
Andrea Frittoli247058f2014-07-16 16:09:22 +0100114 name = data_utils.rand_name(self.__class__.__name__)
115 # We don't need to create a keypair by pubkey in scenario
Ken'ichi Ohmichie364bce2015-07-17 10:27:59 +0000116 body = client.create_keypair(name=name)
Yair Frieddb6c9e92014-08-06 08:53:13 +0300117 self.addCleanup(client.delete_keypair, name)
ghanshyamdee01f22015-08-17 11:41:47 +0900118 return body['keypair']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100119
Anusha Ramineni9aaef8b2016-01-19 10:56:40 +0530120 def create_server(self, name=None, image_id=None, flavor=None,
lanoux5fc14522015-09-21 08:17:35 +0000121 validatable=False, wait_until=None,
Jordan Pittierf672b7d2016-06-20 18:50:40 +0200122 clients=None, **kwargs):
lanoux5fc14522015-09-21 08:17:35 +0000123 """Wrapper utility that returns a test server.
Andrea Frittoli247058f2014-07-16 16:09:22 +0100124
lanoux5fc14522015-09-21 08:17:35 +0000125 This wrapper utility calls the common create test server and
126 returns a test server. The purpose of this wrapper is to minimize
127 the impact on the code of the tests already using this
128 function.
Andrea Frittoli247058f2014-07-16 16:09:22 +0100129 """
Andrea Frittoli247058f2014-07-16 16:09:22 +0100130
lanoux5fc14522015-09-21 08:17:35 +0000131 # NOTE(jlanoux): As a first step, ssh checks in the scenario
132 # tests need to be run regardless of the run_validation and
133 # validatable parameters and thus until the ssh validation job
134 # becomes voting in CI. The test resources management and IP
135 # association are taken care of in the scenario tests.
136 # Therefore, the validatable parameter is set to false in all
137 # those tests. In this way create_server just return a standard
138 # server and the scenario tests always perform ssh checks.
139
140 # Needed for the cross_tenant_traffic test:
141 if clients is None:
142 clients = self.manager
143
144 vnic_type = CONF.network.port_vnic_type
145
146 # If vnic_type is configured create port for
147 # every network
148 if vnic_type:
149 ports = []
Lenny Verkhovsky69363502016-07-17 16:33:33 +0300150
lanoux5fc14522015-09-21 08:17:35 +0000151 create_port_body = {'binding:vnic_type': vnic_type,
152 'namestart': 'port-smoke'}
153 if kwargs:
154 # Convert security group names to security group ids
155 # to pass to create_port
156 if 'security_groups' in kwargs:
157 security_groups =\
John Warrenf9606e92015-12-10 12:12:42 -0500158 clients.security_groups_client.list_security_groups(
lanoux5fc14522015-09-21 08:17:35 +0000159 ).get('security_groups')
160 sec_dict = dict([(s['name'], s['id'])
161 for s in security_groups])
162
163 sec_groups_names = [s['name'] for s in kwargs.pop(
164 'security_groups')]
165 security_groups_ids = [sec_dict[s]
166 for s in sec_groups_names]
167
168 if security_groups_ids:
169 create_port_body[
170 'security_groups'] = security_groups_ids
Lenny Verkhovsky69363502016-07-17 16:33:33 +0300171 networks = kwargs.pop('networks', [])
172 else:
173 networks = []
lanoux5fc14522015-09-21 08:17:35 +0000174
175 # If there are no networks passed to us we look up
Lenny Verkhovsky136376f2016-06-29 14:33:34 +0300176 # for the project's private networks and create a port.
177 # The same behaviour as we would expect when passing
178 # the call to the clients with no networks
lanoux5fc14522015-09-21 08:17:35 +0000179 if not networks:
180 networks = clients.networks_client.list_networks(
Lenny Verkhovsky136376f2016-06-29 14:33:34 +0300181 **{'router:external': False, 'fields': 'id'})['networks']
182
183 # It's net['uuid'] if networks come from kwargs
184 # and net['id'] if they come from
185 # clients.networks_client.list_networks
lanoux5fc14522015-09-21 08:17:35 +0000186 for net in networks:
Lenny Verkhovsky97f7cea2016-08-15 13:29:48 +0000187 net_id = net.get('uuid', net.get('id'))
Lenny Verkhovsky69363502016-07-17 16:33:33 +0300188 if 'port' not in net:
189 port = self._create_port(network_id=net_id,
190 client=clients.ports_client,
191 **create_port_body)
192 ports.append({'port': port['id']})
193 else:
194 ports.append({'port': net['port']})
lanoux5fc14522015-09-21 08:17:35 +0000195 if ports:
196 kwargs['networks'] = ports
197 self.ports = ports
198
199 tenant_network = self.get_tenant_network()
200
201 body, servers = compute.create_test_server(
202 clients,
203 tenant_network=tenant_network,
204 wait_until=wait_until,
Anusha Ramineni9aaef8b2016-01-19 10:56:40 +0530205 name=name, flavor=flavor,
206 image_id=image_id, **kwargs)
lanoux5fc14522015-09-21 08:17:35 +0000207
Jordan Pittierf672b7d2016-06-20 18:50:40 +0200208 self.addCleanup(waiters.wait_for_server_termination,
209 clients.servers_client, body['id'])
210 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
211 clients.servers_client.delete_server, body['id'])
lanoux5fc14522015-09-21 08:17:35 +0000212 server = clients.servers_client.show_server(body['id'])['server']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100213 return server
214
Markus Zoeller3d2a21c2015-02-27 12:04:22 +0100215 def create_volume(self, size=None, name=None, snapshot_id=None,
Jordan Pittier5e1741c2016-03-02 18:25:51 +0100216 imageRef=None, volume_type=None):
Ken'ichi Ohmichiadb905e2016-08-26 15:16:23 -0700217 if size is None:
218 size = CONF.volume.volume_size
Andrea Frittoli247058f2014-07-16 16:09:22 +0100219 if name is None:
zhuflf9d95722016-10-19 16:06:17 +0800220 name = data_utils.rand_name(self.__class__.__name__ + "-volume")
Ghanshyam8fc0ed22015-12-18 10:25:14 +0900221 kwargs = {'display_name': name,
222 'snapshot_id': snapshot_id,
223 'imageRef': imageRef,
Ken'ichi Ohmichiadb905e2016-08-26 15:16:23 -0700224 'volume_type': volume_type,
225 'size': size}
Ghanshyam8fc0ed22015-12-18 10:25:14 +0900226 volume = self.volumes_client.create_volume(**kwargs)['volume']
Matt Riedemanne85c2702014-09-10 11:50:13 -0700227
Jordan Pittier5e1741c2016-03-02 18:25:51 +0100228 self.addCleanup(self.volumes_client.wait_for_resource_deletion,
229 volume['id'])
Jordan Pittier9e227c52016-02-09 14:35:18 +0100230 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
Jordan Pittier5e1741c2016-03-02 18:25:51 +0100231 self.volumes_client.delete_volume, volume['id'])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100232
Ivan Kolodyazhnybcfc32e2015-08-06 13:31:36 +0300233 # NOTE(e0ne): Cinder API v2 uses name instead of display_name
234 if 'display_name' in volume:
235 self.assertEqual(name, volume['display_name'])
236 else:
237 self.assertEqual(name, volume['name'])
Yaroslav Lobankoved3a35b2016-03-24 22:41:30 -0500238 waiters.wait_for_volume_status(self.volumes_client,
239 volume['id'], 'available')
Andrea Frittoli247058f2014-07-16 16:09:22 +0100240 # The volume retrieved on creation has a non-up-to-date status.
241 # Retrieval after it becomes active ensures correct details.
John Warren6177c9e2015-08-19 20:00:17 +0000242 volume = self.volumes_client.show_volume(volume['id'])['volume']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100243 return volume
244
Yair Fried1fc32a12014-08-04 09:11:30 +0300245 def _create_loginable_secgroup_rule(self, secgroup_id=None):
John Warrenf2345512015-12-10 13:39:30 -0500246 _client = self.compute_security_groups_client
John Warren5cdbf422016-01-05 12:42:43 -0500247 _client_rules = self.compute_security_group_rules_client
Andrea Frittoli247058f2014-07-16 16:09:22 +0100248 if secgroup_id is None:
ghanshyamb610b772015-08-24 17:29:38 +0900249 sgs = _client.list_security_groups()['security_groups']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100250 for sg in sgs:
251 if sg['name'] == 'default':
252 secgroup_id = sg['id']
253
254 # These rules are intended to permit inbound ssh and icmp
255 # traffic from all sources, so no group_id is provided.
256 # Setting a group_id would only permit traffic from ports
257 # belonging to the same security group.
258 rulesets = [
259 {
260 # ssh
Ken'ichi Ohmichieb7eeec2015-07-21 01:00:06 +0000261 'ip_protocol': 'tcp',
Andrea Frittoli247058f2014-07-16 16:09:22 +0100262 'from_port': 22,
263 'to_port': 22,
264 'cidr': '0.0.0.0/0',
265 },
266 {
267 # ping
Ken'ichi Ohmichieb7eeec2015-07-21 01:00:06 +0000268 'ip_protocol': 'icmp',
Andrea Frittoli247058f2014-07-16 16:09:22 +0100269 'from_port': -1,
270 'to_port': -1,
271 'cidr': '0.0.0.0/0',
272 }
273 ]
274 rules = list()
275 for ruleset in rulesets:
Ken'ichi Ohmichieb7eeec2015-07-21 01:00:06 +0000276 sg_rule = _client_rules.create_security_group_rule(
ghanshyam0a5e1232015-08-24 16:59:59 +0900277 parent_group_id=secgroup_id, **ruleset)['security_group_rule']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100278 rules.append(sg_rule)
279 return rules
280
Yair Fried1fc32a12014-08-04 09:11:30 +0300281 def _create_security_group(self):
Andrea Frittoli247058f2014-07-16 16:09:22 +0100282 # Create security group
283 sg_name = data_utils.rand_name(self.__class__.__name__)
284 sg_desc = sg_name + " description"
John Warrenf2345512015-12-10 13:39:30 -0500285 secgroup = self.compute_security_groups_client.create_security_group(
ghanshyamb610b772015-08-24 17:29:38 +0900286 name=sg_name, description=sg_desc)['security_group']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100287 self.assertEqual(secgroup['name'], sg_name)
288 self.assertEqual(secgroup['description'], sg_desc)
John Warrenf2345512015-12-10 13:39:30 -0500289 self.addCleanup(
Jordan Pittier9e227c52016-02-09 14:35:18 +0100290 test_utils.call_and_ignore_notfound_exc,
John Warrenf2345512015-12-10 13:39:30 -0500291 self.compute_security_groups_client.delete_security_group,
292 secgroup['id'])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100293
294 # Add rules to the security group
Yair Fried1fc32a12014-08-04 09:11:30 +0300295 self._create_loginable_secgroup_rule(secgroup['id'])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100296
297 return secgroup
298
Sean Dague20e98612016-01-06 14:33:28 -0500299 def get_remote_client(self, ip_address, username=None, private_key=None):
JordanP3fe2dc32014-11-17 13:06:01 +0100300 """Get a SSH client to a remote server
301
Sean Dague20e98612016-01-06 14:33:28 -0500302 @param ip_address the server floating or fixed IP address to use
303 for ssh validation
JordanP3fe2dc32014-11-17 13:06:01 +0100304 @param username name of the Linux account on the remote server
305 @param private_key the SSH private key to use
JordanP3fe2dc32014-11-17 13:06:01 +0100306 @return a RemoteClient object
307 """
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700308
Andrea Frittoli247058f2014-07-16 16:09:22 +0100309 if username is None:
lanoux283273b2015-12-04 03:01:54 -0800310 username = CONF.validation.image_ssh_user
wantwatering896300c2015-03-27 15:17:42 +0800311 # Set this with 'keypair' or others to log in with keypair or
312 # username/password.
lanoux5fc14522015-09-21 08:17:35 +0000313 if CONF.validation.auth_method == 'keypair':
wantwatering896300c2015-03-27 15:17:42 +0800314 password = None
315 if private_key is None:
316 private_key = self.keypair['private_key']
317 else:
lanoux283273b2015-12-04 03:01:54 -0800318 password = CONF.validation.image_ssh_password
wantwatering896300c2015-03-27 15:17:42 +0800319 private_key = None
Sean Dague20e98612016-01-06 14:33:28 -0500320 linux_client = remote_client.RemoteClient(ip_address, username,
wantwatering896300c2015-03-27 15:17:42 +0800321 pkey=private_key,
322 password=password)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100323 try:
324 linux_client.validate_authentication()
Matt Riedemann5f0ac522015-05-21 09:16:24 -0700325 except Exception as e:
326 message = ('Initializing SSH connection to %(ip)s failed. '
Eric Brown0911af62016-02-08 17:15:40 -0800327 'Error: %(error)s' % {'ip': ip_address,
Sean Dague20e98612016-01-06 14:33:28 -0500328 'error': e})
Jordan Pittier9e227c52016-02-09 14:35:18 +0100329 caller = test_utils.find_test_caller()
Matt Riedemann5f0ac522015-05-21 09:16:24 -0700330 if caller:
331 message = '(%s) %s' % (caller, message)
332 LOG.exception(message)
Sean Dague2c98a162016-01-06 14:11:13 -0500333 self._log_console_output()
Andrea Frittoli247058f2014-07-16 16:09:22 +0100334 raise
335
336 return linux_client
337
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000338 def _image_create(self, name, fmt, path,
339 disk_format=None, properties=None):
Ghanshyam2a180b82014-06-16 13:54:22 +0900340 if properties is None:
341 properties = {}
Andrea Frittoli247058f2014-07-16 16:09:22 +0100342 name = data_utils.rand_name('%s-' % name)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100343 params = {
344 'name': name,
345 'container_format': fmt,
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000346 'disk_format': disk_format or fmt,
Andrea Frittoli247058f2014-07-16 16:09:22 +0100347 }
Matt Riedemann2aa19d42016-06-06 17:45:41 -0400348 if CONF.image_feature_enabled.api_v1:
349 params['is_public'] = 'False'
350 params['properties'] = properties
Ken'ichi Ohmichi02bcdf32016-06-17 16:41:26 -0700351 params = {'headers': common_image.image_meta_to_headers(**params)}
Matt Riedemann2aa19d42016-06-06 17:45:41 -0400352 else:
353 params['visibility'] = 'private'
354 # Additional properties are flattened out in the v2 API.
355 params.update(properties)
356 body = self.image_client.create_image(**params)
357 image = body['image'] if 'image' in body else body
Andrea Frittoli247058f2014-07-16 16:09:22 +0100358 self.addCleanup(self.image_client.delete_image, image['id'])
359 self.assertEqual("queued", image['status'])
zhang.leia4b1cef2016-03-01 10:50:01 +0800360 with open(path, 'rb') as image_file:
Matt Riedemann2aa19d42016-06-06 17:45:41 -0400361 if CONF.image_feature_enabled.api_v1:
362 self.image_client.update_image(image['id'], data=image_file)
363 else:
364 self.image_client.store_image_file(image['id'], image_file)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100365 return image['id']
366
367 def glance_image_create(self):
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300368 img_path = CONF.scenario.img_dir + "/" + CONF.scenario.img_file
Andrea Frittoli247058f2014-07-16 16:09:22 +0100369 aki_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.aki_img_file
370 ari_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.ari_img_file
371 ami_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.ami_img_file
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300372 img_container_format = CONF.scenario.img_container_format
373 img_disk_format = CONF.scenario.img_disk_format
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000374 img_properties = CONF.scenario.img_properties
PranaliD2aa523c2016-06-07 03:54:34 -0400375 LOG.debug("paths: img: %s, container_format: %s, disk_format: %s, "
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000376 "properties: %s, ami: %s, ari: %s, aki: %s" %
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300377 (img_path, img_container_format, img_disk_format,
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000378 img_properties, ami_img_path, ari_img_path, aki_img_path))
Andrea Frittoli247058f2014-07-16 16:09:22 +0100379 try:
Jordan Pittier1e443ec2015-11-20 16:15:58 +0100380 image = self._image_create('scenario-img',
381 img_container_format,
382 img_path,
383 disk_format=img_disk_format,
384 properties=img_properties)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100385 except IOError:
386 LOG.debug("A qcow2 image was not found. Try to get a uec image.")
387 kernel = self._image_create('scenario-aki', 'aki', aki_img_path)
388 ramdisk = self._image_create('scenario-ari', 'ari', ari_img_path)
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000389 properties = {'kernel_id': kernel, 'ramdisk_id': ramdisk}
Jordan Pittier1e443ec2015-11-20 16:15:58 +0100390 image = self._image_create('scenario-ami', 'ami',
391 path=ami_img_path,
392 properties=properties)
393 LOG.debug("image:%s" % image)
394
395 return image
Andrea Frittoli247058f2014-07-16 16:09:22 +0100396
397 def _log_console_output(self, servers=None):
Matthew Treinish42a3f3a2014-09-04 15:04:53 -0400398 if not CONF.compute_feature_enabled.console_output:
399 LOG.debug('Console output not supported, cannot log')
400 return
Andrea Frittoli247058f2014-07-16 16:09:22 +0100401 if not servers:
David Kranzae99b9a2015-02-16 13:37:01 -0500402 servers = self.servers_client.list_servers()
Andrea Frittoli247058f2014-07-16 16:09:22 +0100403 servers = servers['servers']
404 for server in servers:
Attila Fazekas9a5a1122016-11-08 10:24:57 +0100405 try:
406 console_output = self.servers_client.get_console_output(
407 server['id'])['output']
408 LOG.debug('Console output for %s\nbody=\n%s',
409 server['id'], console_output)
410 except lib_exc.NotFound:
Attila Fazekase1360482016-11-10 11:28:08 +0100411 LOG.debug("Server %s disappeared(deleted) while looking "
Attila Fazekas9a5a1122016-11-08 10:24:57 +0100412 "for the console log", server['id'])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100413
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000414 def _log_net_info(self, exc):
415 # network debug is called as part of ssh init
Andrey Pavlov64723762015-04-29 06:24:58 +0300416 if not isinstance(exc, lib_exc.SSHTimeout):
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000417 LOG.debug('Network information on a devstack host')
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000418
nithya-ganesan882595e2014-07-29 18:51:07 +0000419 def create_server_snapshot(self, server, name=None):
420 # Glance client
421 _image_client = self.image_client
422 # Compute client
Ghanshyamae76c122015-12-22 13:41:35 +0900423 _images_client = self.compute_images_client
nithya-ganesan882595e2014-07-29 18:51:07 +0000424 if name is None:
zhuflf9d95722016-10-19 16:06:17 +0800425 name = data_utils.rand_name(self.__class__.__name__ + 'snapshot')
nithya-ganesan882595e2014-07-29 18:51:07 +0000426 LOG.debug("Creating a snapshot image for server: %s", server['name'])
Ken'ichi Ohmichi28f18672015-07-17 10:00:38 +0000427 image = _images_client.create_image(server['id'], name=name)
David Kranza5299eb2015-01-15 17:24:05 -0500428 image_id = image.response['location'].split('images/')[1]
Yaroslav Lobankov2fea4052016-04-19 15:05:57 +0300429 waiters.wait_for_image_status(_image_client, image_id, 'active')
Jordan Pittierf672b7d2016-06-20 18:50:40 +0200430
431 self.addCleanup(_image_client.wait_for_resource_deletion,
432 image_id)
433 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
434 _image_client.delete_image, image_id)
435
Matt Riedemann2aa19d42016-06-06 17:45:41 -0400436 if CONF.image_feature_enabled.api_v1:
437 # In glance v1 the additional properties are stored in the headers.
Ken'ichi Ohmichi01151e82016-06-10 11:19:52 -0700438 resp = _image_client.check_image(image_id)
439 snapshot_image = common_image.get_image_meta_from_headers(resp)
Matt Riedemann2aa19d42016-06-06 17:45:41 -0400440 image_props = snapshot_image.get('properties', {})
441 else:
442 # In glance v2 the additional properties are flattened.
443 snapshot_image = _image_client.show_image(image_id)
444 image_props = snapshot_image
Andrey Pavlovc8bd4b12015-08-17 10:20:17 +0300445
Matt Riedemann2aa19d42016-06-06 17:45:41 -0400446 bdm = image_props.get('block_device_mapping')
Andrey Pavlovc8bd4b12015-08-17 10:20:17 +0300447 if bdm:
448 bdm = json.loads(bdm)
449 if bdm and 'snapshot_id' in bdm[0]:
450 snapshot_id = bdm[0]['snapshot_id']
451 self.addCleanup(
452 self.snapshots_client.wait_for_resource_deletion,
453 snapshot_id)
Jordan Pittier9e227c52016-02-09 14:35:18 +0100454 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
455 self.snapshots_client.delete_snapshot,
456 snapshot_id)
Yaroslav Lobankov667aaa22016-03-24 23:13:28 -0500457 waiters.wait_for_snapshot_status(self.snapshots_client,
458 snapshot_id, 'available')
nithya-ganesan882595e2014-07-29 18:51:07 +0000459 image_name = snapshot_image['name']
460 self.assertEqual(name, image_name)
461 LOG.debug("Created snapshot image %s for server %s",
462 image_name, server['name'])
463 return snapshot_image
464
Jordan Pittier7cf64762015-10-14 15:01:12 +0200465 def nova_volume_attach(self, server, volume_to_attach):
Joseph Lanoux6809bab2014-12-18 14:57:18 +0000466 volume = self.servers_client.attach_volume(
Jordan Pittier7cf64762015-10-14 15:01:12 +0200467 server['id'], volumeId=volume_to_attach['id'], device='/dev/%s'
ghanshyam0f825252015-08-25 16:02:50 +0900468 % CONF.compute.volume_device_name)['volumeAttachment']
Jordan Pittier7cf64762015-10-14 15:01:12 +0200469 self.assertEqual(volume_to_attach['id'], volume['id'])
Yaroslav Lobankoved3a35b2016-03-24 22:41:30 -0500470 waiters.wait_for_volume_status(self.volumes_client,
471 volume['id'], 'in-use')
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900472
Jordan Pittier7cf64762015-10-14 15:01:12 +0200473 # Return the updated volume after the attachment
474 return self.volumes_client.show_volume(volume['id'])['volume']
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900475
Jordan Pittier7cf64762015-10-14 15:01:12 +0200476 def nova_volume_detach(self, server, volume):
477 self.servers_client.detach_volume(server['id'], volume['id'])
Yaroslav Lobankoved3a35b2016-03-24 22:41:30 -0500478 waiters.wait_for_volume_status(self.volumes_client,
479 volume['id'], 'available')
Jordan Pittier7cf64762015-10-14 15:01:12 +0200480
481 volume = self.volumes_client.show_volume(volume['id'])['volume']
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900482 self.assertEqual('available', volume['status'])
483
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700484 def rebuild_server(self, server_id, image=None,
485 preserve_ephemeral=False, wait=True,
486 rebuild_kwargs=None):
487 if image is None:
488 image = CONF.compute.image_ref
489
490 rebuild_kwargs = rebuild_kwargs or {}
491
492 LOG.debug("Rebuilding server (id: %s, image: %s, preserve eph: %s)",
493 server_id, image, preserve_ephemeral)
Ken'ichi Ohmichi5271b0f2015-08-10 07:53:27 +0000494 self.servers_client.rebuild_server(
495 server_id=server_id, image_ref=image,
496 preserve_ephemeral=preserve_ephemeral,
497 **rebuild_kwargs)
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700498 if wait:
Ken'ichi Ohmichi0eb153c2015-07-13 02:18:25 +0000499 waiters.wait_for_server_status(self.servers_client,
500 server_id, 'ACTIVE')
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700501
Steven Hardyda2a8352014-10-02 12:52:20 +0100502 def ping_ip_address(self, ip_address, should_succeed=True,
Ihar Hrachyshkaf9227c02016-09-15 11:16:47 +0000503 ping_timeout=None, mtu=None):
lanoux5fc14522015-09-21 08:17:35 +0000504 timeout = ping_timeout or CONF.validation.ping_timeout
Ihar Hrachyshkaf9227c02016-09-15 11:16:47 +0000505 cmd = ['ping', '-c1', '-w1']
506
507 if mtu:
508 cmd += [
509 # don't fragment
510 '-M', 'do',
511 # ping receives just the size of ICMP payload
512 '-s', str(net_utils.get_ping_payload_size(mtu, 4))
513 ]
514 cmd.append(ip_address)
Aaron Rosena7df13b2014-09-23 09:45:45 -0700515
516 def ping():
517 proc = subprocess.Popen(cmd,
518 stdout=subprocess.PIPE,
519 stderr=subprocess.PIPE)
520 proc.communicate()
Shuquan Huang753629e2015-07-20 08:52:29 +0000521
Aaron Rosena7df13b2014-09-23 09:45:45 -0700522 return (proc.returncode == 0) == should_succeed
523
Jordan Pittier9e227c52016-02-09 14:35:18 +0100524 caller = test_utils.find_test_caller()
Shuquan Huang753629e2015-07-20 08:52:29 +0000525 LOG.debug('%(caller)s begins to ping %(ip)s in %(timeout)s sec and the'
526 ' expected result is %(should_succeed)s' % {
527 'caller': caller, 'ip': ip_address, 'timeout': timeout,
528 'should_succeed':
529 'reachable' if should_succeed else 'unreachable'
530 })
Jordan Pittier35a63752016-08-30 13:09:12 +0200531 result = test_utils.call_until_true(ping, timeout, 1)
Shuquan Huang753629e2015-07-20 08:52:29 +0000532 LOG.debug('%(caller)s finishes ping %(ip)s in %(timeout)s sec and the '
533 'ping result is %(result)s' % {
534 'caller': caller, 'ip': ip_address, 'timeout': timeout,
535 'result': 'expected' if result else 'unexpected'
536 })
537 return result
Aaron Rosena7df13b2014-09-23 09:45:45 -0700538
Yair Friedae0e73d2014-11-24 11:56:26 +0200539 def check_vm_connectivity(self, ip_address,
540 username=None,
541 private_key=None,
Ihar Hrachyshkaf9227c02016-09-15 11:16:47 +0000542 should_connect=True,
543 mtu=None):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000544 """Check server connectivity
545
Yair Friedae0e73d2014-11-24 11:56:26 +0200546 :param ip_address: server to test against
547 :param username: server's ssh username
548 :param private_key: server's ssh private key to be used
549 :param should_connect: True/False indicates positive/negative test
550 positive - attempt ping and ssh
551 negative - attempt ping and fail if succeed
Ihar Hrachyshkaf9227c02016-09-15 11:16:47 +0000552 :param mtu: network MTU to use for connectivity validation
Yair Friedae0e73d2014-11-24 11:56:26 +0200553
554 :raises: AssertError if the result of the connectivity check does
555 not match the value of the should_connect param
556 """
557 if should_connect:
558 msg = "Timed out waiting for %s to become reachable" % ip_address
559 else:
560 msg = "ip address %s is reachable" % ip_address
561 self.assertTrue(self.ping_ip_address(ip_address,
Ihar Hrachyshkaf9227c02016-09-15 11:16:47 +0000562 should_succeed=should_connect,
563 mtu=mtu),
Yair Friedae0e73d2014-11-24 11:56:26 +0200564 msg=msg)
565 if should_connect:
566 # no need to check ssh for negative connectivity
567 self.get_remote_client(ip_address, username, private_key)
568
569 def check_public_network_connectivity(self, ip_address, username,
570 private_key, should_connect=True,
Ihar Hrachyshkaf9227c02016-09-15 11:16:47 +0000571 msg=None, servers=None, mtu=None):
Yair Friedae0e73d2014-11-24 11:56:26 +0200572 # The target login is assumed to have been configured for
573 # key-based authentication by cloud-init.
574 LOG.debug('checking network connections to IP %s with user: %s' %
575 (ip_address, username))
576 try:
577 self.check_vm_connectivity(ip_address,
578 username,
579 private_key,
Ihar Hrachyshkaf9227c02016-09-15 11:16:47 +0000580 should_connect=should_connect,
581 mtu=mtu)
Matthew Treinish53483132014-12-09 18:50:06 -0500582 except Exception:
Yair Friedae0e73d2014-11-24 11:56:26 +0200583 ex_msg = 'Public network connectivity check failed'
584 if msg:
585 ex_msg += ": " + msg
586 LOG.exception(ex_msg)
587 self._log_console_output(servers)
Yair Friedae0e73d2014-11-24 11:56:26 +0200588 raise
589
590 def create_floating_ip(self, thing, pool_name=None):
Ken'ichi Ohmichia112a592015-11-17 08:49:37 +0000591 """Create a floating IP and associates to a server on Nova"""
Yair Friedae0e73d2014-11-24 11:56:26 +0200592
Marc Koderer3b57d802016-03-22 15:23:31 +0100593 if not pool_name:
594 pool_name = CONF.network.floating_network_name
John Warrene74890a2015-11-11 15:18:01 -0500595 floating_ip = (self.compute_floating_ips_client.
Ken'ichi Ohmichie037a6f2015-12-03 06:41:49 +0000596 create_floating_ip(pool=pool_name)['floating_ip'])
Jordan Pittier9e227c52016-02-09 14:35:18 +0100597 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
John Warrene74890a2015-11-11 15:18:01 -0500598 self.compute_floating_ips_client.delete_floating_ip,
Yair Friedae0e73d2014-11-24 11:56:26 +0200599 floating_ip['id'])
John Warrene74890a2015-11-11 15:18:01 -0500600 self.compute_floating_ips_client.associate_floating_ip_to_server(
Yair Friedae0e73d2014-11-24 11:56:26 +0200601 floating_ip['ip'], thing['id'])
602 return floating_ip
603
Sean Dague20e98612016-01-06 14:33:28 -0500604 def create_timestamp(self, ip_address, dev_name=None, mount_path='/mnt',
Matt Riedemannfd5657d2015-09-30 14:47:07 -0700605 private_key=None):
Sean Dague20e98612016-01-06 14:33:28 -0500606 ssh_client = self.get_remote_client(ip_address,
Matt Riedemannfd5657d2015-09-30 14:47:07 -0700607 private_key=private_key)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300608 if dev_name is not None:
609 ssh_client.make_fs(dev_name)
Matt Riedemann076685a2015-09-30 14:38:16 -0700610 ssh_client.mount(dev_name, mount_path)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300611 cmd_timestamp = 'sudo sh -c "date > %s/timestamp; sync"' % mount_path
612 ssh_client.exec_command(cmd_timestamp)
613 timestamp = ssh_client.exec_command('sudo cat %s/timestamp'
614 % mount_path)
615 if dev_name is not None:
616 ssh_client.umount(mount_path)
617 return timestamp
618
Sean Dague20e98612016-01-06 14:33:28 -0500619 def get_timestamp(self, ip_address, dev_name=None, mount_path='/mnt',
Matt Riedemannfd5657d2015-09-30 14:47:07 -0700620 private_key=None):
Sean Dague20e98612016-01-06 14:33:28 -0500621 ssh_client = self.get_remote_client(ip_address,
Matt Riedemannfd5657d2015-09-30 14:47:07 -0700622 private_key=private_key)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300623 if dev_name is not None:
Matt Riedemann076685a2015-09-30 14:38:16 -0700624 ssh_client.mount(dev_name, mount_path)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300625 timestamp = ssh_client.exec_command('sudo cat %s/timestamp'
626 % mount_path)
627 if dev_name is not None:
628 ssh_client.umount(mount_path)
629 return timestamp
630
Sean Dague20e98612016-01-06 14:33:28 -0500631 def get_server_ip(self, server):
632 """Get the server fixed or floating IP.
633
634 Based on the configuration we're in, return a correct ip
635 address for validating that a guest is up.
636 """
Alexander Gubanovc8829f82015-11-12 10:35:13 +0200637 if CONF.validation.connect_method == 'floating':
Sean Dague20e98612016-01-06 14:33:28 -0500638 # The tests calling this method don't have a floating IP
zhufl0892cb22016-05-06 14:46:00 +0800639 # and can't make use of the validation resources. So the
Sean Dague20e98612016-01-06 14:33:28 -0500640 # method is creating the floating IP there.
641 return self.create_floating_ip(server)['ip']
642 elif CONF.validation.connect_method == 'fixed':
Matt Riedemanna7782552016-08-08 16:26:01 -0400643 # Determine the network name to look for based on config or creds
644 # provider network resources.
645 if CONF.validation.network_for_ssh:
646 addresses = server['addresses'][
647 CONF.validation.network_for_ssh]
648 else:
649 creds_provider = self._get_credentials_provider()
650 net_creds = creds_provider.get_primary_creds()
651 network = getattr(net_creds, 'network', None)
652 addresses = (server['addresses'][network['name']]
653 if network else [])
Sean Dague20e98612016-01-06 14:33:28 -0500654 for address in addresses:
Matt Riedemanna7782552016-08-08 16:26:01 -0400655 if (address['version'] == CONF.validation.ip_version_for_ssh
656 and address['OS-EXT-IPS:type'] == 'fixed'):
Sean Dague20e98612016-01-06 14:33:28 -0500657 return address['addr']
zhufl955f82b2016-07-22 11:14:34 +0800658 raise exceptions.ServerUnreachable(server_id=server['id'])
Alexander Gubanovc8829f82015-11-12 10:35:13 +0200659 else:
Matthew Treinish4217a702016-10-07 17:27:11 -0400660 raise lib_exc.InvalidConfiguration()
Alexander Gubanovc8829f82015-11-12 10:35:13 +0200661
Andrea Frittoli2e733b52014-07-16 14:12:11 +0100662
Andrea Frittoli4971fc82014-09-25 10:22:20 +0100663class NetworkScenarioTest(ScenarioTest):
Yair Fried1fc32a12014-08-04 09:11:30 +0300664 """Base class for network scenario tests.
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000665
Yair Fried1fc32a12014-08-04 09:11:30 +0300666 This class provide helpers for network scenario tests, using the neutron
667 API. Helpers from ancestor which use the nova network API are overridden
668 with the neutron API.
669
670 This Class also enforces using Neutron instead of novanetwork.
671 Subclassed tests will be skipped if Neutron is not enabled
672
673 """
674
Andrea Frittolib21de6c2015-02-06 20:12:38 +0000675 credentials = ['primary', 'admin']
676
Yair Fried1fc32a12014-08-04 09:11:30 +0300677 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +0000678 def skip_checks(cls):
679 super(NetworkScenarioTest, cls).skip_checks()
Andrea Frittoli2ddc2632014-09-25 11:03:00 +0100680 if not CONF.service_available.neutron:
681 raise cls.skipException('Neutron not available')
Yair Fried1fc32a12014-08-04 09:11:30 +0300682
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -0700683 def _create_network(self, networks_client=None,
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000684 routers_client=None, tenant_id=None,
Markus Zoeller156b5da2016-07-11 18:10:31 +0200685 namestart='network-smoke-',
686 port_security_enabled=True):
John Warren94d8faf2015-09-15 12:22:24 -0400687 if not networks_client:
688 networks_client = self.networks_client
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000689 if not routers_client:
690 routers_client = self.routers_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300691 if not tenant_id:
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -0700692 tenant_id = networks_client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300693 name = data_utils.rand_name(namestart)
Matt Riedemann039b2fe2016-09-15 16:12:24 -0400694 network_kwargs = dict(name=name, tenant_id=tenant_id)
695 # Neutron disables port security by default so we have to check the
696 # config before trying to create the network with port_security_enabled
697 if CONF.network_feature_enabled.port_security:
698 network_kwargs['port_security_enabled'] = port_security_enabled
Markus Zoeller156b5da2016-07-11 18:10:31 +0200699 result = networks_client.create_network(**network_kwargs)
Steve Heyman33735f22016-05-24 09:28:08 -0500700 network = result['network']
701
702 self.assertEqual(network['name'], name)
Jordan Pittier9e227c52016-02-09 14:35:18 +0100703 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
Steve Heyman33735f22016-05-24 09:28:08 -0500704 self.networks_client.delete_network,
705 network['id'])
Yair Fried1fc32a12014-08-04 09:11:30 +0300706 return network
707
708 def _list_networks(self, *args, **kwargs):
709 """List networks using admin creds """
John Warren94d8faf2015-09-15 12:22:24 -0400710 networks_list = self.admin_manager.networks_client.list_networks(
ghanshyam2f7cc022015-06-26 18:18:11 +0900711 *args, **kwargs)
712 return networks_list['networks']
Yair Fried1fc32a12014-08-04 09:11:30 +0300713
714 def _list_subnets(self, *args, **kwargs):
715 """List subnets using admin creds """
John Warren3961acd2015-10-02 14:38:53 -0400716 subnets_list = self.admin_manager.subnets_client.list_subnets(
ghanshyam2f7cc022015-06-26 18:18:11 +0900717 *args, **kwargs)
718 return subnets_list['subnets']
Yair Fried1fc32a12014-08-04 09:11:30 +0300719
720 def _list_routers(self, *args, **kwargs):
721 """List routers using admin creds """
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000722 routers_list = self.admin_manager.routers_client.list_routers(
ghanshyam2f7cc022015-06-26 18:18:11 +0900723 *args, **kwargs)
724 return routers_list['routers']
Yair Fried1fc32a12014-08-04 09:11:30 +0300725
726 def _list_ports(self, *args, **kwargs):
727 """List ports using admin creds """
John Warren49c0fe52015-10-22 12:35:54 -0400728 ports_list = self.admin_manager.ports_client.list_ports(
ghanshyam2f7cc022015-06-26 18:18:11 +0900729 *args, **kwargs)
730 return ports_list['ports']
Yair Fried1fc32a12014-08-04 09:11:30 +0300731
Yair Fried564d89d2015-08-06 17:02:12 +0300732 def _list_agents(self, *args, **kwargs):
733 """List agents using admin creds """
Ken'ichi Ohmichi71860062015-12-15 08:20:13 +0000734 agents_list = self.admin_manager.network_agents_client.list_agents(
Yair Fried564d89d2015-08-06 17:02:12 +0300735 *args, **kwargs)
736 return agents_list['agents']
737
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -0700738 def _create_subnet(self, network, subnets_client=None,
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000739 routers_client=None, namestart='subnet-smoke',
740 **kwargs):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000741 """Create a subnet for the given network
742
743 within the cidr block configured for tenant networks.
Yair Fried1fc32a12014-08-04 09:11:30 +0300744 """
John Warren3961acd2015-10-02 14:38:53 -0400745 if not subnets_client:
746 subnets_client = self.subnets_client
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000747 if not routers_client:
748 routers_client = self.routers_client
Yair Fried1fc32a12014-08-04 09:11:30 +0300749
750 def cidr_in_use(cidr, tenant_id):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000751 """Check cidr existence
752
lei zhangdd552b22015-11-25 20:41:48 +0800753 :returns: True if subnet with cidr already exist in tenant
754 False else
Yair Fried1fc32a12014-08-04 09:11:30 +0300755 """
756 cidr_in_use = self._list_subnets(tenant_id=tenant_id, cidr=cidr)
757 return len(cidr_in_use) != 0
758
Kirill Shileev14113572014-11-21 16:58:02 +0300759 ip_version = kwargs.pop('ip_version', 4)
760
761 if ip_version == 6:
762 tenant_cidr = netaddr.IPNetwork(
Sean Dagueed6e5862016-04-04 10:49:13 -0400763 CONF.network.project_network_v6_cidr)
764 num_bits = CONF.network.project_network_v6_mask_bits
Kirill Shileev14113572014-11-21 16:58:02 +0300765 else:
Sean Dagueed6e5862016-04-04 10:49:13 -0400766 tenant_cidr = netaddr.IPNetwork(CONF.network.project_network_cidr)
767 num_bits = CONF.network.project_network_mask_bits
Kirill Shileev14113572014-11-21 16:58:02 +0300768
Yair Fried1fc32a12014-08-04 09:11:30 +0300769 result = None
Kirill Shileev14113572014-11-21 16:58:02 +0300770 str_cidr = None
Yair Fried1fc32a12014-08-04 09:11:30 +0300771 # Repeatedly attempt subnet creation with sequential cidr
772 # blocks until an unallocated block is found.
Kirill Shileev14113572014-11-21 16:58:02 +0300773 for subnet_cidr in tenant_cidr.subnet(num_bits):
Yair Fried1fc32a12014-08-04 09:11:30 +0300774 str_cidr = str(subnet_cidr)
Steve Heyman33735f22016-05-24 09:28:08 -0500775 if cidr_in_use(str_cidr, tenant_id=network['tenant_id']):
Yair Fried1fc32a12014-08-04 09:11:30 +0300776 continue
777
778 subnet = dict(
779 name=data_utils.rand_name(namestart),
Steve Heyman33735f22016-05-24 09:28:08 -0500780 network_id=network['id'],
781 tenant_id=network['tenant_id'],
Yair Fried1fc32a12014-08-04 09:11:30 +0300782 cidr=str_cidr,
Kirill Shileev14113572014-11-21 16:58:02 +0300783 ip_version=ip_version,
Yair Fried1fc32a12014-08-04 09:11:30 +0300784 **kwargs
785 )
786 try:
John Warren3961acd2015-10-02 14:38:53 -0400787 result = subnets_client.create_subnet(**subnet)
Yair Fried1fc32a12014-08-04 09:11:30 +0300788 break
Masayuki Igawad9388762015-01-20 14:56:42 +0900789 except lib_exc.Conflict as e:
Yair Fried1fc32a12014-08-04 09:11:30 +0300790 is_overlapping_cidr = 'overlaps with another subnet' in str(e)
791 if not is_overlapping_cidr:
792 raise
793 self.assertIsNotNone(result, 'Unable to allocate tenant network')
Steve Heyman33735f22016-05-24 09:28:08 -0500794
795 subnet = result['subnet']
796 self.assertEqual(subnet['cidr'], str_cidr)
797
798 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
799 subnets_client.delete_subnet, subnet['id'])
800
Yair Fried1fc32a12014-08-04 09:11:30 +0300801 return subnet
802
Kirill Shileev14113572014-11-21 16:58:02 +0300803 def _get_server_port_id_and_ip4(self, server, ip_addr=None):
Kevin Benton1d0c1dc2016-02-04 14:30:08 -0800804 ports = self._list_ports(device_id=server['id'], fixed_ip=ip_addr)
Kobi Samoray166500a2016-10-09 14:42:48 +0300805 # A port can have more than one IP address in some cases.
Sean M. Collins2e896832015-12-15 13:58:47 -0500806 # If the network is dual-stack (IPv4 + IPv6), this port is associated
807 # with 2 subnets
Vasyl Saienko8fd517c2016-05-30 09:52:54 +0300808 p_status = ['ACTIVE']
809 # NOTE(vsaienko) With Ironic, instances live on separate hardware
810 # servers. Neutron does not bind ports for Ironic instances, as a
811 # result the port remains in the DOWN state.
Vasyl Saienkoc8aa34b2016-08-01 14:18:37 +0300812 # TODO(vsaienko) remove once bug: #1599836 is resolved.
Vasyl Saienko8fd517c2016-05-30 09:52:54 +0300813 if CONF.service_available.ironic:
814 p_status.append('DOWN')
Daniel Mellado9e3e1062015-08-06 18:07:05 +0200815 port_map = [(p["id"], fxip["ip_address"])
816 for p in ports
817 for fxip in p["fixed_ips"]
Yatin Kumbhareee4924c2016-06-09 15:12:06 +0530818 if netutils.is_valid_ipv4(fxip["ip_address"])
Vasyl Saienko8fd517c2016-05-30 09:52:54 +0300819 and p['status'] in p_status]
Kevin Benton1d0c1dc2016-02-04 14:30:08 -0800820 inactive = [p for p in ports if p['status'] != 'ACTIVE']
821 if inactive:
822 LOG.warning("Instance has ports that are not ACTIVE: %s", inactive)
Daniel Mellado9e3e1062015-08-06 18:07:05 +0200823
John L. Villalovosb83286f2015-11-04 14:46:57 -0800824 self.assertNotEqual(0, len(port_map),
825 "No IPv4 addresses found in: %s" % ports)
Daniel Mellado9e3e1062015-08-06 18:07:05 +0200826 self.assertEqual(len(port_map), 1,
827 "Found multiple IPv4 addresses: %s. "
828 "Unable to determine which port to target."
829 % port_map)
830 return port_map[0]
Yair Fried1fc32a12014-08-04 09:11:30 +0300831
David Shrewsbury9bac3662014-08-07 15:07:01 -0400832 def _get_network_by_name(self, network_name):
833 net = self._list_networks(name=network_name)
Adam Gandelman878a5fd2015-03-30 14:33:36 -0700834 self.assertNotEqual(len(net), 0,
835 "Unable to get network by name: %s" % network_name)
Steve Heyman33735f22016-05-24 09:28:08 -0500836 return net[0]
David Shrewsbury9bac3662014-08-07 15:07:01 -0400837
Yair Friedae0e73d2014-11-24 11:56:26 +0200838 def create_floating_ip(self, thing, external_network_id=None,
839 port_id=None, client=None):
Ken'ichi Ohmichia112a592015-11-17 08:49:37 +0000840 """Create a floating IP and associates to a resource/port on Neutron"""
Yair Friedae0e73d2014-11-24 11:56:26 +0200841 if not external_network_id:
842 external_network_id = CONF.network.public_network_id
Yair Frieddb6c9e92014-08-06 08:53:13 +0300843 if not client:
John Warrenfbf2a892015-11-17 12:36:14 -0500844 client = self.floating_ips_client
Yair Fried1fc32a12014-08-04 09:11:30 +0300845 if not port_id:
Kirill Shileev14113572014-11-21 16:58:02 +0300846 port_id, ip4 = self._get_server_port_id_and_ip4(thing)
847 else:
848 ip4 = None
David Kranz34e88122014-12-11 15:24:05 -0500849 result = client.create_floatingip(
Yair Fried1fc32a12014-08-04 09:11:30 +0300850 floating_network_id=external_network_id,
851 port_id=port_id,
Kirill Shileev14113572014-11-21 16:58:02 +0300852 tenant_id=thing['tenant_id'],
853 fixed_ip_address=ip4
Yair Fried1fc32a12014-08-04 09:11:30 +0300854 )
Steve Heyman33735f22016-05-24 09:28:08 -0500855 floating_ip = result['floatingip']
Jordan Pittier9e227c52016-02-09 14:35:18 +0100856 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
Steve Heyman33735f22016-05-24 09:28:08 -0500857 self.floating_ips_client.delete_floatingip,
858 floating_ip['id'])
Yair Fried1fc32a12014-08-04 09:11:30 +0300859 return floating_ip
860
861 def _associate_floating_ip(self, floating_ip, server):
Kirill Shileev14113572014-11-21 16:58:02 +0300862 port_id, _ = self._get_server_port_id_and_ip4(server)
Steve Heyman33735f22016-05-24 09:28:08 -0500863 kwargs = dict(port_id=port_id)
864 floating_ip = self.floating_ips_client.update_floatingip(
865 floating_ip['id'], **kwargs)['floatingip']
866 self.assertEqual(port_id, floating_ip['port_id'])
Yair Fried1fc32a12014-08-04 09:11:30 +0300867 return floating_ip
868
869 def _disassociate_floating_ip(self, floating_ip):
Steve Heyman33735f22016-05-24 09:28:08 -0500870 """:param floating_ip: floating_ips_client.create_floatingip"""
871 kwargs = dict(port_id=None)
872 floating_ip = self.floating_ips_client.update_floatingip(
873 floating_ip['id'], **kwargs)['floatingip']
874 self.assertIsNone(floating_ip['port_id'])
Yair Fried1fc32a12014-08-04 09:11:30 +0300875 return floating_ip
876
Yair Fried45f92952014-06-26 05:19:19 +0300877 def check_floating_ip_status(self, floating_ip, status):
Carl Baldwina754e2d2014-10-23 22:47:41 +0000878 """Verifies floatingip reaches the given status
Yair Fried45f92952014-06-26 05:19:19 +0300879
Steve Heyman33735f22016-05-24 09:28:08 -0500880 :param dict floating_ip: floating IP dict to check status
Yair Fried45f92952014-06-26 05:19:19 +0300881 :param status: target status
882 :raises: AssertionError if status doesn't match
883 """
Steve Heyman33735f22016-05-24 09:28:08 -0500884 floatingip_id = floating_ip['id']
885
Carl Baldwina754e2d2014-10-23 22:47:41 +0000886 def refresh():
Steve Heyman33735f22016-05-24 09:28:08 -0500887 result = (self.floating_ips_client.
888 show_floatingip(floatingip_id)['floatingip'])
889 return status == result['status']
Carl Baldwina754e2d2014-10-23 22:47:41 +0000890
Jordan Pittier35a63752016-08-30 13:09:12 +0200891 test_utils.call_until_true(refresh,
892 CONF.network.build_timeout,
893 CONF.network.build_interval)
Steve Heyman33735f22016-05-24 09:28:08 -0500894 floating_ip = self.floating_ips_client.show_floatingip(
895 floatingip_id)['floatingip']
896 self.assertEqual(status, floating_ip['status'],
Yair Fried45f92952014-06-26 05:19:19 +0300897 message="FloatingIP: {fp} is at status: {cst}. "
898 "failed to reach status: {st}"
Steve Heyman33735f22016-05-24 09:28:08 -0500899 .format(fp=floating_ip, cst=floating_ip['status'],
Yair Fried45f92952014-06-26 05:19:19 +0300900 st=status))
901 LOG.info("FloatingIP: {fp} is at status: {st}"
902 .format(fp=floating_ip, st=status))
903
Yair Fried1fc32a12014-08-04 09:11:30 +0300904 def _check_tenant_network_connectivity(self, server,
905 username,
906 private_key,
907 should_connect=True,
908 servers_for_debug=None):
Sean Dagueed6e5862016-04-04 10:49:13 -0400909 if not CONF.network.project_networks_reachable:
Yair Fried1fc32a12014-08-04 09:11:30 +0300910 msg = 'Tenant networks not configured to be reachable.'
911 LOG.info(msg)
912 return
913 # The target login is assumed to have been configured for
914 # key-based authentication by cloud-init.
915 try:
Matthew Treinish71426682015-04-23 11:19:38 -0400916 for net_name, ip_addresses in six.iteritems(server['addresses']):
Yair Fried1fc32a12014-08-04 09:11:30 +0300917 for ip_address in ip_addresses:
ghanshyam807211c2014-12-18 13:21:22 +0900918 self.check_vm_connectivity(ip_address['addr'],
Yair Friedae0e73d2014-11-24 11:56:26 +0200919 username,
920 private_key,
921 should_connect=should_connect)
Yair Fried1fc32a12014-08-04 09:11:30 +0300922 except Exception as e:
923 LOG.exception('Tenant network connectivity check failed')
924 self._log_console_output(servers_for_debug)
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000925 self._log_net_info(e)
Yair Fried1fc32a12014-08-04 09:11:30 +0300926 raise
927
Yair Friedbc46f592015-11-18 16:29:34 +0200928 def _check_remote_connectivity(self, source, dest, should_succeed=True,
929 nic=None):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000930 """check ping server via source ssh connection
Yair Fried1fc32a12014-08-04 09:11:30 +0300931
932 :param source: RemoteClient: an ssh connection from which to ping
933 :param dest: and IP to ping against
934 :param should_succeed: boolean should ping succeed or not
Yair Friedbc46f592015-11-18 16:29:34 +0200935 :param nic: specific network interface to ping from
Yair Fried1fc32a12014-08-04 09:11:30 +0300936 :returns: boolean -- should_succeed == ping
937 :returns: ping is false if ping failed
938 """
939 def ping_remote():
940 try:
Yair Friedbc46f592015-11-18 16:29:34 +0200941 source.ping_host(dest, nic=nic)
Andrey Pavlov64723762015-04-29 06:24:58 +0300942 except lib_exc.SSHExecCommandFailed:
zhangguoqing6c096642016-01-04 06:17:21 +0000943 LOG.warning('Failed to ping IP: %s via a ssh connection '
944 'from: %s.' % (dest, source.ssh_client.host))
Yair Fried1fc32a12014-08-04 09:11:30 +0300945 return not should_succeed
946 return should_succeed
947
Jordan Pittier35a63752016-08-30 13:09:12 +0200948 return test_utils.call_until_true(ping_remote,
949 CONF.validation.ping_timeout,
950 1)
Yair Fried1fc32a12014-08-04 09:11:30 +0300951
John Warren456d9ae2016-01-12 15:36:33 -0500952 def _create_security_group(self, security_group_rules_client=None,
953 tenant_id=None,
John Warrenf9606e92015-12-10 12:12:42 -0500954 namestart='secgroup-smoke',
955 security_groups_client=None):
John Warren456d9ae2016-01-12 15:36:33 -0500956 if security_group_rules_client is None:
957 security_group_rules_client = self.security_group_rules_client
John Warrenf9606e92015-12-10 12:12:42 -0500958 if security_groups_client is None:
959 security_groups_client = self.security_groups_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300960 if tenant_id is None:
John Warrenf9606e92015-12-10 12:12:42 -0500961 tenant_id = security_groups_client.tenant_id
962 secgroup = self._create_empty_security_group(
963 namestart=namestart, client=security_groups_client,
964 tenant_id=tenant_id)
Yair Fried1fc32a12014-08-04 09:11:30 +0300965
966 # Add rules to the security group
John Warrenf9606e92015-12-10 12:12:42 -0500967 rules = self._create_loginable_secgroup_rule(
John Warren456d9ae2016-01-12 15:36:33 -0500968 security_group_rules_client=security_group_rules_client,
969 secgroup=secgroup,
John Warrenf9606e92015-12-10 12:12:42 -0500970 security_groups_client=security_groups_client)
Yair Fried1fc32a12014-08-04 09:11:30 +0300971 for rule in rules:
Steve Heyman33735f22016-05-24 09:28:08 -0500972 self.assertEqual(tenant_id, rule['tenant_id'])
973 self.assertEqual(secgroup['id'], rule['security_group_id'])
Yair Fried1fc32a12014-08-04 09:11:30 +0300974 return secgroup
975
Yair Frieddb6c9e92014-08-06 08:53:13 +0300976 def _create_empty_security_group(self, client=None, tenant_id=None,
Yair Fried1fc32a12014-08-04 09:11:30 +0300977 namestart='secgroup-smoke'):
978 """Create a security group without rules.
979
980 Default rules will be created:
981 - IPv4 egress to any
982 - IPv6 egress to any
983
984 :param tenant_id: secgroup will be created in this tenant
Steve Heyman33735f22016-05-24 09:28:08 -0500985 :returns: the created security group
Yair Fried1fc32a12014-08-04 09:11:30 +0300986 """
987 if client is None:
John Warrenf9606e92015-12-10 12:12:42 -0500988 client = self.security_groups_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300989 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000990 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300991 sg_name = data_utils.rand_name(namestart)
992 sg_desc = sg_name + " description"
993 sg_dict = dict(name=sg_name,
994 description=sg_desc)
995 sg_dict['tenant_id'] = tenant_id
David Kranz34e88122014-12-11 15:24:05 -0500996 result = client.create_security_group(**sg_dict)
Steve Heyman33735f22016-05-24 09:28:08 -0500997
998 secgroup = result['security_group']
999 self.assertEqual(secgroup['name'], sg_name)
1000 self.assertEqual(tenant_id, secgroup['tenant_id'])
1001 self.assertEqual(secgroup['description'], sg_desc)
1002
Jordan Pittier9e227c52016-02-09 14:35:18 +01001003 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
Steve Heyman33735f22016-05-24 09:28:08 -05001004 client.delete_security_group, secgroup['id'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001005 return secgroup
1006
Yair Frieddb6c9e92014-08-06 08:53:13 +03001007 def _default_security_group(self, client=None, tenant_id=None):
Yair Fried1fc32a12014-08-04 09:11:30 +03001008 """Get default secgroup for given tenant_id.
1009
Ken'ichi Ohmichid67c8da2016-09-13 16:18:11 -07001010 :returns: default secgroup for given tenant
Yair Fried1fc32a12014-08-04 09:11:30 +03001011 """
1012 if client is None:
John Warrenf9606e92015-12-10 12:12:42 -05001013 client = self.security_groups_client
Yair Frieddb6c9e92014-08-06 08:53:13 +03001014 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +00001015 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001016 sgs = [
Jordan Pittier8ad86172016-04-25 16:20:53 +02001017 sg for sg in list(client.list_security_groups().values())[0]
Yair Fried1fc32a12014-08-04 09:11:30 +03001018 if sg['tenant_id'] == tenant_id and sg['name'] == 'default'
1019 ]
1020 msg = "No default security group for tenant %s." % (tenant_id)
1021 self.assertTrue(len(sgs) > 0, msg)
Steve Heyman33735f22016-05-24 09:28:08 -05001022 return sgs[0]
Yair Fried1fc32a12014-08-04 09:11:30 +03001023
John Warren456d9ae2016-01-12 15:36:33 -05001024 def _create_security_group_rule(self, secgroup=None,
1025 sec_group_rules_client=None,
John Warrenf9606e92015-12-10 12:12:42 -05001026 tenant_id=None,
1027 security_groups_client=None, **kwargs):
Yair Fried1fc32a12014-08-04 09:11:30 +03001028 """Create a rule from a dictionary of rule parameters.
1029
1030 Create a rule in a secgroup. if secgroup not defined will search for
1031 default secgroup in tenant_id.
1032
Steve Heyman33735f22016-05-24 09:28:08 -05001033 :param secgroup: the security group.
Yair Fried1fc32a12014-08-04 09:11:30 +03001034 :param tenant_id: if secgroup not passed -- the tenant in which to
1035 search for default secgroup
1036 :param kwargs: a dictionary containing rule parameters:
1037 for example, to allow incoming ssh:
1038 rule = {
1039 direction: 'ingress'
1040 protocol:'tcp',
1041 port_range_min: 22,
1042 port_range_max: 22
1043 }
1044 """
John Warren456d9ae2016-01-12 15:36:33 -05001045 if sec_group_rules_client is None:
1046 sec_group_rules_client = self.security_group_rules_client
John Warrenf9606e92015-12-10 12:12:42 -05001047 if security_groups_client is None:
1048 security_groups_client = self.security_groups_client
Yair Frieddb6c9e92014-08-06 08:53:13 +03001049 if not tenant_id:
John Warrenf9606e92015-12-10 12:12:42 -05001050 tenant_id = security_groups_client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001051 if secgroup is None:
John Warrenf9606e92015-12-10 12:12:42 -05001052 secgroup = self._default_security_group(
1053 client=security_groups_client, tenant_id=tenant_id)
Yair Fried1fc32a12014-08-04 09:11:30 +03001054
Steve Heyman33735f22016-05-24 09:28:08 -05001055 ruleset = dict(security_group_id=secgroup['id'],
1056 tenant_id=secgroup['tenant_id'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001057 ruleset.update(kwargs)
1058
John Warren456d9ae2016-01-12 15:36:33 -05001059 sg_rule = sec_group_rules_client.create_security_group_rule(**ruleset)
Steve Heyman33735f22016-05-24 09:28:08 -05001060 sg_rule = sg_rule['security_group_rule']
1061
1062 self.assertEqual(secgroup['tenant_id'], sg_rule['tenant_id'])
1063 self.assertEqual(secgroup['id'], sg_rule['security_group_id'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001064
1065 return sg_rule
1066
John Warren456d9ae2016-01-12 15:36:33 -05001067 def _create_loginable_secgroup_rule(self, security_group_rules_client=None,
1068 secgroup=None,
John Warrenf9606e92015-12-10 12:12:42 -05001069 security_groups_client=None):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001070 """Create loginable security group rule
1071
Alex Stafeyevdd5dde92016-05-08 14:35:04 +03001072 This function will create:
1073 1. egress and ingress tcp port 22 allow rule in order to allow ssh
1074 access for ipv4.
1075 2. egress and ingress ipv6 icmp allow rule, in order to allow icmpv6.
1076 3. egress and ingress ipv4 icmp allow rule, in order to allow icmpv4.
Yair Fried1fc32a12014-08-04 09:11:30 +03001077 """
1078
John Warren456d9ae2016-01-12 15:36:33 -05001079 if security_group_rules_client is None:
1080 security_group_rules_client = self.security_group_rules_client
John Warrenf9606e92015-12-10 12:12:42 -05001081 if security_groups_client is None:
1082 security_groups_client = self.security_groups_client
Yair Fried1fc32a12014-08-04 09:11:30 +03001083 rules = []
1084 rulesets = [
1085 dict(
1086 # ssh
1087 protocol='tcp',
1088 port_range_min=22,
1089 port_range_max=22,
1090 ),
1091 dict(
1092 # ping
1093 protocol='icmp',
Andreas Scheuring887ca8e2015-02-03 17:56:12 +01001094 ),
1095 dict(
1096 # ipv6-icmp for ping6
1097 protocol='icmp',
1098 ethertype='IPv6',
Yair Fried1fc32a12014-08-04 09:11:30 +03001099 )
1100 ]
John Warren456d9ae2016-01-12 15:36:33 -05001101 sec_group_rules_client = security_group_rules_client
Yair Fried1fc32a12014-08-04 09:11:30 +03001102 for ruleset in rulesets:
1103 for r_direction in ['ingress', 'egress']:
1104 ruleset['direction'] = r_direction
1105 try:
1106 sg_rule = self._create_security_group_rule(
John Warren456d9ae2016-01-12 15:36:33 -05001107 sec_group_rules_client=sec_group_rules_client,
1108 secgroup=secgroup,
John Warrenf9606e92015-12-10 12:12:42 -05001109 security_groups_client=security_groups_client,
1110 **ruleset)
Masayuki Igawad9388762015-01-20 14:56:42 +09001111 except lib_exc.Conflict as ex:
Yair Fried1fc32a12014-08-04 09:11:30 +03001112 # if rule already exist - skip rule and continue
1113 msg = 'Security group rule already exists'
1114 if msg not in ex._error_string:
1115 raise ex
1116 else:
Steve Heyman33735f22016-05-24 09:28:08 -05001117 self.assertEqual(r_direction, sg_rule['direction'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001118 rules.append(sg_rule)
1119
1120 return rules
1121
Yair Frieddb6c9e92014-08-06 08:53:13 +03001122 def _get_router(self, client=None, tenant_id=None):
Yair Fried1fc32a12014-08-04 09:11:30 +03001123 """Retrieve a router for the given tenant id.
1124
1125 If a public router has been configured, it will be returned.
1126
1127 If a public router has not been configured, but a public
1128 network has, a tenant router will be created and returned that
1129 routes traffic to the public network.
1130 """
Yair Frieddb6c9e92014-08-06 08:53:13 +03001131 if not client:
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +00001132 client = self.routers_client
Yair Frieddb6c9e92014-08-06 08:53:13 +03001133 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +00001134 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001135 router_id = CONF.network.public_router_id
1136 network_id = CONF.network.public_network_id
1137 if router_id:
David Kranzca4c7e72015-05-27 11:39:19 -04001138 body = client.show_router(router_id)
Steve Heyman33735f22016-05-24 09:28:08 -05001139 return body['router']
Yair Fried1fc32a12014-08-04 09:11:30 +03001140 elif network_id:
Yair Frieddb6c9e92014-08-06 08:53:13 +03001141 router = self._create_router(client, tenant_id)
Steve Heyman33735f22016-05-24 09:28:08 -05001142 kwargs = {'external_gateway_info': dict(network_id=network_id)}
1143 router = client.update_router(router['id'], **kwargs)['router']
Yair Fried1fc32a12014-08-04 09:11:30 +03001144 return router
1145 else:
1146 raise Exception("Neither of 'public_router_id' or "
1147 "'public_network_id' has been defined.")
1148
Yair Frieddb6c9e92014-08-06 08:53:13 +03001149 def _create_router(self, client=None, tenant_id=None,
1150 namestart='router-smoke'):
1151 if not client:
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +00001152 client = self.routers_client
Yair Frieddb6c9e92014-08-06 08:53:13 +03001153 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +00001154 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001155 name = data_utils.rand_name(namestart)
David Kranz34e88122014-12-11 15:24:05 -05001156 result = client.create_router(name=name,
1157 admin_state_up=True,
1158 tenant_id=tenant_id)
Steve Heyman33735f22016-05-24 09:28:08 -05001159 router = result['router']
1160 self.assertEqual(router['name'], name)
1161 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
1162 client.delete_router,
1163 router['id'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001164 return router
1165
Alok Maurya6384bbb2014-07-13 06:44:29 -07001166 def _update_router_admin_state(self, router, admin_state_up):
Steve Heyman33735f22016-05-24 09:28:08 -05001167 kwargs = dict(admin_state_up=admin_state_up)
1168 router = self.routers_client.update_router(
1169 router['id'], **kwargs)['router']
1170 self.assertEqual(admin_state_up, router['admin_state_up'])
Alok Maurya6384bbb2014-07-13 06:44:29 -07001171
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -07001172 def create_networks(self, networks_client=None,
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +00001173 routers_client=None, subnets_client=None,
Markus Zoeller156b5da2016-07-11 18:10:31 +02001174 tenant_id=None, dns_nameservers=None,
1175 port_security_enabled=True):
Yair Fried1fc32a12014-08-04 09:11:30 +03001176 """Create a network with a subnet connected to a router.
1177
David Shrewsbury9bac3662014-08-07 15:07:01 -04001178 The baremetal driver is a special case since all nodes are
1179 on the same shared network.
1180
Yair Fried413bf2d2014-11-19 17:07:11 +02001181 :param tenant_id: id of tenant to create resources in.
1182 :param dns_nameservers: list of dns servers to send to subnet.
Yair Fried1fc32a12014-08-04 09:11:30 +03001183 :returns: network, subnet, router
1184 """
David Shrewsbury9bac3662014-08-07 15:07:01 -04001185 if CONF.baremetal.driver_enabled:
1186 # NOTE(Shrews): This exception is for environments where tenant
1187 # credential isolation is available, but network separation is
1188 # not (the current baremetal case). Likely can be removed when
1189 # test account mgmt is reworked:
1190 # https://blueprints.launchpad.net/tempest/+spec/test-accounts
Adam Gandelman878a5fd2015-03-30 14:33:36 -07001191 if not CONF.compute.fixed_network_name:
1192 m = 'fixed_network_name must be specified in config'
Matthew Treinish4217a702016-10-07 17:27:11 -04001193 raise lib_exc.InvalidConfiguration(m)
David Shrewsbury9bac3662014-08-07 15:07:01 -04001194 network = self._get_network_by_name(
1195 CONF.compute.fixed_network_name)
1196 router = None
1197 subnet = None
1198 else:
John Warren94d8faf2015-09-15 12:22:24 -04001199 network = self._create_network(
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -07001200 networks_client=networks_client,
Markus Zoeller156b5da2016-07-11 18:10:31 +02001201 tenant_id=tenant_id,
1202 port_security_enabled=port_security_enabled)
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +00001203 router = self._get_router(client=routers_client,
1204 tenant_id=tenant_id)
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -07001205 subnet_kwargs = dict(network=network,
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +00001206 subnets_client=subnets_client,
1207 routers_client=routers_client)
Yair Fried413bf2d2014-11-19 17:07:11 +02001208 # use explicit check because empty list is a valid option
1209 if dns_nameservers is not None:
1210 subnet_kwargs['dns_nameservers'] = dns_nameservers
1211 subnet = self._create_subnet(**subnet_kwargs)
Steve Heyman33735f22016-05-24 09:28:08 -05001212 if not routers_client:
1213 routers_client = self.routers_client
1214 router_id = router['id']
1215 routers_client.add_router_interface(router_id,
1216 subnet_id=subnet['id'])
1217
1218 # save a cleanup job to remove this association between
1219 # router and subnet
1220 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
1221 routers_client.remove_router_interface, router_id,
1222 subnet_id=subnet['id'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001223 return network, subnet, router
1224
1225
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001226# power/provision states as of icehouse
1227class BaremetalPowerStates(object):
1228 """Possible power states of an Ironic node."""
1229 POWER_ON = 'power on'
1230 POWER_OFF = 'power off'
1231 REBOOT = 'rebooting'
1232 SUSPEND = 'suspended'
1233
1234
1235class BaremetalProvisionStates(object):
1236 """Possible provision states of an Ironic node."""
1237 NOSTATE = None
1238 INIT = 'initializing'
1239 ACTIVE = 'active'
1240 BUILDING = 'building'
1241 DEPLOYWAIT = 'wait call-back'
1242 DEPLOYING = 'deploying'
1243 DEPLOYFAIL = 'deploy failed'
1244 DEPLOYDONE = 'deploy complete'
1245 DELETING = 'deleting'
1246 DELETED = 'deleted'
1247 ERROR = 'error'
1248
1249
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001250class BaremetalScenarioTest(ScenarioTest):
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001251
1252 credentials = ['primary', 'admin']
1253
Adam Gandelman4a48a602014-03-20 18:23:18 -07001254 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001255 def skip_checks(cls):
1256 super(BaremetalScenarioTest, cls).skip_checks()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001257 if (not CONF.service_available.ironic or
1258 not CONF.baremetal.driver_enabled):
1259 msg = 'Ironic not available or Ironic compute driver not enabled'
1260 raise cls.skipException(msg)
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001261
1262 @classmethod
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001263 def setup_clients(cls):
1264 super(BaremetalScenarioTest, cls).setup_clients()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001265
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001266 cls.baremetal_client = cls.admin_manager.baremetal_client
Adam Gandelman4a48a602014-03-20 18:23:18 -07001267
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001268 @classmethod
1269 def resource_setup(cls):
1270 super(BaremetalScenarioTest, cls).resource_setup()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001271 # allow any issues obtaining the node list to raise early
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001272 cls.baremetal_client.list_nodes()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001273
1274 def _node_state_timeout(self, node_id, state_attr,
1275 target_states, timeout=10, interval=1):
1276 if not isinstance(target_states, list):
1277 target_states = [target_states]
1278
1279 def check_state():
1280 node = self.get_node(node_id=node_id)
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001281 if node.get(state_attr) in target_states:
Adam Gandelman4a48a602014-03-20 18:23:18 -07001282 return True
1283 return False
1284
Jordan Pittier35a63752016-08-30 13:09:12 +02001285 if not test_utils.call_until_true(
Adam Gandelman4a48a602014-03-20 18:23:18 -07001286 check_state, timeout, interval):
1287 msg = ("Timed out waiting for node %s to reach %s state(s) %s" %
1288 (node_id, state_attr, target_states))
guo yunxianebb15f22016-11-01 21:03:35 +08001289 raise lib_exc.TimeoutException(msg)
Adam Gandelman4a48a602014-03-20 18:23:18 -07001290
1291 def wait_provisioning_state(self, node_id, state, timeout):
1292 self._node_state_timeout(
1293 node_id=node_id, state_attr='provision_state',
1294 target_states=state, timeout=timeout)
1295
1296 def wait_power_state(self, node_id, state):
1297 self._node_state_timeout(
1298 node_id=node_id, state_attr='power_state',
1299 target_states=state, timeout=CONF.baremetal.power_timeout)
1300
1301 def wait_node(self, instance_id):
1302 """Waits for a node to be associated with instance_id."""
Zhi Kun Liu4a8d1ea2014-04-15 22:08:21 -05001303
Adam Gandelman4a48a602014-03-20 18:23:18 -07001304 def _get_node():
Jordan Pittier9e227c52016-02-09 14:35:18 +01001305 node = test_utils.call_and_ignore_notfound_exc(
1306 self.get_node, instance_id=instance_id)
Adam Gandelman4a48a602014-03-20 18:23:18 -07001307 return node is not None
1308
Jordan Pittier35a63752016-08-30 13:09:12 +02001309 if not test_utils.call_until_true(
Adam Gandelman4a48a602014-03-20 18:23:18 -07001310 _get_node, CONF.baremetal.association_timeout, 1):
1311 msg = ('Timed out waiting to get Ironic node by instance id %s'
1312 % instance_id)
guo yunxianebb15f22016-11-01 21:03:35 +08001313 raise lib_exc.TimeoutException(msg)
Adam Gandelman4a48a602014-03-20 18:23:18 -07001314
1315 def get_node(self, node_id=None, instance_id=None):
1316 if node_id:
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001317 _, body = self.baremetal_client.show_node(node_id)
1318 return body
Adam Gandelman4a48a602014-03-20 18:23:18 -07001319 elif instance_id:
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001320 _, body = self.baremetal_client.show_node_by_instance_uuid(
1321 instance_id)
1322 if body['nodes']:
1323 return body['nodes'][0]
Adam Gandelman4a48a602014-03-20 18:23:18 -07001324
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001325 def get_ports(self, node_uuid):
Adam Gandelman4a48a602014-03-20 18:23:18 -07001326 ports = []
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001327 _, body = self.baremetal_client.list_node_ports(node_uuid)
1328 for port in body['ports']:
1329 _, p = self.baremetal_client.show_port(port['uuid'])
1330 ports.append(p)
Adam Gandelman4a48a602014-03-20 18:23:18 -07001331 return ports
1332
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001333 def add_keypair(self):
1334 self.keypair = self.create_keypair()
1335
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001336 def boot_instance(self):
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001337 self.instance = self.create_server(
lanoux5fc14522015-09-21 08:17:35 +00001338 key_name=self.keypair['name'])
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001339
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001340 self.wait_node(self.instance['id'])
1341 self.node = self.get_node(instance_id=self.instance['id'])
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001342
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001343 self.wait_power_state(self.node['uuid'], BaremetalPowerStates.POWER_ON)
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001344
1345 self.wait_provisioning_state(
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001346 self.node['uuid'],
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001347 [BaremetalProvisionStates.DEPLOYWAIT,
1348 BaremetalProvisionStates.ACTIVE],
1349 timeout=15)
1350
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001351 self.wait_provisioning_state(self.node['uuid'],
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001352 BaremetalProvisionStates.ACTIVE,
1353 timeout=CONF.baremetal.active_timeout)
1354
Ken'ichi Ohmichi0eb153c2015-07-13 02:18:25 +00001355 waiters.wait_for_server_status(self.servers_client,
1356 self.instance['id'], 'ACTIVE')
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001357 self.node = self.get_node(instance_id=self.instance['id'])
ghanshyam0f825252015-08-25 16:02:50 +09001358 self.instance = (self.servers_client.show_server(self.instance['id'])
1359 ['server'])
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001360
1361 def terminate_instance(self):
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001362 self.servers_client.delete_server(self.instance['id'])
1363 self.wait_power_state(self.node['uuid'],
1364 BaremetalPowerStates.POWER_OFF)
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001365 self.wait_provisioning_state(
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001366 self.node['uuid'],
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001367 BaremetalProvisionStates.NOSTATE,
1368 timeout=CONF.baremetal.unprovision_timeout)
1369
Adam Gandelman4a48a602014-03-20 18:23:18 -07001370
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001371class EncryptionScenarioTest(ScenarioTest):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001372 """Base class for encryption scenario tests"""
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001373
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001374 credentials = ['primary', 'admin']
David Kranz4cc852b2015-03-09 14:57:11 -04001375
1376 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001377 def setup_clients(cls):
1378 super(EncryptionScenarioTest, cls).setup_clients()
Jordan Pittierc3f76be2016-10-11 17:06:21 +02001379 if CONF.volume_feature_enabled.api_v2:
Ivan Kolodyazhnybcfc32e2015-08-06 13:31:36 +03001380 cls.admin_volume_types_client = cls.os_adm.volume_types_v2_client
Ken'ichi Ohmichia6ebf622016-08-25 11:52:27 -07001381 cls.admin_encryption_types_client =\
1382 cls.os_adm.encryption_types_v2_client
Jordan Pittierc3f76be2016-10-11 17:06:21 +02001383 else:
1384 cls.admin_volume_types_client = cls.os_adm.volume_types_client
1385 cls.admin_encryption_types_client =\
1386 cls.os_adm.encryption_types_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001387
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001388 def create_volume_type(self, client=None, name=None):
1389 if not client:
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001390 client = self.admin_volume_types_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001391 if not name:
1392 name = 'generic'
Ken'ichi Ohmichi6ded8df2015-03-23 02:00:19 +00001393 randomized_name = data_utils.rand_name('scenario-type-' + name)
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001394 LOG.debug("Creating a volume type: %s", randomized_name)
Joseph Lanoux6809bab2014-12-18 14:57:18 +00001395 body = client.create_volume_type(
lei zhang83c4bbd2015-11-27 00:35:21 +08001396 name=randomized_name)['volume_type']
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001397 self.assertIn('id', body)
1398 self.addCleanup(client.delete_volume_type, body['id'])
1399 return body
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001400
1401 def create_encryption_type(self, client=None, type_id=None, provider=None,
1402 key_size=None, cipher=None,
1403 control_location=None):
1404 if not client:
Ken'ichi Ohmichia6ebf622016-08-25 11:52:27 -07001405 client = self.admin_encryption_types_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001406 if not type_id:
1407 volume_type = self.create_volume_type()
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001408 type_id = volume_type['id']
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001409 LOG.debug("Creating an encryption type for volume type: %s", type_id)
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001410 client.create_encryption_type(
1411 type_id, provider=provider, key_size=key_size, cipher=cipher,
John Warrend053ded2015-08-13 15:22:48 +00001412 control_location=control_location)['encryption']
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001413
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001414
Masayuki Igawa0870db52015-09-18 21:08:36 +09001415class ObjectStorageScenarioTest(ScenarioTest):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001416 """Provide harness to do Object Storage scenario tests.
Chris Dent0d494112014-08-26 13:48:30 +01001417
1418 Subclasses implement the tests that use the methods provided by this
1419 class.
1420 """
1421
1422 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001423 def skip_checks(cls):
Masayuki Igawa0870db52015-09-18 21:08:36 +09001424 super(ObjectStorageScenarioTest, cls).skip_checks()
Chris Dent0d494112014-08-26 13:48:30 +01001425 if not CONF.service_available.swift:
1426 skip_msg = ("%s skipped as swift is not available" %
1427 cls.__name__)
1428 raise cls.skipException(skip_msg)
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001429
1430 @classmethod
1431 def setup_credentials(cls):
Masayuki Igawa60ea6c52014-10-15 17:32:14 +09001432 cls.set_network_resources()
Masayuki Igawa0870db52015-09-18 21:08:36 +09001433 super(ObjectStorageScenarioTest, cls).setup_credentials()
Matthew Treinish4a596932015-03-06 20:37:01 -05001434 operator_role = CONF.object_storage.operator_role
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +01001435 cls.os_operator = cls.get_client_manager(roles=[operator_role])
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001436
1437 @classmethod
1438 def setup_clients(cls):
Masayuki Igawa0870db52015-09-18 21:08:36 +09001439 super(ObjectStorageScenarioTest, cls).setup_clients()
Chris Dent0d494112014-08-26 13:48:30 +01001440 # Clients for Swift
Matthew Treinish8f268292015-02-24 20:01:36 -05001441 cls.account_client = cls.os_operator.account_client
1442 cls.container_client = cls.os_operator.container_client
1443 cls.object_client = cls.os_operator.object_client
Chris Dent0d494112014-08-26 13:48:30 +01001444
Chris Dentde456a12014-09-10 12:41:15 +01001445 def get_swift_stat(self):
Chris Dent0d494112014-08-26 13:48:30 +01001446 """get swift status for our user account."""
1447 self.account_client.list_account_containers()
1448 LOG.debug('Swift status information obtained successfully')
1449
Chris Dentde456a12014-09-10 12:41:15 +01001450 def create_container(self, container_name=None):
Chris Dent0d494112014-08-26 13:48:30 +01001451 name = container_name or data_utils.rand_name(
1452 'swift-scenario-container')
1453 self.container_client.create_container(name)
1454 # look for the container to assure it is created
Chris Dentde456a12014-09-10 12:41:15 +01001455 self.list_and_check_container_objects(name)
Chris Dent0d494112014-08-26 13:48:30 +01001456 LOG.debug('Container %s created' % (name))
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.container_client.delete_container,
1459 name)
Chris Dent0d494112014-08-26 13:48:30 +01001460 return name
1461
Chris Dentde456a12014-09-10 12:41:15 +01001462 def delete_container(self, container_name):
Chris Dent0d494112014-08-26 13:48:30 +01001463 self.container_client.delete_container(container_name)
1464 LOG.debug('Container %s deleted' % (container_name))
1465
Chris Dentde456a12014-09-10 12:41:15 +01001466 def upload_object_to_container(self, container_name, obj_name=None):
Chris Dent0d494112014-08-26 13:48:30 +01001467 obj_name = obj_name or data_utils.rand_name('swift-scenario-object')
1468 obj_data = data_utils.arbitrary_string()
1469 self.object_client.create_object(container_name, obj_name, obj_data)
Jordan Pittier9e227c52016-02-09 14:35:18 +01001470 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
Chris Dent1d4313a2014-10-28 12:16:48 +00001471 self.object_client.delete_object,
1472 container_name,
1473 obj_name)
Chris Dent0d494112014-08-26 13:48:30 +01001474 return obj_name, obj_data
1475
Chris Dentde456a12014-09-10 12:41:15 +01001476 def delete_object(self, container_name, filename):
Chris Dent0d494112014-08-26 13:48:30 +01001477 self.object_client.delete_object(container_name, filename)
Chris Dentde456a12014-09-10 12:41:15 +01001478 self.list_and_check_container_objects(container_name,
1479 not_present_obj=[filename])
Chris Dent0d494112014-08-26 13:48:30 +01001480
Chris Dentde456a12014-09-10 12:41:15 +01001481 def list_and_check_container_objects(self, container_name,
1482 present_obj=None,
1483 not_present_obj=None):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001484 # List objects for a given container and assert which are present and
1485 # which are not.
Ghanshyam2a180b82014-06-16 13:54:22 +09001486 if present_obj is None:
1487 present_obj = []
1488 if not_present_obj is None:
1489 not_present_obj = []
Chris Dent0d494112014-08-26 13:48:30 +01001490 _, object_list = self.container_client.list_container_contents(
1491 container_name)
1492 if present_obj:
1493 for obj in present_obj:
1494 self.assertIn(obj, object_list)
1495 if not_present_obj:
1496 for obj in not_present_obj:
1497 self.assertNotIn(obj, object_list)
1498
Chris Dentde456a12014-09-10 12:41:15 +01001499 def change_container_acl(self, container_name, acl):
Chris Dent0d494112014-08-26 13:48:30 +01001500 metadata_param = {'metadata_prefix': 'x-container-',
1501 'metadata': {'read': acl}}
1502 self.container_client.update_container_metadata(container_name,
1503 **metadata_param)
1504 resp, _ = self.container_client.list_container_metadata(container_name)
1505 self.assertEqual(resp['x-container-read'], acl)
1506
Chris Dentde456a12014-09-10 12:41:15 +01001507 def download_and_verify(self, container_name, obj_name, expected_data):
Chris Dent0d494112014-08-26 13:48:30 +01001508 _, obj = self.object_client.get_object(container_name, obj_name)
1509 self.assertEqual(obj, expected_data)