blob: 62ab67d85a1382f3c479ed81315301065ab7d0ac [file] [log] [blame]
ZhiQiang Fan39f97222013-09-20 04:49:44 +08001# Copyright 2012 OpenStack Foundation
Sean Dague6dbc6da2013-05-08 17:49:46 -04002# Copyright 2013 IBM Corp.
3# All Rights Reserved.
4#
5# Licensed under the Apache License, Version 2.0 (the "License"); you may
6# not use this file except in compliance with the License. You may obtain
7# a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14# License for the specific language governing permissions and limitations
15# under the License.
16
Sean Dague6dbc6da2013-05-08 17:49:46 -040017import subprocess
18
Sean Dague6dbc6da2013-05-08 17:49:46 -040019import netaddr
Doug Hellmann583ce2c2015-03-11 14:55:46 +000020from oslo_log import log
Andrey Pavlovc8bd4b12015-08-17 10:20:17 +030021from oslo_serialization import jsonutils as json
Yatin Kumbhareee4924c2016-06-09 15:12:06 +053022from oslo_utils import netutils
Matthew Treinish96e9e882014-06-09 18:37:19 -040023import six
Sean Dague6dbc6da2013-05-08 17:49:46 -040024
lanoux5fc14522015-09-21 08:17:35 +000025from tempest.common import compute
Ken'ichi Ohmichi01151e82016-06-10 11:19:52 -070026from tempest.common import image as common_image
Fei Long Wangd39431f2015-05-14 11:30:48 +120027from tempest.common.utils import data_utils
Masayuki Igawa4ded9f02014-02-17 15:05:59 +090028from tempest.common.utils.linux import remote_client
Ken'ichi Ohmichi0eb153c2015-07-13 02:18:25 +000029from tempest.common import waiters
Matthew Treinish6c072292014-01-29 19:15:52 +000030from tempest import config
Giulio Fidente92f77192013-08-26 17:13:28 +020031from tempest import exceptions
Jordan Pittier9e227c52016-02-09 14:35:18 +010032from tempest.lib.common.utils import test_utils
Andrea Frittoli (andreaf)db9672e2016-02-23 14:07:24 -050033from tempest.lib import exceptions as lib_exc
Sean Dague6dbc6da2013-05-08 17:49:46 -040034import tempest.test
Sean Dague6dbc6da2013-05-08 17:49:46 -040035
Matthew Treinish6c072292014-01-29 19:15:52 +000036CONF = config.CONF
Sean Dague6dbc6da2013-05-08 17:49:46 -040037
Attila Fazekasfb7552a2013-08-27 13:02:26 +020038LOG = log.getLogger(__name__)
39
Sean Dague6dbc6da2013-05-08 17:49:46 -040040
Andrea Frittoli2e733b52014-07-16 14:12:11 +010041class ScenarioTest(tempest.test.BaseTestCase):
Andrea Frittoli486ede72014-09-25 11:50:05 +010042 """Base class for scenario tests. Uses tempest own clients. """
Andrea Frittoli2e733b52014-07-16 14:12:11 +010043
Andrea Frittolib21de6c2015-02-06 20:12:38 +000044 credentials = ['primary']
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +000045
46 @classmethod
47 def setup_clients(cls):
48 super(ScenarioTest, cls).setup_clients()
Andrea Frittoli247058f2014-07-16 16:09:22 +010049 # Clients (in alphabetical order)
Adam Gandelmanc78c7572014-08-28 18:38:55 -070050 cls.flavors_client = cls.manager.flavors_client
John Warrene74890a2015-11-11 15:18:01 -050051 cls.compute_floating_ips_client = (
52 cls.manager.compute_floating_ips_client)
Jordan Pittier1d2e40f2016-01-05 18:49:14 +010053 if CONF.service_available.glance:
Matt Riedemann2aa19d42016-06-06 17:45:41 -040054 # Check if glance v1 is available to determine which client to use.
55 if CONF.image_feature_enabled.api_v1:
56 cls.image_client = cls.manager.image_client
57 elif CONF.image_feature_enabled.api_v2:
58 cls.image_client = cls.manager.image_client_v2
59 else:
60 raise exceptions.InvalidConfiguration(
61 'Either api_v1 or api_v2 must be True in '
62 '[image-feature-enabled].')
nithya-ganesan882595e2014-07-29 18:51:07 +000063 # Compute image client
Ghanshyamae76c122015-12-22 13:41:35 +090064 cls.compute_images_client = cls.manager.compute_images_client
Andrea Frittoli247058f2014-07-16 16:09:22 +010065 cls.keypairs_client = cls.manager.keypairs_client
Andrea Frittoli247058f2014-07-16 16:09:22 +010066 # Nova security groups client
John Warrenf2345512015-12-10 13:39:30 -050067 cls.compute_security_groups_client = (
68 cls.manager.compute_security_groups_client)
John Warren5cdbf422016-01-05 12:42:43 -050069 cls.compute_security_group_rules_client = (
70 cls.manager.compute_security_group_rules_client)
Andrea Frittoli247058f2014-07-16 16:09:22 +010071 cls.servers_client = cls.manager.servers_client
Yair Fried1fc32a12014-08-04 09:11:30 +030072 cls.interface_client = cls.manager.interfaces_client
73 # Neutron network client
John Warren94d8faf2015-09-15 12:22:24 -040074 cls.networks_client = cls.manager.networks_client
John Warren49c0fe52015-10-22 12:35:54 -040075 cls.ports_client = cls.manager.ports_client
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +000076 cls.routers_client = cls.manager.routers_client
John Warren3961acd2015-10-02 14:38:53 -040077 cls.subnets_client = cls.manager.subnets_client
John Warrenfbf2a892015-11-17 12:36:14 -050078 cls.floating_ips_client = cls.manager.floating_ips_client
John Warrenf9606e92015-12-10 12:12:42 -050079 cls.security_groups_client = cls.manager.security_groups_client
John Warren456d9ae2016-01-12 15:36:33 -050080 cls.security_group_rules_client = (
81 cls.manager.security_group_rules_client)
Andrea Frittoli2e733b52014-07-16 14:12:11 +010082
Ivan Kolodyazhnybcfc32e2015-08-06 13:31:36 +030083 if CONF.volume_feature_enabled.api_v1:
84 cls.volumes_client = cls.manager.volumes_client
85 cls.snapshots_client = cls.manager.snapshots_client
86 else:
87 cls.volumes_client = cls.manager.volumes_v2_client
88 cls.snapshots_client = cls.manager.snapshots_v2_client
89
Andrea Frittoli247058f2014-07-16 16:09:22 +010090 # ## Methods to handle sync and async deletes
91
92 def setUp(self):
93 super(ScenarioTest, self).setUp()
94 self.cleanup_waits = []
95 # NOTE(mtreinish) This is safe to do in setUp instead of setUp class
96 # because scenario tests in the same test class should not share
97 # resources. If resources were shared between test cases then it
98 # should be a single scenario test instead of multiples.
99
100 # NOTE(yfried): this list is cleaned at the end of test_methods and
101 # not at the end of the class
102 self.addCleanup(self._wait_for_cleanups)
103
Andrea Frittoli247058f2014-07-16 16:09:22 +0100104 def addCleanup_with_wait(self, waiter_callable, thing_id, thing_id_param,
Ghanshyam2a180b82014-06-16 13:54:22 +0900105 cleanup_callable, cleanup_args=None,
Ken'ichi Ohmichie91a0c62015-08-13 02:09:16 +0000106 cleanup_kwargs=None, waiter_client=None):
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700107 """Adds wait for async resource deletion at the end of cleanups
Andrea Frittoli247058f2014-07-16 16:09:22 +0100108
109 @param waiter_callable: callable to wait for the resource to delete
Ken'ichi Ohmichie91a0c62015-08-13 02:09:16 +0000110 with the following waiter_client if specified.
Andrea Frittoli247058f2014-07-16 16:09:22 +0100111 @param thing_id: the id of the resource to be cleaned-up
112 @param thing_id_param: the name of the id param in the waiter
113 @param cleanup_callable: method to load pass to self.addCleanup with
114 the following *cleanup_args, **cleanup_kwargs.
115 usually a delete method.
116 """
Ghanshyam2a180b82014-06-16 13:54:22 +0900117 if cleanup_args is None:
118 cleanup_args = []
119 if cleanup_kwargs is None:
120 cleanup_kwargs = {}
Andrea Frittoli247058f2014-07-16 16:09:22 +0100121 self.addCleanup(cleanup_callable, *cleanup_args, **cleanup_kwargs)
122 wait_dict = {
123 'waiter_callable': waiter_callable,
124 thing_id_param: thing_id
125 }
Ken'ichi Ohmichie91a0c62015-08-13 02:09:16 +0000126 if waiter_client:
127 wait_dict['client'] = waiter_client
Andrea Frittoli247058f2014-07-16 16:09:22 +0100128 self.cleanup_waits.append(wait_dict)
129
Lenny Verkhovsky136376f2016-06-29 14:33:34 +0300130 def _create_port(self, network_id, client=None, namestart='port-quotatest',
131 **kwargs):
132 if not client:
133 client = self.ports_client
134 name = data_utils.rand_name(namestart)
135 result = client.create_port(
136 name=name,
137 network_id=network_id,
138 **kwargs)
139 self.assertIsNotNone(result, 'Unable to allocate port')
140 port = result['port']
141 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
142 client.delete_port, port['id'])
143 return port
144
Andrea Frittoli247058f2014-07-16 16:09:22 +0100145 def _wait_for_cleanups(self):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000146 # To handle async delete actions, a list of waits is added
147 # which will be iterated over as the last step of clearing the
148 # cleanup queue. That way all the delete calls are made up front
149 # and the tests won't succeed unless the deletes are eventually
150 # successful. This is the same basic approach used in the api tests to
151 # limit cleanup execution time except here it is multi-resource,
152 # because of the nature of the scenario tests.
Andrea Frittoli247058f2014-07-16 16:09:22 +0100153 for wait in self.cleanup_waits:
154 waiter_callable = wait.pop('waiter_callable')
155 waiter_callable(**wait)
156
157 # ## Test functions library
158 #
159 # The create_[resource] functions only return body and discard the
160 # resp part which is not used in scenario tests
161
Yair Frieddb6c9e92014-08-06 08:53:13 +0300162 def create_keypair(self, client=None):
163 if not client:
164 client = self.keypairs_client
Andrea Frittoli247058f2014-07-16 16:09:22 +0100165 name = data_utils.rand_name(self.__class__.__name__)
166 # We don't need to create a keypair by pubkey in scenario
Ken'ichi Ohmichie364bce2015-07-17 10:27:59 +0000167 body = client.create_keypair(name=name)
Yair Frieddb6c9e92014-08-06 08:53:13 +0300168 self.addCleanup(client.delete_keypair, name)
ghanshyamdee01f22015-08-17 11:41:47 +0900169 return body['keypair']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100170
Anusha Ramineni9aaef8b2016-01-19 10:56:40 +0530171 def create_server(self, name=None, image_id=None, flavor=None,
lanoux5fc14522015-09-21 08:17:35 +0000172 validatable=False, wait_until=None,
173 wait_on_delete=True, clients=None, **kwargs):
174 """Wrapper utility that returns a test server.
Andrea Frittoli247058f2014-07-16 16:09:22 +0100175
lanoux5fc14522015-09-21 08:17:35 +0000176 This wrapper utility calls the common create test server and
177 returns a test server. The purpose of this wrapper is to minimize
178 the impact on the code of the tests already using this
179 function.
Andrea Frittoli247058f2014-07-16 16:09:22 +0100180 """
Andrea Frittoli247058f2014-07-16 16:09:22 +0100181
lanoux5fc14522015-09-21 08:17:35 +0000182 # NOTE(jlanoux): As a first step, ssh checks in the scenario
183 # tests need to be run regardless of the run_validation and
184 # validatable parameters and thus until the ssh validation job
185 # becomes voting in CI. The test resources management and IP
186 # association are taken care of in the scenario tests.
187 # Therefore, the validatable parameter is set to false in all
188 # those tests. In this way create_server just return a standard
189 # server and the scenario tests always perform ssh checks.
190
191 # Needed for the cross_tenant_traffic test:
192 if clients is None:
193 clients = self.manager
194
195 vnic_type = CONF.network.port_vnic_type
196
197 # If vnic_type is configured create port for
198 # every network
199 if vnic_type:
200 ports = []
Lenny Verkhovsky69363502016-07-17 16:33:33 +0300201
lanoux5fc14522015-09-21 08:17:35 +0000202 create_port_body = {'binding:vnic_type': vnic_type,
203 'namestart': 'port-smoke'}
204 if kwargs:
205 # Convert security group names to security group ids
206 # to pass to create_port
207 if 'security_groups' in kwargs:
208 security_groups =\
John Warrenf9606e92015-12-10 12:12:42 -0500209 clients.security_groups_client.list_security_groups(
lanoux5fc14522015-09-21 08:17:35 +0000210 ).get('security_groups')
211 sec_dict = dict([(s['name'], s['id'])
212 for s in security_groups])
213
214 sec_groups_names = [s['name'] for s in kwargs.pop(
215 'security_groups')]
216 security_groups_ids = [sec_dict[s]
217 for s in sec_groups_names]
218
219 if security_groups_ids:
220 create_port_body[
221 'security_groups'] = security_groups_ids
Lenny Verkhovsky69363502016-07-17 16:33:33 +0300222 networks = kwargs.pop('networks', [])
223 else:
224 networks = []
lanoux5fc14522015-09-21 08:17:35 +0000225
226 # If there are no networks passed to us we look up
Lenny Verkhovsky136376f2016-06-29 14:33:34 +0300227 # for the project's private networks and create a port.
228 # The same behaviour as we would expect when passing
229 # the call to the clients with no networks
lanoux5fc14522015-09-21 08:17:35 +0000230 if not networks:
231 networks = clients.networks_client.list_networks(
Lenny Verkhovsky136376f2016-06-29 14:33:34 +0300232 **{'router:external': False, 'fields': 'id'})['networks']
233
234 # It's net['uuid'] if networks come from kwargs
235 # and net['id'] if they come from
236 # clients.networks_client.list_networks
lanoux5fc14522015-09-21 08:17:35 +0000237 for net in networks:
Lenny Verkhovsky97f7cea2016-08-15 13:29:48 +0000238 net_id = net.get('uuid', net.get('id'))
Lenny Verkhovsky69363502016-07-17 16:33:33 +0300239 if 'port' not in net:
240 port = self._create_port(network_id=net_id,
241 client=clients.ports_client,
242 **create_port_body)
243 ports.append({'port': port['id']})
244 else:
245 ports.append({'port': net['port']})
lanoux5fc14522015-09-21 08:17:35 +0000246 if ports:
247 kwargs['networks'] = ports
248 self.ports = ports
249
250 tenant_network = self.get_tenant_network()
251
252 body, servers = compute.create_test_server(
253 clients,
254 tenant_network=tenant_network,
255 wait_until=wait_until,
Anusha Ramineni9aaef8b2016-01-19 10:56:40 +0530256 name=name, flavor=flavor,
257 image_id=image_id, **kwargs)
lanoux5fc14522015-09-21 08:17:35 +0000258
259 # TODO(jlanoux) Move wait_on_delete in compute.py
Andrea Frittoli247058f2014-07-16 16:09:22 +0100260 if wait_on_delete:
Ken'ichi Ohmichie91a0c62015-08-13 02:09:16 +0000261 self.addCleanup(waiters.wait_for_server_termination,
lanoux5fc14522015-09-21 08:17:35 +0000262 clients.servers_client,
263 body['id'])
264
Andrea Frittoli247058f2014-07-16 16:09:22 +0100265 self.addCleanup_with_wait(
Ken'ichi Ohmichie91a0c62015-08-13 02:09:16 +0000266 waiter_callable=waiters.wait_for_server_termination,
lanoux5fc14522015-09-21 08:17:35 +0000267 thing_id=body['id'], thing_id_param='server_id',
Jordan Pittier9e227c52016-02-09 14:35:18 +0100268 cleanup_callable=test_utils.call_and_ignore_notfound_exc,
lanoux5fc14522015-09-21 08:17:35 +0000269 cleanup_args=[clients.servers_client.delete_server, body['id']],
270 waiter_client=clients.servers_client)
271 server = clients.servers_client.show_server(body['id'])['server']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100272 return server
273
Markus Zoeller3d2a21c2015-02-27 12:04:22 +0100274 def create_volume(self, size=None, name=None, snapshot_id=None,
Jordan Pittier5e1741c2016-03-02 18:25:51 +0100275 imageRef=None, volume_type=None):
Andrea Frittoli247058f2014-07-16 16:09:22 +0100276 if name is None:
277 name = data_utils.rand_name(self.__class__.__name__)
Ghanshyam8fc0ed22015-12-18 10:25:14 +0900278 kwargs = {'display_name': name,
279 'snapshot_id': snapshot_id,
280 'imageRef': imageRef,
281 'volume_type': volume_type}
282 if size is not None:
283 kwargs.update({'size': size})
284 volume = self.volumes_client.create_volume(**kwargs)['volume']
Matt Riedemanne85c2702014-09-10 11:50:13 -0700285
Jordan Pittier5e1741c2016-03-02 18:25:51 +0100286 self.addCleanup(self.volumes_client.wait_for_resource_deletion,
287 volume['id'])
Jordan Pittier9e227c52016-02-09 14:35:18 +0100288 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
Jordan Pittier5e1741c2016-03-02 18:25:51 +0100289 self.volumes_client.delete_volume, volume['id'])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100290
Ivan Kolodyazhnybcfc32e2015-08-06 13:31:36 +0300291 # NOTE(e0ne): Cinder API v2 uses name instead of display_name
292 if 'display_name' in volume:
293 self.assertEqual(name, volume['display_name'])
294 else:
295 self.assertEqual(name, volume['name'])
Yaroslav Lobankoved3a35b2016-03-24 22:41:30 -0500296 waiters.wait_for_volume_status(self.volumes_client,
297 volume['id'], 'available')
Andrea Frittoli247058f2014-07-16 16:09:22 +0100298 # The volume retrieved on creation has a non-up-to-date status.
299 # Retrieval after it becomes active ensures correct details.
John Warren6177c9e2015-08-19 20:00:17 +0000300 volume = self.volumes_client.show_volume(volume['id'])['volume']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100301 return volume
302
Yair Fried1fc32a12014-08-04 09:11:30 +0300303 def _create_loginable_secgroup_rule(self, secgroup_id=None):
John Warrenf2345512015-12-10 13:39:30 -0500304 _client = self.compute_security_groups_client
John Warren5cdbf422016-01-05 12:42:43 -0500305 _client_rules = self.compute_security_group_rules_client
Andrea Frittoli247058f2014-07-16 16:09:22 +0100306 if secgroup_id is None:
ghanshyamb610b772015-08-24 17:29:38 +0900307 sgs = _client.list_security_groups()['security_groups']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100308 for sg in sgs:
309 if sg['name'] == 'default':
310 secgroup_id = sg['id']
311
312 # These rules are intended to permit inbound ssh and icmp
313 # traffic from all sources, so no group_id is provided.
314 # Setting a group_id would only permit traffic from ports
315 # belonging to the same security group.
316 rulesets = [
317 {
318 # ssh
Ken'ichi Ohmichieb7eeec2015-07-21 01:00:06 +0000319 'ip_protocol': 'tcp',
Andrea Frittoli247058f2014-07-16 16:09:22 +0100320 'from_port': 22,
321 'to_port': 22,
322 'cidr': '0.0.0.0/0',
323 },
324 {
325 # ping
Ken'ichi Ohmichieb7eeec2015-07-21 01:00:06 +0000326 'ip_protocol': 'icmp',
Andrea Frittoli247058f2014-07-16 16:09:22 +0100327 'from_port': -1,
328 'to_port': -1,
329 'cidr': '0.0.0.0/0',
330 }
331 ]
332 rules = list()
333 for ruleset in rulesets:
Ken'ichi Ohmichieb7eeec2015-07-21 01:00:06 +0000334 sg_rule = _client_rules.create_security_group_rule(
ghanshyam0a5e1232015-08-24 16:59:59 +0900335 parent_group_id=secgroup_id, **ruleset)['security_group_rule']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100336 rules.append(sg_rule)
337 return rules
338
Yair Fried1fc32a12014-08-04 09:11:30 +0300339 def _create_security_group(self):
Andrea Frittoli247058f2014-07-16 16:09:22 +0100340 # Create security group
341 sg_name = data_utils.rand_name(self.__class__.__name__)
342 sg_desc = sg_name + " description"
John Warrenf2345512015-12-10 13:39:30 -0500343 secgroup = self.compute_security_groups_client.create_security_group(
ghanshyamb610b772015-08-24 17:29:38 +0900344 name=sg_name, description=sg_desc)['security_group']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100345 self.assertEqual(secgroup['name'], sg_name)
346 self.assertEqual(secgroup['description'], sg_desc)
John Warrenf2345512015-12-10 13:39:30 -0500347 self.addCleanup(
Jordan Pittier9e227c52016-02-09 14:35:18 +0100348 test_utils.call_and_ignore_notfound_exc,
John Warrenf2345512015-12-10 13:39:30 -0500349 self.compute_security_groups_client.delete_security_group,
350 secgroup['id'])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100351
352 # Add rules to the security group
Yair Fried1fc32a12014-08-04 09:11:30 +0300353 self._create_loginable_secgroup_rule(secgroup['id'])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100354
355 return secgroup
356
Sean Dague20e98612016-01-06 14:33:28 -0500357 def get_remote_client(self, ip_address, username=None, private_key=None):
JordanP3fe2dc32014-11-17 13:06:01 +0100358 """Get a SSH client to a remote server
359
Sean Dague20e98612016-01-06 14:33:28 -0500360 @param ip_address the server floating or fixed IP address to use
361 for ssh validation
JordanP3fe2dc32014-11-17 13:06:01 +0100362 @param username name of the Linux account on the remote server
363 @param private_key the SSH private key to use
JordanP3fe2dc32014-11-17 13:06:01 +0100364 @return a RemoteClient object
365 """
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700366
Andrea Frittoli247058f2014-07-16 16:09:22 +0100367 if username is None:
lanoux283273b2015-12-04 03:01:54 -0800368 username = CONF.validation.image_ssh_user
wantwatering896300c2015-03-27 15:17:42 +0800369 # Set this with 'keypair' or others to log in with keypair or
370 # username/password.
lanoux5fc14522015-09-21 08:17:35 +0000371 if CONF.validation.auth_method == 'keypair':
wantwatering896300c2015-03-27 15:17:42 +0800372 password = None
373 if private_key is None:
374 private_key = self.keypair['private_key']
375 else:
lanoux283273b2015-12-04 03:01:54 -0800376 password = CONF.validation.image_ssh_password
wantwatering896300c2015-03-27 15:17:42 +0800377 private_key = None
Sean Dague20e98612016-01-06 14:33:28 -0500378 linux_client = remote_client.RemoteClient(ip_address, username,
wantwatering896300c2015-03-27 15:17:42 +0800379 pkey=private_key,
380 password=password)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100381 try:
382 linux_client.validate_authentication()
Matt Riedemann5f0ac522015-05-21 09:16:24 -0700383 except Exception as e:
384 message = ('Initializing SSH connection to %(ip)s failed. '
Eric Brown0911af62016-02-08 17:15:40 -0800385 'Error: %(error)s' % {'ip': ip_address,
Sean Dague20e98612016-01-06 14:33:28 -0500386 'error': e})
Jordan Pittier9e227c52016-02-09 14:35:18 +0100387 caller = test_utils.find_test_caller()
Matt Riedemann5f0ac522015-05-21 09:16:24 -0700388 if caller:
389 message = '(%s) %s' % (caller, message)
390 LOG.exception(message)
Sean Dague2c98a162016-01-06 14:11:13 -0500391 self._log_console_output()
Andrea Frittoli247058f2014-07-16 16:09:22 +0100392 raise
393
394 return linux_client
395
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000396 def _image_create(self, name, fmt, path,
397 disk_format=None, properties=None):
Ghanshyam2a180b82014-06-16 13:54:22 +0900398 if properties is None:
399 properties = {}
Andrea Frittoli247058f2014-07-16 16:09:22 +0100400 name = data_utils.rand_name('%s-' % name)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100401 params = {
402 'name': name,
403 'container_format': fmt,
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000404 'disk_format': disk_format or fmt,
Andrea Frittoli247058f2014-07-16 16:09:22 +0100405 }
Matt Riedemann2aa19d42016-06-06 17:45:41 -0400406 if CONF.image_feature_enabled.api_v1:
407 params['is_public'] = 'False'
408 params['properties'] = properties
Ken'ichi Ohmichi02bcdf32016-06-17 16:41:26 -0700409 params = {'headers': common_image.image_meta_to_headers(**params)}
Matt Riedemann2aa19d42016-06-06 17:45:41 -0400410 else:
411 params['visibility'] = 'private'
412 # Additional properties are flattened out in the v2 API.
413 params.update(properties)
414 body = self.image_client.create_image(**params)
415 image = body['image'] if 'image' in body else body
Andrea Frittoli247058f2014-07-16 16:09:22 +0100416 self.addCleanup(self.image_client.delete_image, image['id'])
417 self.assertEqual("queued", image['status'])
zhang.leia4b1cef2016-03-01 10:50:01 +0800418 with open(path, 'rb') as image_file:
Matt Riedemann2aa19d42016-06-06 17:45:41 -0400419 if CONF.image_feature_enabled.api_v1:
420 self.image_client.update_image(image['id'], data=image_file)
421 else:
422 self.image_client.store_image_file(image['id'], image_file)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100423 return image['id']
424
425 def glance_image_create(self):
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300426 img_path = CONF.scenario.img_dir + "/" + CONF.scenario.img_file
Andrea Frittoli247058f2014-07-16 16:09:22 +0100427 aki_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.aki_img_file
428 ari_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.ari_img_file
429 ami_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.ami_img_file
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300430 img_container_format = CONF.scenario.img_container_format
431 img_disk_format = CONF.scenario.img_disk_format
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000432 img_properties = CONF.scenario.img_properties
PranaliD2aa523c2016-06-07 03:54:34 -0400433 LOG.debug("paths: img: %s, container_format: %s, disk_format: %s, "
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000434 "properties: %s, ami: %s, ari: %s, aki: %s" %
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300435 (img_path, img_container_format, img_disk_format,
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000436 img_properties, ami_img_path, ari_img_path, aki_img_path))
Andrea Frittoli247058f2014-07-16 16:09:22 +0100437 try:
Jordan Pittier1e443ec2015-11-20 16:15:58 +0100438 image = self._image_create('scenario-img',
439 img_container_format,
440 img_path,
441 disk_format=img_disk_format,
442 properties=img_properties)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100443 except IOError:
444 LOG.debug("A qcow2 image was not found. Try to get a uec image.")
445 kernel = self._image_create('scenario-aki', 'aki', aki_img_path)
446 ramdisk = self._image_create('scenario-ari', 'ari', ari_img_path)
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000447 properties = {'kernel_id': kernel, 'ramdisk_id': ramdisk}
Jordan Pittier1e443ec2015-11-20 16:15:58 +0100448 image = self._image_create('scenario-ami', 'ami',
449 path=ami_img_path,
450 properties=properties)
451 LOG.debug("image:%s" % image)
452
453 return image
Andrea Frittoli247058f2014-07-16 16:09:22 +0100454
455 def _log_console_output(self, servers=None):
Matthew Treinish42a3f3a2014-09-04 15:04:53 -0400456 if not CONF.compute_feature_enabled.console_output:
457 LOG.debug('Console output not supported, cannot log')
458 return
Andrea Frittoli247058f2014-07-16 16:09:22 +0100459 if not servers:
David Kranzae99b9a2015-02-16 13:37:01 -0500460 servers = self.servers_client.list_servers()
Andrea Frittoli247058f2014-07-16 16:09:22 +0100461 servers = servers['servers']
462 for server in servers:
Brant Knudson566c5712014-09-24 20:04:50 -0500463 console_output = self.servers_client.get_console_output(
Ken'ichi Ohmichibf4766a2015-12-09 07:48:43 +0000464 server['id'])['output']
David Kranzae99b9a2015-02-16 13:37:01 -0500465 LOG.debug('Console output for %s\nbody=\n%s',
466 server['id'], console_output)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100467
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000468 def _log_net_info(self, exc):
469 # network debug is called as part of ssh init
Andrey Pavlov64723762015-04-29 06:24:58 +0300470 if not isinstance(exc, lib_exc.SSHTimeout):
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000471 LOG.debug('Network information on a devstack host')
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000472
nithya-ganesan882595e2014-07-29 18:51:07 +0000473 def create_server_snapshot(self, server, name=None):
474 # Glance client
475 _image_client = self.image_client
476 # Compute client
Ghanshyamae76c122015-12-22 13:41:35 +0900477 _images_client = self.compute_images_client
nithya-ganesan882595e2014-07-29 18:51:07 +0000478 if name is None:
Ken'ichi Ohmichi6ded8df2015-03-23 02:00:19 +0000479 name = data_utils.rand_name('scenario-snapshot')
nithya-ganesan882595e2014-07-29 18:51:07 +0000480 LOG.debug("Creating a snapshot image for server: %s", server['name'])
Ken'ichi Ohmichi28f18672015-07-17 10:00:38 +0000481 image = _images_client.create_image(server['id'], name=name)
David Kranza5299eb2015-01-15 17:24:05 -0500482 image_id = image.response['location'].split('images/')[1]
Yaroslav Lobankov2fea4052016-04-19 15:05:57 +0300483 waiters.wait_for_image_status(_image_client, image_id, 'active')
nithya-ganesan882595e2014-07-29 18:51:07 +0000484 self.addCleanup_with_wait(
485 waiter_callable=_image_client.wait_for_resource_deletion,
486 thing_id=image_id, thing_id_param='id',
Jordan Pittier9e227c52016-02-09 14:35:18 +0100487 cleanup_callable=test_utils.call_and_ignore_notfound_exc,
nithya-ganesan882595e2014-07-29 18:51:07 +0000488 cleanup_args=[_image_client.delete_image, image_id])
Matt Riedemann2aa19d42016-06-06 17:45:41 -0400489 if CONF.image_feature_enabled.api_v1:
490 # In glance v1 the additional properties are stored in the headers.
Ken'ichi Ohmichi01151e82016-06-10 11:19:52 -0700491 resp = _image_client.check_image(image_id)
492 snapshot_image = common_image.get_image_meta_from_headers(resp)
Matt Riedemann2aa19d42016-06-06 17:45:41 -0400493 image_props = snapshot_image.get('properties', {})
494 else:
495 # In glance v2 the additional properties are flattened.
496 snapshot_image = _image_client.show_image(image_id)
497 image_props = snapshot_image
Andrey Pavlovc8bd4b12015-08-17 10:20:17 +0300498
Matt Riedemann2aa19d42016-06-06 17:45:41 -0400499 bdm = image_props.get('block_device_mapping')
Andrey Pavlovc8bd4b12015-08-17 10:20:17 +0300500 if bdm:
501 bdm = json.loads(bdm)
502 if bdm and 'snapshot_id' in bdm[0]:
503 snapshot_id = bdm[0]['snapshot_id']
504 self.addCleanup(
505 self.snapshots_client.wait_for_resource_deletion,
506 snapshot_id)
Jordan Pittier9e227c52016-02-09 14:35:18 +0100507 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
508 self.snapshots_client.delete_snapshot,
509 snapshot_id)
Yaroslav Lobankov667aaa22016-03-24 23:13:28 -0500510 waiters.wait_for_snapshot_status(self.snapshots_client,
511 snapshot_id, 'available')
nithya-ganesan882595e2014-07-29 18:51:07 +0000512 image_name = snapshot_image['name']
513 self.assertEqual(name, image_name)
514 LOG.debug("Created snapshot image %s for server %s",
515 image_name, server['name'])
516 return snapshot_image
517
Jordan Pittier7cf64762015-10-14 15:01:12 +0200518 def nova_volume_attach(self, server, volume_to_attach):
Joseph Lanoux6809bab2014-12-18 14:57:18 +0000519 volume = self.servers_client.attach_volume(
Jordan Pittier7cf64762015-10-14 15:01:12 +0200520 server['id'], volumeId=volume_to_attach['id'], device='/dev/%s'
ghanshyam0f825252015-08-25 16:02:50 +0900521 % CONF.compute.volume_device_name)['volumeAttachment']
Jordan Pittier7cf64762015-10-14 15:01:12 +0200522 self.assertEqual(volume_to_attach['id'], volume['id'])
Yaroslav Lobankoved3a35b2016-03-24 22:41:30 -0500523 waiters.wait_for_volume_status(self.volumes_client,
524 volume['id'], 'in-use')
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900525
Jordan Pittier7cf64762015-10-14 15:01:12 +0200526 # Return the updated volume after the attachment
527 return self.volumes_client.show_volume(volume['id'])['volume']
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900528
Jordan Pittier7cf64762015-10-14 15:01:12 +0200529 def nova_volume_detach(self, server, volume):
530 self.servers_client.detach_volume(server['id'], volume['id'])
Yaroslav Lobankoved3a35b2016-03-24 22:41:30 -0500531 waiters.wait_for_volume_status(self.volumes_client,
532 volume['id'], 'available')
Jordan Pittier7cf64762015-10-14 15:01:12 +0200533
534 volume = self.volumes_client.show_volume(volume['id'])['volume']
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900535 self.assertEqual('available', volume['status'])
536
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700537 def rebuild_server(self, server_id, image=None,
538 preserve_ephemeral=False, wait=True,
539 rebuild_kwargs=None):
540 if image is None:
541 image = CONF.compute.image_ref
542
543 rebuild_kwargs = rebuild_kwargs or {}
544
545 LOG.debug("Rebuilding server (id: %s, image: %s, preserve eph: %s)",
546 server_id, image, preserve_ephemeral)
Ken'ichi Ohmichi5271b0f2015-08-10 07:53:27 +0000547 self.servers_client.rebuild_server(
548 server_id=server_id, image_ref=image,
549 preserve_ephemeral=preserve_ephemeral,
550 **rebuild_kwargs)
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700551 if wait:
Ken'ichi Ohmichi0eb153c2015-07-13 02:18:25 +0000552 waiters.wait_for_server_status(self.servers_client,
553 server_id, 'ACTIVE')
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700554
Steven Hardyda2a8352014-10-02 12:52:20 +0100555 def ping_ip_address(self, ip_address, should_succeed=True,
556 ping_timeout=None):
lanoux5fc14522015-09-21 08:17:35 +0000557 timeout = ping_timeout or CONF.validation.ping_timeout
Aaron Rosena7df13b2014-09-23 09:45:45 -0700558 cmd = ['ping', '-c1', '-w1', ip_address]
559
560 def ping():
561 proc = subprocess.Popen(cmd,
562 stdout=subprocess.PIPE,
563 stderr=subprocess.PIPE)
564 proc.communicate()
Shuquan Huang753629e2015-07-20 08:52:29 +0000565
Aaron Rosena7df13b2014-09-23 09:45:45 -0700566 return (proc.returncode == 0) == should_succeed
567
Jordan Pittier9e227c52016-02-09 14:35:18 +0100568 caller = test_utils.find_test_caller()
Shuquan Huang753629e2015-07-20 08:52:29 +0000569 LOG.debug('%(caller)s begins to ping %(ip)s in %(timeout)s sec and the'
570 ' expected result is %(should_succeed)s' % {
571 'caller': caller, 'ip': ip_address, 'timeout': timeout,
572 'should_succeed':
573 'reachable' if should_succeed else 'unreachable'
574 })
575 result = tempest.test.call_until_true(ping, timeout, 1)
576 LOG.debug('%(caller)s finishes ping %(ip)s in %(timeout)s sec and the '
577 'ping result is %(result)s' % {
578 'caller': caller, 'ip': ip_address, 'timeout': timeout,
579 'result': 'expected' if result else 'unexpected'
580 })
581 return result
Aaron Rosena7df13b2014-09-23 09:45:45 -0700582
Yair Friedae0e73d2014-11-24 11:56:26 +0200583 def check_vm_connectivity(self, ip_address,
584 username=None,
585 private_key=None,
586 should_connect=True):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000587 """Check server connectivity
588
Yair Friedae0e73d2014-11-24 11:56:26 +0200589 :param ip_address: server to test against
590 :param username: server's ssh username
591 :param private_key: server's ssh private key to be used
592 :param should_connect: True/False indicates positive/negative test
593 positive - attempt ping and ssh
594 negative - attempt ping and fail if succeed
595
596 :raises: AssertError if the result of the connectivity check does
597 not match the value of the should_connect param
598 """
599 if should_connect:
600 msg = "Timed out waiting for %s to become reachable" % ip_address
601 else:
602 msg = "ip address %s is reachable" % ip_address
603 self.assertTrue(self.ping_ip_address(ip_address,
604 should_succeed=should_connect),
605 msg=msg)
606 if should_connect:
607 # no need to check ssh for negative connectivity
608 self.get_remote_client(ip_address, username, private_key)
609
610 def check_public_network_connectivity(self, ip_address, username,
611 private_key, should_connect=True,
612 msg=None, servers=None):
613 # The target login is assumed to have been configured for
614 # key-based authentication by cloud-init.
615 LOG.debug('checking network connections to IP %s with user: %s' %
616 (ip_address, username))
617 try:
618 self.check_vm_connectivity(ip_address,
619 username,
620 private_key,
621 should_connect=should_connect)
Matthew Treinish53483132014-12-09 18:50:06 -0500622 except Exception:
Yair Friedae0e73d2014-11-24 11:56:26 +0200623 ex_msg = 'Public network connectivity check failed'
624 if msg:
625 ex_msg += ": " + msg
626 LOG.exception(ex_msg)
627 self._log_console_output(servers)
Yair Friedae0e73d2014-11-24 11:56:26 +0200628 raise
629
630 def create_floating_ip(self, thing, pool_name=None):
Ken'ichi Ohmichia112a592015-11-17 08:49:37 +0000631 """Create a floating IP and associates to a server on Nova"""
Yair Friedae0e73d2014-11-24 11:56:26 +0200632
Marc Koderer3b57d802016-03-22 15:23:31 +0100633 if not pool_name:
634 pool_name = CONF.network.floating_network_name
John Warrene74890a2015-11-11 15:18:01 -0500635 floating_ip = (self.compute_floating_ips_client.
Ken'ichi Ohmichie037a6f2015-12-03 06:41:49 +0000636 create_floating_ip(pool=pool_name)['floating_ip'])
Jordan Pittier9e227c52016-02-09 14:35:18 +0100637 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
John Warrene74890a2015-11-11 15:18:01 -0500638 self.compute_floating_ips_client.delete_floating_ip,
Yair Friedae0e73d2014-11-24 11:56:26 +0200639 floating_ip['id'])
John Warrene74890a2015-11-11 15:18:01 -0500640 self.compute_floating_ips_client.associate_floating_ip_to_server(
Yair Friedae0e73d2014-11-24 11:56:26 +0200641 floating_ip['ip'], thing['id'])
642 return floating_ip
643
Sean Dague20e98612016-01-06 14:33:28 -0500644 def create_timestamp(self, ip_address, dev_name=None, mount_path='/mnt',
Matt Riedemannfd5657d2015-09-30 14:47:07 -0700645 private_key=None):
Sean Dague20e98612016-01-06 14:33:28 -0500646 ssh_client = self.get_remote_client(ip_address,
Matt Riedemannfd5657d2015-09-30 14:47:07 -0700647 private_key=private_key)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300648 if dev_name is not None:
649 ssh_client.make_fs(dev_name)
Matt Riedemann076685a2015-09-30 14:38:16 -0700650 ssh_client.mount(dev_name, mount_path)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300651 cmd_timestamp = 'sudo sh -c "date > %s/timestamp; sync"' % mount_path
652 ssh_client.exec_command(cmd_timestamp)
653 timestamp = ssh_client.exec_command('sudo cat %s/timestamp'
654 % mount_path)
655 if dev_name is not None:
656 ssh_client.umount(mount_path)
657 return timestamp
658
Sean Dague20e98612016-01-06 14:33:28 -0500659 def get_timestamp(self, ip_address, dev_name=None, mount_path='/mnt',
Matt Riedemannfd5657d2015-09-30 14:47:07 -0700660 private_key=None):
Sean Dague20e98612016-01-06 14:33:28 -0500661 ssh_client = self.get_remote_client(ip_address,
Matt Riedemannfd5657d2015-09-30 14:47:07 -0700662 private_key=private_key)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300663 if dev_name is not None:
Matt Riedemann076685a2015-09-30 14:38:16 -0700664 ssh_client.mount(dev_name, mount_path)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300665 timestamp = ssh_client.exec_command('sudo cat %s/timestamp'
666 % mount_path)
667 if dev_name is not None:
668 ssh_client.umount(mount_path)
669 return timestamp
670
Sean Dague20e98612016-01-06 14:33:28 -0500671 def get_server_ip(self, server):
672 """Get the server fixed or floating IP.
673
674 Based on the configuration we're in, return a correct ip
675 address for validating that a guest is up.
676 """
Alexander Gubanovc8829f82015-11-12 10:35:13 +0200677 if CONF.validation.connect_method == 'floating':
Sean Dague20e98612016-01-06 14:33:28 -0500678 # The tests calling this method don't have a floating IP
zhufl0892cb22016-05-06 14:46:00 +0800679 # and can't make use of the validation resources. So the
Sean Dague20e98612016-01-06 14:33:28 -0500680 # method is creating the floating IP there.
681 return self.create_floating_ip(server)['ip']
682 elif CONF.validation.connect_method == 'fixed':
683 addresses = server['addresses'][CONF.validation.network_for_ssh]
684 for address in addresses:
685 if address['version'] == CONF.validation.ip_version_for_ssh:
686 return address['addr']
zhufl955f82b2016-07-22 11:14:34 +0800687 raise exceptions.ServerUnreachable(server_id=server['id'])
Alexander Gubanovc8829f82015-11-12 10:35:13 +0200688 else:
Sean Dague20e98612016-01-06 14:33:28 -0500689 raise exceptions.InvalidConfiguration()
Alexander Gubanovc8829f82015-11-12 10:35:13 +0200690
Andrea Frittoli2e733b52014-07-16 14:12:11 +0100691
Andrea Frittoli4971fc82014-09-25 10:22:20 +0100692class NetworkScenarioTest(ScenarioTest):
Yair Fried1fc32a12014-08-04 09:11:30 +0300693 """Base class for network scenario tests.
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000694
Yair Fried1fc32a12014-08-04 09:11:30 +0300695 This class provide helpers for network scenario tests, using the neutron
696 API. Helpers from ancestor which use the nova network API are overridden
697 with the neutron API.
698
699 This Class also enforces using Neutron instead of novanetwork.
700 Subclassed tests will be skipped if Neutron is not enabled
701
702 """
703
Andrea Frittolib21de6c2015-02-06 20:12:38 +0000704 credentials = ['primary', 'admin']
705
Yair Fried1fc32a12014-08-04 09:11:30 +0300706 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +0000707 def skip_checks(cls):
708 super(NetworkScenarioTest, cls).skip_checks()
Andrea Frittoli2ddc2632014-09-25 11:03:00 +0100709 if not CONF.service_available.neutron:
710 raise cls.skipException('Neutron not available')
Yair Fried1fc32a12014-08-04 09:11:30 +0300711
712 @classmethod
Andrea Frittoliac20b5e2014-09-15 13:31:14 +0100713 def resource_setup(cls):
714 super(NetworkScenarioTest, cls).resource_setup()
Yair Fried1fc32a12014-08-04 09:11:30 +0300715 cls.tenant_id = cls.manager.identity_client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300716
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -0700717 def _create_network(self, networks_client=None,
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000718 routers_client=None, tenant_id=None,
719 namestart='network-smoke-'):
John Warren94d8faf2015-09-15 12:22:24 -0400720 if not networks_client:
721 networks_client = self.networks_client
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000722 if not routers_client:
723 routers_client = self.routers_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300724 if not tenant_id:
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -0700725 tenant_id = networks_client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300726 name = data_utils.rand_name(namestart)
John Warren94d8faf2015-09-15 12:22:24 -0400727 result = networks_client.create_network(name=name, tenant_id=tenant_id)
Steve Heyman33735f22016-05-24 09:28:08 -0500728 network = result['network']
729
730 self.assertEqual(network['name'], name)
Jordan Pittier9e227c52016-02-09 14:35:18 +0100731 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
Steve Heyman33735f22016-05-24 09:28:08 -0500732 self.networks_client.delete_network,
733 network['id'])
Yair Fried1fc32a12014-08-04 09:11:30 +0300734 return network
735
736 def _list_networks(self, *args, **kwargs):
737 """List networks using admin creds """
John Warren94d8faf2015-09-15 12:22:24 -0400738 networks_list = self.admin_manager.networks_client.list_networks(
ghanshyam2f7cc022015-06-26 18:18:11 +0900739 *args, **kwargs)
740 return networks_list['networks']
Yair Fried1fc32a12014-08-04 09:11:30 +0300741
742 def _list_subnets(self, *args, **kwargs):
743 """List subnets using admin creds """
John Warren3961acd2015-10-02 14:38:53 -0400744 subnets_list = self.admin_manager.subnets_client.list_subnets(
ghanshyam2f7cc022015-06-26 18:18:11 +0900745 *args, **kwargs)
746 return subnets_list['subnets']
Yair Fried1fc32a12014-08-04 09:11:30 +0300747
748 def _list_routers(self, *args, **kwargs):
749 """List routers using admin creds """
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000750 routers_list = self.admin_manager.routers_client.list_routers(
ghanshyam2f7cc022015-06-26 18:18:11 +0900751 *args, **kwargs)
752 return routers_list['routers']
Yair Fried1fc32a12014-08-04 09:11:30 +0300753
754 def _list_ports(self, *args, **kwargs):
755 """List ports using admin creds """
John Warren49c0fe52015-10-22 12:35:54 -0400756 ports_list = self.admin_manager.ports_client.list_ports(
ghanshyam2f7cc022015-06-26 18:18:11 +0900757 *args, **kwargs)
758 return ports_list['ports']
Yair Fried1fc32a12014-08-04 09:11:30 +0300759
Yair Fried564d89d2015-08-06 17:02:12 +0300760 def _list_agents(self, *args, **kwargs):
761 """List agents using admin creds """
Ken'ichi Ohmichi71860062015-12-15 08:20:13 +0000762 agents_list = self.admin_manager.network_agents_client.list_agents(
Yair Fried564d89d2015-08-06 17:02:12 +0300763 *args, **kwargs)
764 return agents_list['agents']
765
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -0700766 def _create_subnet(self, network, subnets_client=None,
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000767 routers_client=None, namestart='subnet-smoke',
768 **kwargs):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000769 """Create a subnet for the given network
770
771 within the cidr block configured for tenant networks.
Yair Fried1fc32a12014-08-04 09:11:30 +0300772 """
John Warren3961acd2015-10-02 14:38:53 -0400773 if not subnets_client:
774 subnets_client = self.subnets_client
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000775 if not routers_client:
776 routers_client = self.routers_client
Yair Fried1fc32a12014-08-04 09:11:30 +0300777
778 def cidr_in_use(cidr, tenant_id):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000779 """Check cidr existence
780
lei zhangdd552b22015-11-25 20:41:48 +0800781 :returns: True if subnet with cidr already exist in tenant
782 False else
Yair Fried1fc32a12014-08-04 09:11:30 +0300783 """
784 cidr_in_use = self._list_subnets(tenant_id=tenant_id, cidr=cidr)
785 return len(cidr_in_use) != 0
786
Kirill Shileev14113572014-11-21 16:58:02 +0300787 ip_version = kwargs.pop('ip_version', 4)
788
789 if ip_version == 6:
790 tenant_cidr = netaddr.IPNetwork(
Sean Dagueed6e5862016-04-04 10:49:13 -0400791 CONF.network.project_network_v6_cidr)
792 num_bits = CONF.network.project_network_v6_mask_bits
Kirill Shileev14113572014-11-21 16:58:02 +0300793 else:
Sean Dagueed6e5862016-04-04 10:49:13 -0400794 tenant_cidr = netaddr.IPNetwork(CONF.network.project_network_cidr)
795 num_bits = CONF.network.project_network_mask_bits
Kirill Shileev14113572014-11-21 16:58:02 +0300796
Yair Fried1fc32a12014-08-04 09:11:30 +0300797 result = None
Kirill Shileev14113572014-11-21 16:58:02 +0300798 str_cidr = None
Yair Fried1fc32a12014-08-04 09:11:30 +0300799 # Repeatedly attempt subnet creation with sequential cidr
800 # blocks until an unallocated block is found.
Kirill Shileev14113572014-11-21 16:58:02 +0300801 for subnet_cidr in tenant_cidr.subnet(num_bits):
Yair Fried1fc32a12014-08-04 09:11:30 +0300802 str_cidr = str(subnet_cidr)
Steve Heyman33735f22016-05-24 09:28:08 -0500803 if cidr_in_use(str_cidr, tenant_id=network['tenant_id']):
Yair Fried1fc32a12014-08-04 09:11:30 +0300804 continue
805
806 subnet = dict(
807 name=data_utils.rand_name(namestart),
Steve Heyman33735f22016-05-24 09:28:08 -0500808 network_id=network['id'],
809 tenant_id=network['tenant_id'],
Yair Fried1fc32a12014-08-04 09:11:30 +0300810 cidr=str_cidr,
Kirill Shileev14113572014-11-21 16:58:02 +0300811 ip_version=ip_version,
Yair Fried1fc32a12014-08-04 09:11:30 +0300812 **kwargs
813 )
814 try:
John Warren3961acd2015-10-02 14:38:53 -0400815 result = subnets_client.create_subnet(**subnet)
Yair Fried1fc32a12014-08-04 09:11:30 +0300816 break
Masayuki Igawad9388762015-01-20 14:56:42 +0900817 except lib_exc.Conflict as e:
Yair Fried1fc32a12014-08-04 09:11:30 +0300818 is_overlapping_cidr = 'overlaps with another subnet' in str(e)
819 if not is_overlapping_cidr:
820 raise
821 self.assertIsNotNone(result, 'Unable to allocate tenant network')
Steve Heyman33735f22016-05-24 09:28:08 -0500822
823 subnet = result['subnet']
824 self.assertEqual(subnet['cidr'], str_cidr)
825
826 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
827 subnets_client.delete_subnet, subnet['id'])
828
Yair Fried1fc32a12014-08-04 09:11:30 +0300829 return subnet
830
Kirill Shileev14113572014-11-21 16:58:02 +0300831 def _get_server_port_id_and_ip4(self, server, ip_addr=None):
Kevin Benton1d0c1dc2016-02-04 14:30:08 -0800832 ports = self._list_ports(device_id=server['id'], fixed_ip=ip_addr)
Sean M. Collins2e896832015-12-15 13:58:47 -0500833 # A port can have more then one IP address in some cases.
834 # If the network is dual-stack (IPv4 + IPv6), this port is associated
835 # with 2 subnets
Vasyl Saienko8fd517c2016-05-30 09:52:54 +0300836 p_status = ['ACTIVE']
837 # NOTE(vsaienko) With Ironic, instances live on separate hardware
838 # servers. Neutron does not bind ports for Ironic instances, as a
839 # result the port remains in the DOWN state.
Vasyl Saienkoc8aa34b2016-08-01 14:18:37 +0300840 # TODO(vsaienko) remove once bug: #1599836 is resolved.
Vasyl Saienko8fd517c2016-05-30 09:52:54 +0300841 if CONF.service_available.ironic:
842 p_status.append('DOWN')
Daniel Mellado9e3e1062015-08-06 18:07:05 +0200843 port_map = [(p["id"], fxip["ip_address"])
844 for p in ports
845 for fxip in p["fixed_ips"]
Yatin Kumbhareee4924c2016-06-09 15:12:06 +0530846 if netutils.is_valid_ipv4(fxip["ip_address"])
Vasyl Saienko8fd517c2016-05-30 09:52:54 +0300847 and p['status'] in p_status]
Kevin Benton1d0c1dc2016-02-04 14:30:08 -0800848 inactive = [p for p in ports if p['status'] != 'ACTIVE']
849 if inactive:
850 LOG.warning("Instance has ports that are not ACTIVE: %s", inactive)
Daniel Mellado9e3e1062015-08-06 18:07:05 +0200851
John L. Villalovosb83286f2015-11-04 14:46:57 -0800852 self.assertNotEqual(0, len(port_map),
853 "No IPv4 addresses found in: %s" % ports)
Daniel Mellado9e3e1062015-08-06 18:07:05 +0200854 self.assertEqual(len(port_map), 1,
855 "Found multiple IPv4 addresses: %s. "
856 "Unable to determine which port to target."
857 % port_map)
858 return port_map[0]
Yair Fried1fc32a12014-08-04 09:11:30 +0300859
David Shrewsbury9bac3662014-08-07 15:07:01 -0400860 def _get_network_by_name(self, network_name):
861 net = self._list_networks(name=network_name)
Adam Gandelman878a5fd2015-03-30 14:33:36 -0700862 self.assertNotEqual(len(net), 0,
863 "Unable to get network by name: %s" % network_name)
Steve Heyman33735f22016-05-24 09:28:08 -0500864 return net[0]
David Shrewsbury9bac3662014-08-07 15:07:01 -0400865
Yair Friedae0e73d2014-11-24 11:56:26 +0200866 def create_floating_ip(self, thing, external_network_id=None,
867 port_id=None, client=None):
Ken'ichi Ohmichia112a592015-11-17 08:49:37 +0000868 """Create a floating IP and associates to a resource/port on Neutron"""
Yair Friedae0e73d2014-11-24 11:56:26 +0200869 if not external_network_id:
870 external_network_id = CONF.network.public_network_id
Yair Frieddb6c9e92014-08-06 08:53:13 +0300871 if not client:
John Warrenfbf2a892015-11-17 12:36:14 -0500872 client = self.floating_ips_client
Yair Fried1fc32a12014-08-04 09:11:30 +0300873 if not port_id:
Kirill Shileev14113572014-11-21 16:58:02 +0300874 port_id, ip4 = self._get_server_port_id_and_ip4(thing)
875 else:
876 ip4 = None
David Kranz34e88122014-12-11 15:24:05 -0500877 result = client.create_floatingip(
Yair Fried1fc32a12014-08-04 09:11:30 +0300878 floating_network_id=external_network_id,
879 port_id=port_id,
Kirill Shileev14113572014-11-21 16:58:02 +0300880 tenant_id=thing['tenant_id'],
881 fixed_ip_address=ip4
Yair Fried1fc32a12014-08-04 09:11:30 +0300882 )
Steve Heyman33735f22016-05-24 09:28:08 -0500883 floating_ip = result['floatingip']
Jordan Pittier9e227c52016-02-09 14:35:18 +0100884 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
Steve Heyman33735f22016-05-24 09:28:08 -0500885 self.floating_ips_client.delete_floatingip,
886 floating_ip['id'])
Yair Fried1fc32a12014-08-04 09:11:30 +0300887 return floating_ip
888
889 def _associate_floating_ip(self, floating_ip, server):
Kirill Shileev14113572014-11-21 16:58:02 +0300890 port_id, _ = self._get_server_port_id_and_ip4(server)
Steve Heyman33735f22016-05-24 09:28:08 -0500891 kwargs = dict(port_id=port_id)
892 floating_ip = self.floating_ips_client.update_floatingip(
893 floating_ip['id'], **kwargs)['floatingip']
894 self.assertEqual(port_id, floating_ip['port_id'])
Yair Fried1fc32a12014-08-04 09:11:30 +0300895 return floating_ip
896
897 def _disassociate_floating_ip(self, floating_ip):
Steve Heyman33735f22016-05-24 09:28:08 -0500898 """:param floating_ip: floating_ips_client.create_floatingip"""
899 kwargs = dict(port_id=None)
900 floating_ip = self.floating_ips_client.update_floatingip(
901 floating_ip['id'], **kwargs)['floatingip']
902 self.assertIsNone(floating_ip['port_id'])
Yair Fried1fc32a12014-08-04 09:11:30 +0300903 return floating_ip
904
Yair Fried45f92952014-06-26 05:19:19 +0300905 def check_floating_ip_status(self, floating_ip, status):
Carl Baldwina754e2d2014-10-23 22:47:41 +0000906 """Verifies floatingip reaches the given status
Yair Fried45f92952014-06-26 05:19:19 +0300907
Steve Heyman33735f22016-05-24 09:28:08 -0500908 :param dict floating_ip: floating IP dict to check status
Yair Fried45f92952014-06-26 05:19:19 +0300909 :param status: target status
910 :raises: AssertionError if status doesn't match
911 """
Steve Heyman33735f22016-05-24 09:28:08 -0500912 floatingip_id = floating_ip['id']
913
Carl Baldwina754e2d2014-10-23 22:47:41 +0000914 def refresh():
Steve Heyman33735f22016-05-24 09:28:08 -0500915 result = (self.floating_ips_client.
916 show_floatingip(floatingip_id)['floatingip'])
917 return status == result['status']
Carl Baldwina754e2d2014-10-23 22:47:41 +0000918
919 tempest.test.call_until_true(refresh,
920 CONF.network.build_timeout,
921 CONF.network.build_interval)
Steve Heyman33735f22016-05-24 09:28:08 -0500922 floating_ip = self.floating_ips_client.show_floatingip(
923 floatingip_id)['floatingip']
924 self.assertEqual(status, floating_ip['status'],
Yair Fried45f92952014-06-26 05:19:19 +0300925 message="FloatingIP: {fp} is at status: {cst}. "
926 "failed to reach status: {st}"
Steve Heyman33735f22016-05-24 09:28:08 -0500927 .format(fp=floating_ip, cst=floating_ip['status'],
Yair Fried45f92952014-06-26 05:19:19 +0300928 st=status))
929 LOG.info("FloatingIP: {fp} is at status: {st}"
930 .format(fp=floating_ip, st=status))
931
Yair Fried1fc32a12014-08-04 09:11:30 +0300932 def _check_tenant_network_connectivity(self, server,
933 username,
934 private_key,
935 should_connect=True,
936 servers_for_debug=None):
Sean Dagueed6e5862016-04-04 10:49:13 -0400937 if not CONF.network.project_networks_reachable:
Yair Fried1fc32a12014-08-04 09:11:30 +0300938 msg = 'Tenant networks not configured to be reachable.'
939 LOG.info(msg)
940 return
941 # The target login is assumed to have been configured for
942 # key-based authentication by cloud-init.
943 try:
Matthew Treinish71426682015-04-23 11:19:38 -0400944 for net_name, ip_addresses in six.iteritems(server['addresses']):
Yair Fried1fc32a12014-08-04 09:11:30 +0300945 for ip_address in ip_addresses:
ghanshyam807211c2014-12-18 13:21:22 +0900946 self.check_vm_connectivity(ip_address['addr'],
Yair Friedae0e73d2014-11-24 11:56:26 +0200947 username,
948 private_key,
949 should_connect=should_connect)
Yair Fried1fc32a12014-08-04 09:11:30 +0300950 except Exception as e:
951 LOG.exception('Tenant network connectivity check failed')
952 self._log_console_output(servers_for_debug)
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000953 self._log_net_info(e)
Yair Fried1fc32a12014-08-04 09:11:30 +0300954 raise
955
Yair Friedbc46f592015-11-18 16:29:34 +0200956 def _check_remote_connectivity(self, source, dest, should_succeed=True,
957 nic=None):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000958 """check ping server via source ssh connection
Yair Fried1fc32a12014-08-04 09:11:30 +0300959
960 :param source: RemoteClient: an ssh connection from which to ping
961 :param dest: and IP to ping against
962 :param should_succeed: boolean should ping succeed or not
Yair Friedbc46f592015-11-18 16:29:34 +0200963 :param nic: specific network interface to ping from
Yair Fried1fc32a12014-08-04 09:11:30 +0300964 :returns: boolean -- should_succeed == ping
965 :returns: ping is false if ping failed
966 """
967 def ping_remote():
968 try:
Yair Friedbc46f592015-11-18 16:29:34 +0200969 source.ping_host(dest, nic=nic)
Andrey Pavlov64723762015-04-29 06:24:58 +0300970 except lib_exc.SSHExecCommandFailed:
zhangguoqing6c096642016-01-04 06:17:21 +0000971 LOG.warning('Failed to ping IP: %s via a ssh connection '
972 'from: %s.' % (dest, source.ssh_client.host))
Yair Fried1fc32a12014-08-04 09:11:30 +0300973 return not should_succeed
974 return should_succeed
975
976 return tempest.test.call_until_true(ping_remote,
lanoux5fc14522015-09-21 08:17:35 +0000977 CONF.validation.ping_timeout,
Yair Fried1fc32a12014-08-04 09:11:30 +0300978 1)
979
John Warren456d9ae2016-01-12 15:36:33 -0500980 def _create_security_group(self, security_group_rules_client=None,
981 tenant_id=None,
John Warrenf9606e92015-12-10 12:12:42 -0500982 namestart='secgroup-smoke',
983 security_groups_client=None):
John Warren456d9ae2016-01-12 15:36:33 -0500984 if security_group_rules_client is None:
985 security_group_rules_client = self.security_group_rules_client
John Warrenf9606e92015-12-10 12:12:42 -0500986 if security_groups_client is None:
987 security_groups_client = self.security_groups_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300988 if tenant_id is None:
John Warrenf9606e92015-12-10 12:12:42 -0500989 tenant_id = security_groups_client.tenant_id
990 secgroup = self._create_empty_security_group(
991 namestart=namestart, client=security_groups_client,
992 tenant_id=tenant_id)
Yair Fried1fc32a12014-08-04 09:11:30 +0300993
994 # Add rules to the security group
John Warrenf9606e92015-12-10 12:12:42 -0500995 rules = self._create_loginable_secgroup_rule(
John Warren456d9ae2016-01-12 15:36:33 -0500996 security_group_rules_client=security_group_rules_client,
997 secgroup=secgroup,
John Warrenf9606e92015-12-10 12:12:42 -0500998 security_groups_client=security_groups_client)
Yair Fried1fc32a12014-08-04 09:11:30 +0300999 for rule in rules:
Steve Heyman33735f22016-05-24 09:28:08 -05001000 self.assertEqual(tenant_id, rule['tenant_id'])
1001 self.assertEqual(secgroup['id'], rule['security_group_id'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001002 return secgroup
1003
Yair Frieddb6c9e92014-08-06 08:53:13 +03001004 def _create_empty_security_group(self, client=None, tenant_id=None,
Yair Fried1fc32a12014-08-04 09:11:30 +03001005 namestart='secgroup-smoke'):
1006 """Create a security group without rules.
1007
1008 Default rules will be created:
1009 - IPv4 egress to any
1010 - IPv6 egress to any
1011
1012 :param tenant_id: secgroup will be created in this tenant
Steve Heyman33735f22016-05-24 09:28:08 -05001013 :returns: the created security group
Yair Fried1fc32a12014-08-04 09:11:30 +03001014 """
1015 if client is None:
John Warrenf9606e92015-12-10 12:12:42 -05001016 client = self.security_groups_client
Yair Frieddb6c9e92014-08-06 08:53:13 +03001017 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +00001018 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001019 sg_name = data_utils.rand_name(namestart)
1020 sg_desc = sg_name + " description"
1021 sg_dict = dict(name=sg_name,
1022 description=sg_desc)
1023 sg_dict['tenant_id'] = tenant_id
David Kranz34e88122014-12-11 15:24:05 -05001024 result = client.create_security_group(**sg_dict)
Steve Heyman33735f22016-05-24 09:28:08 -05001025
1026 secgroup = result['security_group']
1027 self.assertEqual(secgroup['name'], sg_name)
1028 self.assertEqual(tenant_id, secgroup['tenant_id'])
1029 self.assertEqual(secgroup['description'], sg_desc)
1030
Jordan Pittier9e227c52016-02-09 14:35:18 +01001031 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
Steve Heyman33735f22016-05-24 09:28:08 -05001032 client.delete_security_group, secgroup['id'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001033 return secgroup
1034
Yair Frieddb6c9e92014-08-06 08:53:13 +03001035 def _default_security_group(self, client=None, tenant_id=None):
Yair Fried1fc32a12014-08-04 09:11:30 +03001036 """Get default secgroup for given tenant_id.
1037
1038 :returns: DeletableSecurityGroup -- default secgroup for given tenant
1039 """
1040 if client is None:
John Warrenf9606e92015-12-10 12:12:42 -05001041 client = self.security_groups_client
Yair Frieddb6c9e92014-08-06 08:53:13 +03001042 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +00001043 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001044 sgs = [
Jordan Pittier8ad86172016-04-25 16:20:53 +02001045 sg for sg in list(client.list_security_groups().values())[0]
Yair Fried1fc32a12014-08-04 09:11:30 +03001046 if sg['tenant_id'] == tenant_id and sg['name'] == 'default'
1047 ]
1048 msg = "No default security group for tenant %s." % (tenant_id)
1049 self.assertTrue(len(sgs) > 0, msg)
Steve Heyman33735f22016-05-24 09:28:08 -05001050 return sgs[0]
Yair Fried1fc32a12014-08-04 09:11:30 +03001051
John Warren456d9ae2016-01-12 15:36:33 -05001052 def _create_security_group_rule(self, secgroup=None,
1053 sec_group_rules_client=None,
John Warrenf9606e92015-12-10 12:12:42 -05001054 tenant_id=None,
1055 security_groups_client=None, **kwargs):
Yair Fried1fc32a12014-08-04 09:11:30 +03001056 """Create a rule from a dictionary of rule parameters.
1057
1058 Create a rule in a secgroup. if secgroup not defined will search for
1059 default secgroup in tenant_id.
1060
Steve Heyman33735f22016-05-24 09:28:08 -05001061 :param secgroup: the security group.
Yair Fried1fc32a12014-08-04 09:11:30 +03001062 :param tenant_id: if secgroup not passed -- the tenant in which to
1063 search for default secgroup
1064 :param kwargs: a dictionary containing rule parameters:
1065 for example, to allow incoming ssh:
1066 rule = {
1067 direction: 'ingress'
1068 protocol:'tcp',
1069 port_range_min: 22,
1070 port_range_max: 22
1071 }
1072 """
John Warren456d9ae2016-01-12 15:36:33 -05001073 if sec_group_rules_client is None:
1074 sec_group_rules_client = self.security_group_rules_client
John Warrenf9606e92015-12-10 12:12:42 -05001075 if security_groups_client is None:
1076 security_groups_client = self.security_groups_client
Yair Frieddb6c9e92014-08-06 08:53:13 +03001077 if not tenant_id:
John Warrenf9606e92015-12-10 12:12:42 -05001078 tenant_id = security_groups_client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001079 if secgroup is None:
John Warrenf9606e92015-12-10 12:12:42 -05001080 secgroup = self._default_security_group(
1081 client=security_groups_client, tenant_id=tenant_id)
Yair Fried1fc32a12014-08-04 09:11:30 +03001082
Steve Heyman33735f22016-05-24 09:28:08 -05001083 ruleset = dict(security_group_id=secgroup['id'],
1084 tenant_id=secgroup['tenant_id'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001085 ruleset.update(kwargs)
1086
John Warren456d9ae2016-01-12 15:36:33 -05001087 sg_rule = sec_group_rules_client.create_security_group_rule(**ruleset)
Steve Heyman33735f22016-05-24 09:28:08 -05001088 sg_rule = sg_rule['security_group_rule']
1089
1090 self.assertEqual(secgroup['tenant_id'], sg_rule['tenant_id'])
1091 self.assertEqual(secgroup['id'], sg_rule['security_group_id'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001092
1093 return sg_rule
1094
John Warren456d9ae2016-01-12 15:36:33 -05001095 def _create_loginable_secgroup_rule(self, security_group_rules_client=None,
1096 secgroup=None,
John Warrenf9606e92015-12-10 12:12:42 -05001097 security_groups_client=None):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001098 """Create loginable security group rule
1099
Alex Stafeyevdd5dde92016-05-08 14:35:04 +03001100 This function will create:
1101 1. egress and ingress tcp port 22 allow rule in order to allow ssh
1102 access for ipv4.
1103 2. egress and ingress ipv6 icmp allow rule, in order to allow icmpv6.
1104 3. egress and ingress ipv4 icmp allow rule, in order to allow icmpv4.
Yair Fried1fc32a12014-08-04 09:11:30 +03001105 """
1106
John Warren456d9ae2016-01-12 15:36:33 -05001107 if security_group_rules_client is None:
1108 security_group_rules_client = self.security_group_rules_client
John Warrenf9606e92015-12-10 12:12:42 -05001109 if security_groups_client is None:
1110 security_groups_client = self.security_groups_client
Yair Fried1fc32a12014-08-04 09:11:30 +03001111 rules = []
1112 rulesets = [
1113 dict(
1114 # ssh
1115 protocol='tcp',
1116 port_range_min=22,
1117 port_range_max=22,
1118 ),
1119 dict(
1120 # ping
1121 protocol='icmp',
Andreas Scheuring887ca8e2015-02-03 17:56:12 +01001122 ),
1123 dict(
1124 # ipv6-icmp for ping6
1125 protocol='icmp',
1126 ethertype='IPv6',
Yair Fried1fc32a12014-08-04 09:11:30 +03001127 )
1128 ]
John Warren456d9ae2016-01-12 15:36:33 -05001129 sec_group_rules_client = security_group_rules_client
Yair Fried1fc32a12014-08-04 09:11:30 +03001130 for ruleset in rulesets:
1131 for r_direction in ['ingress', 'egress']:
1132 ruleset['direction'] = r_direction
1133 try:
1134 sg_rule = self._create_security_group_rule(
John Warren456d9ae2016-01-12 15:36:33 -05001135 sec_group_rules_client=sec_group_rules_client,
1136 secgroup=secgroup,
John Warrenf9606e92015-12-10 12:12:42 -05001137 security_groups_client=security_groups_client,
1138 **ruleset)
Masayuki Igawad9388762015-01-20 14:56:42 +09001139 except lib_exc.Conflict as ex:
Yair Fried1fc32a12014-08-04 09:11:30 +03001140 # if rule already exist - skip rule and continue
1141 msg = 'Security group rule already exists'
1142 if msg not in ex._error_string:
1143 raise ex
1144 else:
Steve Heyman33735f22016-05-24 09:28:08 -05001145 self.assertEqual(r_direction, sg_rule['direction'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001146 rules.append(sg_rule)
1147
1148 return rules
1149
Yair Frieddb6c9e92014-08-06 08:53:13 +03001150 def _get_router(self, client=None, tenant_id=None):
Yair Fried1fc32a12014-08-04 09:11:30 +03001151 """Retrieve a router for the given tenant id.
1152
1153 If a public router has been configured, it will be returned.
1154
1155 If a public router has not been configured, but a public
1156 network has, a tenant router will be created and returned that
1157 routes traffic to the public network.
1158 """
Yair Frieddb6c9e92014-08-06 08:53:13 +03001159 if not client:
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +00001160 client = self.routers_client
Yair Frieddb6c9e92014-08-06 08:53:13 +03001161 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +00001162 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001163 router_id = CONF.network.public_router_id
1164 network_id = CONF.network.public_network_id
1165 if router_id:
David Kranzca4c7e72015-05-27 11:39:19 -04001166 body = client.show_router(router_id)
Steve Heyman33735f22016-05-24 09:28:08 -05001167 return body['router']
Yair Fried1fc32a12014-08-04 09:11:30 +03001168 elif network_id:
Yair Frieddb6c9e92014-08-06 08:53:13 +03001169 router = self._create_router(client, tenant_id)
Steve Heyman33735f22016-05-24 09:28:08 -05001170 kwargs = {'external_gateway_info': dict(network_id=network_id)}
1171 router = client.update_router(router['id'], **kwargs)['router']
Yair Fried1fc32a12014-08-04 09:11:30 +03001172 return router
1173 else:
1174 raise Exception("Neither of 'public_router_id' or "
1175 "'public_network_id' has been defined.")
1176
Yair Frieddb6c9e92014-08-06 08:53:13 +03001177 def _create_router(self, client=None, tenant_id=None,
1178 namestart='router-smoke'):
1179 if not client:
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +00001180 client = self.routers_client
Yair Frieddb6c9e92014-08-06 08:53:13 +03001181 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +00001182 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001183 name = data_utils.rand_name(namestart)
David Kranz34e88122014-12-11 15:24:05 -05001184 result = client.create_router(name=name,
1185 admin_state_up=True,
1186 tenant_id=tenant_id)
Steve Heyman33735f22016-05-24 09:28:08 -05001187 router = result['router']
1188 self.assertEqual(router['name'], name)
1189 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
1190 client.delete_router,
1191 router['id'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001192 return router
1193
Alok Maurya6384bbb2014-07-13 06:44:29 -07001194 def _update_router_admin_state(self, router, admin_state_up):
Steve Heyman33735f22016-05-24 09:28:08 -05001195 kwargs = dict(admin_state_up=admin_state_up)
1196 router = self.routers_client.update_router(
1197 router['id'], **kwargs)['router']
1198 self.assertEqual(admin_state_up, router['admin_state_up'])
Alok Maurya6384bbb2014-07-13 06:44:29 -07001199
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -07001200 def create_networks(self, networks_client=None,
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +00001201 routers_client=None, subnets_client=None,
1202 tenant_id=None, dns_nameservers=None):
Yair Fried1fc32a12014-08-04 09:11:30 +03001203 """Create a network with a subnet connected to a router.
1204
David Shrewsbury9bac3662014-08-07 15:07:01 -04001205 The baremetal driver is a special case since all nodes are
1206 on the same shared network.
1207
Yair Fried413bf2d2014-11-19 17:07:11 +02001208 :param tenant_id: id of tenant to create resources in.
1209 :param dns_nameservers: list of dns servers to send to subnet.
Yair Fried1fc32a12014-08-04 09:11:30 +03001210 :returns: network, subnet, router
1211 """
David Shrewsbury9bac3662014-08-07 15:07:01 -04001212 if CONF.baremetal.driver_enabled:
1213 # NOTE(Shrews): This exception is for environments where tenant
1214 # credential isolation is available, but network separation is
1215 # not (the current baremetal case). Likely can be removed when
1216 # test account mgmt is reworked:
1217 # https://blueprints.launchpad.net/tempest/+spec/test-accounts
Adam Gandelman878a5fd2015-03-30 14:33:36 -07001218 if not CONF.compute.fixed_network_name:
1219 m = 'fixed_network_name must be specified in config'
1220 raise exceptions.InvalidConfiguration(m)
David Shrewsbury9bac3662014-08-07 15:07:01 -04001221 network = self._get_network_by_name(
1222 CONF.compute.fixed_network_name)
1223 router = None
1224 subnet = None
1225 else:
John Warren94d8faf2015-09-15 12:22:24 -04001226 network = self._create_network(
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -07001227 networks_client=networks_client,
John Warren94d8faf2015-09-15 12:22:24 -04001228 tenant_id=tenant_id)
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +00001229 router = self._get_router(client=routers_client,
1230 tenant_id=tenant_id)
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -07001231 subnet_kwargs = dict(network=network,
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +00001232 subnets_client=subnets_client,
1233 routers_client=routers_client)
Yair Fried413bf2d2014-11-19 17:07:11 +02001234 # use explicit check because empty list is a valid option
1235 if dns_nameservers is not None:
1236 subnet_kwargs['dns_nameservers'] = dns_nameservers
1237 subnet = self._create_subnet(**subnet_kwargs)
Steve Heyman33735f22016-05-24 09:28:08 -05001238 if not routers_client:
1239 routers_client = self.routers_client
1240 router_id = router['id']
1241 routers_client.add_router_interface(router_id,
1242 subnet_id=subnet['id'])
1243
1244 # save a cleanup job to remove this association between
1245 # router and subnet
1246 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
1247 routers_client.remove_router_interface, router_id,
1248 subnet_id=subnet['id'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001249 return network, subnet, router
1250
1251
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001252# power/provision states as of icehouse
1253class BaremetalPowerStates(object):
1254 """Possible power states of an Ironic node."""
1255 POWER_ON = 'power on'
1256 POWER_OFF = 'power off'
1257 REBOOT = 'rebooting'
1258 SUSPEND = 'suspended'
1259
1260
1261class BaremetalProvisionStates(object):
1262 """Possible provision states of an Ironic node."""
1263 NOSTATE = None
1264 INIT = 'initializing'
1265 ACTIVE = 'active'
1266 BUILDING = 'building'
1267 DEPLOYWAIT = 'wait call-back'
1268 DEPLOYING = 'deploying'
1269 DEPLOYFAIL = 'deploy failed'
1270 DEPLOYDONE = 'deploy complete'
1271 DELETING = 'deleting'
1272 DELETED = 'deleted'
1273 ERROR = 'error'
1274
1275
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001276class BaremetalScenarioTest(ScenarioTest):
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001277
1278 credentials = ['primary', 'admin']
1279
Adam Gandelman4a48a602014-03-20 18:23:18 -07001280 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001281 def skip_checks(cls):
1282 super(BaremetalScenarioTest, cls).skip_checks()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001283 if (not CONF.service_available.ironic or
1284 not CONF.baremetal.driver_enabled):
1285 msg = 'Ironic not available or Ironic compute driver not enabled'
1286 raise cls.skipException(msg)
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001287
1288 @classmethod
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001289 def setup_clients(cls):
1290 super(BaremetalScenarioTest, cls).setup_clients()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001291
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001292 cls.baremetal_client = cls.admin_manager.baremetal_client
Adam Gandelman4a48a602014-03-20 18:23:18 -07001293
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001294 @classmethod
1295 def resource_setup(cls):
1296 super(BaremetalScenarioTest, cls).resource_setup()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001297 # allow any issues obtaining the node list to raise early
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001298 cls.baremetal_client.list_nodes()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001299
1300 def _node_state_timeout(self, node_id, state_attr,
1301 target_states, timeout=10, interval=1):
1302 if not isinstance(target_states, list):
1303 target_states = [target_states]
1304
1305 def check_state():
1306 node = self.get_node(node_id=node_id)
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001307 if node.get(state_attr) in target_states:
Adam Gandelman4a48a602014-03-20 18:23:18 -07001308 return True
1309 return False
1310
1311 if not tempest.test.call_until_true(
1312 check_state, timeout, interval):
1313 msg = ("Timed out waiting for node %s to reach %s state(s) %s" %
1314 (node_id, state_attr, target_states))
1315 raise exceptions.TimeoutException(msg)
1316
1317 def wait_provisioning_state(self, node_id, state, timeout):
1318 self._node_state_timeout(
1319 node_id=node_id, state_attr='provision_state',
1320 target_states=state, timeout=timeout)
1321
1322 def wait_power_state(self, node_id, state):
1323 self._node_state_timeout(
1324 node_id=node_id, state_attr='power_state',
1325 target_states=state, timeout=CONF.baremetal.power_timeout)
1326
1327 def wait_node(self, instance_id):
1328 """Waits for a node to be associated with instance_id."""
Zhi Kun Liu4a8d1ea2014-04-15 22:08:21 -05001329
Adam Gandelman4a48a602014-03-20 18:23:18 -07001330 def _get_node():
Jordan Pittier9e227c52016-02-09 14:35:18 +01001331 node = test_utils.call_and_ignore_notfound_exc(
1332 self.get_node, instance_id=instance_id)
Adam Gandelman4a48a602014-03-20 18:23:18 -07001333 return node is not None
1334
1335 if not tempest.test.call_until_true(
1336 _get_node, CONF.baremetal.association_timeout, 1):
1337 msg = ('Timed out waiting to get Ironic node by instance id %s'
1338 % instance_id)
1339 raise exceptions.TimeoutException(msg)
1340
1341 def get_node(self, node_id=None, instance_id=None):
1342 if node_id:
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001343 _, body = self.baremetal_client.show_node(node_id)
1344 return body
Adam Gandelman4a48a602014-03-20 18:23:18 -07001345 elif instance_id:
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001346 _, body = self.baremetal_client.show_node_by_instance_uuid(
1347 instance_id)
1348 if body['nodes']:
1349 return body['nodes'][0]
Adam Gandelman4a48a602014-03-20 18:23:18 -07001350
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001351 def get_ports(self, node_uuid):
Adam Gandelman4a48a602014-03-20 18:23:18 -07001352 ports = []
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001353 _, body = self.baremetal_client.list_node_ports(node_uuid)
1354 for port in body['ports']:
1355 _, p = self.baremetal_client.show_port(port['uuid'])
1356 ports.append(p)
Adam Gandelman4a48a602014-03-20 18:23:18 -07001357 return ports
1358
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001359 def add_keypair(self):
1360 self.keypair = self.create_keypair()
1361
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001362 def boot_instance(self):
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001363 self.instance = self.create_server(
lanoux5fc14522015-09-21 08:17:35 +00001364 key_name=self.keypair['name'])
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001365
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001366 self.wait_node(self.instance['id'])
1367 self.node = self.get_node(instance_id=self.instance['id'])
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001368
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001369 self.wait_power_state(self.node['uuid'], BaremetalPowerStates.POWER_ON)
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001370
1371 self.wait_provisioning_state(
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001372 self.node['uuid'],
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001373 [BaremetalProvisionStates.DEPLOYWAIT,
1374 BaremetalProvisionStates.ACTIVE],
1375 timeout=15)
1376
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001377 self.wait_provisioning_state(self.node['uuid'],
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001378 BaremetalProvisionStates.ACTIVE,
1379 timeout=CONF.baremetal.active_timeout)
1380
Ken'ichi Ohmichi0eb153c2015-07-13 02:18:25 +00001381 waiters.wait_for_server_status(self.servers_client,
1382 self.instance['id'], 'ACTIVE')
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001383 self.node = self.get_node(instance_id=self.instance['id'])
ghanshyam0f825252015-08-25 16:02:50 +09001384 self.instance = (self.servers_client.show_server(self.instance['id'])
1385 ['server'])
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001386
1387 def terminate_instance(self):
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001388 self.servers_client.delete_server(self.instance['id'])
1389 self.wait_power_state(self.node['uuid'],
1390 BaremetalPowerStates.POWER_OFF)
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001391 self.wait_provisioning_state(
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001392 self.node['uuid'],
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001393 BaremetalProvisionStates.NOSTATE,
1394 timeout=CONF.baremetal.unprovision_timeout)
1395
Adam Gandelman4a48a602014-03-20 18:23:18 -07001396
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001397class EncryptionScenarioTest(ScenarioTest):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001398 """Base class for encryption scenario tests"""
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001399
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001400 credentials = ['primary', 'admin']
David Kranz4cc852b2015-03-09 14:57:11 -04001401
1402 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001403 def setup_clients(cls):
1404 super(EncryptionScenarioTest, cls).setup_clients()
Ivan Kolodyazhnybcfc32e2015-08-06 13:31:36 +03001405 if CONF.volume_feature_enabled.api_v1:
1406 cls.admin_volume_types_client = cls.os_adm.volume_types_client
1407 else:
1408 cls.admin_volume_types_client = cls.os_adm.volume_types_v2_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001409
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001410 def create_volume_type(self, client=None, name=None):
1411 if not client:
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001412 client = self.admin_volume_types_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001413 if not name:
1414 name = 'generic'
Ken'ichi Ohmichi6ded8df2015-03-23 02:00:19 +00001415 randomized_name = data_utils.rand_name('scenario-type-' + name)
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001416 LOG.debug("Creating a volume type: %s", randomized_name)
Joseph Lanoux6809bab2014-12-18 14:57:18 +00001417 body = client.create_volume_type(
lei zhang83c4bbd2015-11-27 00:35:21 +08001418 name=randomized_name)['volume_type']
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001419 self.assertIn('id', body)
1420 self.addCleanup(client.delete_volume_type, body['id'])
1421 return body
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001422
1423 def create_encryption_type(self, client=None, type_id=None, provider=None,
1424 key_size=None, cipher=None,
1425 control_location=None):
1426 if not client:
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001427 client = self.admin_volume_types_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001428 if not type_id:
1429 volume_type = self.create_volume_type()
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001430 type_id = volume_type['id']
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001431 LOG.debug("Creating an encryption type for volume type: %s", type_id)
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001432 client.create_encryption_type(
1433 type_id, provider=provider, key_size=key_size, cipher=cipher,
John Warrend053ded2015-08-13 15:22:48 +00001434 control_location=control_location)['encryption']
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001435
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001436
Masayuki Igawa0870db52015-09-18 21:08:36 +09001437class ObjectStorageScenarioTest(ScenarioTest):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001438 """Provide harness to do Object Storage scenario tests.
Chris Dent0d494112014-08-26 13:48:30 +01001439
1440 Subclasses implement the tests that use the methods provided by this
1441 class.
1442 """
1443
1444 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001445 def skip_checks(cls):
Masayuki Igawa0870db52015-09-18 21:08:36 +09001446 super(ObjectStorageScenarioTest, cls).skip_checks()
Chris Dent0d494112014-08-26 13:48:30 +01001447 if not CONF.service_available.swift:
1448 skip_msg = ("%s skipped as swift is not available" %
1449 cls.__name__)
1450 raise cls.skipException(skip_msg)
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001451
1452 @classmethod
1453 def setup_credentials(cls):
Masayuki Igawa60ea6c52014-10-15 17:32:14 +09001454 cls.set_network_resources()
Masayuki Igawa0870db52015-09-18 21:08:36 +09001455 super(ObjectStorageScenarioTest, cls).setup_credentials()
Matthew Treinish4a596932015-03-06 20:37:01 -05001456 operator_role = CONF.object_storage.operator_role
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +01001457 cls.os_operator = cls.get_client_manager(roles=[operator_role])
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001458
1459 @classmethod
1460 def setup_clients(cls):
Masayuki Igawa0870db52015-09-18 21:08:36 +09001461 super(ObjectStorageScenarioTest, cls).setup_clients()
Chris Dent0d494112014-08-26 13:48:30 +01001462 # Clients for Swift
Matthew Treinish8f268292015-02-24 20:01:36 -05001463 cls.account_client = cls.os_operator.account_client
1464 cls.container_client = cls.os_operator.container_client
1465 cls.object_client = cls.os_operator.object_client
Chris Dent0d494112014-08-26 13:48:30 +01001466
Chris Dentde456a12014-09-10 12:41:15 +01001467 def get_swift_stat(self):
Chris Dent0d494112014-08-26 13:48:30 +01001468 """get swift status for our user account."""
1469 self.account_client.list_account_containers()
1470 LOG.debug('Swift status information obtained successfully')
1471
Chris Dentde456a12014-09-10 12:41:15 +01001472 def create_container(self, container_name=None):
Chris Dent0d494112014-08-26 13:48:30 +01001473 name = container_name or data_utils.rand_name(
1474 'swift-scenario-container')
1475 self.container_client.create_container(name)
1476 # look for the container to assure it is created
Chris Dentde456a12014-09-10 12:41:15 +01001477 self.list_and_check_container_objects(name)
Chris Dent0d494112014-08-26 13:48:30 +01001478 LOG.debug('Container %s created' % (name))
Jordan Pittier9e227c52016-02-09 14:35:18 +01001479 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
Chris Dent1d4313a2014-10-28 12:16:48 +00001480 self.container_client.delete_container,
1481 name)
Chris Dent0d494112014-08-26 13:48:30 +01001482 return name
1483
Chris Dentde456a12014-09-10 12:41:15 +01001484 def delete_container(self, container_name):
Chris Dent0d494112014-08-26 13:48:30 +01001485 self.container_client.delete_container(container_name)
1486 LOG.debug('Container %s deleted' % (container_name))
1487
Chris Dentde456a12014-09-10 12:41:15 +01001488 def upload_object_to_container(self, container_name, obj_name=None):
Chris Dent0d494112014-08-26 13:48:30 +01001489 obj_name = obj_name or data_utils.rand_name('swift-scenario-object')
1490 obj_data = data_utils.arbitrary_string()
1491 self.object_client.create_object(container_name, obj_name, obj_data)
Jordan Pittier9e227c52016-02-09 14:35:18 +01001492 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
Chris Dent1d4313a2014-10-28 12:16:48 +00001493 self.object_client.delete_object,
1494 container_name,
1495 obj_name)
Chris Dent0d494112014-08-26 13:48:30 +01001496 return obj_name, obj_data
1497
Chris Dentde456a12014-09-10 12:41:15 +01001498 def delete_object(self, container_name, filename):
Chris Dent0d494112014-08-26 13:48:30 +01001499 self.object_client.delete_object(container_name, filename)
Chris Dentde456a12014-09-10 12:41:15 +01001500 self.list_and_check_container_objects(container_name,
1501 not_present_obj=[filename])
Chris Dent0d494112014-08-26 13:48:30 +01001502
Chris Dentde456a12014-09-10 12:41:15 +01001503 def list_and_check_container_objects(self, container_name,
1504 present_obj=None,
1505 not_present_obj=None):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001506 # List objects for a given container and assert which are present and
1507 # which are not.
Ghanshyam2a180b82014-06-16 13:54:22 +09001508 if present_obj is None:
1509 present_obj = []
1510 if not_present_obj is None:
1511 not_present_obj = []
Chris Dent0d494112014-08-26 13:48:30 +01001512 _, object_list = self.container_client.list_container_contents(
1513 container_name)
1514 if present_obj:
1515 for obj in present_obj:
1516 self.assertIn(obj, object_list)
1517 if not_present_obj:
1518 for obj in not_present_obj:
1519 self.assertNotIn(obj, object_list)
1520
Chris Dentde456a12014-09-10 12:41:15 +01001521 def change_container_acl(self, container_name, acl):
Chris Dent0d494112014-08-26 13:48:30 +01001522 metadata_param = {'metadata_prefix': 'x-container-',
1523 'metadata': {'read': acl}}
1524 self.container_client.update_container_metadata(container_name,
1525 **metadata_param)
1526 resp, _ = self.container_client.list_container_metadata(container_name)
1527 self.assertEqual(resp['x-container-read'], acl)
1528
Chris Dentde456a12014-09-10 12:41:15 +01001529 def download_and_verify(self, container_name, obj_name, expected_data):
Chris Dent0d494112014-08-26 13:48:30 +01001530 _, obj = self.object_client.get_object(container_name, obj_name)
1531 self.assertEqual(obj, expected_data)