blob: 12a986b3f4e5bf4721e53030c6e8d940c762a030 [file] [log] [blame]
Marc Koderer0abc93b2015-07-15 09:18:35 +02001# Copyright 2014 Mirantis Inc.
2# All Rights Reserved.
3#
4# Licensed under the Apache License, Version 2.0 (the "License"); you may
5# not use this file except in compliance with the License. You may obtain
6# a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13# License for the specific language governing permissions and limitations
14# under the License.
15
16import copy
17import inspect
Valeriy Ponomaryov2abf5d72016-06-01 18:30:12 +030018import re
Marc Koderer0abc93b2015-07-15 09:18:35 +020019import traceback
20
21from oslo_concurrency import lockutils
22from oslo_log import log
23import six
Sam Wanc7b7f1f2015-11-25 00:22:28 -050024from tempest.common import credentials_factory as common_creds
Raissa Sarmento7b86b9d2017-07-21 14:32:48 +010025
Valeriy Ponomaryov48a2bd72015-11-05 13:22:44 +020026from tempest import config
Raissa Sarmento7b86b9d2017-07-21 14:32:48 +010027from tempest.lib.common import dynamic_creds
Ben Swartzlander1c4ff522016-03-02 22:16:23 -050028from tempest.lib.common.utils import data_utils
haobing1264a6022018-03-13 20:39:10 +080029from tempest.lib.common.utils import test_utils
Ben Swartzlander1c4ff522016-03-02 22:16:23 -050030from tempest.lib import exceptions
Valeriy Ponomaryov48a2bd72015-11-05 13:22:44 +020031from tempest import test
Marc Koderer0abc93b2015-07-15 09:18:35 +020032
Andrea Frittoli (andreaf)369391a2016-06-27 18:59:13 +010033from manila_tempest_tests import clients
Yogeshbdb88102015-09-29 23:41:02 -040034from manila_tempest_tests.common import constants
Marc Koderer0abc93b2015-07-15 09:18:35 +020035from manila_tempest_tests import share_exceptions
Valeriy Ponomaryovfcde7712015-12-14 18:06:13 +020036from manila_tempest_tests import utils
Marc Koderer0abc93b2015-07-15 09:18:35 +020037
38CONF = config.CONF
39LOG = log.getLogger(__name__)
40
Valeriy Ponomaryov2abf5d72016-06-01 18:30:12 +030041# Test tags related to test direction
42TAG_POSITIVE = "positive"
43TAG_NEGATIVE = "negative"
44
45# Test tags related to service involvement
46TAG_API = "api"
47TAG_BACKEND = "backend"
48TAG_API_WITH_BACKEND = "api_with_backend"
49
50TAGS_MAPPER = {
51 "p": TAG_POSITIVE,
52 "n": TAG_NEGATIVE,
53 "a": TAG_API,
54 "b": TAG_BACKEND,
55 "ab": TAG_API_WITH_BACKEND,
56}
57TAGS_PATTERN = re.compile(
58 r"(?=.*\[.*\b(%(p)s|%(n)s)\b.*\])(?=.*\[.*\b(%(a)s|%(b)s|%(ab)s)\b.*\])" %
59 TAGS_MAPPER)
60
61
62def verify_test_has_appropriate_tags(self):
63 if not TAGS_PATTERN.match(self.id()):
64 msg = (
65 "Required attributes either not set or set improperly. "
66 "Two test attributes are expected:\n"
67 " - one of '%(p)s' or '%(n)s' and \n"
68 " - one of '%(a)s', '%(b)s' or '%(ab)s'."
69 ) % TAGS_MAPPER
70 raise self.failureException(msg)
71
Marc Koderer0abc93b2015-07-15 09:18:35 +020072
73class handle_cleanup_exceptions(object):
74 """Handle exceptions raised with cleanup operations.
75
76 Always suppress errors when exceptions.NotFound or exceptions.Forbidden
77 are raised.
78 Suppress all other exceptions only in case config opt
79 'suppress_errors_in_cleanup' in config group 'share' is True.
80 """
81
82 def __enter__(self):
83 return self
84
85 def __exit__(self, exc_type, exc_value, exc_traceback):
86 if not (isinstance(exc_value,
87 (exceptions.NotFound, exceptions.Forbidden)) or
88 CONF.share.suppress_errors_in_cleanup):
89 return False # Do not suppress error if any
90 if exc_traceback:
91 LOG.error("Suppressed cleanup error in Manila: "
junbolib236c242017-07-18 18:12:37 +080092 "\n%s", traceback.format_exc())
Marc Koderer0abc93b2015-07-15 09:18:35 +020093 return True # Suppress error if any
94
95
96def network_synchronized(f):
97
98 def wrapped_func(self, *args, **kwargs):
99 with_isolated_creds = True if len(args) > 2 else False
100 no_lock_required = kwargs.get(
101 "isolated_creds_client", with_isolated_creds)
102 if no_lock_required:
103 # Usage of not reusable network. No need in lock.
104 return f(self, *args, **kwargs)
105
106 # Use lock assuming reusage of common network.
107 @lockutils.synchronized("manila_network_lock", external=True)
108 def source_func(self, *args, **kwargs):
109 return f(self, *args, **kwargs)
110
111 return source_func(self, *args, **kwargs)
112
113 return wrapped_func
114
115
Valeriy Ponomaryovfcde7712015-12-14 18:06:13 +0200116skip_if_microversion_not_supported = utils.skip_if_microversion_not_supported
Xing Yang69b00b52015-11-22 16:10:44 -0500117skip_if_microversion_lt = utils.skip_if_microversion_lt
Valeriy Ponomaryova14c2252015-10-29 13:34:32 +0200118
119
Marc Koderer0abc93b2015-07-15 09:18:35 +0200120class BaseSharesTest(test.BaseTestCase):
121 """Base test case class for all Manila API tests."""
122
Valeriy Ponomaryov39cdf722016-05-30 18:16:15 +0300123 credentials = ('primary', )
Marc Koderer0abc93b2015-07-15 09:18:35 +0200124 force_tenant_isolation = False
Vitaliy Levitksicfebfff2016-12-15 16:16:35 +0200125 protocols = ["nfs", "cifs", "glusterfs", "hdfs", "cephfs", "maprfs"]
Marc Koderer0abc93b2015-07-15 09:18:35 +0200126
127 # Will be cleaned up in resource_cleanup
128 class_resources = []
129
haobing1264a6022018-03-13 20:39:10 +0800130 # Will be cleaned up in clear_net_resources
131 class_net_resources = []
132
Marc Koderer0abc93b2015-07-15 09:18:35 +0200133 # Will be cleaned up in tearDown method
134 method_resources = []
135
136 # Will be cleaned up in resource_cleanup
137 class_isolated_creds = []
138
139 # Will be cleaned up in tearDown method
140 method_isolated_creds = []
141
Andrea Frittoli (andreaf)369391a2016-06-27 18:59:13 +0100142 # NOTE(andreaf) Override the client manager class to be used, so that
143 # a stable class is used, which includes plugin registered services as well
144 client_manager = clients.Clients
145
Valeriy Ponomaryova14c2252015-10-29 13:34:32 +0200146 def skip_if_microversion_not_supported(self, microversion):
Valeriy Ponomaryovfcde7712015-12-14 18:06:13 +0200147 if not utils.is_microversion_supported(microversion):
Valeriy Ponomaryova14c2252015-10-29 13:34:32 +0200148 raise self.skipException(
149 "Microversion '%s' is not supported." % microversion)
150
Xing Yang69b00b52015-11-22 16:10:44 -0500151 def skip_if_microversion_lt(self, microversion):
152 if utils.is_microversion_lt(CONF.share.max_api_microversion,
153 microversion):
154 raise self.skipException(
155 "Microversion must be greater than or equal to '%s'." %
156 microversion)
157
Marc Koderer0abc93b2015-07-15 09:18:35 +0200158 @classmethod
Tom Barron4b8834a2017-02-02 11:02:20 -0500159 def _get_dynamic_creds(cls, name, network_resources=None):
Raissa Sarmento7b86b9d2017-07-21 14:32:48 +0100160 identity_version = CONF.identity.auth_version
161 if identity_version == 'v3':
162 identity_uri = CONF.identity.uri_v3
163 identity_admin_endpoint_type = CONF.identity.v3_endpoint_type
164 elif identity_version == 'v2':
165 identity_uri = CONF.identity.uri
166 identity_admin_endpoint_type = CONF.identity.v2_admin_endpoint_type
167
Tom Barron4b8834a2017-02-02 11:02:20 -0500168 return dynamic_creds.DynamicCredentialProvider(
Raissa Sarmento7b86b9d2017-07-21 14:32:48 +0100169 identity_version=identity_version,
Tom Barron4b8834a2017-02-02 11:02:20 -0500170 name=name,
171 network_resources=network_resources,
172 credentials_domain=CONF.auth.default_credentials_domain_name,
173 admin_role=CONF.identity.admin_role,
174 admin_creds=common_creds.get_configured_admin_credentials(),
175 identity_admin_domain_scope=CONF.identity.admin_domain_scope,
176 identity_admin_role=CONF.identity.admin_role,
177 extra_roles=None,
178 neutron_available=CONF.service_available.neutron,
179 create_networks=(
180 CONF.share.create_networks_when_multitenancy_enabled),
181 project_network_cidr=CONF.network.project_network_cidr,
182 project_network_mask_bits=CONF.network.project_network_mask_bits,
183 public_network_id=CONF.network.public_network_id,
ghanshyam2aea7c32017-12-11 00:03:56 +0000184 resource_prefix='tempest',
Raissa Sarmento7b86b9d2017-07-21 14:32:48 +0100185 identity_admin_endpoint_type=identity_admin_endpoint_type,
186 identity_uri=identity_uri)
Tom Barron4b8834a2017-02-02 11:02:20 -0500187
188 @classmethod
Marc Koderer0abc93b2015-07-15 09:18:35 +0200189 def get_client_with_isolated_creds(cls,
190 name=None,
191 type_of_creds="admin",
Clinton Knighte5c8f092015-08-27 15:00:23 -0400192 cleanup_in_class=False,
193 client_version='1'):
Marc Koderer0abc93b2015-07-15 09:18:35 +0200194 """Creates isolated creds.
195
196 :param name: name, will be used for naming ic and related stuff
197 :param type_of_creds: admin, alt or primary
198 :param cleanup_in_class: defines place where to delete
199 :returns: SharesClient -- shares client with isolated creds.
200 :returns: To client added dict attr 'creds' with
201 :returns: key elements 'tenant' and 'user'.
202 """
203 if name is None:
204 # Get name of test method
205 name = inspect.stack()[1][3]
206 if len(name) > 32:
207 name = name[0:32]
208
209 # Choose type of isolated creds
Tom Barron4b8834a2017-02-02 11:02:20 -0500210 ic = cls._get_dynamic_creds(name)
Marc Koderer0abc93b2015-07-15 09:18:35 +0200211 if "admin" in type_of_creds:
Marc Koderer5880b362016-07-06 10:59:07 +0200212 creds = ic.get_admin_creds().credentials
Marc Koderer0abc93b2015-07-15 09:18:35 +0200213 elif "alt" in type_of_creds:
Marc Koderer5880b362016-07-06 10:59:07 +0200214 creds = ic.get_alt_creds().credentials
Marc Koderer0abc93b2015-07-15 09:18:35 +0200215 else:
Marc Koderer5880b362016-07-06 10:59:07 +0200216 creds = ic.get_credentials(type_of_creds).credentials
Marc Koderer0abc93b2015-07-15 09:18:35 +0200217 ic.type_of_creds = type_of_creds
218
219 # create client with isolated creds
Andrea Frittoli (andreaf)369391a2016-06-27 18:59:13 +0100220 os = clients.Clients(creds)
Clinton Knighte5c8f092015-08-27 15:00:23 -0400221 if client_version == '1':
Andrea Frittoli (andreaf)369391a2016-06-27 18:59:13 +0100222 client = os.share_v1.SharesClient()
Clinton Knighte5c8f092015-08-27 15:00:23 -0400223 elif client_version == '2':
Andrea Frittoli (andreaf)369391a2016-06-27 18:59:13 +0100224 client = os.share_v2.SharesV2Client()
Marc Koderer0abc93b2015-07-15 09:18:35 +0200225
226 # Set place where will be deleted isolated creds
227 ic_res = {
Valeriy Ponomaryov48a2bd72015-11-05 13:22:44 +0200228 "method": ic.clear_creds,
Marc Koderer0abc93b2015-07-15 09:18:35 +0200229 "deleted": False,
230 }
231 if cleanup_in_class:
232 cls.class_isolated_creds.insert(0, ic_res)
233 else:
234 cls.method_isolated_creds.insert(0, ic_res)
235
236 # Provide share network
237 if CONF.share.multitenancy_enabled:
Valeriy Ponomaryovc5dae272016-06-10 18:29:24 +0300238 if (not CONF.service_available.neutron and
239 CONF.share.create_networks_when_multitenancy_enabled):
Marc Koderer0abc93b2015-07-15 09:18:35 +0200240 raise cls.skipException("Neutron support is required")
Andrea Frittoli (andreaf)369391a2016-06-27 18:59:13 +0100241 nc = os.network.NetworksClient()
Marc Koderer0abc93b2015-07-15 09:18:35 +0200242 share_network_id = cls.provide_share_network(client, nc, ic)
243 client.share_network_id = share_network_id
244 resource = {
245 "type": "share_network",
246 "id": client.share_network_id,
247 "client": client,
248 }
249 if cleanup_in_class:
250 cls.class_resources.insert(0, resource)
251 else:
252 cls.method_resources.insert(0, resource)
253 return client
254
255 @classmethod
Daniel Melladoe5269142017-01-12 12:17:58 +0000256 def skip_checks(cls):
257 super(BaseSharesTest, cls).skip_checks()
258 if not CONF.service_available.manila:
259 raise cls.skipException("Manila support is required")
260
261 @classmethod
Marc Koderer0abc93b2015-07-15 09:18:35 +0200262 def verify_nonempty(cls, *args):
263 if not all(args):
264 msg = "Missing API credentials in configuration."
265 raise cls.skipException(msg)
266
267 @classmethod
Valeriy Ponomaryov39cdf722016-05-30 18:16:15 +0300268 def setup_clients(cls):
269 super(BaseSharesTest, cls).setup_clients()
270 os = getattr(cls, 'os_%s' % cls.credentials[0])
Andrea Frittoli (andreaf)369391a2016-06-27 18:59:13 +0100271 # Initialise share clients for test credentials
272 cls.shares_client = os.share_v1.SharesClient()
273 cls.shares_v2_client = os.share_v2.SharesV2Client()
274 # Initialise network clients for test credentials
275 if CONF.service_available.neutron:
276 cls.networks_client = os.network.NetworksClient()
277 cls.subnets_client = os.network.SubnetsClient()
278 else:
279 cls.networks_client = None
280 cls.subnets_client = None
Valeriy Ponomaryov4fb305f2016-10-21 13:46:47 +0300281
282 if CONF.identity.auth_version == 'v3':
283 project_id = os.auth_provider.auth_data[1]['project']['id']
284 else:
285 project_id = os.auth_provider.auth_data[1]['token']['tenant']['id']
286 cls.tenant_id = project_id
287 cls.user_id = os.auth_provider.auth_data[1]['user']['id']
288
Valeriy Ponomaryov39cdf722016-05-30 18:16:15 +0300289 if CONF.share.multitenancy_enabled:
Valeriy Ponomaryovc5dae272016-06-10 18:29:24 +0300290 if (not CONF.service_available.neutron and
291 CONF.share.create_networks_when_multitenancy_enabled):
Valeriy Ponomaryov39cdf722016-05-30 18:16:15 +0300292 raise cls.skipException("Neutron support is required")
293 share_network_id = cls.provide_share_network(
Andrea Frittoli (andreaf)369391a2016-06-27 18:59:13 +0100294 cls.shares_v2_client, cls.networks_client)
Valeriy Ponomaryov39cdf722016-05-30 18:16:15 +0300295 cls.shares_client.share_network_id = share_network_id
296 cls.shares_v2_client.share_network_id = share_network_id
297
298 @classmethod
Marc Koderer0abc93b2015-07-15 09:18:35 +0200299 def resource_setup(cls):
300 if not (any(p in CONF.share.enable_protocols
301 for p in cls.protocols) and
302 CONF.service_available.manila):
303 skip_msg = "Manila is disabled"
304 raise cls.skipException(skip_msg)
305 super(BaseSharesTest, cls).resource_setup()
Marc Koderer0abc93b2015-07-15 09:18:35 +0200306
307 def setUp(self):
308 super(BaseSharesTest, self).setUp()
Marc Koderer0abc93b2015-07-15 09:18:35 +0200309 self.addCleanup(self.clear_isolated_creds)
Valeriy Ponomaryovdd162cb2016-01-20 19:09:49 +0200310 self.addCleanup(self.clear_resources)
haobing1264a6022018-03-13 20:39:10 +0800311 self.addCleanup(self.clear_net_resources)
Valeriy Ponomaryov2abf5d72016-06-01 18:30:12 +0300312 verify_test_has_appropriate_tags(self)
Marc Koderer0abc93b2015-07-15 09:18:35 +0200313
314 @classmethod
315 def resource_cleanup(cls):
Marc Koderer0abc93b2015-07-15 09:18:35 +0200316 cls.clear_resources(cls.class_resources)
317 cls.clear_isolated_creds(cls.class_isolated_creds)
haobing1264a6022018-03-13 20:39:10 +0800318 cls.clear_net_resources(cls.class_net_resources)
Sam Wan241029c2016-07-26 03:37:42 -0400319 super(BaseSharesTest, cls).resource_cleanup()
Marc Koderer0abc93b2015-07-15 09:18:35 +0200320
321 @classmethod
322 @network_synchronized
Valeriy Ponomaryov48a2bd72015-11-05 13:22:44 +0200323 def provide_share_network(cls, shares_client, networks_client,
Rodrigo Barbieri58d9de32016-09-06 13:16:47 -0300324 isolated_creds_client=None,
325 ignore_multitenancy_config=False):
Marc Koderer0abc93b2015-07-15 09:18:35 +0200326 """Used for finding/creating share network for multitenant driver.
327
328 This method creates/gets entity share-network for one tenant. This
329 share-network will be used for creation of service vm.
330
331 :param shares_client: shares client, which requires share-network
Valeriy Ponomaryov48a2bd72015-11-05 13:22:44 +0200332 :param networks_client: network client from same tenant as shares
333 :param isolated_creds_client: DynamicCredentialProvider instance
Marc Koderer0abc93b2015-07-15 09:18:35 +0200334 If provided, then its networking will be used if needed.
335 If not provided, then common network will be used if needed.
Rodrigo Barbieri58d9de32016-09-06 13:16:47 -0300336 :param ignore_multitenancy_config: provide a share network regardless
337 of 'multitenancy_enabled' configuration value.
Marc Koderer0abc93b2015-07-15 09:18:35 +0200338 :returns: str -- share network id for shares_client tenant
339 :returns: None -- if single-tenant driver used
340 """
341
342 sc = shares_client
Valeriy Ponomaryovc5dae272016-06-10 18:29:24 +0300343 search_word = "reusable"
344 sn_name = "autogenerated_by_tempest_%s" % search_word
Marc Koderer0abc93b2015-07-15 09:18:35 +0200345
Rodrigo Barbieri58d9de32016-09-06 13:16:47 -0300346 if (not ignore_multitenancy_config and
347 not CONF.share.multitenancy_enabled):
Marc Koderer0abc93b2015-07-15 09:18:35 +0200348 # Assumed usage of a single-tenant driver
349 share_network_id = None
Marc Koderer0abc93b2015-07-15 09:18:35 +0200350 else:
Rodrigo Barbieri58d9de32016-09-06 13:16:47 -0300351 if sc.share_network_id:
352 # Share-network already exists, use it
353 share_network_id = sc.share_network_id
354 elif not CONF.share.create_networks_when_multitenancy_enabled:
355 share_network_id = None
Marc Koderer0abc93b2015-07-15 09:18:35 +0200356
357 # Try get suitable share-network
358 share_networks = sc.list_share_networks_with_detail()
359 for sn in share_networks:
Rodrigo Barbieri58d9de32016-09-06 13:16:47 -0300360 if (sn["neutron_net_id"] is None and
361 sn["neutron_subnet_id"] is None and
Marc Koderer0abc93b2015-07-15 09:18:35 +0200362 sn["name"] and search_word in sn["name"]):
363 share_network_id = sn["id"]
364 break
Marc Koderer0abc93b2015-07-15 09:18:35 +0200365
Rodrigo Barbieri58d9de32016-09-06 13:16:47 -0300366 # Create new share-network if one was not found
367 if share_network_id is None:
368 sn_desc = "This share-network was created by tempest"
369 sn = sc.create_share_network(name=sn_name,
370 description=sn_desc)
371 share_network_id = sn["id"]
372 else:
373 net_id = subnet_id = share_network_id = None
374
375 if not isolated_creds_client:
376 # Search for networks, created in previous runs
377 service_net_name = "share-service"
378 networks = networks_client.list_networks()
379 if "networks" in networks.keys():
380 networks = networks["networks"]
381 for network in networks:
382 if (service_net_name in network["name"] and
383 sc.tenant_id == network['tenant_id']):
384 net_id = network["id"]
385 if len(network["subnets"]) > 0:
386 subnet_id = network["subnets"][0]
387 break
388
389 # Create suitable network
390 if net_id is None or subnet_id is None:
Tom Barron4b8834a2017-02-02 11:02:20 -0500391 ic = cls._get_dynamic_creds(service_net_name)
Rodrigo Barbieri58d9de32016-09-06 13:16:47 -0300392 net_data = ic._create_network_resources(sc.tenant_id)
393 network, subnet, router = net_data
394 net_id = network["id"]
395 subnet_id = subnet["id"]
haobing1264a6022018-03-13 20:39:10 +0800396 network_res = {
397 "type": "network",
398 "resource": network,
399 "client": ic,
400 }
401 subnet_res = {
402 "type": "subnet",
403 "resource": subnet,
404 "client": ic,
405 }
406 router_res = {
407 "type": "router",
408 "resource": router,
409 "client": ic,
410 }
411 cls.class_net_resources.insert(0, network_res)
412 cls.class_net_resources.insert(0, subnet_res)
413 cls.class_net_resources.insert(0, router_res)
Rodrigo Barbieri58d9de32016-09-06 13:16:47 -0300414
415 # Try get suitable share-network
416 share_networks = sc.list_share_networks_with_detail()
417 for sn in share_networks:
418 if (net_id == sn["neutron_net_id"] and
419 subnet_id == sn["neutron_subnet_id"] and
420 sn["name"] and search_word in sn["name"]):
421 share_network_id = sn["id"]
422 break
423 else:
424 sn_name = "autogenerated_by_tempest_for_isolated_creds"
425 # Use precreated network and subnet from isolated creds
426 net_id = isolated_creds_client.get_credentials(
427 isolated_creds_client.type_of_creds).network['id']
428 subnet_id = isolated_creds_client.get_credentials(
429 isolated_creds_client.type_of_creds).subnet['id']
430
431 # Create suitable share-network
432 if share_network_id is None:
433 sn_desc = "This share-network was created by tempest"
434 sn = sc.create_share_network(name=sn_name,
435 description=sn_desc,
436 neutron_net_id=net_id,
437 neutron_subnet_id=subnet_id)
438 share_network_id = sn["id"]
Marc Koderer0abc93b2015-07-15 09:18:35 +0200439
440 return share_network_id
441
442 @classmethod
haobing1264a6022018-03-13 20:39:10 +0800443 def clear_net_resources(cls, resources=None):
444 if resources is None:
445 resources = cls.class_net_resources
446 for res in resources:
447 if "deleted" not in res.keys():
448 res["deleted"] = False
449 if not (res["deleted"]):
450 if res["type"] is "router":
451 cls.clear_router(res['client'], res['resource'])
452 elif res["type"] is "subnet":
453 cls.clear_subnet(res['client'], res['resource'])
454 elif res["type"] is "network":
455 cls.clear_network(res['client'], res['resource'])
456 else:
457 LOG.warning("Provided unsupported resource type for "
458 "cleanup '%s'. Skipping." % res["type"])
459 res["deleted"] = True
460
461 @classmethod
462 def clear_router(cls, ic, router):
463 body = ic.ports_admin_client.list_ports(device_id=router['id'])
464 interfaces = body['ports']
465 for i in interfaces:
466 test_utils.call_and_ignore_notfound_exc(
467 ic.routers_admin_client.remove_router_interface, router['id'],
468 subnet_id=i['fixed_ips'][0]['subnet_id'])
469
470 try:
471 ic.routers_admin_client.delete_router(router['id'])
472 except exceptions.NotFound:
473 LOG.warning('router with name: %s not found for delete' %
474 router['name'])
475
476 @classmethod
477 def clear_subnet(cls, ic, subnet):
478 client = ic.subnets_admin_client
479 try:
480 client.delete_subnet(subnet['id'])
481 except exceptions.NotFound:
482 LOG.warning('subnet with name: %s not found for delete' %
483 subnet['name'])
484
485 @classmethod
486 def clear_network(cls, ic, network):
487 net_client = ic.networks_admin_client
488 try:
489 net_client.delete_network(network['id'])
490 except exceptions.NotFound:
491 LOG.warning('network with name: %s not found for delete' %
492 network['name'])
493
494 @classmethod
marcusvrne0d7cfd2016-06-24 12:27:55 -0300495 def _create_share(cls, share_protocol=None, size=None, name=None,
Marc Koderer0abc93b2015-07-15 09:18:35 +0200496 snapshot_id=None, description=None, metadata=None,
497 share_network_id=None, share_type_id=None,
Andrew Kerrb8436922016-06-01 15:32:43 -0400498 share_group_id=None, client=None,
Clinton Knighte5c8f092015-08-27 15:00:23 -0400499 cleanup_in_class=True, is_public=False, **kwargs):
Valeriy Ponomaryov1aaa72d2015-09-08 12:59:41 +0300500 client = client or cls.shares_v2_client
Marc Koderer0abc93b2015-07-15 09:18:35 +0200501 description = description or "Tempest's share"
yogesh06f519f2017-06-26 13:16:12 -0400502 share_network_id = (share_network_id or
503 CONF.share.share_network_id or
504 client.share_network_id or None)
Marc Koderer0abc93b2015-07-15 09:18:35 +0200505 metadata = metadata or {}
marcusvrne0d7cfd2016-06-24 12:27:55 -0300506 size = size or CONF.share.share_size
Clinton Knighte5c8f092015-08-27 15:00:23 -0400507 kwargs.update({
Marc Koderer0abc93b2015-07-15 09:18:35 +0200508 'share_protocol': share_protocol,
509 'size': size,
510 'name': name,
511 'snapshot_id': snapshot_id,
512 'description': description,
513 'metadata': metadata,
514 'share_network_id': share_network_id,
515 'share_type_id': share_type_id,
516 'is_public': is_public,
Clinton Knighte5c8f092015-08-27 15:00:23 -0400517 })
Andrew Kerrb8436922016-06-01 15:32:43 -0400518 if share_group_id:
519 kwargs['share_group_id'] = share_group_id
Andrew Kerrbf31e912015-07-29 10:39:38 -0400520
Marc Koderer0abc93b2015-07-15 09:18:35 +0200521 share = client.create_share(**kwargs)
Andrew Kerrbf31e912015-07-29 10:39:38 -0400522 resource = {"type": "share", "id": share["id"], "client": client,
Andrew Kerrb8436922016-06-01 15:32:43 -0400523 "share_group_id": share_group_id}
Marc Koderer0abc93b2015-07-15 09:18:35 +0200524 cleanup_list = (cls.class_resources if cleanup_in_class else
525 cls.method_resources)
526 cleanup_list.insert(0, resource)
527 return share
528
529 @classmethod
Rodrigo Barbieri427bc052016-06-06 17:10:06 -0300530 def migrate_share(
531 cls, share_id, dest_host, wait_for_status, client=None,
Rodrigo Barbieri027df982016-11-24 15:52:03 -0200532 force_host_assisted_migration=False, writable=False,
533 nondisruptive=False, preserve_metadata=False,
534 preserve_snapshots=False, new_share_network_id=None,
Rodrigo Barbierid38d2f52016-07-19 22:24:56 -0300535 new_share_type_id=None, **kwargs):
Clinton Knighte5c8f092015-08-27 15:00:23 -0400536 client = client or cls.shares_v2_client
Rodrigo Barbieri427bc052016-06-06 17:10:06 -0300537 client.migrate_share(
538 share_id, dest_host,
539 force_host_assisted_migration=force_host_assisted_migration,
Rodrigo Barbieri027df982016-11-24 15:52:03 -0200540 writable=writable, preserve_metadata=preserve_metadata,
541 nondisruptive=nondisruptive, preserve_snapshots=preserve_snapshots,
Rodrigo Barbieri427bc052016-06-06 17:10:06 -0300542 new_share_network_id=new_share_network_id,
Rodrigo Barbierid38d2f52016-07-19 22:24:56 -0300543 new_share_type_id=new_share_type_id, **kwargs)
Rodrigo Barbierie3305122016-02-03 14:32:24 -0200544 share = client.wait_for_migration_status(
Rodrigo Barbieri427bc052016-06-06 17:10:06 -0300545 share_id, dest_host, wait_for_status, **kwargs)
Rodrigo Barbierie3305122016-02-03 14:32:24 -0200546 return share
547
548 @classmethod
549 def migration_complete(cls, share_id, dest_host, client=None, **kwargs):
550 client = client or cls.shares_v2_client
551 client.migration_complete(share_id, **kwargs)
552 share = client.wait_for_migration_status(
Rodrigo Barbieri427bc052016-06-06 17:10:06 -0300553 share_id, dest_host, 'migration_success', **kwargs)
Rodrigo Barbierib7137ad2015-09-06 22:53:16 -0300554 return share
555
556 @classmethod
Rodrigo Barbieric9abf282016-08-24 22:01:31 -0300557 def migration_cancel(cls, share_id, dest_host, client=None, **kwargs):
558 client = client or cls.shares_v2_client
559 client.migration_cancel(share_id, **kwargs)
560 share = client.wait_for_migration_status(
561 share_id, dest_host, 'migration_cancelled', **kwargs)
562 return share
563
564 @classmethod
Marc Koderer0abc93b2015-07-15 09:18:35 +0200565 def create_share(cls, *args, **kwargs):
566 """Create one share and wait for available state. Retry if allowed."""
567 result = cls.create_shares([{"args": args, "kwargs": kwargs}])
568 return result[0]
569
570 @classmethod
571 def create_shares(cls, share_data_list):
572 """Creates several shares in parallel with retries.
573
574 Use this method when you want to create more than one share at same
575 time. Especially if config option 'share.share_creation_retry_number'
576 has value more than zero (0).
577 All shares will be expected to have 'available' status with or without
578 recreation else error will be raised.
579
580 :param share_data_list: list -- list of dictionaries with 'args' and
581 'kwargs' for '_create_share' method of this base class.
582 example of data:
583 share_data_list=[{'args': ['quuz'], 'kwargs': {'foo': 'bar'}}}]
584 :returns: list -- list of shares created using provided data.
585 """
586
Valeriy Ponomaryov39cdf722016-05-30 18:16:15 +0300587 for d in share_data_list:
Marc Koderer0abc93b2015-07-15 09:18:35 +0200588 if not isinstance(d, dict):
589 raise exceptions.TempestException(
590 "Expected 'dict', got '%s'" % type(d))
591 if "args" not in d:
592 d["args"] = []
593 if "kwargs" not in d:
594 d["kwargs"] = {}
595 if len(d) > 2:
596 raise exceptions.TempestException(
597 "Expected only 'args' and 'kwargs' keys. "
598 "Provided %s" % list(d))
Valeriy Ponomaryov39cdf722016-05-30 18:16:15 +0300599
600 data = []
601 for d in share_data_list:
602 client = d["kwargs"].pop("client", cls.shares_v2_client)
yogeshdb32f462016-09-28 15:09:50 -0400603 wait_for_status = d["kwargs"].pop("wait_for_status", True)
Valeriy Ponomaryov39cdf722016-05-30 18:16:15 +0300604 local_d = {
605 "args": d["args"],
606 "kwargs": copy.deepcopy(d["kwargs"]),
607 }
608 local_d["kwargs"]["client"] = client
609 local_d["share"] = cls._create_share(
610 *local_d["args"], **local_d["kwargs"])
611 local_d["cnt"] = 0
612 local_d["available"] = False
yogeshdb32f462016-09-28 15:09:50 -0400613 local_d["wait_for_status"] = wait_for_status
Valeriy Ponomaryov39cdf722016-05-30 18:16:15 +0300614 data.append(local_d)
Marc Koderer0abc93b2015-07-15 09:18:35 +0200615
616 while not all(d["available"] for d in data):
617 for d in data:
yogeshdb32f462016-09-28 15:09:50 -0400618 if not d["wait_for_status"]:
619 d["available"] = True
Marc Koderer0abc93b2015-07-15 09:18:35 +0200620 if d["available"]:
621 continue
Valeriy Ponomaryov1a3e3382016-06-08 15:17:16 +0300622 client = d["kwargs"]["client"]
623 share_id = d["share"]["id"]
Marc Koderer0abc93b2015-07-15 09:18:35 +0200624 try:
Valeriy Ponomaryov1a3e3382016-06-08 15:17:16 +0300625 client.wait_for_share_status(share_id, "available")
Marc Koderer0abc93b2015-07-15 09:18:35 +0200626 d["available"] = True
627 except (share_exceptions.ShareBuildErrorException,
628 exceptions.TimeoutException) as e:
629 if CONF.share.share_creation_retry_number > d["cnt"]:
630 d["cnt"] += 1
631 msg = ("Share '%s' failed to be built. "
Valeriy Ponomaryov1a3e3382016-06-08 15:17:16 +0300632 "Trying create another." % share_id)
Marc Koderer0abc93b2015-07-15 09:18:35 +0200633 LOG.error(msg)
634 LOG.error(e)
Valeriy Ponomaryov1a3e3382016-06-08 15:17:16 +0300635 cg_id = d["kwargs"].get("consistency_group_id")
636 if cg_id:
637 # NOTE(vponomaryov): delete errored share
638 # immediately in case share is part of CG.
639 client.delete_share(
640 share_id,
641 params={"consistency_group_id": cg_id})
642 client.wait_for_resource_deletion(
643 share_id=share_id)
Marc Koderer0abc93b2015-07-15 09:18:35 +0200644 d["share"] = cls._create_share(
645 *d["args"], **d["kwargs"])
646 else:
gecong197358663802016-08-25 11:08:45 +0800647 raise
Marc Koderer0abc93b2015-07-15 09:18:35 +0200648
649 return [d["share"] for d in data]
650
651 @classmethod
Andrew Kerrb8436922016-06-01 15:32:43 -0400652 def create_share_group(cls, client=None, cleanup_in_class=True,
653 share_network_id=None, **kwargs):
Clinton Knighte5c8f092015-08-27 15:00:23 -0400654 client = client or cls.shares_v2_client
Andrew Kerrb8436922016-06-01 15:32:43 -0400655 if kwargs.get('source_share_group_snapshot_id') is None:
Goutham Pacha Ravi9221f5e2016-04-21 13:17:49 -0400656 kwargs['share_network_id'] = (share_network_id or
657 client.share_network_id or None)
Andrew Kerrb8436922016-06-01 15:32:43 -0400658 share_group = client.create_share_group(**kwargs)
Andrew Kerrbf31e912015-07-29 10:39:38 -0400659 resource = {
Andrew Kerrb8436922016-06-01 15:32:43 -0400660 "type": "share_group",
661 "id": share_group["id"],
662 "client": client,
663 }
Andrew Kerrbf31e912015-07-29 10:39:38 -0400664 if cleanup_in_class:
665 cls.class_resources.insert(0, resource)
666 else:
667 cls.method_resources.insert(0, resource)
668
Andrew Kerrb8436922016-06-01 15:32:43 -0400669 if kwargs.get('source_share_group_snapshot_id'):
670 new_share_group_shares = client.list_shares(
Andrew Kerrbf31e912015-07-29 10:39:38 -0400671 detailed=True,
Andrew Kerrb8436922016-06-01 15:32:43 -0400672 params={'share_group_id': share_group['id']},
673 experimental=True)
Andrew Kerrbf31e912015-07-29 10:39:38 -0400674
Andrew Kerrb8436922016-06-01 15:32:43 -0400675 for share in new_share_group_shares:
Andrew Kerrbf31e912015-07-29 10:39:38 -0400676 resource = {"type": "share",
677 "id": share["id"],
678 "client": client,
Andrew Kerrb8436922016-06-01 15:32:43 -0400679 "share_group_id": share.get("share_group_id")}
Andrew Kerrbf31e912015-07-29 10:39:38 -0400680 if cleanup_in_class:
681 cls.class_resources.insert(0, resource)
682 else:
683 cls.method_resources.insert(0, resource)
684
Andrew Kerrb8436922016-06-01 15:32:43 -0400685 client.wait_for_share_group_status(share_group['id'], 'available')
686 return share_group
687
688 @classmethod
689 def create_share_group_type(cls, name=None, share_types=(), is_public=None,
690 group_specs=None, client=None,
691 cleanup_in_class=True, **kwargs):
692 client = client or cls.shares_v2_client
Valeriy Ponomaryove92f09f2017-03-16 17:25:47 +0300693 if (group_specs is None and
694 CONF.share.capability_sg_consistent_snapshot_support):
Valeriy Ponomaryov3c188932017-03-15 19:06:23 +0300695 group_specs = {
696 'consistent_snapshot_support': (
697 CONF.share.capability_sg_consistent_snapshot_support),
698 }
Andrew Kerrb8436922016-06-01 15:32:43 -0400699 share_group_type = client.create_share_group_type(
700 name=name,
701 share_types=share_types,
702 is_public=is_public,
703 group_specs=group_specs,
704 **kwargs)
705 resource = {
706 "type": "share_group_type",
707 "id": share_group_type["id"],
708 "client": client,
709 }
710 if cleanup_in_class:
711 cls.class_resources.insert(0, resource)
712 else:
713 cls.method_resources.insert(0, resource)
714 return share_group_type
Andrew Kerrbf31e912015-07-29 10:39:38 -0400715
716 @classmethod
Marc Koderer0abc93b2015-07-15 09:18:35 +0200717 def create_snapshot_wait_for_active(cls, share_id, name=None,
718 description=None, force=False,
719 client=None, cleanup_in_class=True):
720 if client is None:
Yogesh1f931ff2015-09-29 23:41:02 -0400721 client = cls.shares_v2_client
Marc Koderer0abc93b2015-07-15 09:18:35 +0200722 if description is None:
723 description = "Tempest's snapshot"
724 snapshot = client.create_snapshot(share_id, name, description, force)
725 resource = {
726 "type": "snapshot",
727 "id": snapshot["id"],
728 "client": client,
729 }
730 if cleanup_in_class:
731 cls.class_resources.insert(0, resource)
732 else:
733 cls.method_resources.insert(0, resource)
734 client.wait_for_snapshot_status(snapshot["id"], "available")
735 return snapshot
736
737 @classmethod
Andrew Kerrb8436922016-06-01 15:32:43 -0400738 def create_share_group_snapshot_wait_for_active(
739 cls, share_group_id, name=None, description=None, client=None,
740 cleanup_in_class=True, **kwargs):
Clinton Knighte5c8f092015-08-27 15:00:23 -0400741 client = client or cls.shares_v2_client
Andrew Kerrbf31e912015-07-29 10:39:38 -0400742 if description is None:
Andrew Kerrb8436922016-06-01 15:32:43 -0400743 description = "Tempest's share group snapshot"
744 sg_snapshot = client.create_share_group_snapshot(
745 share_group_id, name=name, description=description, **kwargs)
Andrew Kerrbf31e912015-07-29 10:39:38 -0400746 resource = {
Andrew Kerrb8436922016-06-01 15:32:43 -0400747 "type": "share_group_snapshot",
748 "id": sg_snapshot["id"],
Andrew Kerrbf31e912015-07-29 10:39:38 -0400749 "client": client,
750 }
751 if cleanup_in_class:
752 cls.class_resources.insert(0, resource)
753 else:
754 cls.method_resources.insert(0, resource)
Andrew Kerrb8436922016-06-01 15:32:43 -0400755 client.wait_for_share_group_snapshot_status(
756 sg_snapshot["id"], "available")
757 return sg_snapshot
Andrew Kerrbf31e912015-07-29 10:39:38 -0400758
759 @classmethod
Yogeshbdb88102015-09-29 23:41:02 -0400760 def get_availability_zones(cls, client=None):
761 """List the availability zones for "manila-share" services
762
763 that are currently in "up" state.
764 """
765 client = client or cls.shares_v2_client
766 cls.services = client.list_services()
767 zones = [service['zone'] for service in cls.services if
768 service['binary'] == "manila-share" and
769 service['state'] == 'up']
770 return zones
771
Yogesh1f931ff2015-09-29 23:41:02 -0400772 def get_pools_for_replication_domain(self):
773 # Get the list of pools for the replication domain
774 pools = self.admin_client.list_pools(detail=True)['pools']
Ben Swartzlander7150c652017-02-13 22:31:18 -0500775 instance_host = self.admin_client.get_share(
776 self.shares[0]['id'])['host']
Yogesh1f931ff2015-09-29 23:41:02 -0400777 host_pool = [p for p in pools if p['name'] == instance_host][0]
778 rep_domain = host_pool['capabilities']['replication_domain']
779 pools_in_rep_domain = [p for p in pools if p['capabilities'][
780 'replication_domain'] == rep_domain]
781 return rep_domain, pools_in_rep_domain
782
Yogeshbdb88102015-09-29 23:41:02 -0400783 @classmethod
784 def create_share_replica(cls, share_id, availability_zone, client=None,
785 cleanup_in_class=False, cleanup=True):
786 client = client or cls.shares_v2_client
787 replica = client.create_share_replica(share_id, availability_zone)
788 resource = {
789 "type": "share_replica",
790 "id": replica["id"],
791 "client": client,
792 "share_id": share_id,
793 }
794 # NOTE(Yogi1): Cleanup needs to be disabled during promotion tests.
795 if cleanup:
796 if cleanup_in_class:
797 cls.class_resources.insert(0, resource)
798 else:
799 cls.method_resources.insert(0, resource)
800 client.wait_for_share_replica_status(
801 replica["id"], constants.STATUS_AVAILABLE)
802 return replica
803
804 @classmethod
805 def delete_share_replica(cls, replica_id, client=None):
806 client = client or cls.shares_v2_client
Yogesh1f931ff2015-09-29 23:41:02 -0400807 try:
808 client.delete_share_replica(replica_id)
809 client.wait_for_resource_deletion(replica_id=replica_id)
810 except exceptions.NotFound:
811 pass
Yogeshbdb88102015-09-29 23:41:02 -0400812
813 @classmethod
814 def promote_share_replica(cls, replica_id, client=None):
815 client = client or cls.shares_v2_client
816 replica = client.promote_share_replica(replica_id)
817 client.wait_for_share_replica_status(
818 replica["id"],
819 constants.REPLICATION_STATE_ACTIVE,
820 status_attr="replica_state")
821 return replica
822
yogeshdb32f462016-09-28 15:09:50 -0400823 def _get_access_rule_data_from_config(self):
824 """Get the first available access type/to combination from config.
825
826 This method opportunistically picks the first configured protocol
827 to create the share. Do not use this method in tests where you need
828 to test depth and breadth in the access types and access recipients.
829 """
830 protocol = self.shares_v2_client.share_protocol
831
832 if protocol in CONF.share.enable_ip_rules_for_protocols:
833 access_type = "ip"
834 access_to = utils.rand_ip()
835 elif protocol in CONF.share.enable_user_rules_for_protocols:
836 access_type = "user"
837 access_to = CONF.share.username_for_user_rules
838 elif protocol in CONF.share.enable_cert_rules_for_protocols:
839 access_type = "cert"
840 access_to = "client3.com"
841 elif protocol in CONF.share.enable_cephx_rules_for_protocols:
842 access_type = "cephx"
843 access_to = "eve"
844 else:
845 message = "Unrecognized protocol and access rules configuration."
846 raise self.skipException(message)
847
848 return access_type, access_to
849
Yogeshbdb88102015-09-29 23:41:02 -0400850 @classmethod
Marc Koderer0abc93b2015-07-15 09:18:35 +0200851 def create_share_network(cls, client=None,
852 cleanup_in_class=False, **kwargs):
853 if client is None:
854 client = cls.shares_client
855 share_network = client.create_share_network(**kwargs)
856 resource = {
857 "type": "share_network",
858 "id": share_network["id"],
859 "client": client,
860 }
861 if cleanup_in_class:
862 cls.class_resources.insert(0, resource)
863 else:
864 cls.method_resources.insert(0, resource)
865 return share_network
866
867 @classmethod
868 def create_security_service(cls, ss_type="ldap", client=None,
869 cleanup_in_class=False, **kwargs):
870 if client is None:
871 client = cls.shares_client
872 security_service = client.create_security_service(ss_type, **kwargs)
873 resource = {
874 "type": "security_service",
875 "id": security_service["id"],
876 "client": client,
877 }
878 if cleanup_in_class:
879 cls.class_resources.insert(0, resource)
880 else:
881 cls.method_resources.insert(0, resource)
882 return security_service
883
884 @classmethod
885 def create_share_type(cls, name, is_public=True, client=None,
886 cleanup_in_class=True, **kwargs):
887 if client is None:
Valeriy Ponomaryova14c2252015-10-29 13:34:32 +0200888 client = cls.shares_v2_client
Marc Koderer0abc93b2015-07-15 09:18:35 +0200889 share_type = client.create_share_type(name, is_public, **kwargs)
890 resource = {
891 "type": "share_type",
892 "id": share_type["share_type"]["id"],
893 "client": client,
894 }
895 if cleanup_in_class:
896 cls.class_resources.insert(0, resource)
897 else:
898 cls.method_resources.insert(0, resource)
899 return share_type
900
901 @staticmethod
Clinton Knight4699a8c2016-08-16 22:36:13 -0400902 def add_extra_specs_to_dict(extra_specs=None):
903 """Add any required extra-specs to share type dictionary"""
Valeriy Ponomaryovad55dc52015-09-23 13:54:00 +0300904 dhss = six.text_type(CONF.share.multitenancy_enabled)
905 snapshot_support = six.text_type(
906 CONF.share.capability_snapshot_support)
Clinton Knight4699a8c2016-08-16 22:36:13 -0400907 create_from_snapshot_support = six.text_type(
908 CONF.share.capability_create_share_from_snapshot_support)
909
910 extra_specs_dict = {
Valeriy Ponomaryovad55dc52015-09-23 13:54:00 +0300911 "driver_handles_share_servers": dhss,
Marc Koderer0abc93b2015-07-15 09:18:35 +0200912 }
Clinton Knight4699a8c2016-08-16 22:36:13 -0400913
914 optional = {
915 "snapshot_support": snapshot_support,
916 "create_share_from_snapshot_support": create_from_snapshot_support,
917 }
918 # NOTE(gouthamr): In micro-versions < 2.24, snapshot_support is a
919 # required extra-spec
920 extra_specs_dict.update(optional)
921
Marc Koderer0abc93b2015-07-15 09:18:35 +0200922 if extra_specs:
Clinton Knight4699a8c2016-08-16 22:36:13 -0400923 extra_specs_dict.update(extra_specs)
924
925 return extra_specs_dict
Marc Koderer0abc93b2015-07-15 09:18:35 +0200926
927 @classmethod
928 def clear_isolated_creds(cls, creds=None):
929 if creds is None:
930 creds = cls.method_isolated_creds
931 for ic in creds:
932 if "deleted" not in ic.keys():
933 ic["deleted"] = False
934 if not ic["deleted"]:
935 with handle_cleanup_exceptions():
936 ic["method"]()
937 ic["deleted"] = True
938
939 @classmethod
Yogesh1f931ff2015-09-29 23:41:02 -0400940 def clear_share_replicas(cls, share_id, client=None):
941 client = client or cls.shares_v2_client
942 share_replicas = client.list_share_replicas(
943 share_id=share_id)
944
945 for replica in share_replicas:
946 try:
947 cls.delete_share_replica(replica['id'])
948 except exceptions.BadRequest:
949 # Ignore the exception due to deletion of last active replica
950 pass
951
952 @classmethod
Marc Koderer0abc93b2015-07-15 09:18:35 +0200953 def clear_resources(cls, resources=None):
954 """Deletes resources, that were created in test suites.
955
956 This method tries to remove resources from resource list,
957 if it is not found, assumed it was deleted in test itself.
958 It is expected, that all resources were added as LIFO
959 due to restriction of deletion resources, that is in the chain.
960
961 :param resources: dict with keys 'type','id','client' and 'deleted'
962 """
Marc Koderer0abc93b2015-07-15 09:18:35 +0200963 if resources is None:
964 resources = cls.method_resources
965 for res in resources:
966 if "deleted" not in res.keys():
967 res["deleted"] = False
968 if "client" not in res.keys():
969 res["client"] = cls.shares_client
970 if not(res["deleted"]):
971 res_id = res['id']
972 client = res["client"]
973 with handle_cleanup_exceptions():
974 if res["type"] is "share":
Yogesh1f931ff2015-09-29 23:41:02 -0400975 cls.clear_share_replicas(res_id)
Andrew Kerrb8436922016-06-01 15:32:43 -0400976 share_group_id = res.get('share_group_id')
977 if share_group_id:
978 params = {'share_group_id': share_group_id}
Clinton Knighte5c8f092015-08-27 15:00:23 -0400979 client.delete_share(res_id, params=params)
980 else:
981 client.delete_share(res_id)
Marc Koderer0abc93b2015-07-15 09:18:35 +0200982 client.wait_for_resource_deletion(share_id=res_id)
983 elif res["type"] is "snapshot":
984 client.delete_snapshot(res_id)
985 client.wait_for_resource_deletion(snapshot_id=res_id)
yogesh06f519f2017-06-26 13:16:12 -0400986 elif (res["type"] is "share_network" and
987 res_id != CONF.share.share_network_id):
988 client.delete_share_network(res_id)
989 client.wait_for_resource_deletion(sn_id=res_id)
Marc Koderer0abc93b2015-07-15 09:18:35 +0200990 elif res["type"] is "security_service":
991 client.delete_security_service(res_id)
992 client.wait_for_resource_deletion(ss_id=res_id)
993 elif res["type"] is "share_type":
994 client.delete_share_type(res_id)
995 client.wait_for_resource_deletion(st_id=res_id)
Andrew Kerrb8436922016-06-01 15:32:43 -0400996 elif res["type"] is "share_group":
997 client.delete_share_group(res_id)
998 client.wait_for_resource_deletion(
999 share_group_id=res_id)
1000 elif res["type"] is "share_group_type":
1001 client.delete_share_group_type(res_id)
1002 client.wait_for_resource_deletion(
1003 share_group_type_id=res_id)
1004 elif res["type"] is "share_group_snapshot":
1005 client.delete_share_group_snapshot(res_id)
1006 client.wait_for_resource_deletion(
1007 share_group_snapshot_id=res_id)
Yogeshbdb88102015-09-29 23:41:02 -04001008 elif res["type"] is "share_replica":
1009 client.delete_share_replica(res_id)
1010 client.wait_for_resource_deletion(replica_id=res_id)
Marc Koderer0abc93b2015-07-15 09:18:35 +02001011 else:
huayue97bacbf2016-01-04 09:57:39 +08001012 LOG.warning("Provided unsupported resource type for "
junbolib236c242017-07-18 18:12:37 +08001013 "cleanup '%s'. Skipping.", res["type"])
Marc Koderer0abc93b2015-07-15 09:18:35 +02001014 res["deleted"] = True
1015
1016 @classmethod
1017 def generate_share_network_data(self):
1018 data = {
1019 "name": data_utils.rand_name("sn-name"),
1020 "description": data_utils.rand_name("sn-desc"),
1021 "neutron_net_id": data_utils.rand_name("net-id"),
1022 "neutron_subnet_id": data_utils.rand_name("subnet-id"),
1023 }
1024 return data
1025
1026 @classmethod
1027 def generate_security_service_data(self):
1028 data = {
1029 "name": data_utils.rand_name("ss-name"),
1030 "description": data_utils.rand_name("ss-desc"),
Valeriy Ponomaryovfcde7712015-12-14 18:06:13 +02001031 "dns_ip": utils.rand_ip(),
1032 "server": utils.rand_ip(),
Marc Koderer0abc93b2015-07-15 09:18:35 +02001033 "domain": data_utils.rand_name("ss-domain"),
1034 "user": data_utils.rand_name("ss-user"),
1035 "password": data_utils.rand_name("ss-password"),
1036 }
1037 return data
1038
1039 # Useful assertions
1040 def assertDictMatch(self, d1, d2, approx_equal=False, tolerance=0.001):
1041 """Assert two dicts are equivalent.
1042
1043 This is a 'deep' match in the sense that it handles nested
1044 dictionaries appropriately.
1045
1046 NOTE:
1047
1048 If you don't care (or don't know) a given value, you can specify
1049 the string DONTCARE as the value. This will cause that dict-item
1050 to be skipped.
1051
1052 """
1053 def raise_assertion(msg):
1054 d1str = str(d1)
1055 d2str = str(d2)
1056 base_msg = ('Dictionaries do not match. %(msg)s d1: %(d1str)s '
1057 'd2: %(d2str)s' %
1058 {"msg": msg, "d1str": d1str, "d2str": d2str})
1059 raise AssertionError(base_msg)
1060
1061 d1keys = set(d1.keys())
1062 d2keys = set(d2.keys())
1063 if d1keys != d2keys:
1064 d1only = d1keys - d2keys
1065 d2only = d2keys - d1keys
1066 raise_assertion('Keys in d1 and not d2: %(d1only)s. '
1067 'Keys in d2 and not d1: %(d2only)s' %
1068 {"d1only": d1only, "d2only": d2only})
1069
1070 for key in d1keys:
1071 d1value = d1[key]
1072 d2value = d2[key]
1073 try:
1074 error = abs(float(d1value) - float(d2value))
1075 within_tolerance = error <= tolerance
1076 except (ValueError, TypeError):
daiki kato6914b1a2016-03-16 17:16:57 +09001077 # If both values aren't convertible to float, just ignore
Marc Koderer0abc93b2015-07-15 09:18:35 +02001078 # ValueError if arg is a str, TypeError if it's something else
1079 # (like None)
1080 within_tolerance = False
1081
1082 if hasattr(d1value, 'keys') and hasattr(d2value, 'keys'):
1083 self.assertDictMatch(d1value, d2value)
1084 elif 'DONTCARE' in (d1value, d2value):
1085 continue
1086 elif approx_equal and within_tolerance:
1087 continue
1088 elif d1value != d2value:
1089 raise_assertion("d1['%(key)s']=%(d1value)s != "
1090 "d2['%(key)s']=%(d2value)s" %
1091 {
1092 "key": key,
1093 "d1value": d1value,
1094 "d2value": d2value
1095 })
1096
Alex Meadeba8a1602016-05-06 09:33:09 -04001097 def create_user_message(self):
1098 """Trigger a 'no valid host' situation to generate a message."""
1099 extra_specs = {
1100 'vendor_name': 'foobar',
1101 'driver_handles_share_servers': CONF.share.multitenancy_enabled,
1102 }
1103 share_type_name = data_utils.rand_name("share-type")
1104
1105 bogus_type = self.create_share_type(
1106 name=share_type_name,
1107 extra_specs=extra_specs)['share_type']
1108
1109 params = {'share_type_id': bogus_type['id'],
1110 'share_network_id': self.shares_v2_client.share_network_id}
1111 share = self.shares_v2_client.create_share(**params)
1112 self.addCleanup(self.shares_v2_client.delete_share, share['id'])
1113 self.shares_v2_client.wait_for_share_status(share['id'], "error")
1114 return self.shares_v2_client.wait_for_message(share['id'])
1115
Marc Koderer0abc93b2015-07-15 09:18:35 +02001116
1117class BaseSharesAltTest(BaseSharesTest):
1118 """Base test case class for all Shares Alt API tests."""
Valeriy Ponomaryov39cdf722016-05-30 18:16:15 +03001119 credentials = ('alt', )
Marc Koderer0abc93b2015-07-15 09:18:35 +02001120
1121
1122class BaseSharesAdminTest(BaseSharesTest):
1123 """Base test case class for all Shares Admin API tests."""
Valeriy Ponomaryov39cdf722016-05-30 18:16:15 +03001124 credentials = ('admin', )
1125
1126
1127class BaseSharesMixedTest(BaseSharesTest):
1128 """Base test case class for all Shares API tests with all user roles."""
1129 credentials = ('primary', 'alt', 'admin')
Marc Koderer0abc93b2015-07-15 09:18:35 +02001130
1131 @classmethod
Valeriy Ponomaryov39cdf722016-05-30 18:16:15 +03001132 def setup_clients(cls):
1133 super(BaseSharesMixedTest, cls).setup_clients()
Andrea Frittoli (andreaf)369391a2016-06-27 18:59:13 +01001134 # Initialise share clients
1135 cls.admin_shares_client = cls.os_admin.share_v1.SharesClient()
1136 cls.admin_shares_v2_client = cls.os_admin.share_v2.SharesV2Client()
1137 cls.alt_shares_client = cls.os_alt.share_v1.SharesClient()
1138 cls.alt_shares_v2_client = cls.os_alt.share_v2.SharesV2Client()
1139 # Initialise network clients
1140 cls.os_admin.networks_client = cls.os_admin.network.NetworksClient()
1141 cls.os_alt.networks_client = cls.os_alt.network.NetworksClient()
Valeriy Ponomaryov39cdf722016-05-30 18:16:15 +03001142
1143 if CONF.share.multitenancy_enabled:
1144 admin_share_network_id = cls.provide_share_network(
1145 cls.admin_shares_v2_client, cls.os_admin.networks_client)
1146 cls.admin_shares_client.share_network_id = admin_share_network_id
1147 cls.admin_shares_v2_client.share_network_id = (
1148 admin_share_network_id)
1149
1150 alt_share_network_id = cls.provide_share_network(
1151 cls.alt_shares_v2_client, cls.os_alt.networks_client)
1152 cls.alt_shares_client.share_network_id = alt_share_network_id
1153 cls.alt_shares_v2_client.share_network_id = alt_share_network_id