blob: 9cf3e6981789e56ea5f8ff641eca19985fc44b23 [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
Valeriy Ponomaryov39cdf722016-05-30 18:16:15 +030024from tempest import clients
Sam Wanc7b7f1f2015-11-25 00:22:28 -050025from tempest.common import credentials_factory as common_creds
Valeriy Ponomaryov48a2bd72015-11-05 13:22:44 +020026from tempest.common import dynamic_creds
27from tempest import config
Ben Swartzlander1c4ff522016-03-02 22:16:23 -050028from tempest.lib.common.utils import data_utils
29from tempest.lib import exceptions
Valeriy Ponomaryov48a2bd72015-11-05 13:22:44 +020030from tempest import test
Marc Koderer0abc93b2015-07-15 09:18:35 +020031
Yogeshbdb88102015-09-29 23:41:02 -040032from manila_tempest_tests.common import constants
Valeriy Ponomaryov39cdf722016-05-30 18:16:15 +030033from manila_tempest_tests.services.share.json import shares_client
34from manila_tempest_tests.services.share.v2.json import (
35 shares_client as shares_v2_client)
Marc Koderer0abc93b2015-07-15 09:18:35 +020036from manila_tempest_tests import share_exceptions
Valeriy Ponomaryovfcde7712015-12-14 18:06:13 +020037from manila_tempest_tests import utils
Marc Koderer0abc93b2015-07-15 09:18:35 +020038
39CONF = config.CONF
40LOG = log.getLogger(__name__)
41
Valeriy Ponomaryov2abf5d72016-06-01 18:30:12 +030042# Test tags related to test direction
43TAG_POSITIVE = "positive"
44TAG_NEGATIVE = "negative"
45
46# Test tags related to service involvement
47TAG_API = "api"
48TAG_BACKEND = "backend"
49TAG_API_WITH_BACKEND = "api_with_backend"
50
51TAGS_MAPPER = {
52 "p": TAG_POSITIVE,
53 "n": TAG_NEGATIVE,
54 "a": TAG_API,
55 "b": TAG_BACKEND,
56 "ab": TAG_API_WITH_BACKEND,
57}
58TAGS_PATTERN = re.compile(
59 r"(?=.*\[.*\b(%(p)s|%(n)s)\b.*\])(?=.*\[.*\b(%(a)s|%(b)s|%(ab)s)\b.*\])" %
60 TAGS_MAPPER)
61
62
63def verify_test_has_appropriate_tags(self):
64 if not TAGS_PATTERN.match(self.id()):
65 msg = (
66 "Required attributes either not set or set improperly. "
67 "Two test attributes are expected:\n"
68 " - one of '%(p)s' or '%(n)s' and \n"
69 " - one of '%(a)s', '%(b)s' or '%(ab)s'."
70 ) % TAGS_MAPPER
71 raise self.failureException(msg)
72
Marc Koderer0abc93b2015-07-15 09:18:35 +020073
74class handle_cleanup_exceptions(object):
75 """Handle exceptions raised with cleanup operations.
76
77 Always suppress errors when exceptions.NotFound or exceptions.Forbidden
78 are raised.
79 Suppress all other exceptions only in case config opt
80 'suppress_errors_in_cleanup' in config group 'share' is True.
81 """
82
83 def __enter__(self):
84 return self
85
86 def __exit__(self, exc_type, exc_value, exc_traceback):
87 if not (isinstance(exc_value,
88 (exceptions.NotFound, exceptions.Forbidden)) or
89 CONF.share.suppress_errors_in_cleanup):
90 return False # Do not suppress error if any
91 if exc_traceback:
92 LOG.error("Suppressed cleanup error in Manila: "
93 "\n%s" % traceback.format_exc())
94 return True # Suppress error if any
95
96
97def network_synchronized(f):
98
99 def wrapped_func(self, *args, **kwargs):
100 with_isolated_creds = True if len(args) > 2 else False
101 no_lock_required = kwargs.get(
102 "isolated_creds_client", with_isolated_creds)
103 if no_lock_required:
104 # Usage of not reusable network. No need in lock.
105 return f(self, *args, **kwargs)
106
107 # Use lock assuming reusage of common network.
108 @lockutils.synchronized("manila_network_lock", external=True)
109 def source_func(self, *args, **kwargs):
110 return f(self, *args, **kwargs)
111
112 return source_func(self, *args, **kwargs)
113
114 return wrapped_func
115
116
Valeriy Ponomaryovfcde7712015-12-14 18:06:13 +0200117skip_if_microversion_not_supported = utils.skip_if_microversion_not_supported
Xing Yang69b00b52015-11-22 16:10:44 -0500118skip_if_microversion_lt = utils.skip_if_microversion_lt
Valeriy Ponomaryova14c2252015-10-29 13:34:32 +0200119
120
Marc Koderer0abc93b2015-07-15 09:18:35 +0200121class BaseSharesTest(test.BaseTestCase):
122 """Base test case class for all Manila API tests."""
123
Valeriy Ponomaryov39cdf722016-05-30 18:16:15 +0300124 credentials = ('primary', )
Marc Koderer0abc93b2015-07-15 09:18:35 +0200125 force_tenant_isolation = False
Vitaliy Levitksicfebfff2016-12-15 16:16:35 +0200126 protocols = ["nfs", "cifs", "glusterfs", "hdfs", "cephfs", "maprfs"]
Marc Koderer0abc93b2015-07-15 09:18:35 +0200127
128 # Will be cleaned up in resource_cleanup
129 class_resources = []
130
131 # Will be cleaned up in tearDown method
132 method_resources = []
133
134 # Will be cleaned up in resource_cleanup
135 class_isolated_creds = []
136
137 # Will be cleaned up in tearDown method
138 method_isolated_creds = []
139
Valeriy Ponomaryova14c2252015-10-29 13:34:32 +0200140 def skip_if_microversion_not_supported(self, microversion):
Valeriy Ponomaryovfcde7712015-12-14 18:06:13 +0200141 if not utils.is_microversion_supported(microversion):
Valeriy Ponomaryova14c2252015-10-29 13:34:32 +0200142 raise self.skipException(
143 "Microversion '%s' is not supported." % microversion)
144
Xing Yang69b00b52015-11-22 16:10:44 -0500145 def skip_if_microversion_lt(self, microversion):
146 if utils.is_microversion_lt(CONF.share.max_api_microversion,
147 microversion):
148 raise self.skipException(
149 "Microversion must be greater than or equal to '%s'." %
150 microversion)
151
Marc Koderer0abc93b2015-07-15 09:18:35 +0200152 @classmethod
153 def get_client_with_isolated_creds(cls,
154 name=None,
155 type_of_creds="admin",
Clinton Knighte5c8f092015-08-27 15:00:23 -0400156 cleanup_in_class=False,
157 client_version='1'):
Marc Koderer0abc93b2015-07-15 09:18:35 +0200158 """Creates isolated creds.
159
160 :param name: name, will be used for naming ic and related stuff
161 :param type_of_creds: admin, alt or primary
162 :param cleanup_in_class: defines place where to delete
163 :returns: SharesClient -- shares client with isolated creds.
164 :returns: To client added dict attr 'creds' with
165 :returns: key elements 'tenant' and 'user'.
166 """
167 if name is None:
168 # Get name of test method
169 name = inspect.stack()[1][3]
170 if len(name) > 32:
171 name = name[0:32]
172
173 # Choose type of isolated creds
Valeriy Ponomaryov48a2bd72015-11-05 13:22:44 +0200174 ic = dynamic_creds.DynamicCredentialProvider(
175 identity_version=CONF.identity.auth_version,
176 name=name,
Sam Wanc7b7f1f2015-11-25 00:22:28 -0500177 admin_role=CONF.identity.admin_role,
Valeriy Ponomaryov0ddd29b2016-06-07 17:49:31 +0300178 admin_creds=common_creds.get_configured_admin_credentials())
Marc Koderer0abc93b2015-07-15 09:18:35 +0200179 if "admin" in type_of_creds:
Marc Koderer5880b362016-07-06 10:59:07 +0200180 creds = ic.get_admin_creds().credentials
Marc Koderer0abc93b2015-07-15 09:18:35 +0200181 elif "alt" in type_of_creds:
Marc Koderer5880b362016-07-06 10:59:07 +0200182 creds = ic.get_alt_creds().credentials
Marc Koderer0abc93b2015-07-15 09:18:35 +0200183 else:
Marc Koderer5880b362016-07-06 10:59:07 +0200184 creds = ic.get_credentials(type_of_creds).credentials
Marc Koderer0abc93b2015-07-15 09:18:35 +0200185 ic.type_of_creds = type_of_creds
186
187 # create client with isolated creds
188 os = clients.Manager(credentials=creds)
Clinton Knighte5c8f092015-08-27 15:00:23 -0400189 if client_version == '1':
Valeriy Ponomaryov39cdf722016-05-30 18:16:15 +0300190 client = shares_client.SharesClient(os.auth_provider)
Clinton Knighte5c8f092015-08-27 15:00:23 -0400191 elif client_version == '2':
Valeriy Ponomaryov39cdf722016-05-30 18:16:15 +0300192 client = shares_v2_client.SharesV2Client(os.auth_provider)
Marc Koderer0abc93b2015-07-15 09:18:35 +0200193
194 # Set place where will be deleted isolated creds
195 ic_res = {
Valeriy Ponomaryov48a2bd72015-11-05 13:22:44 +0200196 "method": ic.clear_creds,
Marc Koderer0abc93b2015-07-15 09:18:35 +0200197 "deleted": False,
198 }
199 if cleanup_in_class:
200 cls.class_isolated_creds.insert(0, ic_res)
201 else:
202 cls.method_isolated_creds.insert(0, ic_res)
203
204 # Provide share network
205 if CONF.share.multitenancy_enabled:
Valeriy Ponomaryovc5dae272016-06-10 18:29:24 +0300206 if (not CONF.service_available.neutron and
207 CONF.share.create_networks_when_multitenancy_enabled):
Marc Koderer0abc93b2015-07-15 09:18:35 +0200208 raise cls.skipException("Neutron support is required")
Valeriy Ponomaryov48a2bd72015-11-05 13:22:44 +0200209 nc = os.networks_client
Marc Koderer0abc93b2015-07-15 09:18:35 +0200210 share_network_id = cls.provide_share_network(client, nc, ic)
211 client.share_network_id = share_network_id
212 resource = {
213 "type": "share_network",
214 "id": client.share_network_id,
215 "client": client,
216 }
217 if cleanup_in_class:
218 cls.class_resources.insert(0, resource)
219 else:
220 cls.method_resources.insert(0, resource)
221 return client
222
223 @classmethod
Daniel Melladoe5269142017-01-12 12:17:58 +0000224 def skip_checks(cls):
225 super(BaseSharesTest, cls).skip_checks()
226 if not CONF.service_available.manila:
227 raise cls.skipException("Manila support is required")
228
229 @classmethod
Marc Koderer0abc93b2015-07-15 09:18:35 +0200230 def verify_nonempty(cls, *args):
231 if not all(args):
232 msg = "Missing API credentials in configuration."
233 raise cls.skipException(msg)
234
235 @classmethod
Valeriy Ponomaryov39cdf722016-05-30 18:16:15 +0300236 def setup_clients(cls):
237 super(BaseSharesTest, cls).setup_clients()
238 os = getattr(cls, 'os_%s' % cls.credentials[0])
239 os.shares_client = shares_client.SharesClient(os.auth_provider)
Valeriy Ponomaryov4fb305f2016-10-21 13:46:47 +0300240
241 if CONF.identity.auth_version == 'v3':
242 project_id = os.auth_provider.auth_data[1]['project']['id']
243 else:
244 project_id = os.auth_provider.auth_data[1]['token']['tenant']['id']
245 cls.tenant_id = project_id
246 cls.user_id = os.auth_provider.auth_data[1]['user']['id']
247
Valeriy Ponomaryov39cdf722016-05-30 18:16:15 +0300248 cls.shares_client = os.shares_client
249 os.shares_v2_client = shares_v2_client.SharesV2Client(
250 os.auth_provider)
251 cls.shares_v2_client = os.shares_v2_client
252 if CONF.share.multitenancy_enabled:
Valeriy Ponomaryovc5dae272016-06-10 18:29:24 +0300253 if (not CONF.service_available.neutron and
254 CONF.share.create_networks_when_multitenancy_enabled):
Valeriy Ponomaryov39cdf722016-05-30 18:16:15 +0300255 raise cls.skipException("Neutron support is required")
256 share_network_id = cls.provide_share_network(
257 cls.shares_v2_client, os.networks_client)
258 cls.shares_client.share_network_id = share_network_id
259 cls.shares_v2_client.share_network_id = share_network_id
260
261 @classmethod
Marc Koderer0abc93b2015-07-15 09:18:35 +0200262 def resource_setup(cls):
263 if not (any(p in CONF.share.enable_protocols
264 for p in cls.protocols) and
265 CONF.service_available.manila):
266 skip_msg = "Manila is disabled"
267 raise cls.skipException(skip_msg)
268 super(BaseSharesTest, cls).resource_setup()
Marc Koderer0abc93b2015-07-15 09:18:35 +0200269
270 def setUp(self):
271 super(BaseSharesTest, self).setUp()
Marc Koderer0abc93b2015-07-15 09:18:35 +0200272 self.addCleanup(self.clear_isolated_creds)
Valeriy Ponomaryovdd162cb2016-01-20 19:09:49 +0200273 self.addCleanup(self.clear_resources)
Valeriy Ponomaryov2abf5d72016-06-01 18:30:12 +0300274 verify_test_has_appropriate_tags(self)
Marc Koderer0abc93b2015-07-15 09:18:35 +0200275
276 @classmethod
277 def resource_cleanup(cls):
Marc Koderer0abc93b2015-07-15 09:18:35 +0200278 cls.clear_resources(cls.class_resources)
279 cls.clear_isolated_creds(cls.class_isolated_creds)
Sam Wan241029c2016-07-26 03:37:42 -0400280 super(BaseSharesTest, cls).resource_cleanup()
Marc Koderer0abc93b2015-07-15 09:18:35 +0200281
282 @classmethod
283 @network_synchronized
Valeriy Ponomaryov48a2bd72015-11-05 13:22:44 +0200284 def provide_share_network(cls, shares_client, networks_client,
Rodrigo Barbieri58d9de32016-09-06 13:16:47 -0300285 isolated_creds_client=None,
286 ignore_multitenancy_config=False):
Marc Koderer0abc93b2015-07-15 09:18:35 +0200287 """Used for finding/creating share network for multitenant driver.
288
289 This method creates/gets entity share-network for one tenant. This
290 share-network will be used for creation of service vm.
291
292 :param shares_client: shares client, which requires share-network
Valeriy Ponomaryov48a2bd72015-11-05 13:22:44 +0200293 :param networks_client: network client from same tenant as shares
294 :param isolated_creds_client: DynamicCredentialProvider instance
Marc Koderer0abc93b2015-07-15 09:18:35 +0200295 If provided, then its networking will be used if needed.
296 If not provided, then common network will be used if needed.
Rodrigo Barbieri58d9de32016-09-06 13:16:47 -0300297 :param ignore_multitenancy_config: provide a share network regardless
298 of 'multitenancy_enabled' configuration value.
Marc Koderer0abc93b2015-07-15 09:18:35 +0200299 :returns: str -- share network id for shares_client tenant
300 :returns: None -- if single-tenant driver used
301 """
302
303 sc = shares_client
Valeriy Ponomaryovc5dae272016-06-10 18:29:24 +0300304 search_word = "reusable"
305 sn_name = "autogenerated_by_tempest_%s" % search_word
Marc Koderer0abc93b2015-07-15 09:18:35 +0200306
Rodrigo Barbieri58d9de32016-09-06 13:16:47 -0300307 if (not ignore_multitenancy_config and
308 not CONF.share.multitenancy_enabled):
Marc Koderer0abc93b2015-07-15 09:18:35 +0200309 # Assumed usage of a single-tenant driver
310 share_network_id = None
Marc Koderer0abc93b2015-07-15 09:18:35 +0200311 else:
Rodrigo Barbieri58d9de32016-09-06 13:16:47 -0300312 if sc.share_network_id:
313 # Share-network already exists, use it
314 share_network_id = sc.share_network_id
315 elif not CONF.share.create_networks_when_multitenancy_enabled:
316 share_network_id = None
Marc Koderer0abc93b2015-07-15 09:18:35 +0200317
318 # Try get suitable share-network
319 share_networks = sc.list_share_networks_with_detail()
320 for sn in share_networks:
Rodrigo Barbieri58d9de32016-09-06 13:16:47 -0300321 if (sn["neutron_net_id"] is None and
322 sn["neutron_subnet_id"] is None and
Marc Koderer0abc93b2015-07-15 09:18:35 +0200323 sn["name"] and search_word in sn["name"]):
324 share_network_id = sn["id"]
325 break
Marc Koderer0abc93b2015-07-15 09:18:35 +0200326
Rodrigo Barbieri58d9de32016-09-06 13:16:47 -0300327 # Create new share-network if one was not found
328 if share_network_id is None:
329 sn_desc = "This share-network was created by tempest"
330 sn = sc.create_share_network(name=sn_name,
331 description=sn_desc)
332 share_network_id = sn["id"]
333 else:
334 net_id = subnet_id = share_network_id = None
335
336 if not isolated_creds_client:
337 # Search for networks, created in previous runs
338 service_net_name = "share-service"
339 networks = networks_client.list_networks()
340 if "networks" in networks.keys():
341 networks = networks["networks"]
342 for network in networks:
343 if (service_net_name in network["name"] and
344 sc.tenant_id == network['tenant_id']):
345 net_id = network["id"]
346 if len(network["subnets"]) > 0:
347 subnet_id = network["subnets"][0]
348 break
349
350 # Create suitable network
351 if net_id is None or subnet_id is None:
352 ic = dynamic_creds.DynamicCredentialProvider(
353 identity_version=CONF.identity.auth_version,
354 name=service_net_name,
355 admin_role=CONF.identity.admin_role,
356 admin_creds=(
357 common_creds.
358 get_configured_admin_credentials()))
359 net_data = ic._create_network_resources(sc.tenant_id)
360 network, subnet, router = net_data
361 net_id = network["id"]
362 subnet_id = subnet["id"]
363
364 # Try get suitable share-network
365 share_networks = sc.list_share_networks_with_detail()
366 for sn in share_networks:
367 if (net_id == sn["neutron_net_id"] and
368 subnet_id == sn["neutron_subnet_id"] and
369 sn["name"] and search_word in sn["name"]):
370 share_network_id = sn["id"]
371 break
372 else:
373 sn_name = "autogenerated_by_tempest_for_isolated_creds"
374 # Use precreated network and subnet from isolated creds
375 net_id = isolated_creds_client.get_credentials(
376 isolated_creds_client.type_of_creds).network['id']
377 subnet_id = isolated_creds_client.get_credentials(
378 isolated_creds_client.type_of_creds).subnet['id']
379
380 # Create suitable share-network
381 if share_network_id is None:
382 sn_desc = "This share-network was created by tempest"
383 sn = sc.create_share_network(name=sn_name,
384 description=sn_desc,
385 neutron_net_id=net_id,
386 neutron_subnet_id=subnet_id)
387 share_network_id = sn["id"]
Marc Koderer0abc93b2015-07-15 09:18:35 +0200388
389 return share_network_id
390
391 @classmethod
marcusvrne0d7cfd2016-06-24 12:27:55 -0300392 def _create_share(cls, share_protocol=None, size=None, name=None,
Marc Koderer0abc93b2015-07-15 09:18:35 +0200393 snapshot_id=None, description=None, metadata=None,
394 share_network_id=None, share_type_id=None,
Andrew Kerrb8436922016-06-01 15:32:43 -0400395 share_group_id=None, client=None,
Clinton Knighte5c8f092015-08-27 15:00:23 -0400396 cleanup_in_class=True, is_public=False, **kwargs):
Valeriy Ponomaryov1aaa72d2015-09-08 12:59:41 +0300397 client = client or cls.shares_v2_client
Marc Koderer0abc93b2015-07-15 09:18:35 +0200398 description = description or "Tempest's share"
399 share_network_id = share_network_id or client.share_network_id or None
400 metadata = metadata or {}
marcusvrne0d7cfd2016-06-24 12:27:55 -0300401 size = size or CONF.share.share_size
Clinton Knighte5c8f092015-08-27 15:00:23 -0400402 kwargs.update({
Marc Koderer0abc93b2015-07-15 09:18:35 +0200403 'share_protocol': share_protocol,
404 'size': size,
405 'name': name,
406 'snapshot_id': snapshot_id,
407 'description': description,
408 'metadata': metadata,
409 'share_network_id': share_network_id,
410 'share_type_id': share_type_id,
411 'is_public': is_public,
Clinton Knighte5c8f092015-08-27 15:00:23 -0400412 })
Andrew Kerrb8436922016-06-01 15:32:43 -0400413 if share_group_id:
414 kwargs['share_group_id'] = share_group_id
Andrew Kerrbf31e912015-07-29 10:39:38 -0400415
Marc Koderer0abc93b2015-07-15 09:18:35 +0200416 share = client.create_share(**kwargs)
Andrew Kerrbf31e912015-07-29 10:39:38 -0400417 resource = {"type": "share", "id": share["id"], "client": client,
Andrew Kerrb8436922016-06-01 15:32:43 -0400418 "share_group_id": share_group_id}
Marc Koderer0abc93b2015-07-15 09:18:35 +0200419 cleanup_list = (cls.class_resources if cleanup_in_class else
420 cls.method_resources)
421 cleanup_list.insert(0, resource)
422 return share
423
424 @classmethod
Rodrigo Barbieri427bc052016-06-06 17:10:06 -0300425 def migrate_share(
426 cls, share_id, dest_host, wait_for_status, client=None,
Rodrigo Barbieri027df982016-11-24 15:52:03 -0200427 force_host_assisted_migration=False, writable=False,
428 nondisruptive=False, preserve_metadata=False,
429 preserve_snapshots=False, new_share_network_id=None,
Rodrigo Barbierid38d2f52016-07-19 22:24:56 -0300430 new_share_type_id=None, **kwargs):
Clinton Knighte5c8f092015-08-27 15:00:23 -0400431 client = client or cls.shares_v2_client
Rodrigo Barbieri427bc052016-06-06 17:10:06 -0300432 client.migrate_share(
433 share_id, dest_host,
434 force_host_assisted_migration=force_host_assisted_migration,
Rodrigo Barbieri027df982016-11-24 15:52:03 -0200435 writable=writable, preserve_metadata=preserve_metadata,
436 nondisruptive=nondisruptive, preserve_snapshots=preserve_snapshots,
Rodrigo Barbieri427bc052016-06-06 17:10:06 -0300437 new_share_network_id=new_share_network_id,
Rodrigo Barbierid38d2f52016-07-19 22:24:56 -0300438 new_share_type_id=new_share_type_id, **kwargs)
Rodrigo Barbierie3305122016-02-03 14:32:24 -0200439 share = client.wait_for_migration_status(
Rodrigo Barbieri427bc052016-06-06 17:10:06 -0300440 share_id, dest_host, wait_for_status, **kwargs)
Rodrigo Barbierie3305122016-02-03 14:32:24 -0200441 return share
442
443 @classmethod
444 def migration_complete(cls, share_id, dest_host, client=None, **kwargs):
445 client = client or cls.shares_v2_client
446 client.migration_complete(share_id, **kwargs)
447 share = client.wait_for_migration_status(
Rodrigo Barbieri427bc052016-06-06 17:10:06 -0300448 share_id, dest_host, 'migration_success', **kwargs)
Rodrigo Barbierib7137ad2015-09-06 22:53:16 -0300449 return share
450
451 @classmethod
Rodrigo Barbieric9abf282016-08-24 22:01:31 -0300452 def migration_cancel(cls, share_id, dest_host, client=None, **kwargs):
453 client = client or cls.shares_v2_client
454 client.migration_cancel(share_id, **kwargs)
455 share = client.wait_for_migration_status(
456 share_id, dest_host, 'migration_cancelled', **kwargs)
457 return share
458
459 @classmethod
Marc Koderer0abc93b2015-07-15 09:18:35 +0200460 def create_share(cls, *args, **kwargs):
461 """Create one share and wait for available state. Retry if allowed."""
462 result = cls.create_shares([{"args": args, "kwargs": kwargs}])
463 return result[0]
464
465 @classmethod
466 def create_shares(cls, share_data_list):
467 """Creates several shares in parallel with retries.
468
469 Use this method when you want to create more than one share at same
470 time. Especially if config option 'share.share_creation_retry_number'
471 has value more than zero (0).
472 All shares will be expected to have 'available' status with or without
473 recreation else error will be raised.
474
475 :param share_data_list: list -- list of dictionaries with 'args' and
476 'kwargs' for '_create_share' method of this base class.
477 example of data:
478 share_data_list=[{'args': ['quuz'], 'kwargs': {'foo': 'bar'}}}]
479 :returns: list -- list of shares created using provided data.
480 """
481
Valeriy Ponomaryov39cdf722016-05-30 18:16:15 +0300482 for d in share_data_list:
Marc Koderer0abc93b2015-07-15 09:18:35 +0200483 if not isinstance(d, dict):
484 raise exceptions.TempestException(
485 "Expected 'dict', got '%s'" % type(d))
486 if "args" not in d:
487 d["args"] = []
488 if "kwargs" not in d:
489 d["kwargs"] = {}
490 if len(d) > 2:
491 raise exceptions.TempestException(
492 "Expected only 'args' and 'kwargs' keys. "
493 "Provided %s" % list(d))
Valeriy Ponomaryov39cdf722016-05-30 18:16:15 +0300494
495 data = []
496 for d in share_data_list:
497 client = d["kwargs"].pop("client", cls.shares_v2_client)
yogeshdb32f462016-09-28 15:09:50 -0400498 wait_for_status = d["kwargs"].pop("wait_for_status", True)
Valeriy Ponomaryov39cdf722016-05-30 18:16:15 +0300499 local_d = {
500 "args": d["args"],
501 "kwargs": copy.deepcopy(d["kwargs"]),
502 }
503 local_d["kwargs"]["client"] = client
504 local_d["share"] = cls._create_share(
505 *local_d["args"], **local_d["kwargs"])
506 local_d["cnt"] = 0
507 local_d["available"] = False
yogeshdb32f462016-09-28 15:09:50 -0400508 local_d["wait_for_status"] = wait_for_status
Valeriy Ponomaryov39cdf722016-05-30 18:16:15 +0300509 data.append(local_d)
Marc Koderer0abc93b2015-07-15 09:18:35 +0200510
511 while not all(d["available"] for d in data):
512 for d in data:
yogeshdb32f462016-09-28 15:09:50 -0400513 if not d["wait_for_status"]:
514 d["available"] = True
Marc Koderer0abc93b2015-07-15 09:18:35 +0200515 if d["available"]:
516 continue
Valeriy Ponomaryov1a3e3382016-06-08 15:17:16 +0300517 client = d["kwargs"]["client"]
518 share_id = d["share"]["id"]
Marc Koderer0abc93b2015-07-15 09:18:35 +0200519 try:
Valeriy Ponomaryov1a3e3382016-06-08 15:17:16 +0300520 client.wait_for_share_status(share_id, "available")
Marc Koderer0abc93b2015-07-15 09:18:35 +0200521 d["available"] = True
522 except (share_exceptions.ShareBuildErrorException,
523 exceptions.TimeoutException) as e:
524 if CONF.share.share_creation_retry_number > d["cnt"]:
525 d["cnt"] += 1
526 msg = ("Share '%s' failed to be built. "
Valeriy Ponomaryov1a3e3382016-06-08 15:17:16 +0300527 "Trying create another." % share_id)
Marc Koderer0abc93b2015-07-15 09:18:35 +0200528 LOG.error(msg)
529 LOG.error(e)
Valeriy Ponomaryov1a3e3382016-06-08 15:17:16 +0300530 cg_id = d["kwargs"].get("consistency_group_id")
531 if cg_id:
532 # NOTE(vponomaryov): delete errored share
533 # immediately in case share is part of CG.
534 client.delete_share(
535 share_id,
536 params={"consistency_group_id": cg_id})
537 client.wait_for_resource_deletion(
538 share_id=share_id)
Marc Koderer0abc93b2015-07-15 09:18:35 +0200539 d["share"] = cls._create_share(
540 *d["args"], **d["kwargs"])
541 else:
gecong197358663802016-08-25 11:08:45 +0800542 raise
Marc Koderer0abc93b2015-07-15 09:18:35 +0200543
544 return [d["share"] for d in data]
545
546 @classmethod
Andrew Kerrb8436922016-06-01 15:32:43 -0400547 def create_share_group(cls, client=None, cleanup_in_class=True,
548 share_network_id=None, **kwargs):
Clinton Knighte5c8f092015-08-27 15:00:23 -0400549 client = client or cls.shares_v2_client
Andrew Kerrb8436922016-06-01 15:32:43 -0400550 if kwargs.get('source_share_group_snapshot_id') is None:
Goutham Pacha Ravi9221f5e2016-04-21 13:17:49 -0400551 kwargs['share_network_id'] = (share_network_id or
552 client.share_network_id or None)
Andrew Kerrb8436922016-06-01 15:32:43 -0400553 share_group = client.create_share_group(**kwargs)
Andrew Kerrbf31e912015-07-29 10:39:38 -0400554 resource = {
Andrew Kerrb8436922016-06-01 15:32:43 -0400555 "type": "share_group",
556 "id": share_group["id"],
557 "client": client,
558 }
Andrew Kerrbf31e912015-07-29 10:39:38 -0400559 if cleanup_in_class:
560 cls.class_resources.insert(0, resource)
561 else:
562 cls.method_resources.insert(0, resource)
563
Andrew Kerrb8436922016-06-01 15:32:43 -0400564 if kwargs.get('source_share_group_snapshot_id'):
565 new_share_group_shares = client.list_shares(
Andrew Kerrbf31e912015-07-29 10:39:38 -0400566 detailed=True,
Andrew Kerrb8436922016-06-01 15:32:43 -0400567 params={'share_group_id': share_group['id']},
568 experimental=True)
Andrew Kerrbf31e912015-07-29 10:39:38 -0400569
Andrew Kerrb8436922016-06-01 15:32:43 -0400570 for share in new_share_group_shares:
Andrew Kerrbf31e912015-07-29 10:39:38 -0400571 resource = {"type": "share",
572 "id": share["id"],
573 "client": client,
Andrew Kerrb8436922016-06-01 15:32:43 -0400574 "share_group_id": share.get("share_group_id")}
Andrew Kerrbf31e912015-07-29 10:39:38 -0400575 if cleanup_in_class:
576 cls.class_resources.insert(0, resource)
577 else:
578 cls.method_resources.insert(0, resource)
579
Andrew Kerrb8436922016-06-01 15:32:43 -0400580 client.wait_for_share_group_status(share_group['id'], 'available')
581 return share_group
582
583 @classmethod
584 def create_share_group_type(cls, name=None, share_types=(), is_public=None,
585 group_specs=None, client=None,
586 cleanup_in_class=True, **kwargs):
587 client = client or cls.shares_v2_client
588 share_group_type = client.create_share_group_type(
589 name=name,
590 share_types=share_types,
591 is_public=is_public,
592 group_specs=group_specs,
593 **kwargs)
594 resource = {
595 "type": "share_group_type",
596 "id": share_group_type["id"],
597 "client": client,
598 }
599 if cleanup_in_class:
600 cls.class_resources.insert(0, resource)
601 else:
602 cls.method_resources.insert(0, resource)
603 return share_group_type
Andrew Kerrbf31e912015-07-29 10:39:38 -0400604
605 @classmethod
Marc Koderer0abc93b2015-07-15 09:18:35 +0200606 def create_snapshot_wait_for_active(cls, share_id, name=None,
607 description=None, force=False,
608 client=None, cleanup_in_class=True):
609 if client is None:
Yogesh1f931ff2015-09-29 23:41:02 -0400610 client = cls.shares_v2_client
Marc Koderer0abc93b2015-07-15 09:18:35 +0200611 if description is None:
612 description = "Tempest's snapshot"
613 snapshot = client.create_snapshot(share_id, name, description, force)
614 resource = {
615 "type": "snapshot",
616 "id": snapshot["id"],
617 "client": client,
618 }
619 if cleanup_in_class:
620 cls.class_resources.insert(0, resource)
621 else:
622 cls.method_resources.insert(0, resource)
623 client.wait_for_snapshot_status(snapshot["id"], "available")
624 return snapshot
625
626 @classmethod
Andrew Kerrb8436922016-06-01 15:32:43 -0400627 def create_share_group_snapshot_wait_for_active(
628 cls, share_group_id, name=None, description=None, client=None,
629 cleanup_in_class=True, **kwargs):
Clinton Knighte5c8f092015-08-27 15:00:23 -0400630 client = client or cls.shares_v2_client
Andrew Kerrbf31e912015-07-29 10:39:38 -0400631 if description is None:
Andrew Kerrb8436922016-06-01 15:32:43 -0400632 description = "Tempest's share group snapshot"
633 sg_snapshot = client.create_share_group_snapshot(
634 share_group_id, name=name, description=description, **kwargs)
Andrew Kerrbf31e912015-07-29 10:39:38 -0400635 resource = {
Andrew Kerrb8436922016-06-01 15:32:43 -0400636 "type": "share_group_snapshot",
637 "id": sg_snapshot["id"],
Andrew Kerrbf31e912015-07-29 10:39:38 -0400638 "client": client,
639 }
640 if cleanup_in_class:
641 cls.class_resources.insert(0, resource)
642 else:
643 cls.method_resources.insert(0, resource)
Andrew Kerrb8436922016-06-01 15:32:43 -0400644 client.wait_for_share_group_snapshot_status(
645 sg_snapshot["id"], "available")
646 return sg_snapshot
Andrew Kerrbf31e912015-07-29 10:39:38 -0400647
648 @classmethod
Yogeshbdb88102015-09-29 23:41:02 -0400649 def get_availability_zones(cls, client=None):
650 """List the availability zones for "manila-share" services
651
652 that are currently in "up" state.
653 """
654 client = client or cls.shares_v2_client
655 cls.services = client.list_services()
656 zones = [service['zone'] for service in cls.services if
657 service['binary'] == "manila-share" and
658 service['state'] == 'up']
659 return zones
660
Yogesh1f931ff2015-09-29 23:41:02 -0400661 def get_pools_for_replication_domain(self):
662 # Get the list of pools for the replication domain
663 pools = self.admin_client.list_pools(detail=True)['pools']
664 instance_host = self.shares[0]['host']
665 host_pool = [p for p in pools if p['name'] == instance_host][0]
666 rep_domain = host_pool['capabilities']['replication_domain']
667 pools_in_rep_domain = [p for p in pools if p['capabilities'][
668 'replication_domain'] == rep_domain]
669 return rep_domain, pools_in_rep_domain
670
Yogeshbdb88102015-09-29 23:41:02 -0400671 @classmethod
672 def create_share_replica(cls, share_id, availability_zone, client=None,
673 cleanup_in_class=False, cleanup=True):
674 client = client or cls.shares_v2_client
675 replica = client.create_share_replica(share_id, availability_zone)
676 resource = {
677 "type": "share_replica",
678 "id": replica["id"],
679 "client": client,
680 "share_id": share_id,
681 }
682 # NOTE(Yogi1): Cleanup needs to be disabled during promotion tests.
683 if cleanup:
684 if cleanup_in_class:
685 cls.class_resources.insert(0, resource)
686 else:
687 cls.method_resources.insert(0, resource)
688 client.wait_for_share_replica_status(
689 replica["id"], constants.STATUS_AVAILABLE)
690 return replica
691
692 @classmethod
693 def delete_share_replica(cls, replica_id, client=None):
694 client = client or cls.shares_v2_client
Yogesh1f931ff2015-09-29 23:41:02 -0400695 try:
696 client.delete_share_replica(replica_id)
697 client.wait_for_resource_deletion(replica_id=replica_id)
698 except exceptions.NotFound:
699 pass
Yogeshbdb88102015-09-29 23:41:02 -0400700
701 @classmethod
702 def promote_share_replica(cls, replica_id, client=None):
703 client = client or cls.shares_v2_client
704 replica = client.promote_share_replica(replica_id)
705 client.wait_for_share_replica_status(
706 replica["id"],
707 constants.REPLICATION_STATE_ACTIVE,
708 status_attr="replica_state")
709 return replica
710
yogeshdb32f462016-09-28 15:09:50 -0400711 def _get_access_rule_data_from_config(self):
712 """Get the first available access type/to combination from config.
713
714 This method opportunistically picks the first configured protocol
715 to create the share. Do not use this method in tests where you need
716 to test depth and breadth in the access types and access recipients.
717 """
718 protocol = self.shares_v2_client.share_protocol
719
720 if protocol in CONF.share.enable_ip_rules_for_protocols:
721 access_type = "ip"
722 access_to = utils.rand_ip()
723 elif protocol in CONF.share.enable_user_rules_for_protocols:
724 access_type = "user"
725 access_to = CONF.share.username_for_user_rules
726 elif protocol in CONF.share.enable_cert_rules_for_protocols:
727 access_type = "cert"
728 access_to = "client3.com"
729 elif protocol in CONF.share.enable_cephx_rules_for_protocols:
730 access_type = "cephx"
731 access_to = "eve"
732 else:
733 message = "Unrecognized protocol and access rules configuration."
734 raise self.skipException(message)
735
736 return access_type, access_to
737
Yogeshbdb88102015-09-29 23:41:02 -0400738 @classmethod
Marc Koderer0abc93b2015-07-15 09:18:35 +0200739 def create_share_network(cls, client=None,
740 cleanup_in_class=False, **kwargs):
741 if client is None:
742 client = cls.shares_client
743 share_network = client.create_share_network(**kwargs)
744 resource = {
745 "type": "share_network",
746 "id": share_network["id"],
747 "client": client,
748 }
749 if cleanup_in_class:
750 cls.class_resources.insert(0, resource)
751 else:
752 cls.method_resources.insert(0, resource)
753 return share_network
754
755 @classmethod
756 def create_security_service(cls, ss_type="ldap", client=None,
757 cleanup_in_class=False, **kwargs):
758 if client is None:
759 client = cls.shares_client
760 security_service = client.create_security_service(ss_type, **kwargs)
761 resource = {
762 "type": "security_service",
763 "id": security_service["id"],
764 "client": client,
765 }
766 if cleanup_in_class:
767 cls.class_resources.insert(0, resource)
768 else:
769 cls.method_resources.insert(0, resource)
770 return security_service
771
772 @classmethod
773 def create_share_type(cls, name, is_public=True, client=None,
774 cleanup_in_class=True, **kwargs):
775 if client is None:
Valeriy Ponomaryova14c2252015-10-29 13:34:32 +0200776 client = cls.shares_v2_client
Marc Koderer0abc93b2015-07-15 09:18:35 +0200777 share_type = client.create_share_type(name, is_public, **kwargs)
778 resource = {
779 "type": "share_type",
780 "id": share_type["share_type"]["id"],
781 "client": client,
782 }
783 if cleanup_in_class:
784 cls.class_resources.insert(0, resource)
785 else:
786 cls.method_resources.insert(0, resource)
787 return share_type
788
789 @staticmethod
Clinton Knight4699a8c2016-08-16 22:36:13 -0400790 def add_extra_specs_to_dict(extra_specs=None):
791 """Add any required extra-specs to share type dictionary"""
Valeriy Ponomaryovad55dc52015-09-23 13:54:00 +0300792 dhss = six.text_type(CONF.share.multitenancy_enabled)
793 snapshot_support = six.text_type(
794 CONF.share.capability_snapshot_support)
Clinton Knight4699a8c2016-08-16 22:36:13 -0400795 create_from_snapshot_support = six.text_type(
796 CONF.share.capability_create_share_from_snapshot_support)
Clinton Knight7f16b8c2016-06-08 13:46:51 -0700797 revert_to_snapshot_support = six.text_type(
798 CONF.share.capability_revert_to_snapshot_support)
Clinton Knight4699a8c2016-08-16 22:36:13 -0400799
800 extra_specs_dict = {
Valeriy Ponomaryovad55dc52015-09-23 13:54:00 +0300801 "driver_handles_share_servers": dhss,
Marc Koderer0abc93b2015-07-15 09:18:35 +0200802 }
Clinton Knight4699a8c2016-08-16 22:36:13 -0400803
804 optional = {
805 "snapshot_support": snapshot_support,
806 "create_share_from_snapshot_support": create_from_snapshot_support,
Clinton Knight7f16b8c2016-06-08 13:46:51 -0700807 "revert_to_snapshot_support": revert_to_snapshot_support,
Clinton Knight4699a8c2016-08-16 22:36:13 -0400808 }
809 # NOTE(gouthamr): In micro-versions < 2.24, snapshot_support is a
810 # required extra-spec
811 extra_specs_dict.update(optional)
812
Marc Koderer0abc93b2015-07-15 09:18:35 +0200813 if extra_specs:
Clinton Knight4699a8c2016-08-16 22:36:13 -0400814 extra_specs_dict.update(extra_specs)
815
816 return extra_specs_dict
Marc Koderer0abc93b2015-07-15 09:18:35 +0200817
818 @classmethod
819 def clear_isolated_creds(cls, creds=None):
820 if creds is None:
821 creds = cls.method_isolated_creds
822 for ic in creds:
823 if "deleted" not in ic.keys():
824 ic["deleted"] = False
825 if not ic["deleted"]:
826 with handle_cleanup_exceptions():
827 ic["method"]()
828 ic["deleted"] = True
829
830 @classmethod
Yogesh1f931ff2015-09-29 23:41:02 -0400831 def clear_share_replicas(cls, share_id, client=None):
832 client = client or cls.shares_v2_client
833 share_replicas = client.list_share_replicas(
834 share_id=share_id)
835
836 for replica in share_replicas:
837 try:
838 cls.delete_share_replica(replica['id'])
839 except exceptions.BadRequest:
840 # Ignore the exception due to deletion of last active replica
841 pass
842
843 @classmethod
Marc Koderer0abc93b2015-07-15 09:18:35 +0200844 def clear_resources(cls, resources=None):
845 """Deletes resources, that were created in test suites.
846
847 This method tries to remove resources from resource list,
848 if it is not found, assumed it was deleted in test itself.
849 It is expected, that all resources were added as LIFO
850 due to restriction of deletion resources, that is in the chain.
851
852 :param resources: dict with keys 'type','id','client' and 'deleted'
853 """
Marc Koderer0abc93b2015-07-15 09:18:35 +0200854 if resources is None:
855 resources = cls.method_resources
856 for res in resources:
857 if "deleted" not in res.keys():
858 res["deleted"] = False
859 if "client" not in res.keys():
860 res["client"] = cls.shares_client
861 if not(res["deleted"]):
862 res_id = res['id']
863 client = res["client"]
864 with handle_cleanup_exceptions():
865 if res["type"] is "share":
Yogesh1f931ff2015-09-29 23:41:02 -0400866 cls.clear_share_replicas(res_id)
Andrew Kerrb8436922016-06-01 15:32:43 -0400867 share_group_id = res.get('share_group_id')
868 if share_group_id:
869 params = {'share_group_id': share_group_id}
Clinton Knighte5c8f092015-08-27 15:00:23 -0400870 client.delete_share(res_id, params=params)
871 else:
872 client.delete_share(res_id)
Marc Koderer0abc93b2015-07-15 09:18:35 +0200873 client.wait_for_resource_deletion(share_id=res_id)
874 elif res["type"] is "snapshot":
875 client.delete_snapshot(res_id)
876 client.wait_for_resource_deletion(snapshot_id=res_id)
877 elif res["type"] is "share_network":
878 client.delete_share_network(res_id)
879 client.wait_for_resource_deletion(sn_id=res_id)
880 elif res["type"] is "security_service":
881 client.delete_security_service(res_id)
882 client.wait_for_resource_deletion(ss_id=res_id)
883 elif res["type"] is "share_type":
884 client.delete_share_type(res_id)
885 client.wait_for_resource_deletion(st_id=res_id)
Andrew Kerrb8436922016-06-01 15:32:43 -0400886 elif res["type"] is "share_group":
887 client.delete_share_group(res_id)
888 client.wait_for_resource_deletion(
889 share_group_id=res_id)
890 elif res["type"] is "share_group_type":
891 client.delete_share_group_type(res_id)
892 client.wait_for_resource_deletion(
893 share_group_type_id=res_id)
894 elif res["type"] is "share_group_snapshot":
895 client.delete_share_group_snapshot(res_id)
896 client.wait_for_resource_deletion(
897 share_group_snapshot_id=res_id)
Yogeshbdb88102015-09-29 23:41:02 -0400898 elif res["type"] is "share_replica":
899 client.delete_share_replica(res_id)
900 client.wait_for_resource_deletion(replica_id=res_id)
Marc Koderer0abc93b2015-07-15 09:18:35 +0200901 else:
huayue97bacbf2016-01-04 09:57:39 +0800902 LOG.warning("Provided unsupported resource type for "
903 "cleanup '%s'. Skipping." % res["type"])
Marc Koderer0abc93b2015-07-15 09:18:35 +0200904 res["deleted"] = True
905
906 @classmethod
907 def generate_share_network_data(self):
908 data = {
909 "name": data_utils.rand_name("sn-name"),
910 "description": data_utils.rand_name("sn-desc"),
911 "neutron_net_id": data_utils.rand_name("net-id"),
912 "neutron_subnet_id": data_utils.rand_name("subnet-id"),
913 }
914 return data
915
916 @classmethod
917 def generate_security_service_data(self):
918 data = {
919 "name": data_utils.rand_name("ss-name"),
920 "description": data_utils.rand_name("ss-desc"),
Valeriy Ponomaryovfcde7712015-12-14 18:06:13 +0200921 "dns_ip": utils.rand_ip(),
922 "server": utils.rand_ip(),
Marc Koderer0abc93b2015-07-15 09:18:35 +0200923 "domain": data_utils.rand_name("ss-domain"),
924 "user": data_utils.rand_name("ss-user"),
925 "password": data_utils.rand_name("ss-password"),
926 }
927 return data
928
929 # Useful assertions
930 def assertDictMatch(self, d1, d2, approx_equal=False, tolerance=0.001):
931 """Assert two dicts are equivalent.
932
933 This is a 'deep' match in the sense that it handles nested
934 dictionaries appropriately.
935
936 NOTE:
937
938 If you don't care (or don't know) a given value, you can specify
939 the string DONTCARE as the value. This will cause that dict-item
940 to be skipped.
941
942 """
943 def raise_assertion(msg):
944 d1str = str(d1)
945 d2str = str(d2)
946 base_msg = ('Dictionaries do not match. %(msg)s d1: %(d1str)s '
947 'd2: %(d2str)s' %
948 {"msg": msg, "d1str": d1str, "d2str": d2str})
949 raise AssertionError(base_msg)
950
951 d1keys = set(d1.keys())
952 d2keys = set(d2.keys())
953 if d1keys != d2keys:
954 d1only = d1keys - d2keys
955 d2only = d2keys - d1keys
956 raise_assertion('Keys in d1 and not d2: %(d1only)s. '
957 'Keys in d2 and not d1: %(d2only)s' %
958 {"d1only": d1only, "d2only": d2only})
959
960 for key in d1keys:
961 d1value = d1[key]
962 d2value = d2[key]
963 try:
964 error = abs(float(d1value) - float(d2value))
965 within_tolerance = error <= tolerance
966 except (ValueError, TypeError):
daiki kato6914b1a2016-03-16 17:16:57 +0900967 # If both values aren't convertible to float, just ignore
Marc Koderer0abc93b2015-07-15 09:18:35 +0200968 # ValueError if arg is a str, TypeError if it's something else
969 # (like None)
970 within_tolerance = False
971
972 if hasattr(d1value, 'keys') and hasattr(d2value, 'keys'):
973 self.assertDictMatch(d1value, d2value)
974 elif 'DONTCARE' in (d1value, d2value):
975 continue
976 elif approx_equal and within_tolerance:
977 continue
978 elif d1value != d2value:
979 raise_assertion("d1['%(key)s']=%(d1value)s != "
980 "d2['%(key)s']=%(d2value)s" %
981 {
982 "key": key,
983 "d1value": d1value,
984 "d2value": d2value
985 })
986
987
988class BaseSharesAltTest(BaseSharesTest):
989 """Base test case class for all Shares Alt API tests."""
Valeriy Ponomaryov39cdf722016-05-30 18:16:15 +0300990 credentials = ('alt', )
Marc Koderer0abc93b2015-07-15 09:18:35 +0200991
992
993class BaseSharesAdminTest(BaseSharesTest):
994 """Base test case class for all Shares Admin API tests."""
Valeriy Ponomaryov39cdf722016-05-30 18:16:15 +0300995 credentials = ('admin', )
996
997
998class BaseSharesMixedTest(BaseSharesTest):
999 """Base test case class for all Shares API tests with all user roles."""
1000 credentials = ('primary', 'alt', 'admin')
Marc Koderer0abc93b2015-07-15 09:18:35 +02001001
1002 @classmethod
Valeriy Ponomaryov39cdf722016-05-30 18:16:15 +03001003 def setup_clients(cls):
1004 super(BaseSharesMixedTest, cls).setup_clients()
1005 cls.admin_shares_client = shares_client.SharesClient(
1006 cls.os_admin.auth_provider)
1007 cls.admin_shares_v2_client = shares_v2_client.SharesV2Client(
1008 cls.os_admin.auth_provider)
1009 cls.alt_shares_client = shares_client.SharesClient(
1010 cls.os_alt.auth_provider)
1011 cls.alt_shares_v2_client = shares_v2_client.SharesV2Client(
1012 cls.os_alt.auth_provider)
1013
1014 if CONF.share.multitenancy_enabled:
1015 admin_share_network_id = cls.provide_share_network(
1016 cls.admin_shares_v2_client, cls.os_admin.networks_client)
1017 cls.admin_shares_client.share_network_id = admin_share_network_id
1018 cls.admin_shares_v2_client.share_network_id = (
1019 admin_share_network_id)
1020
1021 alt_share_network_id = cls.provide_share_network(
1022 cls.alt_shares_v2_client, cls.os_alt.networks_client)
1023 cls.alt_shares_client.share_network_id = alt_share_network_id
1024 cls.alt_shares_v2_client.share_network_id = alt_share_network_id