blob: 952c0c20cc8746f5051bdc7016a3df09f42b25bc [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
130 def _wait_for_cleanups(self):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000131 # To handle async delete actions, a list of waits is added
132 # which will be iterated over as the last step of clearing the
133 # cleanup queue. That way all the delete calls are made up front
134 # and the tests won't succeed unless the deletes are eventually
135 # successful. This is the same basic approach used in the api tests to
136 # limit cleanup execution time except here it is multi-resource,
137 # because of the nature of the scenario tests.
Andrea Frittoli247058f2014-07-16 16:09:22 +0100138 for wait in self.cleanup_waits:
139 waiter_callable = wait.pop('waiter_callable')
140 waiter_callable(**wait)
141
142 # ## Test functions library
143 #
144 # The create_[resource] functions only return body and discard the
145 # resp part which is not used in scenario tests
146
Yair Frieddb6c9e92014-08-06 08:53:13 +0300147 def create_keypair(self, client=None):
148 if not client:
149 client = self.keypairs_client
Andrea Frittoli247058f2014-07-16 16:09:22 +0100150 name = data_utils.rand_name(self.__class__.__name__)
151 # We don't need to create a keypair by pubkey in scenario
Ken'ichi Ohmichie364bce2015-07-17 10:27:59 +0000152 body = client.create_keypair(name=name)
Yair Frieddb6c9e92014-08-06 08:53:13 +0300153 self.addCleanup(client.delete_keypair, name)
ghanshyamdee01f22015-08-17 11:41:47 +0900154 return body['keypair']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100155
Anusha Ramineni9aaef8b2016-01-19 10:56:40 +0530156 def create_server(self, name=None, image_id=None, flavor=None,
lanoux5fc14522015-09-21 08:17:35 +0000157 validatable=False, wait_until=None,
158 wait_on_delete=True, clients=None, **kwargs):
159 """Wrapper utility that returns a test server.
Andrea Frittoli247058f2014-07-16 16:09:22 +0100160
lanoux5fc14522015-09-21 08:17:35 +0000161 This wrapper utility calls the common create test server and
162 returns a test server. The purpose of this wrapper is to minimize
163 the impact on the code of the tests already using this
164 function.
Andrea Frittoli247058f2014-07-16 16:09:22 +0100165 """
Andrea Frittoli247058f2014-07-16 16:09:22 +0100166
lanoux5fc14522015-09-21 08:17:35 +0000167 # NOTE(jlanoux): As a first step, ssh checks in the scenario
168 # tests need to be run regardless of the run_validation and
169 # validatable parameters and thus until the ssh validation job
170 # becomes voting in CI. The test resources management and IP
171 # association are taken care of in the scenario tests.
172 # Therefore, the validatable parameter is set to false in all
173 # those tests. In this way create_server just return a standard
174 # server and the scenario tests always perform ssh checks.
175
176 # Needed for the cross_tenant_traffic test:
177 if clients is None:
178 clients = self.manager
179
180 vnic_type = CONF.network.port_vnic_type
181
182 # If vnic_type is configured create port for
183 # every network
184 if vnic_type:
185 ports = []
Lenny Verkhovsky69363502016-07-17 16:33:33 +0300186
lanoux5fc14522015-09-21 08:17:35 +0000187 create_port_body = {'binding:vnic_type': vnic_type,
188 'namestart': 'port-smoke'}
189 if kwargs:
190 # Convert security group names to security group ids
191 # to pass to create_port
192 if 'security_groups' in kwargs:
193 security_groups =\
John Warrenf9606e92015-12-10 12:12:42 -0500194 clients.security_groups_client.list_security_groups(
lanoux5fc14522015-09-21 08:17:35 +0000195 ).get('security_groups')
196 sec_dict = dict([(s['name'], s['id'])
197 for s in security_groups])
198
199 sec_groups_names = [s['name'] for s in kwargs.pop(
200 'security_groups')]
201 security_groups_ids = [sec_dict[s]
202 for s in sec_groups_names]
203
204 if security_groups_ids:
205 create_port_body[
206 'security_groups'] = security_groups_ids
Lenny Verkhovsky69363502016-07-17 16:33:33 +0300207 networks = kwargs.pop('networks', [])
208 else:
209 networks = []
lanoux5fc14522015-09-21 08:17:35 +0000210
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']
Lenny Verkhovsky69363502016-07-17 16:33:33 +0300224 if 'port' not in net:
225 port = self._create_port(network_id=net_id,
226 client=clients.ports_client,
227 **create_port_body)
228 ports.append({'port': port['id']})
229 else:
230 ports.append({'port': net['port']})
lanoux5fc14522015-09-21 08:17:35 +0000231 if ports:
232 kwargs['networks'] = ports
233 self.ports = ports
234
235 tenant_network = self.get_tenant_network()
236
237 body, servers = compute.create_test_server(
238 clients,
239 tenant_network=tenant_network,
240 wait_until=wait_until,
Anusha Ramineni9aaef8b2016-01-19 10:56:40 +0530241 name=name, flavor=flavor,
242 image_id=image_id, **kwargs)
lanoux5fc14522015-09-21 08:17:35 +0000243
244 # TODO(jlanoux) Move wait_on_delete in compute.py
Andrea Frittoli247058f2014-07-16 16:09:22 +0100245 if wait_on_delete:
Ken'ichi Ohmichie91a0c62015-08-13 02:09:16 +0000246 self.addCleanup(waiters.wait_for_server_termination,
lanoux5fc14522015-09-21 08:17:35 +0000247 clients.servers_client,
248 body['id'])
249
Andrea Frittoli247058f2014-07-16 16:09:22 +0100250 self.addCleanup_with_wait(
Ken'ichi Ohmichie91a0c62015-08-13 02:09:16 +0000251 waiter_callable=waiters.wait_for_server_termination,
lanoux5fc14522015-09-21 08:17:35 +0000252 thing_id=body['id'], thing_id_param='server_id',
Jordan Pittier9e227c52016-02-09 14:35:18 +0100253 cleanup_callable=test_utils.call_and_ignore_notfound_exc,
lanoux5fc14522015-09-21 08:17:35 +0000254 cleanup_args=[clients.servers_client.delete_server, body['id']],
255 waiter_client=clients.servers_client)
256 server = clients.servers_client.show_server(body['id'])['server']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100257 return server
258
Markus Zoeller3d2a21c2015-02-27 12:04:22 +0100259 def create_volume(self, size=None, name=None, snapshot_id=None,
Jordan Pittier5e1741c2016-03-02 18:25:51 +0100260 imageRef=None, volume_type=None):
Andrea Frittoli247058f2014-07-16 16:09:22 +0100261 if name is None:
262 name = data_utils.rand_name(self.__class__.__name__)
Ghanshyam8fc0ed22015-12-18 10:25:14 +0900263 kwargs = {'display_name': name,
264 'snapshot_id': snapshot_id,
265 'imageRef': imageRef,
266 'volume_type': volume_type}
267 if size is not None:
268 kwargs.update({'size': size})
269 volume = self.volumes_client.create_volume(**kwargs)['volume']
Matt Riedemanne85c2702014-09-10 11:50:13 -0700270
Jordan Pittier5e1741c2016-03-02 18:25:51 +0100271 self.addCleanup(self.volumes_client.wait_for_resource_deletion,
272 volume['id'])
Jordan Pittier9e227c52016-02-09 14:35:18 +0100273 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
Jordan Pittier5e1741c2016-03-02 18:25:51 +0100274 self.volumes_client.delete_volume, volume['id'])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100275
Ivan Kolodyazhnybcfc32e2015-08-06 13:31:36 +0300276 # NOTE(e0ne): Cinder API v2 uses name instead of display_name
277 if 'display_name' in volume:
278 self.assertEqual(name, volume['display_name'])
279 else:
280 self.assertEqual(name, volume['name'])
Yaroslav Lobankoved3a35b2016-03-24 22:41:30 -0500281 waiters.wait_for_volume_status(self.volumes_client,
282 volume['id'], 'available')
Andrea Frittoli247058f2014-07-16 16:09:22 +0100283 # The volume retrieved on creation has a non-up-to-date status.
284 # Retrieval after it becomes active ensures correct details.
John Warren6177c9e2015-08-19 20:00:17 +0000285 volume = self.volumes_client.show_volume(volume['id'])['volume']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100286 return volume
287
Yair Fried1fc32a12014-08-04 09:11:30 +0300288 def _create_loginable_secgroup_rule(self, secgroup_id=None):
John Warrenf2345512015-12-10 13:39:30 -0500289 _client = self.compute_security_groups_client
John Warren5cdbf422016-01-05 12:42:43 -0500290 _client_rules = self.compute_security_group_rules_client
Andrea Frittoli247058f2014-07-16 16:09:22 +0100291 if secgroup_id is None:
ghanshyamb610b772015-08-24 17:29:38 +0900292 sgs = _client.list_security_groups()['security_groups']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100293 for sg in sgs:
294 if sg['name'] == 'default':
295 secgroup_id = sg['id']
296
297 # These rules are intended to permit inbound ssh and icmp
298 # traffic from all sources, so no group_id is provided.
299 # Setting a group_id would only permit traffic from ports
300 # belonging to the same security group.
301 rulesets = [
302 {
303 # ssh
Ken'ichi Ohmichieb7eeec2015-07-21 01:00:06 +0000304 'ip_protocol': 'tcp',
Andrea Frittoli247058f2014-07-16 16:09:22 +0100305 'from_port': 22,
306 'to_port': 22,
307 'cidr': '0.0.0.0/0',
308 },
309 {
310 # ping
Ken'ichi Ohmichieb7eeec2015-07-21 01:00:06 +0000311 'ip_protocol': 'icmp',
Andrea Frittoli247058f2014-07-16 16:09:22 +0100312 'from_port': -1,
313 'to_port': -1,
314 'cidr': '0.0.0.0/0',
315 }
316 ]
317 rules = list()
318 for ruleset in rulesets:
Ken'ichi Ohmichieb7eeec2015-07-21 01:00:06 +0000319 sg_rule = _client_rules.create_security_group_rule(
ghanshyam0a5e1232015-08-24 16:59:59 +0900320 parent_group_id=secgroup_id, **ruleset)['security_group_rule']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100321 rules.append(sg_rule)
322 return rules
323
Yair Fried1fc32a12014-08-04 09:11:30 +0300324 def _create_security_group(self):
Andrea Frittoli247058f2014-07-16 16:09:22 +0100325 # Create security group
326 sg_name = data_utils.rand_name(self.__class__.__name__)
327 sg_desc = sg_name + " description"
John Warrenf2345512015-12-10 13:39:30 -0500328 secgroup = self.compute_security_groups_client.create_security_group(
ghanshyamb610b772015-08-24 17:29:38 +0900329 name=sg_name, description=sg_desc)['security_group']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100330 self.assertEqual(secgroup['name'], sg_name)
331 self.assertEqual(secgroup['description'], sg_desc)
John Warrenf2345512015-12-10 13:39:30 -0500332 self.addCleanup(
Jordan Pittier9e227c52016-02-09 14:35:18 +0100333 test_utils.call_and_ignore_notfound_exc,
John Warrenf2345512015-12-10 13:39:30 -0500334 self.compute_security_groups_client.delete_security_group,
335 secgroup['id'])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100336
337 # Add rules to the security group
Yair Fried1fc32a12014-08-04 09:11:30 +0300338 self._create_loginable_secgroup_rule(secgroup['id'])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100339
340 return secgroup
341
Sean Dague20e98612016-01-06 14:33:28 -0500342 def get_remote_client(self, ip_address, username=None, private_key=None):
JordanP3fe2dc32014-11-17 13:06:01 +0100343 """Get a SSH client to a remote server
344
Sean Dague20e98612016-01-06 14:33:28 -0500345 @param ip_address the server floating or fixed IP address to use
346 for ssh validation
JordanP3fe2dc32014-11-17 13:06:01 +0100347 @param username name of the Linux account on the remote server
348 @param private_key the SSH private key to use
JordanP3fe2dc32014-11-17 13:06:01 +0100349 @return a RemoteClient object
350 """
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700351
Andrea Frittoli247058f2014-07-16 16:09:22 +0100352 if username is None:
lanoux283273b2015-12-04 03:01:54 -0800353 username = CONF.validation.image_ssh_user
wantwatering896300c2015-03-27 15:17:42 +0800354 # Set this with 'keypair' or others to log in with keypair or
355 # username/password.
lanoux5fc14522015-09-21 08:17:35 +0000356 if CONF.validation.auth_method == 'keypair':
wantwatering896300c2015-03-27 15:17:42 +0800357 password = None
358 if private_key is None:
359 private_key = self.keypair['private_key']
360 else:
lanoux283273b2015-12-04 03:01:54 -0800361 password = CONF.validation.image_ssh_password
wantwatering896300c2015-03-27 15:17:42 +0800362 private_key = None
Sean Dague20e98612016-01-06 14:33:28 -0500363 linux_client = remote_client.RemoteClient(ip_address, username,
wantwatering896300c2015-03-27 15:17:42 +0800364 pkey=private_key,
365 password=password)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100366 try:
367 linux_client.validate_authentication()
Matt Riedemann5f0ac522015-05-21 09:16:24 -0700368 except Exception as e:
369 message = ('Initializing SSH connection to %(ip)s failed. '
Eric Brown0911af62016-02-08 17:15:40 -0800370 'Error: %(error)s' % {'ip': ip_address,
Sean Dague20e98612016-01-06 14:33:28 -0500371 'error': e})
Jordan Pittier9e227c52016-02-09 14:35:18 +0100372 caller = test_utils.find_test_caller()
Matt Riedemann5f0ac522015-05-21 09:16:24 -0700373 if caller:
374 message = '(%s) %s' % (caller, message)
375 LOG.exception(message)
Sean Dague2c98a162016-01-06 14:11:13 -0500376 self._log_console_output()
Andrea Frittoli247058f2014-07-16 16:09:22 +0100377 raise
378
379 return linux_client
380
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000381 def _image_create(self, name, fmt, path,
382 disk_format=None, properties=None):
Ghanshyam2a180b82014-06-16 13:54:22 +0900383 if properties is None:
384 properties = {}
Andrea Frittoli247058f2014-07-16 16:09:22 +0100385 name = data_utils.rand_name('%s-' % name)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100386 params = {
387 'name': name,
388 'container_format': fmt,
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000389 'disk_format': disk_format or fmt,
Andrea Frittoli247058f2014-07-16 16:09:22 +0100390 }
Matt Riedemann2aa19d42016-06-06 17:45:41 -0400391 if CONF.image_feature_enabled.api_v1:
392 params['is_public'] = 'False'
393 params['properties'] = properties
Ken'ichi Ohmichi02bcdf32016-06-17 16:41:26 -0700394 params = {'headers': common_image.image_meta_to_headers(**params)}
Matt Riedemann2aa19d42016-06-06 17:45:41 -0400395 else:
396 params['visibility'] = 'private'
397 # Additional properties are flattened out in the v2 API.
398 params.update(properties)
399 body = self.image_client.create_image(**params)
400 image = body['image'] if 'image' in body else body
Andrea Frittoli247058f2014-07-16 16:09:22 +0100401 self.addCleanup(self.image_client.delete_image, image['id'])
402 self.assertEqual("queued", image['status'])
zhang.leia4b1cef2016-03-01 10:50:01 +0800403 with open(path, 'rb') as image_file:
Matt Riedemann2aa19d42016-06-06 17:45:41 -0400404 if CONF.image_feature_enabled.api_v1:
405 self.image_client.update_image(image['id'], data=image_file)
406 else:
407 self.image_client.store_image_file(image['id'], image_file)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100408 return image['id']
409
410 def glance_image_create(self):
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300411 img_path = CONF.scenario.img_dir + "/" + CONF.scenario.img_file
Andrea Frittoli247058f2014-07-16 16:09:22 +0100412 aki_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.aki_img_file
413 ari_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.ari_img_file
414 ami_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.ami_img_file
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300415 img_container_format = CONF.scenario.img_container_format
416 img_disk_format = CONF.scenario.img_disk_format
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000417 img_properties = CONF.scenario.img_properties
PranaliD2aa523c2016-06-07 03:54:34 -0400418 LOG.debug("paths: img: %s, container_format: %s, disk_format: %s, "
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000419 "properties: %s, ami: %s, ari: %s, aki: %s" %
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300420 (img_path, img_container_format, img_disk_format,
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000421 img_properties, ami_img_path, ari_img_path, aki_img_path))
Andrea Frittoli247058f2014-07-16 16:09:22 +0100422 try:
Jordan Pittier1e443ec2015-11-20 16:15:58 +0100423 image = self._image_create('scenario-img',
424 img_container_format,
425 img_path,
426 disk_format=img_disk_format,
427 properties=img_properties)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100428 except IOError:
429 LOG.debug("A qcow2 image was not found. Try to get a uec image.")
430 kernel = self._image_create('scenario-aki', 'aki', aki_img_path)
431 ramdisk = self._image_create('scenario-ari', 'ari', ari_img_path)
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000432 properties = {'kernel_id': kernel, 'ramdisk_id': ramdisk}
Jordan Pittier1e443ec2015-11-20 16:15:58 +0100433 image = self._image_create('scenario-ami', 'ami',
434 path=ami_img_path,
435 properties=properties)
436 LOG.debug("image:%s" % image)
437
438 return image
Andrea Frittoli247058f2014-07-16 16:09:22 +0100439
440 def _log_console_output(self, servers=None):
Matthew Treinish42a3f3a2014-09-04 15:04:53 -0400441 if not CONF.compute_feature_enabled.console_output:
442 LOG.debug('Console output not supported, cannot log')
443 return
Andrea Frittoli247058f2014-07-16 16:09:22 +0100444 if not servers:
David Kranzae99b9a2015-02-16 13:37:01 -0500445 servers = self.servers_client.list_servers()
Andrea Frittoli247058f2014-07-16 16:09:22 +0100446 servers = servers['servers']
447 for server in servers:
Brant Knudson566c5712014-09-24 20:04:50 -0500448 console_output = self.servers_client.get_console_output(
Ken'ichi Ohmichibf4766a2015-12-09 07:48:43 +0000449 server['id'])['output']
David Kranzae99b9a2015-02-16 13:37:01 -0500450 LOG.debug('Console output for %s\nbody=\n%s',
451 server['id'], console_output)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100452
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000453 def _log_net_info(self, exc):
454 # network debug is called as part of ssh init
Andrey Pavlov64723762015-04-29 06:24:58 +0300455 if not isinstance(exc, lib_exc.SSHTimeout):
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000456 LOG.debug('Network information on a devstack host')
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000457
nithya-ganesan882595e2014-07-29 18:51:07 +0000458 def create_server_snapshot(self, server, name=None):
459 # Glance client
460 _image_client = self.image_client
461 # Compute client
Ghanshyamae76c122015-12-22 13:41:35 +0900462 _images_client = self.compute_images_client
nithya-ganesan882595e2014-07-29 18:51:07 +0000463 if name is None:
Ken'ichi Ohmichi6ded8df2015-03-23 02:00:19 +0000464 name = data_utils.rand_name('scenario-snapshot')
nithya-ganesan882595e2014-07-29 18:51:07 +0000465 LOG.debug("Creating a snapshot image for server: %s", server['name'])
Ken'ichi Ohmichi28f18672015-07-17 10:00:38 +0000466 image = _images_client.create_image(server['id'], name=name)
David Kranza5299eb2015-01-15 17:24:05 -0500467 image_id = image.response['location'].split('images/')[1]
Yaroslav Lobankov2fea4052016-04-19 15:05:57 +0300468 waiters.wait_for_image_status(_image_client, image_id, 'active')
nithya-ganesan882595e2014-07-29 18:51:07 +0000469 self.addCleanup_with_wait(
470 waiter_callable=_image_client.wait_for_resource_deletion,
471 thing_id=image_id, thing_id_param='id',
Jordan Pittier9e227c52016-02-09 14:35:18 +0100472 cleanup_callable=test_utils.call_and_ignore_notfound_exc,
nithya-ganesan882595e2014-07-29 18:51:07 +0000473 cleanup_args=[_image_client.delete_image, image_id])
Matt Riedemann2aa19d42016-06-06 17:45:41 -0400474 if CONF.image_feature_enabled.api_v1:
475 # In glance v1 the additional properties are stored in the headers.
Ken'ichi Ohmichi01151e82016-06-10 11:19:52 -0700476 resp = _image_client.check_image(image_id)
477 snapshot_image = common_image.get_image_meta_from_headers(resp)
Matt Riedemann2aa19d42016-06-06 17:45:41 -0400478 image_props = snapshot_image.get('properties', {})
479 else:
480 # In glance v2 the additional properties are flattened.
481 snapshot_image = _image_client.show_image(image_id)
482 image_props = snapshot_image
Andrey Pavlovc8bd4b12015-08-17 10:20:17 +0300483
Matt Riedemann2aa19d42016-06-06 17:45:41 -0400484 bdm = image_props.get('block_device_mapping')
Andrey Pavlovc8bd4b12015-08-17 10:20:17 +0300485 if bdm:
486 bdm = json.loads(bdm)
487 if bdm and 'snapshot_id' in bdm[0]:
488 snapshot_id = bdm[0]['snapshot_id']
489 self.addCleanup(
490 self.snapshots_client.wait_for_resource_deletion,
491 snapshot_id)
Jordan Pittier9e227c52016-02-09 14:35:18 +0100492 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
493 self.snapshots_client.delete_snapshot,
494 snapshot_id)
Yaroslav Lobankov667aaa22016-03-24 23:13:28 -0500495 waiters.wait_for_snapshot_status(self.snapshots_client,
496 snapshot_id, 'available')
nithya-ganesan882595e2014-07-29 18:51:07 +0000497 image_name = snapshot_image['name']
498 self.assertEqual(name, image_name)
499 LOG.debug("Created snapshot image %s for server %s",
500 image_name, server['name'])
501 return snapshot_image
502
Jordan Pittier7cf64762015-10-14 15:01:12 +0200503 def nova_volume_attach(self, server, volume_to_attach):
Joseph Lanoux6809bab2014-12-18 14:57:18 +0000504 volume = self.servers_client.attach_volume(
Jordan Pittier7cf64762015-10-14 15:01:12 +0200505 server['id'], volumeId=volume_to_attach['id'], device='/dev/%s'
ghanshyam0f825252015-08-25 16:02:50 +0900506 % CONF.compute.volume_device_name)['volumeAttachment']
Jordan Pittier7cf64762015-10-14 15:01:12 +0200507 self.assertEqual(volume_to_attach['id'], volume['id'])
Yaroslav Lobankoved3a35b2016-03-24 22:41:30 -0500508 waiters.wait_for_volume_status(self.volumes_client,
509 volume['id'], 'in-use')
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900510
Jordan Pittier7cf64762015-10-14 15:01:12 +0200511 # Return the updated volume after the attachment
512 return self.volumes_client.show_volume(volume['id'])['volume']
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900513
Jordan Pittier7cf64762015-10-14 15:01:12 +0200514 def nova_volume_detach(self, server, volume):
515 self.servers_client.detach_volume(server['id'], volume['id'])
Yaroslav Lobankoved3a35b2016-03-24 22:41:30 -0500516 waiters.wait_for_volume_status(self.volumes_client,
517 volume['id'], 'available')
Jordan Pittier7cf64762015-10-14 15:01:12 +0200518
519 volume = self.volumes_client.show_volume(volume['id'])['volume']
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900520 self.assertEqual('available', volume['status'])
521
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700522 def rebuild_server(self, server_id, image=None,
523 preserve_ephemeral=False, wait=True,
524 rebuild_kwargs=None):
525 if image is None:
526 image = CONF.compute.image_ref
527
528 rebuild_kwargs = rebuild_kwargs or {}
529
530 LOG.debug("Rebuilding server (id: %s, image: %s, preserve eph: %s)",
531 server_id, image, preserve_ephemeral)
Ken'ichi Ohmichi5271b0f2015-08-10 07:53:27 +0000532 self.servers_client.rebuild_server(
533 server_id=server_id, image_ref=image,
534 preserve_ephemeral=preserve_ephemeral,
535 **rebuild_kwargs)
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700536 if wait:
Ken'ichi Ohmichi0eb153c2015-07-13 02:18:25 +0000537 waiters.wait_for_server_status(self.servers_client,
538 server_id, 'ACTIVE')
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700539
Steven Hardyda2a8352014-10-02 12:52:20 +0100540 def ping_ip_address(self, ip_address, should_succeed=True,
541 ping_timeout=None):
lanoux5fc14522015-09-21 08:17:35 +0000542 timeout = ping_timeout or CONF.validation.ping_timeout
Aaron Rosena7df13b2014-09-23 09:45:45 -0700543 cmd = ['ping', '-c1', '-w1', ip_address]
544
545 def ping():
546 proc = subprocess.Popen(cmd,
547 stdout=subprocess.PIPE,
548 stderr=subprocess.PIPE)
549 proc.communicate()
Shuquan Huang753629e2015-07-20 08:52:29 +0000550
Aaron Rosena7df13b2014-09-23 09:45:45 -0700551 return (proc.returncode == 0) == should_succeed
552
Jordan Pittier9e227c52016-02-09 14:35:18 +0100553 caller = test_utils.find_test_caller()
Shuquan Huang753629e2015-07-20 08:52:29 +0000554 LOG.debug('%(caller)s begins to ping %(ip)s in %(timeout)s sec and the'
555 ' expected result is %(should_succeed)s' % {
556 'caller': caller, 'ip': ip_address, 'timeout': timeout,
557 'should_succeed':
558 'reachable' if should_succeed else 'unreachable'
559 })
560 result = tempest.test.call_until_true(ping, timeout, 1)
561 LOG.debug('%(caller)s finishes ping %(ip)s in %(timeout)s sec and the '
562 'ping result is %(result)s' % {
563 'caller': caller, 'ip': ip_address, 'timeout': timeout,
564 'result': 'expected' if result else 'unexpected'
565 })
566 return result
Aaron Rosena7df13b2014-09-23 09:45:45 -0700567
Yair Friedae0e73d2014-11-24 11:56:26 +0200568 def check_vm_connectivity(self, ip_address,
569 username=None,
570 private_key=None,
571 should_connect=True):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000572 """Check server connectivity
573
Yair Friedae0e73d2014-11-24 11:56:26 +0200574 :param ip_address: server to test against
575 :param username: server's ssh username
576 :param private_key: server's ssh private key to be used
577 :param should_connect: True/False indicates positive/negative test
578 positive - attempt ping and ssh
579 negative - attempt ping and fail if succeed
580
581 :raises: AssertError if the result of the connectivity check does
582 not match the value of the should_connect param
583 """
584 if should_connect:
585 msg = "Timed out waiting for %s to become reachable" % ip_address
586 else:
587 msg = "ip address %s is reachable" % ip_address
588 self.assertTrue(self.ping_ip_address(ip_address,
589 should_succeed=should_connect),
590 msg=msg)
591 if should_connect:
592 # no need to check ssh for negative connectivity
593 self.get_remote_client(ip_address, username, private_key)
594
595 def check_public_network_connectivity(self, ip_address, username,
596 private_key, should_connect=True,
597 msg=None, servers=None):
598 # The target login is assumed to have been configured for
599 # key-based authentication by cloud-init.
600 LOG.debug('checking network connections to IP %s with user: %s' %
601 (ip_address, username))
602 try:
603 self.check_vm_connectivity(ip_address,
604 username,
605 private_key,
606 should_connect=should_connect)
Matthew Treinish53483132014-12-09 18:50:06 -0500607 except Exception:
Yair Friedae0e73d2014-11-24 11:56:26 +0200608 ex_msg = 'Public network connectivity check failed'
609 if msg:
610 ex_msg += ": " + msg
611 LOG.exception(ex_msg)
612 self._log_console_output(servers)
Yair Friedae0e73d2014-11-24 11:56:26 +0200613 raise
614
615 def create_floating_ip(self, thing, pool_name=None):
Ken'ichi Ohmichia112a592015-11-17 08:49:37 +0000616 """Create a floating IP and associates to a server on Nova"""
Yair Friedae0e73d2014-11-24 11:56:26 +0200617
Marc Koderer3b57d802016-03-22 15:23:31 +0100618 if not pool_name:
619 pool_name = CONF.network.floating_network_name
John Warrene74890a2015-11-11 15:18:01 -0500620 floating_ip = (self.compute_floating_ips_client.
Ken'ichi Ohmichie037a6f2015-12-03 06:41:49 +0000621 create_floating_ip(pool=pool_name)['floating_ip'])
Jordan Pittier9e227c52016-02-09 14:35:18 +0100622 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
John Warrene74890a2015-11-11 15:18:01 -0500623 self.compute_floating_ips_client.delete_floating_ip,
Yair Friedae0e73d2014-11-24 11:56:26 +0200624 floating_ip['id'])
John Warrene74890a2015-11-11 15:18:01 -0500625 self.compute_floating_ips_client.associate_floating_ip_to_server(
Yair Friedae0e73d2014-11-24 11:56:26 +0200626 floating_ip['ip'], thing['id'])
627 return floating_ip
628
Sean Dague20e98612016-01-06 14:33:28 -0500629 def create_timestamp(self, ip_address, dev_name=None, mount_path='/mnt',
Matt Riedemannfd5657d2015-09-30 14:47:07 -0700630 private_key=None):
Sean Dague20e98612016-01-06 14:33:28 -0500631 ssh_client = self.get_remote_client(ip_address,
Matt Riedemannfd5657d2015-09-30 14:47:07 -0700632 private_key=private_key)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300633 if dev_name is not None:
634 ssh_client.make_fs(dev_name)
Matt Riedemann076685a2015-09-30 14:38:16 -0700635 ssh_client.mount(dev_name, mount_path)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300636 cmd_timestamp = 'sudo sh -c "date > %s/timestamp; sync"' % mount_path
637 ssh_client.exec_command(cmd_timestamp)
638 timestamp = ssh_client.exec_command('sudo cat %s/timestamp'
639 % mount_path)
640 if dev_name is not None:
641 ssh_client.umount(mount_path)
642 return timestamp
643
Sean Dague20e98612016-01-06 14:33:28 -0500644 def get_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:
Matt Riedemann076685a2015-09-30 14:38:16 -0700649 ssh_client.mount(dev_name, mount_path)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300650 timestamp = ssh_client.exec_command('sudo cat %s/timestamp'
651 % mount_path)
652 if dev_name is not None:
653 ssh_client.umount(mount_path)
654 return timestamp
655
Sean Dague20e98612016-01-06 14:33:28 -0500656 def get_server_ip(self, server):
657 """Get the server fixed or floating IP.
658
659 Based on the configuration we're in, return a correct ip
660 address for validating that a guest is up.
661 """
Alexander Gubanovc8829f82015-11-12 10:35:13 +0200662 if CONF.validation.connect_method == 'floating':
Sean Dague20e98612016-01-06 14:33:28 -0500663 # The tests calling this method don't have a floating IP
zhufl0892cb22016-05-06 14:46:00 +0800664 # and can't make use of the validation resources. So the
Sean Dague20e98612016-01-06 14:33:28 -0500665 # method is creating the floating IP there.
666 return self.create_floating_ip(server)['ip']
667 elif CONF.validation.connect_method == 'fixed':
668 addresses = server['addresses'][CONF.validation.network_for_ssh]
669 for address in addresses:
670 if address['version'] == CONF.validation.ip_version_for_ssh:
671 return address['addr']
zhufl955f82b2016-07-22 11:14:34 +0800672 raise exceptions.ServerUnreachable(server_id=server['id'])
Alexander Gubanovc8829f82015-11-12 10:35:13 +0200673 else:
Sean Dague20e98612016-01-06 14:33:28 -0500674 raise exceptions.InvalidConfiguration()
Alexander Gubanovc8829f82015-11-12 10:35:13 +0200675
Andrea Frittoli2e733b52014-07-16 14:12:11 +0100676
Andrea Frittoli4971fc82014-09-25 10:22:20 +0100677class NetworkScenarioTest(ScenarioTest):
Yair Fried1fc32a12014-08-04 09:11:30 +0300678 """Base class for network scenario tests.
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000679
Yair Fried1fc32a12014-08-04 09:11:30 +0300680 This class provide helpers for network scenario tests, using the neutron
681 API. Helpers from ancestor which use the nova network API are overridden
682 with the neutron API.
683
684 This Class also enforces using Neutron instead of novanetwork.
685 Subclassed tests will be skipped if Neutron is not enabled
686
687 """
688
Andrea Frittolib21de6c2015-02-06 20:12:38 +0000689 credentials = ['primary', 'admin']
690
Yair Fried1fc32a12014-08-04 09:11:30 +0300691 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +0000692 def skip_checks(cls):
693 super(NetworkScenarioTest, cls).skip_checks()
Andrea Frittoli2ddc2632014-09-25 11:03:00 +0100694 if not CONF.service_available.neutron:
695 raise cls.skipException('Neutron not available')
Yair Fried1fc32a12014-08-04 09:11:30 +0300696
697 @classmethod
Andrea Frittoliac20b5e2014-09-15 13:31:14 +0100698 def resource_setup(cls):
699 super(NetworkScenarioTest, cls).resource_setup()
Yair Fried1fc32a12014-08-04 09:11:30 +0300700 cls.tenant_id = cls.manager.identity_client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300701
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -0700702 def _create_network(self, networks_client=None,
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000703 routers_client=None, tenant_id=None,
704 namestart='network-smoke-'):
John Warren94d8faf2015-09-15 12:22:24 -0400705 if not networks_client:
706 networks_client = self.networks_client
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000707 if not routers_client:
708 routers_client = self.routers_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300709 if not tenant_id:
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -0700710 tenant_id = networks_client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300711 name = data_utils.rand_name(namestart)
John Warren94d8faf2015-09-15 12:22:24 -0400712 result = networks_client.create_network(name=name, tenant_id=tenant_id)
Steve Heyman33735f22016-05-24 09:28:08 -0500713 network = result['network']
714
715 self.assertEqual(network['name'], name)
Jordan Pittier9e227c52016-02-09 14:35:18 +0100716 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
Steve Heyman33735f22016-05-24 09:28:08 -0500717 self.networks_client.delete_network,
718 network['id'])
Yair Fried1fc32a12014-08-04 09:11:30 +0300719 return network
720
721 def _list_networks(self, *args, **kwargs):
722 """List networks using admin creds """
John Warren94d8faf2015-09-15 12:22:24 -0400723 networks_list = self.admin_manager.networks_client.list_networks(
ghanshyam2f7cc022015-06-26 18:18:11 +0900724 *args, **kwargs)
725 return networks_list['networks']
Yair Fried1fc32a12014-08-04 09:11:30 +0300726
727 def _list_subnets(self, *args, **kwargs):
728 """List subnets using admin creds """
John Warren3961acd2015-10-02 14:38:53 -0400729 subnets_list = self.admin_manager.subnets_client.list_subnets(
ghanshyam2f7cc022015-06-26 18:18:11 +0900730 *args, **kwargs)
731 return subnets_list['subnets']
Yair Fried1fc32a12014-08-04 09:11:30 +0300732
733 def _list_routers(self, *args, **kwargs):
734 """List routers using admin creds """
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000735 routers_list = self.admin_manager.routers_client.list_routers(
ghanshyam2f7cc022015-06-26 18:18:11 +0900736 *args, **kwargs)
737 return routers_list['routers']
Yair Fried1fc32a12014-08-04 09:11:30 +0300738
739 def _list_ports(self, *args, **kwargs):
740 """List ports using admin creds """
John Warren49c0fe52015-10-22 12:35:54 -0400741 ports_list = self.admin_manager.ports_client.list_ports(
ghanshyam2f7cc022015-06-26 18:18:11 +0900742 *args, **kwargs)
743 return ports_list['ports']
Yair Fried1fc32a12014-08-04 09:11:30 +0300744
Yair Fried564d89d2015-08-06 17:02:12 +0300745 def _list_agents(self, *args, **kwargs):
746 """List agents using admin creds """
Ken'ichi Ohmichi71860062015-12-15 08:20:13 +0000747 agents_list = self.admin_manager.network_agents_client.list_agents(
Yair Fried564d89d2015-08-06 17:02:12 +0300748 *args, **kwargs)
749 return agents_list['agents']
750
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -0700751 def _create_subnet(self, network, subnets_client=None,
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000752 routers_client=None, namestart='subnet-smoke',
753 **kwargs):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000754 """Create a subnet for the given network
755
756 within the cidr block configured for tenant networks.
Yair Fried1fc32a12014-08-04 09:11:30 +0300757 """
John Warren3961acd2015-10-02 14:38:53 -0400758 if not subnets_client:
759 subnets_client = self.subnets_client
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000760 if not routers_client:
761 routers_client = self.routers_client
Yair Fried1fc32a12014-08-04 09:11:30 +0300762
763 def cidr_in_use(cidr, tenant_id):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000764 """Check cidr existence
765
lei zhangdd552b22015-11-25 20:41:48 +0800766 :returns: True if subnet with cidr already exist in tenant
767 False else
Yair Fried1fc32a12014-08-04 09:11:30 +0300768 """
769 cidr_in_use = self._list_subnets(tenant_id=tenant_id, cidr=cidr)
770 return len(cidr_in_use) != 0
771
Kirill Shileev14113572014-11-21 16:58:02 +0300772 ip_version = kwargs.pop('ip_version', 4)
773
774 if ip_version == 6:
775 tenant_cidr = netaddr.IPNetwork(
Sean Dagueed6e5862016-04-04 10:49:13 -0400776 CONF.network.project_network_v6_cidr)
777 num_bits = CONF.network.project_network_v6_mask_bits
Kirill Shileev14113572014-11-21 16:58:02 +0300778 else:
Sean Dagueed6e5862016-04-04 10:49:13 -0400779 tenant_cidr = netaddr.IPNetwork(CONF.network.project_network_cidr)
780 num_bits = CONF.network.project_network_mask_bits
Kirill Shileev14113572014-11-21 16:58:02 +0300781
Yair Fried1fc32a12014-08-04 09:11:30 +0300782 result = None
Kirill Shileev14113572014-11-21 16:58:02 +0300783 str_cidr = None
Yair Fried1fc32a12014-08-04 09:11:30 +0300784 # Repeatedly attempt subnet creation with sequential cidr
785 # blocks until an unallocated block is found.
Kirill Shileev14113572014-11-21 16:58:02 +0300786 for subnet_cidr in tenant_cidr.subnet(num_bits):
Yair Fried1fc32a12014-08-04 09:11:30 +0300787 str_cidr = str(subnet_cidr)
Steve Heyman33735f22016-05-24 09:28:08 -0500788 if cidr_in_use(str_cidr, tenant_id=network['tenant_id']):
Yair Fried1fc32a12014-08-04 09:11:30 +0300789 continue
790
791 subnet = dict(
792 name=data_utils.rand_name(namestart),
Steve Heyman33735f22016-05-24 09:28:08 -0500793 network_id=network['id'],
794 tenant_id=network['tenant_id'],
Yair Fried1fc32a12014-08-04 09:11:30 +0300795 cidr=str_cidr,
Kirill Shileev14113572014-11-21 16:58:02 +0300796 ip_version=ip_version,
Yair Fried1fc32a12014-08-04 09:11:30 +0300797 **kwargs
798 )
799 try:
John Warren3961acd2015-10-02 14:38:53 -0400800 result = subnets_client.create_subnet(**subnet)
Yair Fried1fc32a12014-08-04 09:11:30 +0300801 break
Masayuki Igawad9388762015-01-20 14:56:42 +0900802 except lib_exc.Conflict as e:
Yair Fried1fc32a12014-08-04 09:11:30 +0300803 is_overlapping_cidr = 'overlaps with another subnet' in str(e)
804 if not is_overlapping_cidr:
805 raise
806 self.assertIsNotNone(result, 'Unable to allocate tenant network')
Steve Heyman33735f22016-05-24 09:28:08 -0500807
808 subnet = result['subnet']
809 self.assertEqual(subnet['cidr'], str_cidr)
810
811 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
812 subnets_client.delete_subnet, subnet['id'])
813
Yair Fried1fc32a12014-08-04 09:11:30 +0300814 return subnet
815
Itzik Brown2ca01cd2014-12-08 12:58:20 +0200816 def _create_port(self, network_id, client=None, namestart='port-quotatest',
817 **kwargs):
Yair Frieddb6c9e92014-08-06 08:53:13 +0300818 if not client:
John Warren49c0fe52015-10-22 12:35:54 -0400819 client = self.ports_client
Yair Fried1fc32a12014-08-04 09:11:30 +0300820 name = data_utils.rand_name(namestart)
David Kranz34e88122014-12-11 15:24:05 -0500821 result = client.create_port(
Yair Fried1fc32a12014-08-04 09:11:30 +0300822 name=name,
Itzik Brown2ca01cd2014-12-08 12:58:20 +0200823 network_id=network_id,
824 **kwargs)
Yair Fried1fc32a12014-08-04 09:11:30 +0300825 self.assertIsNotNone(result, 'Unable to allocate port')
Steve Heyman33735f22016-05-24 09:28:08 -0500826 port = result['port']
827 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
828 client.delete_port, port['id'])
Yair Fried1fc32a12014-08-04 09:11:30 +0300829 return port
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)