blob: 11c96e0b4d6a166d382954e0176a53aad5b72242 [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)
Masayuki Igawabc6fe8d2014-08-29 16:50:01 +090082 # Heat client
83 cls.orchestration_client = cls.manager.orchestration_client
Andrea Frittoli2e733b52014-07-16 14:12:11 +010084
Ivan Kolodyazhnybcfc32e2015-08-06 13:31:36 +030085 if CONF.volume_feature_enabled.api_v1:
86 cls.volumes_client = cls.manager.volumes_client
87 cls.snapshots_client = cls.manager.snapshots_client
88 else:
89 cls.volumes_client = cls.manager.volumes_v2_client
90 cls.snapshots_client = cls.manager.snapshots_v2_client
91
Andrea Frittoli247058f2014-07-16 16:09:22 +010092 # ## Methods to handle sync and async deletes
93
94 def setUp(self):
95 super(ScenarioTest, self).setUp()
96 self.cleanup_waits = []
97 # NOTE(mtreinish) This is safe to do in setUp instead of setUp class
98 # because scenario tests in the same test class should not share
99 # resources. If resources were shared between test cases then it
100 # should be a single scenario test instead of multiples.
101
102 # NOTE(yfried): this list is cleaned at the end of test_methods and
103 # not at the end of the class
104 self.addCleanup(self._wait_for_cleanups)
105
Andrea Frittoli247058f2014-07-16 16:09:22 +0100106 def addCleanup_with_wait(self, waiter_callable, thing_id, thing_id_param,
Ghanshyam2a180b82014-06-16 13:54:22 +0900107 cleanup_callable, cleanup_args=None,
Ken'ichi Ohmichie91a0c62015-08-13 02:09:16 +0000108 cleanup_kwargs=None, waiter_client=None):
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700109 """Adds wait for async resource deletion at the end of cleanups
Andrea Frittoli247058f2014-07-16 16:09:22 +0100110
111 @param waiter_callable: callable to wait for the resource to delete
Ken'ichi Ohmichie91a0c62015-08-13 02:09:16 +0000112 with the following waiter_client if specified.
Andrea Frittoli247058f2014-07-16 16:09:22 +0100113 @param thing_id: the id of the resource to be cleaned-up
114 @param thing_id_param: the name of the id param in the waiter
115 @param cleanup_callable: method to load pass to self.addCleanup with
116 the following *cleanup_args, **cleanup_kwargs.
117 usually a delete method.
118 """
Ghanshyam2a180b82014-06-16 13:54:22 +0900119 if cleanup_args is None:
120 cleanup_args = []
121 if cleanup_kwargs is None:
122 cleanup_kwargs = {}
Andrea Frittoli247058f2014-07-16 16:09:22 +0100123 self.addCleanup(cleanup_callable, *cleanup_args, **cleanup_kwargs)
124 wait_dict = {
125 'waiter_callable': waiter_callable,
126 thing_id_param: thing_id
127 }
Ken'ichi Ohmichie91a0c62015-08-13 02:09:16 +0000128 if waiter_client:
129 wait_dict['client'] = waiter_client
Andrea Frittoli247058f2014-07-16 16:09:22 +0100130 self.cleanup_waits.append(wait_dict)
131
132 def _wait_for_cleanups(self):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000133 # To handle async delete actions, a list of waits is added
134 # which will be iterated over as the last step of clearing the
135 # cleanup queue. That way all the delete calls are made up front
136 # and the tests won't succeed unless the deletes are eventually
137 # successful. This is the same basic approach used in the api tests to
138 # limit cleanup execution time except here it is multi-resource,
139 # because of the nature of the scenario tests.
Andrea Frittoli247058f2014-07-16 16:09:22 +0100140 for wait in self.cleanup_waits:
141 waiter_callable = wait.pop('waiter_callable')
142 waiter_callable(**wait)
143
144 # ## Test functions library
145 #
146 # The create_[resource] functions only return body and discard the
147 # resp part which is not used in scenario tests
148
Yair Frieddb6c9e92014-08-06 08:53:13 +0300149 def create_keypair(self, client=None):
150 if not client:
151 client = self.keypairs_client
Andrea Frittoli247058f2014-07-16 16:09:22 +0100152 name = data_utils.rand_name(self.__class__.__name__)
153 # We don't need to create a keypair by pubkey in scenario
Ken'ichi Ohmichie364bce2015-07-17 10:27:59 +0000154 body = client.create_keypair(name=name)
Yair Frieddb6c9e92014-08-06 08:53:13 +0300155 self.addCleanup(client.delete_keypair, name)
ghanshyamdee01f22015-08-17 11:41:47 +0900156 return body['keypair']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100157
Anusha Ramineni9aaef8b2016-01-19 10:56:40 +0530158 def create_server(self, name=None, image_id=None, flavor=None,
lanoux5fc14522015-09-21 08:17:35 +0000159 validatable=False, wait_until=None,
160 wait_on_delete=True, clients=None, **kwargs):
161 """Wrapper utility that returns a test server.
Andrea Frittoli247058f2014-07-16 16:09:22 +0100162
lanoux5fc14522015-09-21 08:17:35 +0000163 This wrapper utility calls the common create test server and
164 returns a test server. The purpose of this wrapper is to minimize
165 the impact on the code of the tests already using this
166 function.
Andrea Frittoli247058f2014-07-16 16:09:22 +0100167 """
Andrea Frittoli247058f2014-07-16 16:09:22 +0100168
lanoux5fc14522015-09-21 08:17:35 +0000169 # NOTE(jlanoux): As a first step, ssh checks in the scenario
170 # tests need to be run regardless of the run_validation and
171 # validatable parameters and thus until the ssh validation job
172 # becomes voting in CI. The test resources management and IP
173 # association are taken care of in the scenario tests.
174 # Therefore, the validatable parameter is set to false in all
175 # those tests. In this way create_server just return a standard
176 # server and the scenario tests always perform ssh checks.
177
178 # Needed for the cross_tenant_traffic test:
179 if clients is None:
180 clients = self.manager
181
182 vnic_type = CONF.network.port_vnic_type
183
184 # If vnic_type is configured create port for
185 # every network
186 if vnic_type:
187 ports = []
188 networks = []
189 create_port_body = {'binding:vnic_type': vnic_type,
190 'namestart': 'port-smoke'}
191 if kwargs:
192 # Convert security group names to security group ids
193 # to pass to create_port
194 if 'security_groups' in kwargs:
195 security_groups =\
John Warrenf9606e92015-12-10 12:12:42 -0500196 clients.security_groups_client.list_security_groups(
lanoux5fc14522015-09-21 08:17:35 +0000197 ).get('security_groups')
198 sec_dict = dict([(s['name'], s['id'])
199 for s in security_groups])
200
201 sec_groups_names = [s['name'] for s in kwargs.pop(
202 'security_groups')]
203 security_groups_ids = [sec_dict[s]
204 for s in sec_groups_names]
205
206 if security_groups_ids:
207 create_port_body[
208 'security_groups'] = security_groups_ids
209 networks = kwargs.pop('networks')
210
211 # If there are no networks passed to us we look up
Sean Dagueed6e5862016-04-04 10:49:13 -0400212 # for the project's private networks and create a port
lanoux5fc14522015-09-21 08:17:35 +0000213 # if there is only one private network. The same behaviour
214 # as we would expect when passing the call to the clients
215 # with no networks
216 if not networks:
217 networks = clients.networks_client.list_networks(
218 filters={'router:external': False})
219 self.assertEqual(1, len(networks),
220 "There is more than one"
221 " network for the tenant")
222 for net in networks:
223 net_id = net['uuid']
224 port = self._create_port(network_id=net_id,
225 client=clients.ports_client,
226 **create_port_body)
Lenny Verkhovsky92530472016-06-16 09:14:25 +0300227 ports.append({'port': port['id']})
lanoux5fc14522015-09-21 08:17:35 +0000228 if ports:
229 kwargs['networks'] = ports
230 self.ports = ports
231
232 tenant_network = self.get_tenant_network()
233
234 body, servers = compute.create_test_server(
235 clients,
236 tenant_network=tenant_network,
237 wait_until=wait_until,
Anusha Ramineni9aaef8b2016-01-19 10:56:40 +0530238 name=name, flavor=flavor,
239 image_id=image_id, **kwargs)
lanoux5fc14522015-09-21 08:17:35 +0000240
241 # TODO(jlanoux) Move wait_on_delete in compute.py
Andrea Frittoli247058f2014-07-16 16:09:22 +0100242 if wait_on_delete:
Ken'ichi Ohmichie91a0c62015-08-13 02:09:16 +0000243 self.addCleanup(waiters.wait_for_server_termination,
lanoux5fc14522015-09-21 08:17:35 +0000244 clients.servers_client,
245 body['id'])
246
Andrea Frittoli247058f2014-07-16 16:09:22 +0100247 self.addCleanup_with_wait(
Ken'ichi Ohmichie91a0c62015-08-13 02:09:16 +0000248 waiter_callable=waiters.wait_for_server_termination,
lanoux5fc14522015-09-21 08:17:35 +0000249 thing_id=body['id'], thing_id_param='server_id',
Jordan Pittier9e227c52016-02-09 14:35:18 +0100250 cleanup_callable=test_utils.call_and_ignore_notfound_exc,
lanoux5fc14522015-09-21 08:17:35 +0000251 cleanup_args=[clients.servers_client.delete_server, body['id']],
252 waiter_client=clients.servers_client)
253 server = clients.servers_client.show_server(body['id'])['server']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100254 return server
255
Markus Zoeller3d2a21c2015-02-27 12:04:22 +0100256 def create_volume(self, size=None, name=None, snapshot_id=None,
Jordan Pittier5e1741c2016-03-02 18:25:51 +0100257 imageRef=None, volume_type=None):
Andrea Frittoli247058f2014-07-16 16:09:22 +0100258 if name is None:
259 name = data_utils.rand_name(self.__class__.__name__)
Ghanshyam8fc0ed22015-12-18 10:25:14 +0900260 kwargs = {'display_name': name,
261 'snapshot_id': snapshot_id,
262 'imageRef': imageRef,
263 'volume_type': volume_type}
264 if size is not None:
265 kwargs.update({'size': size})
266 volume = self.volumes_client.create_volume(**kwargs)['volume']
Matt Riedemanne85c2702014-09-10 11:50:13 -0700267
Jordan Pittier5e1741c2016-03-02 18:25:51 +0100268 self.addCleanup(self.volumes_client.wait_for_resource_deletion,
269 volume['id'])
Jordan Pittier9e227c52016-02-09 14:35:18 +0100270 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
Jordan Pittier5e1741c2016-03-02 18:25:51 +0100271 self.volumes_client.delete_volume, volume['id'])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100272
Ivan Kolodyazhnybcfc32e2015-08-06 13:31:36 +0300273 # NOTE(e0ne): Cinder API v2 uses name instead of display_name
274 if 'display_name' in volume:
275 self.assertEqual(name, volume['display_name'])
276 else:
277 self.assertEqual(name, volume['name'])
Yaroslav Lobankoved3a35b2016-03-24 22:41:30 -0500278 waiters.wait_for_volume_status(self.volumes_client,
279 volume['id'], 'available')
Andrea Frittoli247058f2014-07-16 16:09:22 +0100280 # The volume retrieved on creation has a non-up-to-date status.
281 # Retrieval after it becomes active ensures correct details.
John Warren6177c9e2015-08-19 20:00:17 +0000282 volume = self.volumes_client.show_volume(volume['id'])['volume']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100283 return volume
284
Yair Fried1fc32a12014-08-04 09:11:30 +0300285 def _create_loginable_secgroup_rule(self, secgroup_id=None):
John Warrenf2345512015-12-10 13:39:30 -0500286 _client = self.compute_security_groups_client
John Warren5cdbf422016-01-05 12:42:43 -0500287 _client_rules = self.compute_security_group_rules_client
Andrea Frittoli247058f2014-07-16 16:09:22 +0100288 if secgroup_id is None:
ghanshyamb610b772015-08-24 17:29:38 +0900289 sgs = _client.list_security_groups()['security_groups']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100290 for sg in sgs:
291 if sg['name'] == 'default':
292 secgroup_id = sg['id']
293
294 # These rules are intended to permit inbound ssh and icmp
295 # traffic from all sources, so no group_id is provided.
296 # Setting a group_id would only permit traffic from ports
297 # belonging to the same security group.
298 rulesets = [
299 {
300 # ssh
Ken'ichi Ohmichieb7eeec2015-07-21 01:00:06 +0000301 'ip_protocol': 'tcp',
Andrea Frittoli247058f2014-07-16 16:09:22 +0100302 'from_port': 22,
303 'to_port': 22,
304 'cidr': '0.0.0.0/0',
305 },
306 {
307 # ping
Ken'ichi Ohmichieb7eeec2015-07-21 01:00:06 +0000308 'ip_protocol': 'icmp',
Andrea Frittoli247058f2014-07-16 16:09:22 +0100309 'from_port': -1,
310 'to_port': -1,
311 'cidr': '0.0.0.0/0',
312 }
313 ]
314 rules = list()
315 for ruleset in rulesets:
Ken'ichi Ohmichieb7eeec2015-07-21 01:00:06 +0000316 sg_rule = _client_rules.create_security_group_rule(
ghanshyam0a5e1232015-08-24 16:59:59 +0900317 parent_group_id=secgroup_id, **ruleset)['security_group_rule']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100318 rules.append(sg_rule)
319 return rules
320
Yair Fried1fc32a12014-08-04 09:11:30 +0300321 def _create_security_group(self):
Andrea Frittoli247058f2014-07-16 16:09:22 +0100322 # Create security group
323 sg_name = data_utils.rand_name(self.__class__.__name__)
324 sg_desc = sg_name + " description"
John Warrenf2345512015-12-10 13:39:30 -0500325 secgroup = self.compute_security_groups_client.create_security_group(
ghanshyamb610b772015-08-24 17:29:38 +0900326 name=sg_name, description=sg_desc)['security_group']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100327 self.assertEqual(secgroup['name'], sg_name)
328 self.assertEqual(secgroup['description'], sg_desc)
John Warrenf2345512015-12-10 13:39:30 -0500329 self.addCleanup(
Jordan Pittier9e227c52016-02-09 14:35:18 +0100330 test_utils.call_and_ignore_notfound_exc,
John Warrenf2345512015-12-10 13:39:30 -0500331 self.compute_security_groups_client.delete_security_group,
332 secgroup['id'])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100333
334 # Add rules to the security group
Yair Fried1fc32a12014-08-04 09:11:30 +0300335 self._create_loginable_secgroup_rule(secgroup['id'])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100336
337 return secgroup
338
Sean Dague20e98612016-01-06 14:33:28 -0500339 def get_remote_client(self, ip_address, username=None, private_key=None):
JordanP3fe2dc32014-11-17 13:06:01 +0100340 """Get a SSH client to a remote server
341
Sean Dague20e98612016-01-06 14:33:28 -0500342 @param ip_address the server floating or fixed IP address to use
343 for ssh validation
JordanP3fe2dc32014-11-17 13:06:01 +0100344 @param username name of the Linux account on the remote server
345 @param private_key the SSH private key to use
JordanP3fe2dc32014-11-17 13:06:01 +0100346 @return a RemoteClient object
347 """
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700348
Andrea Frittoli247058f2014-07-16 16:09:22 +0100349 if username is None:
lanoux283273b2015-12-04 03:01:54 -0800350 username = CONF.validation.image_ssh_user
wantwatering896300c2015-03-27 15:17:42 +0800351 # Set this with 'keypair' or others to log in with keypair or
352 # username/password.
lanoux5fc14522015-09-21 08:17:35 +0000353 if CONF.validation.auth_method == 'keypair':
wantwatering896300c2015-03-27 15:17:42 +0800354 password = None
355 if private_key is None:
356 private_key = self.keypair['private_key']
357 else:
lanoux283273b2015-12-04 03:01:54 -0800358 password = CONF.validation.image_ssh_password
wantwatering896300c2015-03-27 15:17:42 +0800359 private_key = None
Sean Dague20e98612016-01-06 14:33:28 -0500360 linux_client = remote_client.RemoteClient(ip_address, username,
wantwatering896300c2015-03-27 15:17:42 +0800361 pkey=private_key,
362 password=password)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100363 try:
364 linux_client.validate_authentication()
Matt Riedemann5f0ac522015-05-21 09:16:24 -0700365 except Exception as e:
366 message = ('Initializing SSH connection to %(ip)s failed. '
Eric Brown0911af62016-02-08 17:15:40 -0800367 'Error: %(error)s' % {'ip': ip_address,
Sean Dague20e98612016-01-06 14:33:28 -0500368 'error': e})
Jordan Pittier9e227c52016-02-09 14:35:18 +0100369 caller = test_utils.find_test_caller()
Matt Riedemann5f0ac522015-05-21 09:16:24 -0700370 if caller:
371 message = '(%s) %s' % (caller, message)
372 LOG.exception(message)
Sean Dague2c98a162016-01-06 14:11:13 -0500373 self._log_console_output()
Andrea Frittoli247058f2014-07-16 16:09:22 +0100374 raise
375
376 return linux_client
377
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000378 def _image_create(self, name, fmt, path,
379 disk_format=None, properties=None):
Ghanshyam2a180b82014-06-16 13:54:22 +0900380 if properties is None:
381 properties = {}
Andrea Frittoli247058f2014-07-16 16:09:22 +0100382 name = data_utils.rand_name('%s-' % name)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100383 params = {
384 'name': name,
385 'container_format': fmt,
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000386 'disk_format': disk_format or fmt,
Andrea Frittoli247058f2014-07-16 16:09:22 +0100387 }
Matt Riedemann2aa19d42016-06-06 17:45:41 -0400388 if CONF.image_feature_enabled.api_v1:
389 params['is_public'] = 'False'
390 params['properties'] = properties
Ken'ichi Ohmichi02bcdf32016-06-17 16:41:26 -0700391 params = {'headers': common_image.image_meta_to_headers(**params)}
Matt Riedemann2aa19d42016-06-06 17:45:41 -0400392 else:
393 params['visibility'] = 'private'
394 # Additional properties are flattened out in the v2 API.
395 params.update(properties)
396 body = self.image_client.create_image(**params)
397 image = body['image'] if 'image' in body else body
Andrea Frittoli247058f2014-07-16 16:09:22 +0100398 self.addCleanup(self.image_client.delete_image, image['id'])
399 self.assertEqual("queued", image['status'])
zhang.leia4b1cef2016-03-01 10:50:01 +0800400 with open(path, 'rb') as image_file:
Matt Riedemann2aa19d42016-06-06 17:45:41 -0400401 if CONF.image_feature_enabled.api_v1:
402 self.image_client.update_image(image['id'], data=image_file)
403 else:
404 self.image_client.store_image_file(image['id'], image_file)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100405 return image['id']
406
407 def glance_image_create(self):
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300408 img_path = CONF.scenario.img_dir + "/" + CONF.scenario.img_file
Andrea Frittoli247058f2014-07-16 16:09:22 +0100409 aki_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.aki_img_file
410 ari_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.ari_img_file
411 ami_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.ami_img_file
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300412 img_container_format = CONF.scenario.img_container_format
413 img_disk_format = CONF.scenario.img_disk_format
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000414 img_properties = CONF.scenario.img_properties
PranaliD2aa523c2016-06-07 03:54:34 -0400415 LOG.debug("paths: img: %s, container_format: %s, disk_format: %s, "
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000416 "properties: %s, ami: %s, ari: %s, aki: %s" %
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300417 (img_path, img_container_format, img_disk_format,
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000418 img_properties, ami_img_path, ari_img_path, aki_img_path))
Andrea Frittoli247058f2014-07-16 16:09:22 +0100419 try:
Jordan Pittier1e443ec2015-11-20 16:15:58 +0100420 image = self._image_create('scenario-img',
421 img_container_format,
422 img_path,
423 disk_format=img_disk_format,
424 properties=img_properties)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100425 except IOError:
426 LOG.debug("A qcow2 image was not found. Try to get a uec image.")
427 kernel = self._image_create('scenario-aki', 'aki', aki_img_path)
428 ramdisk = self._image_create('scenario-ari', 'ari', ari_img_path)
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000429 properties = {'kernel_id': kernel, 'ramdisk_id': ramdisk}
Jordan Pittier1e443ec2015-11-20 16:15:58 +0100430 image = self._image_create('scenario-ami', 'ami',
431 path=ami_img_path,
432 properties=properties)
433 LOG.debug("image:%s" % image)
434
435 return image
Andrea Frittoli247058f2014-07-16 16:09:22 +0100436
437 def _log_console_output(self, servers=None):
Matthew Treinish42a3f3a2014-09-04 15:04:53 -0400438 if not CONF.compute_feature_enabled.console_output:
439 LOG.debug('Console output not supported, cannot log')
440 return
Andrea Frittoli247058f2014-07-16 16:09:22 +0100441 if not servers:
David Kranzae99b9a2015-02-16 13:37:01 -0500442 servers = self.servers_client.list_servers()
Andrea Frittoli247058f2014-07-16 16:09:22 +0100443 servers = servers['servers']
444 for server in servers:
Brant Knudson566c5712014-09-24 20:04:50 -0500445 console_output = self.servers_client.get_console_output(
Ken'ichi Ohmichibf4766a2015-12-09 07:48:43 +0000446 server['id'])['output']
David Kranzae99b9a2015-02-16 13:37:01 -0500447 LOG.debug('Console output for %s\nbody=\n%s',
448 server['id'], console_output)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100449
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000450 def _log_net_info(self, exc):
451 # network debug is called as part of ssh init
Andrey Pavlov64723762015-04-29 06:24:58 +0300452 if not isinstance(exc, lib_exc.SSHTimeout):
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000453 LOG.debug('Network information on a devstack host')
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000454
nithya-ganesan882595e2014-07-29 18:51:07 +0000455 def create_server_snapshot(self, server, name=None):
456 # Glance client
457 _image_client = self.image_client
458 # Compute client
Ghanshyamae76c122015-12-22 13:41:35 +0900459 _images_client = self.compute_images_client
nithya-ganesan882595e2014-07-29 18:51:07 +0000460 if name is None:
Ken'ichi Ohmichi6ded8df2015-03-23 02:00:19 +0000461 name = data_utils.rand_name('scenario-snapshot')
nithya-ganesan882595e2014-07-29 18:51:07 +0000462 LOG.debug("Creating a snapshot image for server: %s", server['name'])
Ken'ichi Ohmichi28f18672015-07-17 10:00:38 +0000463 image = _images_client.create_image(server['id'], name=name)
David Kranza5299eb2015-01-15 17:24:05 -0500464 image_id = image.response['location'].split('images/')[1]
Yaroslav Lobankov2fea4052016-04-19 15:05:57 +0300465 waiters.wait_for_image_status(_image_client, image_id, 'active')
nithya-ganesan882595e2014-07-29 18:51:07 +0000466 self.addCleanup_with_wait(
467 waiter_callable=_image_client.wait_for_resource_deletion,
468 thing_id=image_id, thing_id_param='id',
Jordan Pittier9e227c52016-02-09 14:35:18 +0100469 cleanup_callable=test_utils.call_and_ignore_notfound_exc,
nithya-ganesan882595e2014-07-29 18:51:07 +0000470 cleanup_args=[_image_client.delete_image, image_id])
Matt Riedemann2aa19d42016-06-06 17:45:41 -0400471 if CONF.image_feature_enabled.api_v1:
472 # In glance v1 the additional properties are stored in the headers.
Ken'ichi Ohmichi01151e82016-06-10 11:19:52 -0700473 resp = _image_client.check_image(image_id)
474 snapshot_image = common_image.get_image_meta_from_headers(resp)
Matt Riedemann2aa19d42016-06-06 17:45:41 -0400475 image_props = snapshot_image.get('properties', {})
476 else:
477 # In glance v2 the additional properties are flattened.
478 snapshot_image = _image_client.show_image(image_id)
479 image_props = snapshot_image
Andrey Pavlovc8bd4b12015-08-17 10:20:17 +0300480
Matt Riedemann2aa19d42016-06-06 17:45:41 -0400481 bdm = image_props.get('block_device_mapping')
Andrey Pavlovc8bd4b12015-08-17 10:20:17 +0300482 if bdm:
483 bdm = json.loads(bdm)
484 if bdm and 'snapshot_id' in bdm[0]:
485 snapshot_id = bdm[0]['snapshot_id']
486 self.addCleanup(
487 self.snapshots_client.wait_for_resource_deletion,
488 snapshot_id)
Jordan Pittier9e227c52016-02-09 14:35:18 +0100489 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
490 self.snapshots_client.delete_snapshot,
491 snapshot_id)
Yaroslav Lobankov667aaa22016-03-24 23:13:28 -0500492 waiters.wait_for_snapshot_status(self.snapshots_client,
493 snapshot_id, 'available')
nithya-ganesan882595e2014-07-29 18:51:07 +0000494 image_name = snapshot_image['name']
495 self.assertEqual(name, image_name)
496 LOG.debug("Created snapshot image %s for server %s",
497 image_name, server['name'])
498 return snapshot_image
499
Jordan Pittier7cf64762015-10-14 15:01:12 +0200500 def nova_volume_attach(self, server, volume_to_attach):
Joseph Lanoux6809bab2014-12-18 14:57:18 +0000501 volume = self.servers_client.attach_volume(
Jordan Pittier7cf64762015-10-14 15:01:12 +0200502 server['id'], volumeId=volume_to_attach['id'], device='/dev/%s'
ghanshyam0f825252015-08-25 16:02:50 +0900503 % CONF.compute.volume_device_name)['volumeAttachment']
Jordan Pittier7cf64762015-10-14 15:01:12 +0200504 self.assertEqual(volume_to_attach['id'], volume['id'])
Yaroslav Lobankoved3a35b2016-03-24 22:41:30 -0500505 waiters.wait_for_volume_status(self.volumes_client,
506 volume['id'], 'in-use')
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900507
Jordan Pittier7cf64762015-10-14 15:01:12 +0200508 # Return the updated volume after the attachment
509 return self.volumes_client.show_volume(volume['id'])['volume']
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900510
Jordan Pittier7cf64762015-10-14 15:01:12 +0200511 def nova_volume_detach(self, server, volume):
512 self.servers_client.detach_volume(server['id'], volume['id'])
Yaroslav Lobankoved3a35b2016-03-24 22:41:30 -0500513 waiters.wait_for_volume_status(self.volumes_client,
514 volume['id'], 'available')
Jordan Pittier7cf64762015-10-14 15:01:12 +0200515
516 volume = self.volumes_client.show_volume(volume['id'])['volume']
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900517 self.assertEqual('available', volume['status'])
518
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700519 def rebuild_server(self, server_id, image=None,
520 preserve_ephemeral=False, wait=True,
521 rebuild_kwargs=None):
522 if image is None:
523 image = CONF.compute.image_ref
524
525 rebuild_kwargs = rebuild_kwargs or {}
526
527 LOG.debug("Rebuilding server (id: %s, image: %s, preserve eph: %s)",
528 server_id, image, preserve_ephemeral)
Ken'ichi Ohmichi5271b0f2015-08-10 07:53:27 +0000529 self.servers_client.rebuild_server(
530 server_id=server_id, image_ref=image,
531 preserve_ephemeral=preserve_ephemeral,
532 **rebuild_kwargs)
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700533 if wait:
Ken'ichi Ohmichi0eb153c2015-07-13 02:18:25 +0000534 waiters.wait_for_server_status(self.servers_client,
535 server_id, 'ACTIVE')
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700536
Steven Hardyda2a8352014-10-02 12:52:20 +0100537 def ping_ip_address(self, ip_address, should_succeed=True,
538 ping_timeout=None):
lanoux5fc14522015-09-21 08:17:35 +0000539 timeout = ping_timeout or CONF.validation.ping_timeout
Aaron Rosena7df13b2014-09-23 09:45:45 -0700540 cmd = ['ping', '-c1', '-w1', ip_address]
541
542 def ping():
543 proc = subprocess.Popen(cmd,
544 stdout=subprocess.PIPE,
545 stderr=subprocess.PIPE)
546 proc.communicate()
Shuquan Huang753629e2015-07-20 08:52:29 +0000547
Aaron Rosena7df13b2014-09-23 09:45:45 -0700548 return (proc.returncode == 0) == should_succeed
549
Jordan Pittier9e227c52016-02-09 14:35:18 +0100550 caller = test_utils.find_test_caller()
Shuquan Huang753629e2015-07-20 08:52:29 +0000551 LOG.debug('%(caller)s begins to ping %(ip)s in %(timeout)s sec and the'
552 ' expected result is %(should_succeed)s' % {
553 'caller': caller, 'ip': ip_address, 'timeout': timeout,
554 'should_succeed':
555 'reachable' if should_succeed else 'unreachable'
556 })
557 result = tempest.test.call_until_true(ping, timeout, 1)
558 LOG.debug('%(caller)s finishes ping %(ip)s in %(timeout)s sec and the '
559 'ping result is %(result)s' % {
560 'caller': caller, 'ip': ip_address, 'timeout': timeout,
561 'result': 'expected' if result else 'unexpected'
562 })
563 return result
Aaron Rosena7df13b2014-09-23 09:45:45 -0700564
Yair Friedae0e73d2014-11-24 11:56:26 +0200565 def check_vm_connectivity(self, ip_address,
566 username=None,
567 private_key=None,
568 should_connect=True):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000569 """Check server connectivity
570
Yair Friedae0e73d2014-11-24 11:56:26 +0200571 :param ip_address: server to test against
572 :param username: server's ssh username
573 :param private_key: server's ssh private key to be used
574 :param should_connect: True/False indicates positive/negative test
575 positive - attempt ping and ssh
576 negative - attempt ping and fail if succeed
577
578 :raises: AssertError if the result of the connectivity check does
579 not match the value of the should_connect param
580 """
581 if should_connect:
582 msg = "Timed out waiting for %s to become reachable" % ip_address
583 else:
584 msg = "ip address %s is reachable" % ip_address
585 self.assertTrue(self.ping_ip_address(ip_address,
586 should_succeed=should_connect),
587 msg=msg)
588 if should_connect:
589 # no need to check ssh for negative connectivity
590 self.get_remote_client(ip_address, username, private_key)
591
592 def check_public_network_connectivity(self, ip_address, username,
593 private_key, should_connect=True,
594 msg=None, servers=None):
595 # The target login is assumed to have been configured for
596 # key-based authentication by cloud-init.
597 LOG.debug('checking network connections to IP %s with user: %s' %
598 (ip_address, username))
599 try:
600 self.check_vm_connectivity(ip_address,
601 username,
602 private_key,
603 should_connect=should_connect)
Matthew Treinish53483132014-12-09 18:50:06 -0500604 except Exception:
Yair Friedae0e73d2014-11-24 11:56:26 +0200605 ex_msg = 'Public network connectivity check failed'
606 if msg:
607 ex_msg += ": " + msg
608 LOG.exception(ex_msg)
609 self._log_console_output(servers)
Yair Friedae0e73d2014-11-24 11:56:26 +0200610 raise
611
612 def create_floating_ip(self, thing, pool_name=None):
Ken'ichi Ohmichia112a592015-11-17 08:49:37 +0000613 """Create a floating IP and associates to a server on Nova"""
Yair Friedae0e73d2014-11-24 11:56:26 +0200614
Marc Koderer3b57d802016-03-22 15:23:31 +0100615 if not pool_name:
616 pool_name = CONF.network.floating_network_name
John Warrene74890a2015-11-11 15:18:01 -0500617 floating_ip = (self.compute_floating_ips_client.
Ken'ichi Ohmichie037a6f2015-12-03 06:41:49 +0000618 create_floating_ip(pool=pool_name)['floating_ip'])
Jordan Pittier9e227c52016-02-09 14:35:18 +0100619 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
John Warrene74890a2015-11-11 15:18:01 -0500620 self.compute_floating_ips_client.delete_floating_ip,
Yair Friedae0e73d2014-11-24 11:56:26 +0200621 floating_ip['id'])
John Warrene74890a2015-11-11 15:18:01 -0500622 self.compute_floating_ips_client.associate_floating_ip_to_server(
Yair Friedae0e73d2014-11-24 11:56:26 +0200623 floating_ip['ip'], thing['id'])
624 return floating_ip
625
Sean Dague20e98612016-01-06 14:33:28 -0500626 def create_timestamp(self, ip_address, dev_name=None, mount_path='/mnt',
Matt Riedemannfd5657d2015-09-30 14:47:07 -0700627 private_key=None):
Sean Dague20e98612016-01-06 14:33:28 -0500628 ssh_client = self.get_remote_client(ip_address,
Matt Riedemannfd5657d2015-09-30 14:47:07 -0700629 private_key=private_key)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300630 if dev_name is not None:
631 ssh_client.make_fs(dev_name)
Matt Riedemann076685a2015-09-30 14:38:16 -0700632 ssh_client.mount(dev_name, mount_path)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300633 cmd_timestamp = 'sudo sh -c "date > %s/timestamp; sync"' % mount_path
634 ssh_client.exec_command(cmd_timestamp)
635 timestamp = ssh_client.exec_command('sudo cat %s/timestamp'
636 % mount_path)
637 if dev_name is not None:
638 ssh_client.umount(mount_path)
639 return timestamp
640
Sean Dague20e98612016-01-06 14:33:28 -0500641 def get_timestamp(self, ip_address, dev_name=None, mount_path='/mnt',
Matt Riedemannfd5657d2015-09-30 14:47:07 -0700642 private_key=None):
Sean Dague20e98612016-01-06 14:33:28 -0500643 ssh_client = self.get_remote_client(ip_address,
Matt Riedemannfd5657d2015-09-30 14:47:07 -0700644 private_key=private_key)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300645 if dev_name is not None:
Matt Riedemann076685a2015-09-30 14:38:16 -0700646 ssh_client.mount(dev_name, mount_path)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300647 timestamp = ssh_client.exec_command('sudo cat %s/timestamp'
648 % mount_path)
649 if dev_name is not None:
650 ssh_client.umount(mount_path)
651 return timestamp
652
Sean Dague20e98612016-01-06 14:33:28 -0500653 def get_server_ip(self, server):
654 """Get the server fixed or floating IP.
655
656 Based on the configuration we're in, return a correct ip
657 address for validating that a guest is up.
658 """
Alexander Gubanovc8829f82015-11-12 10:35:13 +0200659 if CONF.validation.connect_method == 'floating':
Sean Dague20e98612016-01-06 14:33:28 -0500660 # The tests calling this method don't have a floating IP
zhufl0892cb22016-05-06 14:46:00 +0800661 # and can't make use of the validation resources. So the
Sean Dague20e98612016-01-06 14:33:28 -0500662 # method is creating the floating IP there.
663 return self.create_floating_ip(server)['ip']
664 elif CONF.validation.connect_method == 'fixed':
665 addresses = server['addresses'][CONF.validation.network_for_ssh]
666 for address in addresses:
667 if address['version'] == CONF.validation.ip_version_for_ssh:
668 return address['addr']
669 raise exceptions.ServerUnreachable()
Alexander Gubanovc8829f82015-11-12 10:35:13 +0200670 else:
Sean Dague20e98612016-01-06 14:33:28 -0500671 raise exceptions.InvalidConfiguration()
Alexander Gubanovc8829f82015-11-12 10:35:13 +0200672
Andrea Frittoli2e733b52014-07-16 14:12:11 +0100673
Andrea Frittoli4971fc82014-09-25 10:22:20 +0100674class NetworkScenarioTest(ScenarioTest):
Yair Fried1fc32a12014-08-04 09:11:30 +0300675 """Base class for network scenario tests.
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000676
Yair Fried1fc32a12014-08-04 09:11:30 +0300677 This class provide helpers for network scenario tests, using the neutron
678 API. Helpers from ancestor which use the nova network API are overridden
679 with the neutron API.
680
681 This Class also enforces using Neutron instead of novanetwork.
682 Subclassed tests will be skipped if Neutron is not enabled
683
684 """
685
Andrea Frittolib21de6c2015-02-06 20:12:38 +0000686 credentials = ['primary', 'admin']
687
Yair Fried1fc32a12014-08-04 09:11:30 +0300688 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +0000689 def skip_checks(cls):
690 super(NetworkScenarioTest, cls).skip_checks()
Andrea Frittoli2ddc2632014-09-25 11:03:00 +0100691 if not CONF.service_available.neutron:
692 raise cls.skipException('Neutron not available')
Yair Fried1fc32a12014-08-04 09:11:30 +0300693
694 @classmethod
Andrea Frittoliac20b5e2014-09-15 13:31:14 +0100695 def resource_setup(cls):
696 super(NetworkScenarioTest, cls).resource_setup()
Yair Fried1fc32a12014-08-04 09:11:30 +0300697 cls.tenant_id = cls.manager.identity_client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300698
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -0700699 def _create_network(self, networks_client=None,
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000700 routers_client=None, tenant_id=None,
701 namestart='network-smoke-'):
John Warren94d8faf2015-09-15 12:22:24 -0400702 if not networks_client:
703 networks_client = self.networks_client
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000704 if not routers_client:
705 routers_client = self.routers_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300706 if not tenant_id:
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -0700707 tenant_id = networks_client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300708 name = data_utils.rand_name(namestart)
John Warren94d8faf2015-09-15 12:22:24 -0400709 result = networks_client.create_network(name=name, tenant_id=tenant_id)
Steve Heyman33735f22016-05-24 09:28:08 -0500710 network = result['network']
711
712 self.assertEqual(network['name'], name)
Jordan Pittier9e227c52016-02-09 14:35:18 +0100713 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
Steve Heyman33735f22016-05-24 09:28:08 -0500714 self.networks_client.delete_network,
715 network['id'])
Yair Fried1fc32a12014-08-04 09:11:30 +0300716 return network
717
718 def _list_networks(self, *args, **kwargs):
719 """List networks using admin creds """
John Warren94d8faf2015-09-15 12:22:24 -0400720 networks_list = self.admin_manager.networks_client.list_networks(
ghanshyam2f7cc022015-06-26 18:18:11 +0900721 *args, **kwargs)
722 return networks_list['networks']
Yair Fried1fc32a12014-08-04 09:11:30 +0300723
724 def _list_subnets(self, *args, **kwargs):
725 """List subnets using admin creds """
John Warren3961acd2015-10-02 14:38:53 -0400726 subnets_list = self.admin_manager.subnets_client.list_subnets(
ghanshyam2f7cc022015-06-26 18:18:11 +0900727 *args, **kwargs)
728 return subnets_list['subnets']
Yair Fried1fc32a12014-08-04 09:11:30 +0300729
730 def _list_routers(self, *args, **kwargs):
731 """List routers using admin creds """
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000732 routers_list = self.admin_manager.routers_client.list_routers(
ghanshyam2f7cc022015-06-26 18:18:11 +0900733 *args, **kwargs)
734 return routers_list['routers']
Yair Fried1fc32a12014-08-04 09:11:30 +0300735
736 def _list_ports(self, *args, **kwargs):
737 """List ports using admin creds """
John Warren49c0fe52015-10-22 12:35:54 -0400738 ports_list = self.admin_manager.ports_client.list_ports(
ghanshyam2f7cc022015-06-26 18:18:11 +0900739 *args, **kwargs)
740 return ports_list['ports']
Yair Fried1fc32a12014-08-04 09:11:30 +0300741
Yair Fried564d89d2015-08-06 17:02:12 +0300742 def _list_agents(self, *args, **kwargs):
743 """List agents using admin creds """
Ken'ichi Ohmichi71860062015-12-15 08:20:13 +0000744 agents_list = self.admin_manager.network_agents_client.list_agents(
Yair Fried564d89d2015-08-06 17:02:12 +0300745 *args, **kwargs)
746 return agents_list['agents']
747
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -0700748 def _create_subnet(self, network, subnets_client=None,
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000749 routers_client=None, namestart='subnet-smoke',
750 **kwargs):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000751 """Create a subnet for the given network
752
753 within the cidr block configured for tenant networks.
Yair Fried1fc32a12014-08-04 09:11:30 +0300754 """
John Warren3961acd2015-10-02 14:38:53 -0400755 if not subnets_client:
756 subnets_client = self.subnets_client
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000757 if not routers_client:
758 routers_client = self.routers_client
Yair Fried1fc32a12014-08-04 09:11:30 +0300759
760 def cidr_in_use(cidr, tenant_id):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000761 """Check cidr existence
762
lei zhangdd552b22015-11-25 20:41:48 +0800763 :returns: True if subnet with cidr already exist in tenant
764 False else
Yair Fried1fc32a12014-08-04 09:11:30 +0300765 """
766 cidr_in_use = self._list_subnets(tenant_id=tenant_id, cidr=cidr)
767 return len(cidr_in_use) != 0
768
Kirill Shileev14113572014-11-21 16:58:02 +0300769 ip_version = kwargs.pop('ip_version', 4)
770
771 if ip_version == 6:
772 tenant_cidr = netaddr.IPNetwork(
Sean Dagueed6e5862016-04-04 10:49:13 -0400773 CONF.network.project_network_v6_cidr)
774 num_bits = CONF.network.project_network_v6_mask_bits
Kirill Shileev14113572014-11-21 16:58:02 +0300775 else:
Sean Dagueed6e5862016-04-04 10:49:13 -0400776 tenant_cidr = netaddr.IPNetwork(CONF.network.project_network_cidr)
777 num_bits = CONF.network.project_network_mask_bits
Kirill Shileev14113572014-11-21 16:58:02 +0300778
Yair Fried1fc32a12014-08-04 09:11:30 +0300779 result = None
Kirill Shileev14113572014-11-21 16:58:02 +0300780 str_cidr = None
Yair Fried1fc32a12014-08-04 09:11:30 +0300781 # Repeatedly attempt subnet creation with sequential cidr
782 # blocks until an unallocated block is found.
Kirill Shileev14113572014-11-21 16:58:02 +0300783 for subnet_cidr in tenant_cidr.subnet(num_bits):
Yair Fried1fc32a12014-08-04 09:11:30 +0300784 str_cidr = str(subnet_cidr)
Steve Heyman33735f22016-05-24 09:28:08 -0500785 if cidr_in_use(str_cidr, tenant_id=network['tenant_id']):
Yair Fried1fc32a12014-08-04 09:11:30 +0300786 continue
787
788 subnet = dict(
789 name=data_utils.rand_name(namestart),
Steve Heyman33735f22016-05-24 09:28:08 -0500790 network_id=network['id'],
791 tenant_id=network['tenant_id'],
Yair Fried1fc32a12014-08-04 09:11:30 +0300792 cidr=str_cidr,
Kirill Shileev14113572014-11-21 16:58:02 +0300793 ip_version=ip_version,
Yair Fried1fc32a12014-08-04 09:11:30 +0300794 **kwargs
795 )
796 try:
John Warren3961acd2015-10-02 14:38:53 -0400797 result = subnets_client.create_subnet(**subnet)
Yair Fried1fc32a12014-08-04 09:11:30 +0300798 break
Masayuki Igawad9388762015-01-20 14:56:42 +0900799 except lib_exc.Conflict as e:
Yair Fried1fc32a12014-08-04 09:11:30 +0300800 is_overlapping_cidr = 'overlaps with another subnet' in str(e)
801 if not is_overlapping_cidr:
802 raise
803 self.assertIsNotNone(result, 'Unable to allocate tenant network')
Steve Heyman33735f22016-05-24 09:28:08 -0500804
805 subnet = result['subnet']
806 self.assertEqual(subnet['cidr'], str_cidr)
807
808 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
809 subnets_client.delete_subnet, subnet['id'])
810
Yair Fried1fc32a12014-08-04 09:11:30 +0300811 return subnet
812
Itzik Brown2ca01cd2014-12-08 12:58:20 +0200813 def _create_port(self, network_id, client=None, namestart='port-quotatest',
814 **kwargs):
Yair Frieddb6c9e92014-08-06 08:53:13 +0300815 if not client:
John Warren49c0fe52015-10-22 12:35:54 -0400816 client = self.ports_client
Yair Fried1fc32a12014-08-04 09:11:30 +0300817 name = data_utils.rand_name(namestart)
David Kranz34e88122014-12-11 15:24:05 -0500818 result = client.create_port(
Yair Fried1fc32a12014-08-04 09:11:30 +0300819 name=name,
Itzik Brown2ca01cd2014-12-08 12:58:20 +0200820 network_id=network_id,
821 **kwargs)
Yair Fried1fc32a12014-08-04 09:11:30 +0300822 self.assertIsNotNone(result, 'Unable to allocate port')
Steve Heyman33735f22016-05-24 09:28:08 -0500823 port = result['port']
824 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
825 client.delete_port, port['id'])
Yair Fried1fc32a12014-08-04 09:11:30 +0300826 return port
827
Kirill Shileev14113572014-11-21 16:58:02 +0300828 def _get_server_port_id_and_ip4(self, server, ip_addr=None):
Kevin Benton1d0c1dc2016-02-04 14:30:08 -0800829 ports = self._list_ports(device_id=server['id'], fixed_ip=ip_addr)
Sean M. Collins2e896832015-12-15 13:58:47 -0500830 # A port can have more then one IP address in some cases.
831 # If the network is dual-stack (IPv4 + IPv6), this port is associated
832 # with 2 subnets
Vasyl Saienko8fd517c2016-05-30 09:52:54 +0300833 p_status = ['ACTIVE']
834 # NOTE(vsaienko) With Ironic, instances live on separate hardware
835 # servers. Neutron does not bind ports for Ironic instances, as a
836 # result the port remains in the DOWN state.
837 if CONF.service_available.ironic:
838 p_status.append('DOWN')
Daniel Mellado9e3e1062015-08-06 18:07:05 +0200839 port_map = [(p["id"], fxip["ip_address"])
840 for p in ports
841 for fxip in p["fixed_ips"]
Yatin Kumbhareee4924c2016-06-09 15:12:06 +0530842 if netutils.is_valid_ipv4(fxip["ip_address"])
Vasyl Saienko8fd517c2016-05-30 09:52:54 +0300843 and p['status'] in p_status]
Kevin Benton1d0c1dc2016-02-04 14:30:08 -0800844 inactive = [p for p in ports if p['status'] != 'ACTIVE']
845 if inactive:
846 LOG.warning("Instance has ports that are not ACTIVE: %s", inactive)
Daniel Mellado9e3e1062015-08-06 18:07:05 +0200847
John L. Villalovosb83286f2015-11-04 14:46:57 -0800848 self.assertNotEqual(0, len(port_map),
849 "No IPv4 addresses found in: %s" % ports)
Daniel Mellado9e3e1062015-08-06 18:07:05 +0200850 self.assertEqual(len(port_map), 1,
851 "Found multiple IPv4 addresses: %s. "
852 "Unable to determine which port to target."
853 % port_map)
854 return port_map[0]
Yair Fried1fc32a12014-08-04 09:11:30 +0300855
David Shrewsbury9bac3662014-08-07 15:07:01 -0400856 def _get_network_by_name(self, network_name):
857 net = self._list_networks(name=network_name)
Adam Gandelman878a5fd2015-03-30 14:33:36 -0700858 self.assertNotEqual(len(net), 0,
859 "Unable to get network by name: %s" % network_name)
Steve Heyman33735f22016-05-24 09:28:08 -0500860 return net[0]
David Shrewsbury9bac3662014-08-07 15:07:01 -0400861
Yair Friedae0e73d2014-11-24 11:56:26 +0200862 def create_floating_ip(self, thing, external_network_id=None,
863 port_id=None, client=None):
Ken'ichi Ohmichia112a592015-11-17 08:49:37 +0000864 """Create a floating IP and associates to a resource/port on Neutron"""
Yair Friedae0e73d2014-11-24 11:56:26 +0200865 if not external_network_id:
866 external_network_id = CONF.network.public_network_id
Yair Frieddb6c9e92014-08-06 08:53:13 +0300867 if not client:
John Warrenfbf2a892015-11-17 12:36:14 -0500868 client = self.floating_ips_client
Yair Fried1fc32a12014-08-04 09:11:30 +0300869 if not port_id:
Kirill Shileev14113572014-11-21 16:58:02 +0300870 port_id, ip4 = self._get_server_port_id_and_ip4(thing)
871 else:
872 ip4 = None
David Kranz34e88122014-12-11 15:24:05 -0500873 result = client.create_floatingip(
Yair Fried1fc32a12014-08-04 09:11:30 +0300874 floating_network_id=external_network_id,
875 port_id=port_id,
Kirill Shileev14113572014-11-21 16:58:02 +0300876 tenant_id=thing['tenant_id'],
877 fixed_ip_address=ip4
Yair Fried1fc32a12014-08-04 09:11:30 +0300878 )
Steve Heyman33735f22016-05-24 09:28:08 -0500879 floating_ip = result['floatingip']
Jordan Pittier9e227c52016-02-09 14:35:18 +0100880 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
Steve Heyman33735f22016-05-24 09:28:08 -0500881 self.floating_ips_client.delete_floatingip,
882 floating_ip['id'])
Yair Fried1fc32a12014-08-04 09:11:30 +0300883 return floating_ip
884
885 def _associate_floating_ip(self, floating_ip, server):
Kirill Shileev14113572014-11-21 16:58:02 +0300886 port_id, _ = self._get_server_port_id_and_ip4(server)
Steve Heyman33735f22016-05-24 09:28:08 -0500887 kwargs = dict(port_id=port_id)
888 floating_ip = self.floating_ips_client.update_floatingip(
889 floating_ip['id'], **kwargs)['floatingip']
890 self.assertEqual(port_id, floating_ip['port_id'])
Yair Fried1fc32a12014-08-04 09:11:30 +0300891 return floating_ip
892
893 def _disassociate_floating_ip(self, floating_ip):
Steve Heyman33735f22016-05-24 09:28:08 -0500894 """:param floating_ip: floating_ips_client.create_floatingip"""
895 kwargs = dict(port_id=None)
896 floating_ip = self.floating_ips_client.update_floatingip(
897 floating_ip['id'], **kwargs)['floatingip']
898 self.assertIsNone(floating_ip['port_id'])
Yair Fried1fc32a12014-08-04 09:11:30 +0300899 return floating_ip
900
Yair Fried45f92952014-06-26 05:19:19 +0300901 def check_floating_ip_status(self, floating_ip, status):
Carl Baldwina754e2d2014-10-23 22:47:41 +0000902 """Verifies floatingip reaches the given status
Yair Fried45f92952014-06-26 05:19:19 +0300903
Steve Heyman33735f22016-05-24 09:28:08 -0500904 :param dict floating_ip: floating IP dict to check status
Yair Fried45f92952014-06-26 05:19:19 +0300905 :param status: target status
906 :raises: AssertionError if status doesn't match
907 """
Steve Heyman33735f22016-05-24 09:28:08 -0500908 floatingip_id = floating_ip['id']
909
Carl Baldwina754e2d2014-10-23 22:47:41 +0000910 def refresh():
Steve Heyman33735f22016-05-24 09:28:08 -0500911 result = (self.floating_ips_client.
912 show_floatingip(floatingip_id)['floatingip'])
913 return status == result['status']
Carl Baldwina754e2d2014-10-23 22:47:41 +0000914
915 tempest.test.call_until_true(refresh,
916 CONF.network.build_timeout,
917 CONF.network.build_interval)
Steve Heyman33735f22016-05-24 09:28:08 -0500918 floating_ip = self.floating_ips_client.show_floatingip(
919 floatingip_id)['floatingip']
920 self.assertEqual(status, floating_ip['status'],
Yair Fried45f92952014-06-26 05:19:19 +0300921 message="FloatingIP: {fp} is at status: {cst}. "
922 "failed to reach status: {st}"
Steve Heyman33735f22016-05-24 09:28:08 -0500923 .format(fp=floating_ip, cst=floating_ip['status'],
Yair Fried45f92952014-06-26 05:19:19 +0300924 st=status))
925 LOG.info("FloatingIP: {fp} is at status: {st}"
926 .format(fp=floating_ip, st=status))
927
Yair Fried1fc32a12014-08-04 09:11:30 +0300928 def _check_tenant_network_connectivity(self, server,
929 username,
930 private_key,
931 should_connect=True,
932 servers_for_debug=None):
Sean Dagueed6e5862016-04-04 10:49:13 -0400933 if not CONF.network.project_networks_reachable:
Yair Fried1fc32a12014-08-04 09:11:30 +0300934 msg = 'Tenant networks not configured to be reachable.'
935 LOG.info(msg)
936 return
937 # The target login is assumed to have been configured for
938 # key-based authentication by cloud-init.
939 try:
Matthew Treinish71426682015-04-23 11:19:38 -0400940 for net_name, ip_addresses in six.iteritems(server['addresses']):
Yair Fried1fc32a12014-08-04 09:11:30 +0300941 for ip_address in ip_addresses:
ghanshyam807211c2014-12-18 13:21:22 +0900942 self.check_vm_connectivity(ip_address['addr'],
Yair Friedae0e73d2014-11-24 11:56:26 +0200943 username,
944 private_key,
945 should_connect=should_connect)
Yair Fried1fc32a12014-08-04 09:11:30 +0300946 except Exception as e:
947 LOG.exception('Tenant network connectivity check failed')
948 self._log_console_output(servers_for_debug)
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000949 self._log_net_info(e)
Yair Fried1fc32a12014-08-04 09:11:30 +0300950 raise
951
Yair Friedbc46f592015-11-18 16:29:34 +0200952 def _check_remote_connectivity(self, source, dest, should_succeed=True,
953 nic=None):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000954 """check ping server via source ssh connection
Yair Fried1fc32a12014-08-04 09:11:30 +0300955
956 :param source: RemoteClient: an ssh connection from which to ping
957 :param dest: and IP to ping against
958 :param should_succeed: boolean should ping succeed or not
Yair Friedbc46f592015-11-18 16:29:34 +0200959 :param nic: specific network interface to ping from
Yair Fried1fc32a12014-08-04 09:11:30 +0300960 :returns: boolean -- should_succeed == ping
961 :returns: ping is false if ping failed
962 """
963 def ping_remote():
964 try:
Yair Friedbc46f592015-11-18 16:29:34 +0200965 source.ping_host(dest, nic=nic)
Andrey Pavlov64723762015-04-29 06:24:58 +0300966 except lib_exc.SSHExecCommandFailed:
zhangguoqing6c096642016-01-04 06:17:21 +0000967 LOG.warning('Failed to ping IP: %s via a ssh connection '
968 'from: %s.' % (dest, source.ssh_client.host))
Yair Fried1fc32a12014-08-04 09:11:30 +0300969 return not should_succeed
970 return should_succeed
971
972 return tempest.test.call_until_true(ping_remote,
lanoux5fc14522015-09-21 08:17:35 +0000973 CONF.validation.ping_timeout,
Yair Fried1fc32a12014-08-04 09:11:30 +0300974 1)
975
John Warren456d9ae2016-01-12 15:36:33 -0500976 def _create_security_group(self, security_group_rules_client=None,
977 tenant_id=None,
John Warrenf9606e92015-12-10 12:12:42 -0500978 namestart='secgroup-smoke',
979 security_groups_client=None):
John Warren456d9ae2016-01-12 15:36:33 -0500980 if security_group_rules_client is None:
981 security_group_rules_client = self.security_group_rules_client
John Warrenf9606e92015-12-10 12:12:42 -0500982 if security_groups_client is None:
983 security_groups_client = self.security_groups_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300984 if tenant_id is None:
John Warrenf9606e92015-12-10 12:12:42 -0500985 tenant_id = security_groups_client.tenant_id
986 secgroup = self._create_empty_security_group(
987 namestart=namestart, client=security_groups_client,
988 tenant_id=tenant_id)
Yair Fried1fc32a12014-08-04 09:11:30 +0300989
990 # Add rules to the security group
John Warrenf9606e92015-12-10 12:12:42 -0500991 rules = self._create_loginable_secgroup_rule(
John Warren456d9ae2016-01-12 15:36:33 -0500992 security_group_rules_client=security_group_rules_client,
993 secgroup=secgroup,
John Warrenf9606e92015-12-10 12:12:42 -0500994 security_groups_client=security_groups_client)
Yair Fried1fc32a12014-08-04 09:11:30 +0300995 for rule in rules:
Steve Heyman33735f22016-05-24 09:28:08 -0500996 self.assertEqual(tenant_id, rule['tenant_id'])
997 self.assertEqual(secgroup['id'], rule['security_group_id'])
Yair Fried1fc32a12014-08-04 09:11:30 +0300998 return secgroup
999
Yair Frieddb6c9e92014-08-06 08:53:13 +03001000 def _create_empty_security_group(self, client=None, tenant_id=None,
Yair Fried1fc32a12014-08-04 09:11:30 +03001001 namestart='secgroup-smoke'):
1002 """Create a security group without rules.
1003
1004 Default rules will be created:
1005 - IPv4 egress to any
1006 - IPv6 egress to any
1007
1008 :param tenant_id: secgroup will be created in this tenant
Steve Heyman33735f22016-05-24 09:28:08 -05001009 :returns: the created security group
Yair Fried1fc32a12014-08-04 09:11:30 +03001010 """
1011 if client is None:
John Warrenf9606e92015-12-10 12:12:42 -05001012 client = self.security_groups_client
Yair Frieddb6c9e92014-08-06 08:53:13 +03001013 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +00001014 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001015 sg_name = data_utils.rand_name(namestart)
1016 sg_desc = sg_name + " description"
1017 sg_dict = dict(name=sg_name,
1018 description=sg_desc)
1019 sg_dict['tenant_id'] = tenant_id
David Kranz34e88122014-12-11 15:24:05 -05001020 result = client.create_security_group(**sg_dict)
Steve Heyman33735f22016-05-24 09:28:08 -05001021
1022 secgroup = result['security_group']
1023 self.assertEqual(secgroup['name'], sg_name)
1024 self.assertEqual(tenant_id, secgroup['tenant_id'])
1025 self.assertEqual(secgroup['description'], sg_desc)
1026
Jordan Pittier9e227c52016-02-09 14:35:18 +01001027 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
Steve Heyman33735f22016-05-24 09:28:08 -05001028 client.delete_security_group, secgroup['id'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001029 return secgroup
1030
Yair Frieddb6c9e92014-08-06 08:53:13 +03001031 def _default_security_group(self, client=None, tenant_id=None):
Yair Fried1fc32a12014-08-04 09:11:30 +03001032 """Get default secgroup for given tenant_id.
1033
1034 :returns: DeletableSecurityGroup -- default secgroup for given tenant
1035 """
1036 if client is None:
John Warrenf9606e92015-12-10 12:12:42 -05001037 client = self.security_groups_client
Yair Frieddb6c9e92014-08-06 08:53:13 +03001038 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +00001039 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001040 sgs = [
1041 sg for sg in client.list_security_groups().values()[0]
1042 if sg['tenant_id'] == tenant_id and sg['name'] == 'default'
1043 ]
1044 msg = "No default security group for tenant %s." % (tenant_id)
1045 self.assertTrue(len(sgs) > 0, msg)
Steve Heyman33735f22016-05-24 09:28:08 -05001046 return sgs[0]
Yair Fried1fc32a12014-08-04 09:11:30 +03001047
John Warren456d9ae2016-01-12 15:36:33 -05001048 def _create_security_group_rule(self, secgroup=None,
1049 sec_group_rules_client=None,
John Warrenf9606e92015-12-10 12:12:42 -05001050 tenant_id=None,
1051 security_groups_client=None, **kwargs):
Yair Fried1fc32a12014-08-04 09:11:30 +03001052 """Create a rule from a dictionary of rule parameters.
1053
1054 Create a rule in a secgroup. if secgroup not defined will search for
1055 default secgroup in tenant_id.
1056
Steve Heyman33735f22016-05-24 09:28:08 -05001057 :param secgroup: the security group.
Yair Fried1fc32a12014-08-04 09:11:30 +03001058 :param tenant_id: if secgroup not passed -- the tenant in which to
1059 search for default secgroup
1060 :param kwargs: a dictionary containing rule parameters:
1061 for example, to allow incoming ssh:
1062 rule = {
1063 direction: 'ingress'
1064 protocol:'tcp',
1065 port_range_min: 22,
1066 port_range_max: 22
1067 }
1068 """
John Warren456d9ae2016-01-12 15:36:33 -05001069 if sec_group_rules_client is None:
1070 sec_group_rules_client = self.security_group_rules_client
John Warrenf9606e92015-12-10 12:12:42 -05001071 if security_groups_client is None:
1072 security_groups_client = self.security_groups_client
Yair Frieddb6c9e92014-08-06 08:53:13 +03001073 if not tenant_id:
John Warrenf9606e92015-12-10 12:12:42 -05001074 tenant_id = security_groups_client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001075 if secgroup is None:
John Warrenf9606e92015-12-10 12:12:42 -05001076 secgroup = self._default_security_group(
1077 client=security_groups_client, tenant_id=tenant_id)
Yair Fried1fc32a12014-08-04 09:11:30 +03001078
Steve Heyman33735f22016-05-24 09:28:08 -05001079 ruleset = dict(security_group_id=secgroup['id'],
1080 tenant_id=secgroup['tenant_id'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001081 ruleset.update(kwargs)
1082
John Warren456d9ae2016-01-12 15:36:33 -05001083 sg_rule = sec_group_rules_client.create_security_group_rule(**ruleset)
Steve Heyman33735f22016-05-24 09:28:08 -05001084 sg_rule = sg_rule['security_group_rule']
1085
1086 self.assertEqual(secgroup['tenant_id'], sg_rule['tenant_id'])
1087 self.assertEqual(secgroup['id'], sg_rule['security_group_id'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001088
1089 return sg_rule
1090
John Warren456d9ae2016-01-12 15:36:33 -05001091 def _create_loginable_secgroup_rule(self, security_group_rules_client=None,
1092 secgroup=None,
John Warrenf9606e92015-12-10 12:12:42 -05001093 security_groups_client=None):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001094 """Create loginable security group rule
1095
Alex Stafeyevdd5dde92016-05-08 14:35:04 +03001096 This function will create:
1097 1. egress and ingress tcp port 22 allow rule in order to allow ssh
1098 access for ipv4.
1099 2. egress and ingress ipv6 icmp allow rule, in order to allow icmpv6.
1100 3. egress and ingress ipv4 icmp allow rule, in order to allow icmpv4.
Yair Fried1fc32a12014-08-04 09:11:30 +03001101 """
1102
John Warren456d9ae2016-01-12 15:36:33 -05001103 if security_group_rules_client is None:
1104 security_group_rules_client = self.security_group_rules_client
John Warrenf9606e92015-12-10 12:12:42 -05001105 if security_groups_client is None:
1106 security_groups_client = self.security_groups_client
Yair Fried1fc32a12014-08-04 09:11:30 +03001107 rules = []
1108 rulesets = [
1109 dict(
1110 # ssh
1111 protocol='tcp',
1112 port_range_min=22,
1113 port_range_max=22,
1114 ),
1115 dict(
1116 # ping
1117 protocol='icmp',
Andreas Scheuring887ca8e2015-02-03 17:56:12 +01001118 ),
1119 dict(
1120 # ipv6-icmp for ping6
1121 protocol='icmp',
1122 ethertype='IPv6',
Yair Fried1fc32a12014-08-04 09:11:30 +03001123 )
1124 ]
John Warren456d9ae2016-01-12 15:36:33 -05001125 sec_group_rules_client = security_group_rules_client
Yair Fried1fc32a12014-08-04 09:11:30 +03001126 for ruleset in rulesets:
1127 for r_direction in ['ingress', 'egress']:
1128 ruleset['direction'] = r_direction
1129 try:
1130 sg_rule = self._create_security_group_rule(
John Warren456d9ae2016-01-12 15:36:33 -05001131 sec_group_rules_client=sec_group_rules_client,
1132 secgroup=secgroup,
John Warrenf9606e92015-12-10 12:12:42 -05001133 security_groups_client=security_groups_client,
1134 **ruleset)
Masayuki Igawad9388762015-01-20 14:56:42 +09001135 except lib_exc.Conflict as ex:
Yair Fried1fc32a12014-08-04 09:11:30 +03001136 # if rule already exist - skip rule and continue
1137 msg = 'Security group rule already exists'
1138 if msg not in ex._error_string:
1139 raise ex
1140 else:
Steve Heyman33735f22016-05-24 09:28:08 -05001141 self.assertEqual(r_direction, sg_rule['direction'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001142 rules.append(sg_rule)
1143
1144 return rules
1145
Yair Frieddb6c9e92014-08-06 08:53:13 +03001146 def _get_router(self, client=None, tenant_id=None):
Yair Fried1fc32a12014-08-04 09:11:30 +03001147 """Retrieve a router for the given tenant id.
1148
1149 If a public router has been configured, it will be returned.
1150
1151 If a public router has not been configured, but a public
1152 network has, a tenant router will be created and returned that
1153 routes traffic to the public network.
1154 """
Yair Frieddb6c9e92014-08-06 08:53:13 +03001155 if not client:
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +00001156 client = self.routers_client
Yair Frieddb6c9e92014-08-06 08:53:13 +03001157 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +00001158 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001159 router_id = CONF.network.public_router_id
1160 network_id = CONF.network.public_network_id
1161 if router_id:
David Kranzca4c7e72015-05-27 11:39:19 -04001162 body = client.show_router(router_id)
Steve Heyman33735f22016-05-24 09:28:08 -05001163 return body['router']
Yair Fried1fc32a12014-08-04 09:11:30 +03001164 elif network_id:
Yair Frieddb6c9e92014-08-06 08:53:13 +03001165 router = self._create_router(client, tenant_id)
Steve Heyman33735f22016-05-24 09:28:08 -05001166 kwargs = {'external_gateway_info': dict(network_id=network_id)}
1167 router = client.update_router(router['id'], **kwargs)['router']
Yair Fried1fc32a12014-08-04 09:11:30 +03001168 return router
1169 else:
1170 raise Exception("Neither of 'public_router_id' or "
1171 "'public_network_id' has been defined.")
1172
Yair Frieddb6c9e92014-08-06 08:53:13 +03001173 def _create_router(self, client=None, tenant_id=None,
1174 namestart='router-smoke'):
1175 if not client:
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +00001176 client = self.routers_client
Yair Frieddb6c9e92014-08-06 08:53:13 +03001177 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +00001178 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001179 name = data_utils.rand_name(namestart)
David Kranz34e88122014-12-11 15:24:05 -05001180 result = client.create_router(name=name,
1181 admin_state_up=True,
1182 tenant_id=tenant_id)
Steve Heyman33735f22016-05-24 09:28:08 -05001183 router = result['router']
1184 self.assertEqual(router['name'], name)
1185 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
1186 client.delete_router,
1187 router['id'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001188 return router
1189
Alok Maurya6384bbb2014-07-13 06:44:29 -07001190 def _update_router_admin_state(self, router, admin_state_up):
Steve Heyman33735f22016-05-24 09:28:08 -05001191 kwargs = dict(admin_state_up=admin_state_up)
1192 router = self.routers_client.update_router(
1193 router['id'], **kwargs)['router']
1194 self.assertEqual(admin_state_up, router['admin_state_up'])
Alok Maurya6384bbb2014-07-13 06:44:29 -07001195
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -07001196 def create_networks(self, networks_client=None,
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +00001197 routers_client=None, subnets_client=None,
1198 tenant_id=None, dns_nameservers=None):
Yair Fried1fc32a12014-08-04 09:11:30 +03001199 """Create a network with a subnet connected to a router.
1200
David Shrewsbury9bac3662014-08-07 15:07:01 -04001201 The baremetal driver is a special case since all nodes are
1202 on the same shared network.
1203
Yair Fried413bf2d2014-11-19 17:07:11 +02001204 :param tenant_id: id of tenant to create resources in.
1205 :param dns_nameservers: list of dns servers to send to subnet.
Yair Fried1fc32a12014-08-04 09:11:30 +03001206 :returns: network, subnet, router
1207 """
David Shrewsbury9bac3662014-08-07 15:07:01 -04001208 if CONF.baremetal.driver_enabled:
1209 # NOTE(Shrews): This exception is for environments where tenant
1210 # credential isolation is available, but network separation is
1211 # not (the current baremetal case). Likely can be removed when
1212 # test account mgmt is reworked:
1213 # https://blueprints.launchpad.net/tempest/+spec/test-accounts
Adam Gandelman878a5fd2015-03-30 14:33:36 -07001214 if not CONF.compute.fixed_network_name:
1215 m = 'fixed_network_name must be specified in config'
1216 raise exceptions.InvalidConfiguration(m)
David Shrewsbury9bac3662014-08-07 15:07:01 -04001217 network = self._get_network_by_name(
1218 CONF.compute.fixed_network_name)
1219 router = None
1220 subnet = None
1221 else:
John Warren94d8faf2015-09-15 12:22:24 -04001222 network = self._create_network(
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -07001223 networks_client=networks_client,
John Warren94d8faf2015-09-15 12:22:24 -04001224 tenant_id=tenant_id)
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +00001225 router = self._get_router(client=routers_client,
1226 tenant_id=tenant_id)
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -07001227 subnet_kwargs = dict(network=network,
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +00001228 subnets_client=subnets_client,
1229 routers_client=routers_client)
Yair Fried413bf2d2014-11-19 17:07:11 +02001230 # use explicit check because empty list is a valid option
1231 if dns_nameservers is not None:
1232 subnet_kwargs['dns_nameservers'] = dns_nameservers
1233 subnet = self._create_subnet(**subnet_kwargs)
Steve Heyman33735f22016-05-24 09:28:08 -05001234 if not routers_client:
1235 routers_client = self.routers_client
1236 router_id = router['id']
1237 routers_client.add_router_interface(router_id,
1238 subnet_id=subnet['id'])
1239
1240 # save a cleanup job to remove this association between
1241 # router and subnet
1242 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
1243 routers_client.remove_router_interface, router_id,
1244 subnet_id=subnet['id'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001245 return network, subnet, router
1246
1247
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001248# power/provision states as of icehouse
1249class BaremetalPowerStates(object):
1250 """Possible power states of an Ironic node."""
1251 POWER_ON = 'power on'
1252 POWER_OFF = 'power off'
1253 REBOOT = 'rebooting'
1254 SUSPEND = 'suspended'
1255
1256
1257class BaremetalProvisionStates(object):
1258 """Possible provision states of an Ironic node."""
1259 NOSTATE = None
1260 INIT = 'initializing'
1261 ACTIVE = 'active'
1262 BUILDING = 'building'
1263 DEPLOYWAIT = 'wait call-back'
1264 DEPLOYING = 'deploying'
1265 DEPLOYFAIL = 'deploy failed'
1266 DEPLOYDONE = 'deploy complete'
1267 DELETING = 'deleting'
1268 DELETED = 'deleted'
1269 ERROR = 'error'
1270
1271
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001272class BaremetalScenarioTest(ScenarioTest):
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001273
1274 credentials = ['primary', 'admin']
1275
Adam Gandelman4a48a602014-03-20 18:23:18 -07001276 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001277 def skip_checks(cls):
1278 super(BaremetalScenarioTest, cls).skip_checks()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001279 if (not CONF.service_available.ironic or
1280 not CONF.baremetal.driver_enabled):
1281 msg = 'Ironic not available or Ironic compute driver not enabled'
1282 raise cls.skipException(msg)
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001283
1284 @classmethod
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001285 def setup_clients(cls):
1286 super(BaremetalScenarioTest, cls).setup_clients()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001287
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001288 cls.baremetal_client = cls.admin_manager.baremetal_client
Adam Gandelman4a48a602014-03-20 18:23:18 -07001289
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001290 @classmethod
1291 def resource_setup(cls):
1292 super(BaremetalScenarioTest, cls).resource_setup()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001293 # allow any issues obtaining the node list to raise early
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001294 cls.baremetal_client.list_nodes()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001295
1296 def _node_state_timeout(self, node_id, state_attr,
1297 target_states, timeout=10, interval=1):
1298 if not isinstance(target_states, list):
1299 target_states = [target_states]
1300
1301 def check_state():
1302 node = self.get_node(node_id=node_id)
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001303 if node.get(state_attr) in target_states:
Adam Gandelman4a48a602014-03-20 18:23:18 -07001304 return True
1305 return False
1306
1307 if not tempest.test.call_until_true(
1308 check_state, timeout, interval):
1309 msg = ("Timed out waiting for node %s to reach %s state(s) %s" %
1310 (node_id, state_attr, target_states))
1311 raise exceptions.TimeoutException(msg)
1312
1313 def wait_provisioning_state(self, node_id, state, timeout):
1314 self._node_state_timeout(
1315 node_id=node_id, state_attr='provision_state',
1316 target_states=state, timeout=timeout)
1317
1318 def wait_power_state(self, node_id, state):
1319 self._node_state_timeout(
1320 node_id=node_id, state_attr='power_state',
1321 target_states=state, timeout=CONF.baremetal.power_timeout)
1322
1323 def wait_node(self, instance_id):
1324 """Waits for a node to be associated with instance_id."""
Zhi Kun Liu4a8d1ea2014-04-15 22:08:21 -05001325
Adam Gandelman4a48a602014-03-20 18:23:18 -07001326 def _get_node():
Jordan Pittier9e227c52016-02-09 14:35:18 +01001327 node = test_utils.call_and_ignore_notfound_exc(
1328 self.get_node, instance_id=instance_id)
Adam Gandelman4a48a602014-03-20 18:23:18 -07001329 return node is not None
1330
1331 if not tempest.test.call_until_true(
1332 _get_node, CONF.baremetal.association_timeout, 1):
1333 msg = ('Timed out waiting to get Ironic node by instance id %s'
1334 % instance_id)
1335 raise exceptions.TimeoutException(msg)
1336
1337 def get_node(self, node_id=None, instance_id=None):
1338 if node_id:
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001339 _, body = self.baremetal_client.show_node(node_id)
1340 return body
Adam Gandelman4a48a602014-03-20 18:23:18 -07001341 elif instance_id:
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001342 _, body = self.baremetal_client.show_node_by_instance_uuid(
1343 instance_id)
1344 if body['nodes']:
1345 return body['nodes'][0]
Adam Gandelman4a48a602014-03-20 18:23:18 -07001346
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001347 def get_ports(self, node_uuid):
Adam Gandelman4a48a602014-03-20 18:23:18 -07001348 ports = []
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001349 _, body = self.baremetal_client.list_node_ports(node_uuid)
1350 for port in body['ports']:
1351 _, p = self.baremetal_client.show_port(port['uuid'])
1352 ports.append(p)
Adam Gandelman4a48a602014-03-20 18:23:18 -07001353 return ports
1354
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001355 def add_keypair(self):
1356 self.keypair = self.create_keypair()
1357
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001358 def boot_instance(self):
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001359 self.instance = self.create_server(
lanoux5fc14522015-09-21 08:17:35 +00001360 key_name=self.keypair['name'])
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001361
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001362 self.wait_node(self.instance['id'])
1363 self.node = self.get_node(instance_id=self.instance['id'])
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001364
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001365 self.wait_power_state(self.node['uuid'], BaremetalPowerStates.POWER_ON)
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001366
1367 self.wait_provisioning_state(
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001368 self.node['uuid'],
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001369 [BaremetalProvisionStates.DEPLOYWAIT,
1370 BaremetalProvisionStates.ACTIVE],
1371 timeout=15)
1372
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001373 self.wait_provisioning_state(self.node['uuid'],
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001374 BaremetalProvisionStates.ACTIVE,
1375 timeout=CONF.baremetal.active_timeout)
1376
Ken'ichi Ohmichi0eb153c2015-07-13 02:18:25 +00001377 waiters.wait_for_server_status(self.servers_client,
1378 self.instance['id'], 'ACTIVE')
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001379 self.node = self.get_node(instance_id=self.instance['id'])
ghanshyam0f825252015-08-25 16:02:50 +09001380 self.instance = (self.servers_client.show_server(self.instance['id'])
1381 ['server'])
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001382
1383 def terminate_instance(self):
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001384 self.servers_client.delete_server(self.instance['id'])
1385 self.wait_power_state(self.node['uuid'],
1386 BaremetalPowerStates.POWER_OFF)
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001387 self.wait_provisioning_state(
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001388 self.node['uuid'],
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001389 BaremetalProvisionStates.NOSTATE,
1390 timeout=CONF.baremetal.unprovision_timeout)
1391
Adam Gandelman4a48a602014-03-20 18:23:18 -07001392
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001393class EncryptionScenarioTest(ScenarioTest):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001394 """Base class for encryption scenario tests"""
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001395
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001396 credentials = ['primary', 'admin']
David Kranz4cc852b2015-03-09 14:57:11 -04001397
1398 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001399 def setup_clients(cls):
1400 super(EncryptionScenarioTest, cls).setup_clients()
Ivan Kolodyazhnybcfc32e2015-08-06 13:31:36 +03001401 if CONF.volume_feature_enabled.api_v1:
1402 cls.admin_volume_types_client = cls.os_adm.volume_types_client
1403 else:
1404 cls.admin_volume_types_client = cls.os_adm.volume_types_v2_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001405
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001406 def create_volume_type(self, client=None, name=None):
1407 if not client:
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001408 client = self.admin_volume_types_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001409 if not name:
1410 name = 'generic'
Ken'ichi Ohmichi6ded8df2015-03-23 02:00:19 +00001411 randomized_name = data_utils.rand_name('scenario-type-' + name)
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001412 LOG.debug("Creating a volume type: %s", randomized_name)
Joseph Lanoux6809bab2014-12-18 14:57:18 +00001413 body = client.create_volume_type(
lei zhang83c4bbd2015-11-27 00:35:21 +08001414 name=randomized_name)['volume_type']
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001415 self.assertIn('id', body)
1416 self.addCleanup(client.delete_volume_type, body['id'])
1417 return body
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001418
1419 def create_encryption_type(self, client=None, type_id=None, provider=None,
1420 key_size=None, cipher=None,
1421 control_location=None):
1422 if not client:
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001423 client = self.admin_volume_types_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001424 if not type_id:
1425 volume_type = self.create_volume_type()
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001426 type_id = volume_type['id']
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001427 LOG.debug("Creating an encryption type for volume type: %s", type_id)
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001428 client.create_encryption_type(
1429 type_id, provider=provider, key_size=key_size, cipher=cipher,
John Warrend053ded2015-08-13 15:22:48 +00001430 control_location=control_location)['encryption']
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001431
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001432
Masayuki Igawa0870db52015-09-18 21:08:36 +09001433class ObjectStorageScenarioTest(ScenarioTest):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001434 """Provide harness to do Object Storage scenario tests.
Chris Dent0d494112014-08-26 13:48:30 +01001435
1436 Subclasses implement the tests that use the methods provided by this
1437 class.
1438 """
1439
1440 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001441 def skip_checks(cls):
Masayuki Igawa0870db52015-09-18 21:08:36 +09001442 super(ObjectStorageScenarioTest, cls).skip_checks()
Chris Dent0d494112014-08-26 13:48:30 +01001443 if not CONF.service_available.swift:
1444 skip_msg = ("%s skipped as swift is not available" %
1445 cls.__name__)
1446 raise cls.skipException(skip_msg)
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001447
1448 @classmethod
1449 def setup_credentials(cls):
Masayuki Igawa60ea6c52014-10-15 17:32:14 +09001450 cls.set_network_resources()
Masayuki Igawa0870db52015-09-18 21:08:36 +09001451 super(ObjectStorageScenarioTest, cls).setup_credentials()
Matthew Treinish4a596932015-03-06 20:37:01 -05001452 operator_role = CONF.object_storage.operator_role
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +01001453 cls.os_operator = cls.get_client_manager(roles=[operator_role])
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001454
1455 @classmethod
1456 def setup_clients(cls):
Masayuki Igawa0870db52015-09-18 21:08:36 +09001457 super(ObjectStorageScenarioTest, cls).setup_clients()
Chris Dent0d494112014-08-26 13:48:30 +01001458 # Clients for Swift
Matthew Treinish8f268292015-02-24 20:01:36 -05001459 cls.account_client = cls.os_operator.account_client
1460 cls.container_client = cls.os_operator.container_client
1461 cls.object_client = cls.os_operator.object_client
Chris Dent0d494112014-08-26 13:48:30 +01001462
Chris Dentde456a12014-09-10 12:41:15 +01001463 def get_swift_stat(self):
Chris Dent0d494112014-08-26 13:48:30 +01001464 """get swift status for our user account."""
1465 self.account_client.list_account_containers()
1466 LOG.debug('Swift status information obtained successfully')
1467
Chris Dentde456a12014-09-10 12:41:15 +01001468 def create_container(self, container_name=None):
Chris Dent0d494112014-08-26 13:48:30 +01001469 name = container_name or data_utils.rand_name(
1470 'swift-scenario-container')
1471 self.container_client.create_container(name)
1472 # look for the container to assure it is created
Chris Dentde456a12014-09-10 12:41:15 +01001473 self.list_and_check_container_objects(name)
Chris Dent0d494112014-08-26 13:48:30 +01001474 LOG.debug('Container %s created' % (name))
Jordan Pittier9e227c52016-02-09 14:35:18 +01001475 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
Chris Dent1d4313a2014-10-28 12:16:48 +00001476 self.container_client.delete_container,
1477 name)
Chris Dent0d494112014-08-26 13:48:30 +01001478 return name
1479
Chris Dentde456a12014-09-10 12:41:15 +01001480 def delete_container(self, container_name):
Chris Dent0d494112014-08-26 13:48:30 +01001481 self.container_client.delete_container(container_name)
1482 LOG.debug('Container %s deleted' % (container_name))
1483
Chris Dentde456a12014-09-10 12:41:15 +01001484 def upload_object_to_container(self, container_name, obj_name=None):
Chris Dent0d494112014-08-26 13:48:30 +01001485 obj_name = obj_name or data_utils.rand_name('swift-scenario-object')
1486 obj_data = data_utils.arbitrary_string()
1487 self.object_client.create_object(container_name, obj_name, obj_data)
Jordan Pittier9e227c52016-02-09 14:35:18 +01001488 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
Chris Dent1d4313a2014-10-28 12:16:48 +00001489 self.object_client.delete_object,
1490 container_name,
1491 obj_name)
Chris Dent0d494112014-08-26 13:48:30 +01001492 return obj_name, obj_data
1493
Chris Dentde456a12014-09-10 12:41:15 +01001494 def delete_object(self, container_name, filename):
Chris Dent0d494112014-08-26 13:48:30 +01001495 self.object_client.delete_object(container_name, filename)
Chris Dentde456a12014-09-10 12:41:15 +01001496 self.list_and_check_container_objects(container_name,
1497 not_present_obj=[filename])
Chris Dent0d494112014-08-26 13:48:30 +01001498
Chris Dentde456a12014-09-10 12:41:15 +01001499 def list_and_check_container_objects(self, container_name,
1500 present_obj=None,
1501 not_present_obj=None):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001502 # List objects for a given container and assert which are present and
1503 # which are not.
Ghanshyam2a180b82014-06-16 13:54:22 +09001504 if present_obj is None:
1505 present_obj = []
1506 if not_present_obj is None:
1507 not_present_obj = []
Chris Dent0d494112014-08-26 13:48:30 +01001508 _, object_list = self.container_client.list_container_contents(
1509 container_name)
1510 if present_obj:
1511 for obj in present_obj:
1512 self.assertIn(obj, object_list)
1513 if not_present_obj:
1514 for obj in not_present_obj:
1515 self.assertNotIn(obj, object_list)
1516
Chris Dentde456a12014-09-10 12:41:15 +01001517 def change_container_acl(self, container_name, acl):
Chris Dent0d494112014-08-26 13:48:30 +01001518 metadata_param = {'metadata_prefix': 'x-container-',
1519 'metadata': {'read': acl}}
1520 self.container_client.update_container_metadata(container_name,
1521 **metadata_param)
1522 resp, _ = self.container_client.list_container_metadata(container_name)
1523 self.assertEqual(resp['x-container-read'], acl)
1524
Chris Dentde456a12014-09-10 12:41:15 +01001525 def download_and_verify(self, container_name, obj_name, expected_data):
Chris Dent0d494112014-08-26 13:48:30 +01001526 _, obj = self.object_client.get_object(container_name, obj_name)
1527 self.assertEqual(obj, expected_data)