blob: 831be99f5f755a06d1e33526ba05193a39f8a645 [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:
Brant Knudson566c5712014-09-24 20:04:50 -0500405 console_output = self.servers_client.get_console_output(
Ken'ichi Ohmichibf4766a2015-12-09 07:48:43 +0000406 server['id'])['output']
David Kranzae99b9a2015-02-16 13:37:01 -0500407 LOG.debug('Console output for %s\nbody=\n%s',
408 server['id'], console_output)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100409
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000410 def _log_net_info(self, exc):
411 # network debug is called as part of ssh init
Andrey Pavlov64723762015-04-29 06:24:58 +0300412 if not isinstance(exc, lib_exc.SSHTimeout):
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000413 LOG.debug('Network information on a devstack host')
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000414
nithya-ganesan882595e2014-07-29 18:51:07 +0000415 def create_server_snapshot(self, server, name=None):
416 # Glance client
417 _image_client = self.image_client
418 # Compute client
Ghanshyamae76c122015-12-22 13:41:35 +0900419 _images_client = self.compute_images_client
nithya-ganesan882595e2014-07-29 18:51:07 +0000420 if name is None:
zhuflf9d95722016-10-19 16:06:17 +0800421 name = data_utils.rand_name(self.__class__.__name__ + 'snapshot')
nithya-ganesan882595e2014-07-29 18:51:07 +0000422 LOG.debug("Creating a snapshot image for server: %s", server['name'])
Ken'ichi Ohmichi28f18672015-07-17 10:00:38 +0000423 image = _images_client.create_image(server['id'], name=name)
David Kranza5299eb2015-01-15 17:24:05 -0500424 image_id = image.response['location'].split('images/')[1]
Yaroslav Lobankov2fea4052016-04-19 15:05:57 +0300425 waiters.wait_for_image_status(_image_client, image_id, 'active')
Jordan Pittierf672b7d2016-06-20 18:50:40 +0200426
427 self.addCleanup(_image_client.wait_for_resource_deletion,
428 image_id)
429 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
430 _image_client.delete_image, image_id)
431
Matt Riedemann2aa19d42016-06-06 17:45:41 -0400432 if CONF.image_feature_enabled.api_v1:
433 # In glance v1 the additional properties are stored in the headers.
Ken'ichi Ohmichi01151e82016-06-10 11:19:52 -0700434 resp = _image_client.check_image(image_id)
435 snapshot_image = common_image.get_image_meta_from_headers(resp)
Matt Riedemann2aa19d42016-06-06 17:45:41 -0400436 image_props = snapshot_image.get('properties', {})
437 else:
438 # In glance v2 the additional properties are flattened.
439 snapshot_image = _image_client.show_image(image_id)
440 image_props = snapshot_image
Andrey Pavlovc8bd4b12015-08-17 10:20:17 +0300441
Matt Riedemann2aa19d42016-06-06 17:45:41 -0400442 bdm = image_props.get('block_device_mapping')
Andrey Pavlovc8bd4b12015-08-17 10:20:17 +0300443 if bdm:
444 bdm = json.loads(bdm)
445 if bdm and 'snapshot_id' in bdm[0]:
446 snapshot_id = bdm[0]['snapshot_id']
447 self.addCleanup(
448 self.snapshots_client.wait_for_resource_deletion,
449 snapshot_id)
Jordan Pittier9e227c52016-02-09 14:35:18 +0100450 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
451 self.snapshots_client.delete_snapshot,
452 snapshot_id)
Yaroslav Lobankov667aaa22016-03-24 23:13:28 -0500453 waiters.wait_for_snapshot_status(self.snapshots_client,
454 snapshot_id, 'available')
nithya-ganesan882595e2014-07-29 18:51:07 +0000455 image_name = snapshot_image['name']
456 self.assertEqual(name, image_name)
457 LOG.debug("Created snapshot image %s for server %s",
458 image_name, server['name'])
459 return snapshot_image
460
Jordan Pittier7cf64762015-10-14 15:01:12 +0200461 def nova_volume_attach(self, server, volume_to_attach):
Joseph Lanoux6809bab2014-12-18 14:57:18 +0000462 volume = self.servers_client.attach_volume(
Jordan Pittier7cf64762015-10-14 15:01:12 +0200463 server['id'], volumeId=volume_to_attach['id'], device='/dev/%s'
ghanshyam0f825252015-08-25 16:02:50 +0900464 % CONF.compute.volume_device_name)['volumeAttachment']
Jordan Pittier7cf64762015-10-14 15:01:12 +0200465 self.assertEqual(volume_to_attach['id'], volume['id'])
Yaroslav Lobankoved3a35b2016-03-24 22:41:30 -0500466 waiters.wait_for_volume_status(self.volumes_client,
467 volume['id'], 'in-use')
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900468
Jordan Pittier7cf64762015-10-14 15:01:12 +0200469 # Return the updated volume after the attachment
470 return self.volumes_client.show_volume(volume['id'])['volume']
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900471
Jordan Pittier7cf64762015-10-14 15:01:12 +0200472 def nova_volume_detach(self, server, volume):
473 self.servers_client.detach_volume(server['id'], volume['id'])
Yaroslav Lobankoved3a35b2016-03-24 22:41:30 -0500474 waiters.wait_for_volume_status(self.volumes_client,
475 volume['id'], 'available')
Jordan Pittier7cf64762015-10-14 15:01:12 +0200476
477 volume = self.volumes_client.show_volume(volume['id'])['volume']
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900478 self.assertEqual('available', volume['status'])
479
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700480 def rebuild_server(self, server_id, image=None,
481 preserve_ephemeral=False, wait=True,
482 rebuild_kwargs=None):
483 if image is None:
484 image = CONF.compute.image_ref
485
486 rebuild_kwargs = rebuild_kwargs or {}
487
488 LOG.debug("Rebuilding server (id: %s, image: %s, preserve eph: %s)",
489 server_id, image, preserve_ephemeral)
Ken'ichi Ohmichi5271b0f2015-08-10 07:53:27 +0000490 self.servers_client.rebuild_server(
491 server_id=server_id, image_ref=image,
492 preserve_ephemeral=preserve_ephemeral,
493 **rebuild_kwargs)
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700494 if wait:
Ken'ichi Ohmichi0eb153c2015-07-13 02:18:25 +0000495 waiters.wait_for_server_status(self.servers_client,
496 server_id, 'ACTIVE')
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700497
Steven Hardyda2a8352014-10-02 12:52:20 +0100498 def ping_ip_address(self, ip_address, should_succeed=True,
Ihar Hrachyshkaf9227c02016-09-15 11:16:47 +0000499 ping_timeout=None, mtu=None):
lanoux5fc14522015-09-21 08:17:35 +0000500 timeout = ping_timeout or CONF.validation.ping_timeout
Ihar Hrachyshkaf9227c02016-09-15 11:16:47 +0000501 cmd = ['ping', '-c1', '-w1']
502
503 if mtu:
504 cmd += [
505 # don't fragment
506 '-M', 'do',
507 # ping receives just the size of ICMP payload
508 '-s', str(net_utils.get_ping_payload_size(mtu, 4))
509 ]
510 cmd.append(ip_address)
Aaron Rosena7df13b2014-09-23 09:45:45 -0700511
512 def ping():
513 proc = subprocess.Popen(cmd,
514 stdout=subprocess.PIPE,
515 stderr=subprocess.PIPE)
516 proc.communicate()
Shuquan Huang753629e2015-07-20 08:52:29 +0000517
Aaron Rosena7df13b2014-09-23 09:45:45 -0700518 return (proc.returncode == 0) == should_succeed
519
Jordan Pittier9e227c52016-02-09 14:35:18 +0100520 caller = test_utils.find_test_caller()
Shuquan Huang753629e2015-07-20 08:52:29 +0000521 LOG.debug('%(caller)s begins to ping %(ip)s in %(timeout)s sec and the'
522 ' expected result is %(should_succeed)s' % {
523 'caller': caller, 'ip': ip_address, 'timeout': timeout,
524 'should_succeed':
525 'reachable' if should_succeed else 'unreachable'
526 })
Jordan Pittier35a63752016-08-30 13:09:12 +0200527 result = test_utils.call_until_true(ping, timeout, 1)
Shuquan Huang753629e2015-07-20 08:52:29 +0000528 LOG.debug('%(caller)s finishes ping %(ip)s in %(timeout)s sec and the '
529 'ping result is %(result)s' % {
530 'caller': caller, 'ip': ip_address, 'timeout': timeout,
531 'result': 'expected' if result else 'unexpected'
532 })
533 return result
Aaron Rosena7df13b2014-09-23 09:45:45 -0700534
Yair Friedae0e73d2014-11-24 11:56:26 +0200535 def check_vm_connectivity(self, ip_address,
536 username=None,
537 private_key=None,
Ihar Hrachyshkaf9227c02016-09-15 11:16:47 +0000538 should_connect=True,
539 mtu=None):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000540 """Check server connectivity
541
Yair Friedae0e73d2014-11-24 11:56:26 +0200542 :param ip_address: server to test against
543 :param username: server's ssh username
544 :param private_key: server's ssh private key to be used
545 :param should_connect: True/False indicates positive/negative test
546 positive - attempt ping and ssh
547 negative - attempt ping and fail if succeed
Ihar Hrachyshkaf9227c02016-09-15 11:16:47 +0000548 :param mtu: network MTU to use for connectivity validation
Yair Friedae0e73d2014-11-24 11:56:26 +0200549
550 :raises: AssertError if the result of the connectivity check does
551 not match the value of the should_connect param
552 """
553 if should_connect:
554 msg = "Timed out waiting for %s to become reachable" % ip_address
555 else:
556 msg = "ip address %s is reachable" % ip_address
557 self.assertTrue(self.ping_ip_address(ip_address,
Ihar Hrachyshkaf9227c02016-09-15 11:16:47 +0000558 should_succeed=should_connect,
559 mtu=mtu),
Yair Friedae0e73d2014-11-24 11:56:26 +0200560 msg=msg)
561 if should_connect:
562 # no need to check ssh for negative connectivity
563 self.get_remote_client(ip_address, username, private_key)
564
565 def check_public_network_connectivity(self, ip_address, username,
566 private_key, should_connect=True,
Ihar Hrachyshkaf9227c02016-09-15 11:16:47 +0000567 msg=None, servers=None, mtu=None):
Yair Friedae0e73d2014-11-24 11:56:26 +0200568 # The target login is assumed to have been configured for
569 # key-based authentication by cloud-init.
570 LOG.debug('checking network connections to IP %s with user: %s' %
571 (ip_address, username))
572 try:
573 self.check_vm_connectivity(ip_address,
574 username,
575 private_key,
Ihar Hrachyshkaf9227c02016-09-15 11:16:47 +0000576 should_connect=should_connect,
577 mtu=mtu)
Matthew Treinish53483132014-12-09 18:50:06 -0500578 except Exception:
Yair Friedae0e73d2014-11-24 11:56:26 +0200579 ex_msg = 'Public network connectivity check failed'
580 if msg:
581 ex_msg += ": " + msg
582 LOG.exception(ex_msg)
583 self._log_console_output(servers)
Yair Friedae0e73d2014-11-24 11:56:26 +0200584 raise
585
586 def create_floating_ip(self, thing, pool_name=None):
Ken'ichi Ohmichia112a592015-11-17 08:49:37 +0000587 """Create a floating IP and associates to a server on Nova"""
Yair Friedae0e73d2014-11-24 11:56:26 +0200588
Marc Koderer3b57d802016-03-22 15:23:31 +0100589 if not pool_name:
590 pool_name = CONF.network.floating_network_name
John Warrene74890a2015-11-11 15:18:01 -0500591 floating_ip = (self.compute_floating_ips_client.
Ken'ichi Ohmichie037a6f2015-12-03 06:41:49 +0000592 create_floating_ip(pool=pool_name)['floating_ip'])
Jordan Pittier9e227c52016-02-09 14:35:18 +0100593 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
John Warrene74890a2015-11-11 15:18:01 -0500594 self.compute_floating_ips_client.delete_floating_ip,
Yair Friedae0e73d2014-11-24 11:56:26 +0200595 floating_ip['id'])
John Warrene74890a2015-11-11 15:18:01 -0500596 self.compute_floating_ips_client.associate_floating_ip_to_server(
Yair Friedae0e73d2014-11-24 11:56:26 +0200597 floating_ip['ip'], thing['id'])
598 return floating_ip
599
Sean Dague20e98612016-01-06 14:33:28 -0500600 def create_timestamp(self, ip_address, dev_name=None, mount_path='/mnt',
Matt Riedemannfd5657d2015-09-30 14:47:07 -0700601 private_key=None):
Sean Dague20e98612016-01-06 14:33:28 -0500602 ssh_client = self.get_remote_client(ip_address,
Matt Riedemannfd5657d2015-09-30 14:47:07 -0700603 private_key=private_key)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300604 if dev_name is not None:
605 ssh_client.make_fs(dev_name)
Matt Riedemann076685a2015-09-30 14:38:16 -0700606 ssh_client.mount(dev_name, mount_path)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300607 cmd_timestamp = 'sudo sh -c "date > %s/timestamp; sync"' % mount_path
608 ssh_client.exec_command(cmd_timestamp)
609 timestamp = ssh_client.exec_command('sudo cat %s/timestamp'
610 % mount_path)
611 if dev_name is not None:
612 ssh_client.umount(mount_path)
613 return timestamp
614
Sean Dague20e98612016-01-06 14:33:28 -0500615 def get_timestamp(self, ip_address, dev_name=None, mount_path='/mnt',
Matt Riedemannfd5657d2015-09-30 14:47:07 -0700616 private_key=None):
Sean Dague20e98612016-01-06 14:33:28 -0500617 ssh_client = self.get_remote_client(ip_address,
Matt Riedemannfd5657d2015-09-30 14:47:07 -0700618 private_key=private_key)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300619 if dev_name is not None:
Matt Riedemann076685a2015-09-30 14:38:16 -0700620 ssh_client.mount(dev_name, mount_path)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300621 timestamp = ssh_client.exec_command('sudo cat %s/timestamp'
622 % mount_path)
623 if dev_name is not None:
624 ssh_client.umount(mount_path)
625 return timestamp
626
Sean Dague20e98612016-01-06 14:33:28 -0500627 def get_server_ip(self, server):
628 """Get the server fixed or floating IP.
629
630 Based on the configuration we're in, return a correct ip
631 address for validating that a guest is up.
632 """
Alexander Gubanovc8829f82015-11-12 10:35:13 +0200633 if CONF.validation.connect_method == 'floating':
Sean Dague20e98612016-01-06 14:33:28 -0500634 # The tests calling this method don't have a floating IP
zhufl0892cb22016-05-06 14:46:00 +0800635 # and can't make use of the validation resources. So the
Sean Dague20e98612016-01-06 14:33:28 -0500636 # method is creating the floating IP there.
637 return self.create_floating_ip(server)['ip']
638 elif CONF.validation.connect_method == 'fixed':
Matt Riedemanna7782552016-08-08 16:26:01 -0400639 # Determine the network name to look for based on config or creds
640 # provider network resources.
641 if CONF.validation.network_for_ssh:
642 addresses = server['addresses'][
643 CONF.validation.network_for_ssh]
644 else:
645 creds_provider = self._get_credentials_provider()
646 net_creds = creds_provider.get_primary_creds()
647 network = getattr(net_creds, 'network', None)
648 addresses = (server['addresses'][network['name']]
649 if network else [])
Sean Dague20e98612016-01-06 14:33:28 -0500650 for address in addresses:
Matt Riedemanna7782552016-08-08 16:26:01 -0400651 if (address['version'] == CONF.validation.ip_version_for_ssh
652 and address['OS-EXT-IPS:type'] == 'fixed'):
Sean Dague20e98612016-01-06 14:33:28 -0500653 return address['addr']
zhufl955f82b2016-07-22 11:14:34 +0800654 raise exceptions.ServerUnreachable(server_id=server['id'])
Alexander Gubanovc8829f82015-11-12 10:35:13 +0200655 else:
Matthew Treinish4217a702016-10-07 17:27:11 -0400656 raise lib_exc.InvalidConfiguration()
Alexander Gubanovc8829f82015-11-12 10:35:13 +0200657
Andrea Frittoli2e733b52014-07-16 14:12:11 +0100658
Andrea Frittoli4971fc82014-09-25 10:22:20 +0100659class NetworkScenarioTest(ScenarioTest):
Yair Fried1fc32a12014-08-04 09:11:30 +0300660 """Base class for network scenario tests.
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000661
Yair Fried1fc32a12014-08-04 09:11:30 +0300662 This class provide helpers for network scenario tests, using the neutron
663 API. Helpers from ancestor which use the nova network API are overridden
664 with the neutron API.
665
666 This Class also enforces using Neutron instead of novanetwork.
667 Subclassed tests will be skipped if Neutron is not enabled
668
669 """
670
Andrea Frittolib21de6c2015-02-06 20:12:38 +0000671 credentials = ['primary', 'admin']
672
Yair Fried1fc32a12014-08-04 09:11:30 +0300673 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +0000674 def skip_checks(cls):
675 super(NetworkScenarioTest, cls).skip_checks()
Andrea Frittoli2ddc2632014-09-25 11:03:00 +0100676 if not CONF.service_available.neutron:
677 raise cls.skipException('Neutron not available')
Yair Fried1fc32a12014-08-04 09:11:30 +0300678
679 @classmethod
Andrea Frittoliac20b5e2014-09-15 13:31:14 +0100680 def resource_setup(cls):
681 super(NetworkScenarioTest, cls).resource_setup()
Yair Fried1fc32a12014-08-04 09:11:30 +0300682 cls.tenant_id = cls.manager.identity_client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300683
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -0700684 def _create_network(self, networks_client=None,
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000685 routers_client=None, tenant_id=None,
Markus Zoeller156b5da2016-07-11 18:10:31 +0200686 namestart='network-smoke-',
687 port_security_enabled=True):
John Warren94d8faf2015-09-15 12:22:24 -0400688 if not networks_client:
689 networks_client = self.networks_client
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000690 if not routers_client:
691 routers_client = self.routers_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300692 if not tenant_id:
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -0700693 tenant_id = networks_client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300694 name = data_utils.rand_name(namestart)
Matt Riedemann039b2fe2016-09-15 16:12:24 -0400695 network_kwargs = dict(name=name, tenant_id=tenant_id)
696 # Neutron disables port security by default so we have to check the
697 # config before trying to create the network with port_security_enabled
698 if CONF.network_feature_enabled.port_security:
699 network_kwargs['port_security_enabled'] = port_security_enabled
Markus Zoeller156b5da2016-07-11 18:10:31 +0200700 result = networks_client.create_network(**network_kwargs)
Steve Heyman33735f22016-05-24 09:28:08 -0500701 network = result['network']
702
703 self.assertEqual(network['name'], name)
Jordan Pittier9e227c52016-02-09 14:35:18 +0100704 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
Steve Heyman33735f22016-05-24 09:28:08 -0500705 self.networks_client.delete_network,
706 network['id'])
Yair Fried1fc32a12014-08-04 09:11:30 +0300707 return network
708
709 def _list_networks(self, *args, **kwargs):
710 """List networks using admin creds """
John Warren94d8faf2015-09-15 12:22:24 -0400711 networks_list = self.admin_manager.networks_client.list_networks(
ghanshyam2f7cc022015-06-26 18:18:11 +0900712 *args, **kwargs)
713 return networks_list['networks']
Yair Fried1fc32a12014-08-04 09:11:30 +0300714
715 def _list_subnets(self, *args, **kwargs):
716 """List subnets using admin creds """
John Warren3961acd2015-10-02 14:38:53 -0400717 subnets_list = self.admin_manager.subnets_client.list_subnets(
ghanshyam2f7cc022015-06-26 18:18:11 +0900718 *args, **kwargs)
719 return subnets_list['subnets']
Yair Fried1fc32a12014-08-04 09:11:30 +0300720
721 def _list_routers(self, *args, **kwargs):
722 """List routers using admin creds """
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000723 routers_list = self.admin_manager.routers_client.list_routers(
ghanshyam2f7cc022015-06-26 18:18:11 +0900724 *args, **kwargs)
725 return routers_list['routers']
Yair Fried1fc32a12014-08-04 09:11:30 +0300726
727 def _list_ports(self, *args, **kwargs):
728 """List ports using admin creds """
John Warren49c0fe52015-10-22 12:35:54 -0400729 ports_list = self.admin_manager.ports_client.list_ports(
ghanshyam2f7cc022015-06-26 18:18:11 +0900730 *args, **kwargs)
731 return ports_list['ports']
Yair Fried1fc32a12014-08-04 09:11:30 +0300732
Yair Fried564d89d2015-08-06 17:02:12 +0300733 def _list_agents(self, *args, **kwargs):
734 """List agents using admin creds """
Ken'ichi Ohmichi71860062015-12-15 08:20:13 +0000735 agents_list = self.admin_manager.network_agents_client.list_agents(
Yair Fried564d89d2015-08-06 17:02:12 +0300736 *args, **kwargs)
737 return agents_list['agents']
738
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -0700739 def _create_subnet(self, network, subnets_client=None,
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000740 routers_client=None, namestart='subnet-smoke',
741 **kwargs):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000742 """Create a subnet for the given network
743
744 within the cidr block configured for tenant networks.
Yair Fried1fc32a12014-08-04 09:11:30 +0300745 """
John Warren3961acd2015-10-02 14:38:53 -0400746 if not subnets_client:
747 subnets_client = self.subnets_client
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000748 if not routers_client:
749 routers_client = self.routers_client
Yair Fried1fc32a12014-08-04 09:11:30 +0300750
751 def cidr_in_use(cidr, tenant_id):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000752 """Check cidr existence
753
lei zhangdd552b22015-11-25 20:41:48 +0800754 :returns: True if subnet with cidr already exist in tenant
755 False else
Yair Fried1fc32a12014-08-04 09:11:30 +0300756 """
757 cidr_in_use = self._list_subnets(tenant_id=tenant_id, cidr=cidr)
758 return len(cidr_in_use) != 0
759
Kirill Shileev14113572014-11-21 16:58:02 +0300760 ip_version = kwargs.pop('ip_version', 4)
761
762 if ip_version == 6:
763 tenant_cidr = netaddr.IPNetwork(
Sean Dagueed6e5862016-04-04 10:49:13 -0400764 CONF.network.project_network_v6_cidr)
765 num_bits = CONF.network.project_network_v6_mask_bits
Kirill Shileev14113572014-11-21 16:58:02 +0300766 else:
Sean Dagueed6e5862016-04-04 10:49:13 -0400767 tenant_cidr = netaddr.IPNetwork(CONF.network.project_network_cidr)
768 num_bits = CONF.network.project_network_mask_bits
Kirill Shileev14113572014-11-21 16:58:02 +0300769
Yair Fried1fc32a12014-08-04 09:11:30 +0300770 result = None
Kirill Shileev14113572014-11-21 16:58:02 +0300771 str_cidr = None
Yair Fried1fc32a12014-08-04 09:11:30 +0300772 # Repeatedly attempt subnet creation with sequential cidr
773 # blocks until an unallocated block is found.
Kirill Shileev14113572014-11-21 16:58:02 +0300774 for subnet_cidr in tenant_cidr.subnet(num_bits):
Yair Fried1fc32a12014-08-04 09:11:30 +0300775 str_cidr = str(subnet_cidr)
Steve Heyman33735f22016-05-24 09:28:08 -0500776 if cidr_in_use(str_cidr, tenant_id=network['tenant_id']):
Yair Fried1fc32a12014-08-04 09:11:30 +0300777 continue
778
779 subnet = dict(
780 name=data_utils.rand_name(namestart),
Steve Heyman33735f22016-05-24 09:28:08 -0500781 network_id=network['id'],
782 tenant_id=network['tenant_id'],
Yair Fried1fc32a12014-08-04 09:11:30 +0300783 cidr=str_cidr,
Kirill Shileev14113572014-11-21 16:58:02 +0300784 ip_version=ip_version,
Yair Fried1fc32a12014-08-04 09:11:30 +0300785 **kwargs
786 )
787 try:
John Warren3961acd2015-10-02 14:38:53 -0400788 result = subnets_client.create_subnet(**subnet)
Yair Fried1fc32a12014-08-04 09:11:30 +0300789 break
Masayuki Igawad9388762015-01-20 14:56:42 +0900790 except lib_exc.Conflict as e:
Yair Fried1fc32a12014-08-04 09:11:30 +0300791 is_overlapping_cidr = 'overlaps with another subnet' in str(e)
792 if not is_overlapping_cidr:
793 raise
794 self.assertIsNotNone(result, 'Unable to allocate tenant network')
Steve Heyman33735f22016-05-24 09:28:08 -0500795
796 subnet = result['subnet']
797 self.assertEqual(subnet['cidr'], str_cidr)
798
799 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
800 subnets_client.delete_subnet, subnet['id'])
801
Yair Fried1fc32a12014-08-04 09:11:30 +0300802 return subnet
803
Kirill Shileev14113572014-11-21 16:58:02 +0300804 def _get_server_port_id_and_ip4(self, server, ip_addr=None):
Kevin Benton1d0c1dc2016-02-04 14:30:08 -0800805 ports = self._list_ports(device_id=server['id'], fixed_ip=ip_addr)
Kobi Samoray166500a2016-10-09 14:42:48 +0300806 # A port can have more than one IP address in some cases.
Sean M. Collins2e896832015-12-15 13:58:47 -0500807 # If the network is dual-stack (IPv4 + IPv6), this port is associated
808 # with 2 subnets
Vasyl Saienko8fd517c2016-05-30 09:52:54 +0300809 p_status = ['ACTIVE']
810 # NOTE(vsaienko) With Ironic, instances live on separate hardware
811 # servers. Neutron does not bind ports for Ironic instances, as a
812 # result the port remains in the DOWN state.
Vasyl Saienkoc8aa34b2016-08-01 14:18:37 +0300813 # TODO(vsaienko) remove once bug: #1599836 is resolved.
Vasyl Saienko8fd517c2016-05-30 09:52:54 +0300814 if CONF.service_available.ironic:
815 p_status.append('DOWN')
Daniel Mellado9e3e1062015-08-06 18:07:05 +0200816 port_map = [(p["id"], fxip["ip_address"])
817 for p in ports
818 for fxip in p["fixed_ips"]
Yatin Kumbhareee4924c2016-06-09 15:12:06 +0530819 if netutils.is_valid_ipv4(fxip["ip_address"])
Vasyl Saienko8fd517c2016-05-30 09:52:54 +0300820 and p['status'] in p_status]
Kevin Benton1d0c1dc2016-02-04 14:30:08 -0800821 inactive = [p for p in ports if p['status'] != 'ACTIVE']
822 if inactive:
823 LOG.warning("Instance has ports that are not ACTIVE: %s", inactive)
Daniel Mellado9e3e1062015-08-06 18:07:05 +0200824
John L. Villalovosb83286f2015-11-04 14:46:57 -0800825 self.assertNotEqual(0, len(port_map),
826 "No IPv4 addresses found in: %s" % ports)
Daniel Mellado9e3e1062015-08-06 18:07:05 +0200827 self.assertEqual(len(port_map), 1,
828 "Found multiple IPv4 addresses: %s. "
829 "Unable to determine which port to target."
830 % port_map)
831 return port_map[0]
Yair Fried1fc32a12014-08-04 09:11:30 +0300832
David Shrewsbury9bac3662014-08-07 15:07:01 -0400833 def _get_network_by_name(self, network_name):
834 net = self._list_networks(name=network_name)
Adam Gandelman878a5fd2015-03-30 14:33:36 -0700835 self.assertNotEqual(len(net), 0,
836 "Unable to get network by name: %s" % network_name)
Steve Heyman33735f22016-05-24 09:28:08 -0500837 return net[0]
David Shrewsbury9bac3662014-08-07 15:07:01 -0400838
Yair Friedae0e73d2014-11-24 11:56:26 +0200839 def create_floating_ip(self, thing, external_network_id=None,
840 port_id=None, client=None):
Ken'ichi Ohmichia112a592015-11-17 08:49:37 +0000841 """Create a floating IP and associates to a resource/port on Neutron"""
Yair Friedae0e73d2014-11-24 11:56:26 +0200842 if not external_network_id:
843 external_network_id = CONF.network.public_network_id
Yair Frieddb6c9e92014-08-06 08:53:13 +0300844 if not client:
John Warrenfbf2a892015-11-17 12:36:14 -0500845 client = self.floating_ips_client
Yair Fried1fc32a12014-08-04 09:11:30 +0300846 if not port_id:
Kirill Shileev14113572014-11-21 16:58:02 +0300847 port_id, ip4 = self._get_server_port_id_and_ip4(thing)
848 else:
849 ip4 = None
David Kranz34e88122014-12-11 15:24:05 -0500850 result = client.create_floatingip(
Yair Fried1fc32a12014-08-04 09:11:30 +0300851 floating_network_id=external_network_id,
852 port_id=port_id,
Kirill Shileev14113572014-11-21 16:58:02 +0300853 tenant_id=thing['tenant_id'],
854 fixed_ip_address=ip4
Yair Fried1fc32a12014-08-04 09:11:30 +0300855 )
Steve Heyman33735f22016-05-24 09:28:08 -0500856 floating_ip = result['floatingip']
Jordan Pittier9e227c52016-02-09 14:35:18 +0100857 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
Steve Heyman33735f22016-05-24 09:28:08 -0500858 self.floating_ips_client.delete_floatingip,
859 floating_ip['id'])
Yair Fried1fc32a12014-08-04 09:11:30 +0300860 return floating_ip
861
862 def _associate_floating_ip(self, floating_ip, server):
Kirill Shileev14113572014-11-21 16:58:02 +0300863 port_id, _ = self._get_server_port_id_and_ip4(server)
Steve Heyman33735f22016-05-24 09:28:08 -0500864 kwargs = dict(port_id=port_id)
865 floating_ip = self.floating_ips_client.update_floatingip(
866 floating_ip['id'], **kwargs)['floatingip']
867 self.assertEqual(port_id, floating_ip['port_id'])
Yair Fried1fc32a12014-08-04 09:11:30 +0300868 return floating_ip
869
870 def _disassociate_floating_ip(self, floating_ip):
Steve Heyman33735f22016-05-24 09:28:08 -0500871 """:param floating_ip: floating_ips_client.create_floatingip"""
872 kwargs = dict(port_id=None)
873 floating_ip = self.floating_ips_client.update_floatingip(
874 floating_ip['id'], **kwargs)['floatingip']
875 self.assertIsNone(floating_ip['port_id'])
Yair Fried1fc32a12014-08-04 09:11:30 +0300876 return floating_ip
877
Yair Fried45f92952014-06-26 05:19:19 +0300878 def check_floating_ip_status(self, floating_ip, status):
Carl Baldwina754e2d2014-10-23 22:47:41 +0000879 """Verifies floatingip reaches the given status
Yair Fried45f92952014-06-26 05:19:19 +0300880
Steve Heyman33735f22016-05-24 09:28:08 -0500881 :param dict floating_ip: floating IP dict to check status
Yair Fried45f92952014-06-26 05:19:19 +0300882 :param status: target status
883 :raises: AssertionError if status doesn't match
884 """
Steve Heyman33735f22016-05-24 09:28:08 -0500885 floatingip_id = floating_ip['id']
886
Carl Baldwina754e2d2014-10-23 22:47:41 +0000887 def refresh():
Steve Heyman33735f22016-05-24 09:28:08 -0500888 result = (self.floating_ips_client.
889 show_floatingip(floatingip_id)['floatingip'])
890 return status == result['status']
Carl Baldwina754e2d2014-10-23 22:47:41 +0000891
Jordan Pittier35a63752016-08-30 13:09:12 +0200892 test_utils.call_until_true(refresh,
893 CONF.network.build_timeout,
894 CONF.network.build_interval)
Steve Heyman33735f22016-05-24 09:28:08 -0500895 floating_ip = self.floating_ips_client.show_floatingip(
896 floatingip_id)['floatingip']
897 self.assertEqual(status, floating_ip['status'],
Yair Fried45f92952014-06-26 05:19:19 +0300898 message="FloatingIP: {fp} is at status: {cst}. "
899 "failed to reach status: {st}"
Steve Heyman33735f22016-05-24 09:28:08 -0500900 .format(fp=floating_ip, cst=floating_ip['status'],
Yair Fried45f92952014-06-26 05:19:19 +0300901 st=status))
902 LOG.info("FloatingIP: {fp} is at status: {st}"
903 .format(fp=floating_ip, st=status))
904
Yair Fried1fc32a12014-08-04 09:11:30 +0300905 def _check_tenant_network_connectivity(self, server,
906 username,
907 private_key,
908 should_connect=True,
909 servers_for_debug=None):
Sean Dagueed6e5862016-04-04 10:49:13 -0400910 if not CONF.network.project_networks_reachable:
Yair Fried1fc32a12014-08-04 09:11:30 +0300911 msg = 'Tenant networks not configured to be reachable.'
912 LOG.info(msg)
913 return
914 # The target login is assumed to have been configured for
915 # key-based authentication by cloud-init.
916 try:
Matthew Treinish71426682015-04-23 11:19:38 -0400917 for net_name, ip_addresses in six.iteritems(server['addresses']):
Yair Fried1fc32a12014-08-04 09:11:30 +0300918 for ip_address in ip_addresses:
ghanshyam807211c2014-12-18 13:21:22 +0900919 self.check_vm_connectivity(ip_address['addr'],
Yair Friedae0e73d2014-11-24 11:56:26 +0200920 username,
921 private_key,
922 should_connect=should_connect)
Yair Fried1fc32a12014-08-04 09:11:30 +0300923 except Exception as e:
924 LOG.exception('Tenant network connectivity check failed')
925 self._log_console_output(servers_for_debug)
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000926 self._log_net_info(e)
Yair Fried1fc32a12014-08-04 09:11:30 +0300927 raise
928
Yair Friedbc46f592015-11-18 16:29:34 +0200929 def _check_remote_connectivity(self, source, dest, should_succeed=True,
930 nic=None):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000931 """check ping server via source ssh connection
Yair Fried1fc32a12014-08-04 09:11:30 +0300932
933 :param source: RemoteClient: an ssh connection from which to ping
934 :param dest: and IP to ping against
935 :param should_succeed: boolean should ping succeed or not
Yair Friedbc46f592015-11-18 16:29:34 +0200936 :param nic: specific network interface to ping from
Yair Fried1fc32a12014-08-04 09:11:30 +0300937 :returns: boolean -- should_succeed == ping
938 :returns: ping is false if ping failed
939 """
940 def ping_remote():
941 try:
Yair Friedbc46f592015-11-18 16:29:34 +0200942 source.ping_host(dest, nic=nic)
Andrey Pavlov64723762015-04-29 06:24:58 +0300943 except lib_exc.SSHExecCommandFailed:
zhangguoqing6c096642016-01-04 06:17:21 +0000944 LOG.warning('Failed to ping IP: %s via a ssh connection '
945 'from: %s.' % (dest, source.ssh_client.host))
Yair Fried1fc32a12014-08-04 09:11:30 +0300946 return not should_succeed
947 return should_succeed
948
Jordan Pittier35a63752016-08-30 13:09:12 +0200949 return test_utils.call_until_true(ping_remote,
950 CONF.validation.ping_timeout,
951 1)
Yair Fried1fc32a12014-08-04 09:11:30 +0300952
John Warren456d9ae2016-01-12 15:36:33 -0500953 def _create_security_group(self, security_group_rules_client=None,
954 tenant_id=None,
John Warrenf9606e92015-12-10 12:12:42 -0500955 namestart='secgroup-smoke',
956 security_groups_client=None):
John Warren456d9ae2016-01-12 15:36:33 -0500957 if security_group_rules_client is None:
958 security_group_rules_client = self.security_group_rules_client
John Warrenf9606e92015-12-10 12:12:42 -0500959 if security_groups_client is None:
960 security_groups_client = self.security_groups_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300961 if tenant_id is None:
John Warrenf9606e92015-12-10 12:12:42 -0500962 tenant_id = security_groups_client.tenant_id
963 secgroup = self._create_empty_security_group(
964 namestart=namestart, client=security_groups_client,
965 tenant_id=tenant_id)
Yair Fried1fc32a12014-08-04 09:11:30 +0300966
967 # Add rules to the security group
John Warrenf9606e92015-12-10 12:12:42 -0500968 rules = self._create_loginable_secgroup_rule(
John Warren456d9ae2016-01-12 15:36:33 -0500969 security_group_rules_client=security_group_rules_client,
970 secgroup=secgroup,
John Warrenf9606e92015-12-10 12:12:42 -0500971 security_groups_client=security_groups_client)
Yair Fried1fc32a12014-08-04 09:11:30 +0300972 for rule in rules:
Steve Heyman33735f22016-05-24 09:28:08 -0500973 self.assertEqual(tenant_id, rule['tenant_id'])
974 self.assertEqual(secgroup['id'], rule['security_group_id'])
Yair Fried1fc32a12014-08-04 09:11:30 +0300975 return secgroup
976
Yair Frieddb6c9e92014-08-06 08:53:13 +0300977 def _create_empty_security_group(self, client=None, tenant_id=None,
Yair Fried1fc32a12014-08-04 09:11:30 +0300978 namestart='secgroup-smoke'):
979 """Create a security group without rules.
980
981 Default rules will be created:
982 - IPv4 egress to any
983 - IPv6 egress to any
984
985 :param tenant_id: secgroup will be created in this tenant
Steve Heyman33735f22016-05-24 09:28:08 -0500986 :returns: the created security group
Yair Fried1fc32a12014-08-04 09:11:30 +0300987 """
988 if client is None:
John Warrenf9606e92015-12-10 12:12:42 -0500989 client = self.security_groups_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300990 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000991 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300992 sg_name = data_utils.rand_name(namestart)
993 sg_desc = sg_name + " description"
994 sg_dict = dict(name=sg_name,
995 description=sg_desc)
996 sg_dict['tenant_id'] = tenant_id
David Kranz34e88122014-12-11 15:24:05 -0500997 result = client.create_security_group(**sg_dict)
Steve Heyman33735f22016-05-24 09:28:08 -0500998
999 secgroup = result['security_group']
1000 self.assertEqual(secgroup['name'], sg_name)
1001 self.assertEqual(tenant_id, secgroup['tenant_id'])
1002 self.assertEqual(secgroup['description'], sg_desc)
1003
Jordan Pittier9e227c52016-02-09 14:35:18 +01001004 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
Steve Heyman33735f22016-05-24 09:28:08 -05001005 client.delete_security_group, secgroup['id'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001006 return secgroup
1007
Yair Frieddb6c9e92014-08-06 08:53:13 +03001008 def _default_security_group(self, client=None, tenant_id=None):
Yair Fried1fc32a12014-08-04 09:11:30 +03001009 """Get default secgroup for given tenant_id.
1010
Ken'ichi Ohmichid67c8da2016-09-13 16:18:11 -07001011 :returns: default secgroup for given tenant
Yair Fried1fc32a12014-08-04 09:11:30 +03001012 """
1013 if client is None:
John Warrenf9606e92015-12-10 12:12:42 -05001014 client = self.security_groups_client
Yair Frieddb6c9e92014-08-06 08:53:13 +03001015 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +00001016 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001017 sgs = [
Jordan Pittier8ad86172016-04-25 16:20:53 +02001018 sg for sg in list(client.list_security_groups().values())[0]
Yair Fried1fc32a12014-08-04 09:11:30 +03001019 if sg['tenant_id'] == tenant_id and sg['name'] == 'default'
1020 ]
1021 msg = "No default security group for tenant %s." % (tenant_id)
1022 self.assertTrue(len(sgs) > 0, msg)
Steve Heyman33735f22016-05-24 09:28:08 -05001023 return sgs[0]
Yair Fried1fc32a12014-08-04 09:11:30 +03001024
John Warren456d9ae2016-01-12 15:36:33 -05001025 def _create_security_group_rule(self, secgroup=None,
1026 sec_group_rules_client=None,
John Warrenf9606e92015-12-10 12:12:42 -05001027 tenant_id=None,
1028 security_groups_client=None, **kwargs):
Yair Fried1fc32a12014-08-04 09:11:30 +03001029 """Create a rule from a dictionary of rule parameters.
1030
1031 Create a rule in a secgroup. if secgroup not defined will search for
1032 default secgroup in tenant_id.
1033
Steve Heyman33735f22016-05-24 09:28:08 -05001034 :param secgroup: the security group.
Yair Fried1fc32a12014-08-04 09:11:30 +03001035 :param tenant_id: if secgroup not passed -- the tenant in which to
1036 search for default secgroup
1037 :param kwargs: a dictionary containing rule parameters:
1038 for example, to allow incoming ssh:
1039 rule = {
1040 direction: 'ingress'
1041 protocol:'tcp',
1042 port_range_min: 22,
1043 port_range_max: 22
1044 }
1045 """
John Warren456d9ae2016-01-12 15:36:33 -05001046 if sec_group_rules_client is None:
1047 sec_group_rules_client = self.security_group_rules_client
John Warrenf9606e92015-12-10 12:12:42 -05001048 if security_groups_client is None:
1049 security_groups_client = self.security_groups_client
Yair Frieddb6c9e92014-08-06 08:53:13 +03001050 if not tenant_id:
John Warrenf9606e92015-12-10 12:12:42 -05001051 tenant_id = security_groups_client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001052 if secgroup is None:
John Warrenf9606e92015-12-10 12:12:42 -05001053 secgroup = self._default_security_group(
1054 client=security_groups_client, tenant_id=tenant_id)
Yair Fried1fc32a12014-08-04 09:11:30 +03001055
Steve Heyman33735f22016-05-24 09:28:08 -05001056 ruleset = dict(security_group_id=secgroup['id'],
1057 tenant_id=secgroup['tenant_id'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001058 ruleset.update(kwargs)
1059
John Warren456d9ae2016-01-12 15:36:33 -05001060 sg_rule = sec_group_rules_client.create_security_group_rule(**ruleset)
Steve Heyman33735f22016-05-24 09:28:08 -05001061 sg_rule = sg_rule['security_group_rule']
1062
1063 self.assertEqual(secgroup['tenant_id'], sg_rule['tenant_id'])
1064 self.assertEqual(secgroup['id'], sg_rule['security_group_id'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001065
1066 return sg_rule
1067
John Warren456d9ae2016-01-12 15:36:33 -05001068 def _create_loginable_secgroup_rule(self, security_group_rules_client=None,
1069 secgroup=None,
John Warrenf9606e92015-12-10 12:12:42 -05001070 security_groups_client=None):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001071 """Create loginable security group rule
1072
Alex Stafeyevdd5dde92016-05-08 14:35:04 +03001073 This function will create:
1074 1. egress and ingress tcp port 22 allow rule in order to allow ssh
1075 access for ipv4.
1076 2. egress and ingress ipv6 icmp allow rule, in order to allow icmpv6.
1077 3. egress and ingress ipv4 icmp allow rule, in order to allow icmpv4.
Yair Fried1fc32a12014-08-04 09:11:30 +03001078 """
1079
John Warren456d9ae2016-01-12 15:36:33 -05001080 if security_group_rules_client is None:
1081 security_group_rules_client = self.security_group_rules_client
John Warrenf9606e92015-12-10 12:12:42 -05001082 if security_groups_client is None:
1083 security_groups_client = self.security_groups_client
Yair Fried1fc32a12014-08-04 09:11:30 +03001084 rules = []
1085 rulesets = [
1086 dict(
1087 # ssh
1088 protocol='tcp',
1089 port_range_min=22,
1090 port_range_max=22,
1091 ),
1092 dict(
1093 # ping
1094 protocol='icmp',
Andreas Scheuring887ca8e2015-02-03 17:56:12 +01001095 ),
1096 dict(
1097 # ipv6-icmp for ping6
1098 protocol='icmp',
1099 ethertype='IPv6',
Yair Fried1fc32a12014-08-04 09:11:30 +03001100 )
1101 ]
John Warren456d9ae2016-01-12 15:36:33 -05001102 sec_group_rules_client = security_group_rules_client
Yair Fried1fc32a12014-08-04 09:11:30 +03001103 for ruleset in rulesets:
1104 for r_direction in ['ingress', 'egress']:
1105 ruleset['direction'] = r_direction
1106 try:
1107 sg_rule = self._create_security_group_rule(
John Warren456d9ae2016-01-12 15:36:33 -05001108 sec_group_rules_client=sec_group_rules_client,
1109 secgroup=secgroup,
John Warrenf9606e92015-12-10 12:12:42 -05001110 security_groups_client=security_groups_client,
1111 **ruleset)
Masayuki Igawad9388762015-01-20 14:56:42 +09001112 except lib_exc.Conflict as ex:
Yair Fried1fc32a12014-08-04 09:11:30 +03001113 # if rule already exist - skip rule and continue
1114 msg = 'Security group rule already exists'
1115 if msg not in ex._error_string:
1116 raise ex
1117 else:
Steve Heyman33735f22016-05-24 09:28:08 -05001118 self.assertEqual(r_direction, sg_rule['direction'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001119 rules.append(sg_rule)
1120
1121 return rules
1122
Yair Frieddb6c9e92014-08-06 08:53:13 +03001123 def _get_router(self, client=None, tenant_id=None):
Yair Fried1fc32a12014-08-04 09:11:30 +03001124 """Retrieve a router for the given tenant id.
1125
1126 If a public router has been configured, it will be returned.
1127
1128 If a public router has not been configured, but a public
1129 network has, a tenant router will be created and returned that
1130 routes traffic to the public network.
1131 """
Yair Frieddb6c9e92014-08-06 08:53:13 +03001132 if not client:
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +00001133 client = self.routers_client
Yair Frieddb6c9e92014-08-06 08:53:13 +03001134 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +00001135 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001136 router_id = CONF.network.public_router_id
1137 network_id = CONF.network.public_network_id
1138 if router_id:
David Kranzca4c7e72015-05-27 11:39:19 -04001139 body = client.show_router(router_id)
Steve Heyman33735f22016-05-24 09:28:08 -05001140 return body['router']
Yair Fried1fc32a12014-08-04 09:11:30 +03001141 elif network_id:
Yair Frieddb6c9e92014-08-06 08:53:13 +03001142 router = self._create_router(client, tenant_id)
Steve Heyman33735f22016-05-24 09:28:08 -05001143 kwargs = {'external_gateway_info': dict(network_id=network_id)}
1144 router = client.update_router(router['id'], **kwargs)['router']
Yair Fried1fc32a12014-08-04 09:11:30 +03001145 return router
1146 else:
1147 raise Exception("Neither of 'public_router_id' or "
1148 "'public_network_id' has been defined.")
1149
Yair Frieddb6c9e92014-08-06 08:53:13 +03001150 def _create_router(self, client=None, tenant_id=None,
1151 namestart='router-smoke'):
1152 if not client:
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +00001153 client = self.routers_client
Yair Frieddb6c9e92014-08-06 08:53:13 +03001154 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +00001155 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001156 name = data_utils.rand_name(namestart)
David Kranz34e88122014-12-11 15:24:05 -05001157 result = client.create_router(name=name,
1158 admin_state_up=True,
1159 tenant_id=tenant_id)
Steve Heyman33735f22016-05-24 09:28:08 -05001160 router = result['router']
1161 self.assertEqual(router['name'], name)
1162 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
1163 client.delete_router,
1164 router['id'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001165 return router
1166
Alok Maurya6384bbb2014-07-13 06:44:29 -07001167 def _update_router_admin_state(self, router, admin_state_up):
Steve Heyman33735f22016-05-24 09:28:08 -05001168 kwargs = dict(admin_state_up=admin_state_up)
1169 router = self.routers_client.update_router(
1170 router['id'], **kwargs)['router']
1171 self.assertEqual(admin_state_up, router['admin_state_up'])
Alok Maurya6384bbb2014-07-13 06:44:29 -07001172
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -07001173 def create_networks(self, networks_client=None,
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +00001174 routers_client=None, subnets_client=None,
Markus Zoeller156b5da2016-07-11 18:10:31 +02001175 tenant_id=None, dns_nameservers=None,
1176 port_security_enabled=True):
Yair Fried1fc32a12014-08-04 09:11:30 +03001177 """Create a network with a subnet connected to a router.
1178
David Shrewsbury9bac3662014-08-07 15:07:01 -04001179 The baremetal driver is a special case since all nodes are
1180 on the same shared network.
1181
Yair Fried413bf2d2014-11-19 17:07:11 +02001182 :param tenant_id: id of tenant to create resources in.
1183 :param dns_nameservers: list of dns servers to send to subnet.
Yair Fried1fc32a12014-08-04 09:11:30 +03001184 :returns: network, subnet, router
1185 """
David Shrewsbury9bac3662014-08-07 15:07:01 -04001186 if CONF.baremetal.driver_enabled:
1187 # NOTE(Shrews): This exception is for environments where tenant
1188 # credential isolation is available, but network separation is
1189 # not (the current baremetal case). Likely can be removed when
1190 # test account mgmt is reworked:
1191 # https://blueprints.launchpad.net/tempest/+spec/test-accounts
Adam Gandelman878a5fd2015-03-30 14:33:36 -07001192 if not CONF.compute.fixed_network_name:
1193 m = 'fixed_network_name must be specified in config'
Matthew Treinish4217a702016-10-07 17:27:11 -04001194 raise lib_exc.InvalidConfiguration(m)
David Shrewsbury9bac3662014-08-07 15:07:01 -04001195 network = self._get_network_by_name(
1196 CONF.compute.fixed_network_name)
1197 router = None
1198 subnet = None
1199 else:
John Warren94d8faf2015-09-15 12:22:24 -04001200 network = self._create_network(
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -07001201 networks_client=networks_client,
Markus Zoeller156b5da2016-07-11 18:10:31 +02001202 tenant_id=tenant_id,
1203 port_security_enabled=port_security_enabled)
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +00001204 router = self._get_router(client=routers_client,
1205 tenant_id=tenant_id)
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -07001206 subnet_kwargs = dict(network=network,
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +00001207 subnets_client=subnets_client,
1208 routers_client=routers_client)
Yair Fried413bf2d2014-11-19 17:07:11 +02001209 # use explicit check because empty list is a valid option
1210 if dns_nameservers is not None:
1211 subnet_kwargs['dns_nameservers'] = dns_nameservers
1212 subnet = self._create_subnet(**subnet_kwargs)
Steve Heyman33735f22016-05-24 09:28:08 -05001213 if not routers_client:
1214 routers_client = self.routers_client
1215 router_id = router['id']
1216 routers_client.add_router_interface(router_id,
1217 subnet_id=subnet['id'])
1218
1219 # save a cleanup job to remove this association between
1220 # router and subnet
1221 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
1222 routers_client.remove_router_interface, router_id,
1223 subnet_id=subnet['id'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001224 return network, subnet, router
1225
1226
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001227# power/provision states as of icehouse
1228class BaremetalPowerStates(object):
1229 """Possible power states of an Ironic node."""
1230 POWER_ON = 'power on'
1231 POWER_OFF = 'power off'
1232 REBOOT = 'rebooting'
1233 SUSPEND = 'suspended'
1234
1235
1236class BaremetalProvisionStates(object):
1237 """Possible provision states of an Ironic node."""
1238 NOSTATE = None
1239 INIT = 'initializing'
1240 ACTIVE = 'active'
1241 BUILDING = 'building'
1242 DEPLOYWAIT = 'wait call-back'
1243 DEPLOYING = 'deploying'
1244 DEPLOYFAIL = 'deploy failed'
1245 DEPLOYDONE = 'deploy complete'
1246 DELETING = 'deleting'
1247 DELETED = 'deleted'
1248 ERROR = 'error'
1249
1250
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001251class BaremetalScenarioTest(ScenarioTest):
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001252
1253 credentials = ['primary', 'admin']
1254
Adam Gandelman4a48a602014-03-20 18:23:18 -07001255 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001256 def skip_checks(cls):
1257 super(BaremetalScenarioTest, cls).skip_checks()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001258 if (not CONF.service_available.ironic or
1259 not CONF.baremetal.driver_enabled):
1260 msg = 'Ironic not available or Ironic compute driver not enabled'
1261 raise cls.skipException(msg)
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001262
1263 @classmethod
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001264 def setup_clients(cls):
1265 super(BaremetalScenarioTest, cls).setup_clients()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001266
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001267 cls.baremetal_client = cls.admin_manager.baremetal_client
Adam Gandelman4a48a602014-03-20 18:23:18 -07001268
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001269 @classmethod
1270 def resource_setup(cls):
1271 super(BaremetalScenarioTest, cls).resource_setup()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001272 # allow any issues obtaining the node list to raise early
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001273 cls.baremetal_client.list_nodes()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001274
1275 def _node_state_timeout(self, node_id, state_attr,
1276 target_states, timeout=10, interval=1):
1277 if not isinstance(target_states, list):
1278 target_states = [target_states]
1279
1280 def check_state():
1281 node = self.get_node(node_id=node_id)
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001282 if node.get(state_attr) in target_states:
Adam Gandelman4a48a602014-03-20 18:23:18 -07001283 return True
1284 return False
1285
Jordan Pittier35a63752016-08-30 13:09:12 +02001286 if not test_utils.call_until_true(
Adam Gandelman4a48a602014-03-20 18:23:18 -07001287 check_state, timeout, interval):
1288 msg = ("Timed out waiting for node %s to reach %s state(s) %s" %
1289 (node_id, state_attr, target_states))
1290 raise exceptions.TimeoutException(msg)
1291
1292 def wait_provisioning_state(self, node_id, state, timeout):
1293 self._node_state_timeout(
1294 node_id=node_id, state_attr='provision_state',
1295 target_states=state, timeout=timeout)
1296
1297 def wait_power_state(self, node_id, state):
1298 self._node_state_timeout(
1299 node_id=node_id, state_attr='power_state',
1300 target_states=state, timeout=CONF.baremetal.power_timeout)
1301
1302 def wait_node(self, instance_id):
1303 """Waits for a node to be associated with instance_id."""
Zhi Kun Liu4a8d1ea2014-04-15 22:08:21 -05001304
Adam Gandelman4a48a602014-03-20 18:23:18 -07001305 def _get_node():
Jordan Pittier9e227c52016-02-09 14:35:18 +01001306 node = test_utils.call_and_ignore_notfound_exc(
1307 self.get_node, instance_id=instance_id)
Adam Gandelman4a48a602014-03-20 18:23:18 -07001308 return node is not None
1309
Jordan Pittier35a63752016-08-30 13:09:12 +02001310 if not test_utils.call_until_true(
Adam Gandelman4a48a602014-03-20 18:23:18 -07001311 _get_node, CONF.baremetal.association_timeout, 1):
1312 msg = ('Timed out waiting to get Ironic node by instance id %s'
1313 % instance_id)
1314 raise exceptions.TimeoutException(msg)
1315
1316 def get_node(self, node_id=None, instance_id=None):
1317 if node_id:
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001318 _, body = self.baremetal_client.show_node(node_id)
1319 return body
Adam Gandelman4a48a602014-03-20 18:23:18 -07001320 elif instance_id:
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001321 _, body = self.baremetal_client.show_node_by_instance_uuid(
1322 instance_id)
1323 if body['nodes']:
1324 return body['nodes'][0]
Adam Gandelman4a48a602014-03-20 18:23:18 -07001325
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001326 def get_ports(self, node_uuid):
Adam Gandelman4a48a602014-03-20 18:23:18 -07001327 ports = []
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001328 _, body = self.baremetal_client.list_node_ports(node_uuid)
1329 for port in body['ports']:
1330 _, p = self.baremetal_client.show_port(port['uuid'])
1331 ports.append(p)
Adam Gandelman4a48a602014-03-20 18:23:18 -07001332 return ports
1333
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001334 def add_keypair(self):
1335 self.keypair = self.create_keypair()
1336
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001337 def boot_instance(self):
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001338 self.instance = self.create_server(
lanoux5fc14522015-09-21 08:17:35 +00001339 key_name=self.keypair['name'])
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001340
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001341 self.wait_node(self.instance['id'])
1342 self.node = self.get_node(instance_id=self.instance['id'])
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001343
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001344 self.wait_power_state(self.node['uuid'], BaremetalPowerStates.POWER_ON)
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001345
1346 self.wait_provisioning_state(
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001347 self.node['uuid'],
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001348 [BaremetalProvisionStates.DEPLOYWAIT,
1349 BaremetalProvisionStates.ACTIVE],
1350 timeout=15)
1351
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001352 self.wait_provisioning_state(self.node['uuid'],
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001353 BaremetalProvisionStates.ACTIVE,
1354 timeout=CONF.baremetal.active_timeout)
1355
Ken'ichi Ohmichi0eb153c2015-07-13 02:18:25 +00001356 waiters.wait_for_server_status(self.servers_client,
1357 self.instance['id'], 'ACTIVE')
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001358 self.node = self.get_node(instance_id=self.instance['id'])
ghanshyam0f825252015-08-25 16:02:50 +09001359 self.instance = (self.servers_client.show_server(self.instance['id'])
1360 ['server'])
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001361
1362 def terminate_instance(self):
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001363 self.servers_client.delete_server(self.instance['id'])
1364 self.wait_power_state(self.node['uuid'],
1365 BaremetalPowerStates.POWER_OFF)
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001366 self.wait_provisioning_state(
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001367 self.node['uuid'],
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001368 BaremetalProvisionStates.NOSTATE,
1369 timeout=CONF.baremetal.unprovision_timeout)
1370
Adam Gandelman4a48a602014-03-20 18:23:18 -07001371
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001372class EncryptionScenarioTest(ScenarioTest):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001373 """Base class for encryption scenario tests"""
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001374
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001375 credentials = ['primary', 'admin']
David Kranz4cc852b2015-03-09 14:57:11 -04001376
1377 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001378 def setup_clients(cls):
1379 super(EncryptionScenarioTest, cls).setup_clients()
Jordan Pittierc3f76be2016-10-11 17:06:21 +02001380 if CONF.volume_feature_enabled.api_v2:
Ivan Kolodyazhnybcfc32e2015-08-06 13:31:36 +03001381 cls.admin_volume_types_client = cls.os_adm.volume_types_v2_client
Ken'ichi Ohmichia6ebf622016-08-25 11:52:27 -07001382 cls.admin_encryption_types_client =\
1383 cls.os_adm.encryption_types_v2_client
Jordan Pittierc3f76be2016-10-11 17:06:21 +02001384 else:
1385 cls.admin_volume_types_client = cls.os_adm.volume_types_client
1386 cls.admin_encryption_types_client =\
1387 cls.os_adm.encryption_types_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001388
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001389 def create_volume_type(self, client=None, name=None):
1390 if not client:
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001391 client = self.admin_volume_types_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001392 if not name:
1393 name = 'generic'
Ken'ichi Ohmichi6ded8df2015-03-23 02:00:19 +00001394 randomized_name = data_utils.rand_name('scenario-type-' + name)
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001395 LOG.debug("Creating a volume type: %s", randomized_name)
Joseph Lanoux6809bab2014-12-18 14:57:18 +00001396 body = client.create_volume_type(
lei zhang83c4bbd2015-11-27 00:35:21 +08001397 name=randomized_name)['volume_type']
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001398 self.assertIn('id', body)
1399 self.addCleanup(client.delete_volume_type, body['id'])
1400 return body
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001401
1402 def create_encryption_type(self, client=None, type_id=None, provider=None,
1403 key_size=None, cipher=None,
1404 control_location=None):
1405 if not client:
Ken'ichi Ohmichia6ebf622016-08-25 11:52:27 -07001406 client = self.admin_encryption_types_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001407 if not type_id:
1408 volume_type = self.create_volume_type()
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001409 type_id = volume_type['id']
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001410 LOG.debug("Creating an encryption type for volume type: %s", type_id)
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001411 client.create_encryption_type(
1412 type_id, provider=provider, key_size=key_size, cipher=cipher,
John Warrend053ded2015-08-13 15:22:48 +00001413 control_location=control_location)['encryption']
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001414
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001415
Masayuki Igawa0870db52015-09-18 21:08:36 +09001416class ObjectStorageScenarioTest(ScenarioTest):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001417 """Provide harness to do Object Storage scenario tests.
Chris Dent0d494112014-08-26 13:48:30 +01001418
1419 Subclasses implement the tests that use the methods provided by this
1420 class.
1421 """
1422
1423 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001424 def skip_checks(cls):
Masayuki Igawa0870db52015-09-18 21:08:36 +09001425 super(ObjectStorageScenarioTest, cls).skip_checks()
Chris Dent0d494112014-08-26 13:48:30 +01001426 if not CONF.service_available.swift:
1427 skip_msg = ("%s skipped as swift is not available" %
1428 cls.__name__)
1429 raise cls.skipException(skip_msg)
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001430
1431 @classmethod
1432 def setup_credentials(cls):
Masayuki Igawa60ea6c52014-10-15 17:32:14 +09001433 cls.set_network_resources()
Masayuki Igawa0870db52015-09-18 21:08:36 +09001434 super(ObjectStorageScenarioTest, cls).setup_credentials()
Matthew Treinish4a596932015-03-06 20:37:01 -05001435 operator_role = CONF.object_storage.operator_role
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +01001436 cls.os_operator = cls.get_client_manager(roles=[operator_role])
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001437
1438 @classmethod
1439 def setup_clients(cls):
Masayuki Igawa0870db52015-09-18 21:08:36 +09001440 super(ObjectStorageScenarioTest, cls).setup_clients()
Chris Dent0d494112014-08-26 13:48:30 +01001441 # Clients for Swift
Matthew Treinish8f268292015-02-24 20:01:36 -05001442 cls.account_client = cls.os_operator.account_client
1443 cls.container_client = cls.os_operator.container_client
1444 cls.object_client = cls.os_operator.object_client
Chris Dent0d494112014-08-26 13:48:30 +01001445
Chris Dentde456a12014-09-10 12:41:15 +01001446 def get_swift_stat(self):
Chris Dent0d494112014-08-26 13:48:30 +01001447 """get swift status for our user account."""
1448 self.account_client.list_account_containers()
1449 LOG.debug('Swift status information obtained successfully')
1450
Chris Dentde456a12014-09-10 12:41:15 +01001451 def create_container(self, container_name=None):
Chris Dent0d494112014-08-26 13:48:30 +01001452 name = container_name or data_utils.rand_name(
1453 'swift-scenario-container')
1454 self.container_client.create_container(name)
1455 # look for the container to assure it is created
Chris Dentde456a12014-09-10 12:41:15 +01001456 self.list_and_check_container_objects(name)
Chris Dent0d494112014-08-26 13:48:30 +01001457 LOG.debug('Container %s created' % (name))
Jordan Pittier9e227c52016-02-09 14:35:18 +01001458 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
Chris Dent1d4313a2014-10-28 12:16:48 +00001459 self.container_client.delete_container,
1460 name)
Chris Dent0d494112014-08-26 13:48:30 +01001461 return name
1462
Chris Dentde456a12014-09-10 12:41:15 +01001463 def delete_container(self, container_name):
Chris Dent0d494112014-08-26 13:48:30 +01001464 self.container_client.delete_container(container_name)
1465 LOG.debug('Container %s deleted' % (container_name))
1466
Chris Dentde456a12014-09-10 12:41:15 +01001467 def upload_object_to_container(self, container_name, obj_name=None):
Chris Dent0d494112014-08-26 13:48:30 +01001468 obj_name = obj_name or data_utils.rand_name('swift-scenario-object')
1469 obj_data = data_utils.arbitrary_string()
1470 self.object_client.create_object(container_name, obj_name, obj_data)
Jordan Pittier9e227c52016-02-09 14:35:18 +01001471 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
Chris Dent1d4313a2014-10-28 12:16:48 +00001472 self.object_client.delete_object,
1473 container_name,
1474 obj_name)
Chris Dent0d494112014-08-26 13:48:30 +01001475 return obj_name, obj_data
1476
Chris Dentde456a12014-09-10 12:41:15 +01001477 def delete_object(self, container_name, filename):
Chris Dent0d494112014-08-26 13:48:30 +01001478 self.object_client.delete_object(container_name, filename)
Chris Dentde456a12014-09-10 12:41:15 +01001479 self.list_and_check_container_objects(container_name,
1480 not_present_obj=[filename])
Chris Dent0d494112014-08-26 13:48:30 +01001481
Chris Dentde456a12014-09-10 12:41:15 +01001482 def list_and_check_container_objects(self, container_name,
1483 present_obj=None,
1484 not_present_obj=None):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001485 # List objects for a given container and assert which are present and
1486 # which are not.
Ghanshyam2a180b82014-06-16 13:54:22 +09001487 if present_obj is None:
1488 present_obj = []
1489 if not_present_obj is None:
1490 not_present_obj = []
Chris Dent0d494112014-08-26 13:48:30 +01001491 _, object_list = self.container_client.list_container_contents(
1492 container_name)
1493 if present_obj:
1494 for obj in present_obj:
1495 self.assertIn(obj, object_list)
1496 if not_present_obj:
1497 for obj in not_present_obj:
1498 self.assertNotIn(obj, object_list)
1499
Chris Dentde456a12014-09-10 12:41:15 +01001500 def change_container_acl(self, container_name, acl):
Chris Dent0d494112014-08-26 13:48:30 +01001501 metadata_param = {'metadata_prefix': 'x-container-',
1502 'metadata': {'read': acl}}
1503 self.container_client.update_container_metadata(container_name,
1504 **metadata_param)
1505 resp, _ = self.container_client.list_container_metadata(container_name)
1506 self.assertEqual(resp['x-container-read'], acl)
1507
Chris Dentde456a12014-09-10 12:41:15 +01001508 def download_and_verify(self, container_name, obj_name, expected_data):
Chris Dent0d494112014-08-26 13:48:30 +01001509 _, obj = self.object_client.get_object(container_name, obj_name)
1510 self.assertEqual(obj, expected_data)