blob: 862a169395b0b6e1fc7bc5f4fec8e84cf51723fc [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
debeltrami1753a592020-05-11 18:27:30 +000017import inspect
18import ipaddress
Valeriy Ponomaryov2abf5d72016-06-01 18:30:12 +030019import re
Marc Koderer0abc93b2015-07-15 09:18:35 +020020import traceback
21
22from oslo_concurrency import lockutils
23from oslo_log import log
24import six
Sam Wanc7b7f1f2015-11-25 00:22:28 -050025from tempest.common import credentials_factory as common_creds
Raissa Sarmento7b86b9d2017-07-21 14:32:48 +010026
Valeriy Ponomaryov48a2bd72015-11-05 13:22:44 +020027from tempest import config
Goutham Pacha Ravic678e212020-03-20 11:13:47 -070028from tempest.lib.common import cred_client
Raissa Sarmento7b86b9d2017-07-21 14:32:48 +010029from tempest.lib.common import dynamic_creds
Ben Swartzlander1c4ff522016-03-02 22:16:23 -050030from tempest.lib.common.utils import data_utils
debeltrami1753a592020-05-11 18:27:30 +000031from tempest.lib.common.utils import test_utils
Ben Swartzlander1c4ff522016-03-02 22:16:23 -050032from tempest.lib import exceptions
Valeriy Ponomaryov48a2bd72015-11-05 13:22:44 +020033from tempest import test
Marc Koderer0abc93b2015-07-15 09:18:35 +020034
Andrea Frittoli (andreaf)369391a2016-06-27 18:59:13 +010035from manila_tempest_tests import clients
Yogeshbdb88102015-09-29 23:41:02 -040036from manila_tempest_tests.common import constants
Marc Koderer0abc93b2015-07-15 09:18:35 +020037from manila_tempest_tests import share_exceptions
Valeriy Ponomaryovfcde7712015-12-14 18:06:13 +020038from manila_tempest_tests import utils
Marc Koderer0abc93b2015-07-15 09:18:35 +020039
40CONF = config.CONF
41LOG = log.getLogger(__name__)
42
Valeriy Ponomaryov2abf5d72016-06-01 18:30:12 +030043# Test tags related to test direction
44TAG_POSITIVE = "positive"
45TAG_NEGATIVE = "negative"
46
47# Test tags related to service involvement
Tom Barron69f96962019-07-29 17:07:03 -040048# Only requires that manila-api service running.
Valeriy Ponomaryov2abf5d72016-06-01 18:30:12 +030049TAG_API = "api"
Tom Barron69f96962019-07-29 17:07:03 -040050# Requires all manila services running, intended to test back-end
51# (manila-share) behavior.
Valeriy Ponomaryov2abf5d72016-06-01 18:30:12 +030052TAG_BACKEND = "backend"
Tom Barron69f96962019-07-29 17:07:03 -040053# Requires all manila services running, intended to test API behavior.
Valeriy Ponomaryov2abf5d72016-06-01 18:30:12 +030054TAG_API_WITH_BACKEND = "api_with_backend"
55
56TAGS_MAPPER = {
57 "p": TAG_POSITIVE,
58 "n": TAG_NEGATIVE,
59 "a": TAG_API,
60 "b": TAG_BACKEND,
61 "ab": TAG_API_WITH_BACKEND,
62}
63TAGS_PATTERN = re.compile(
64 r"(?=.*\[.*\b(%(p)s|%(n)s)\b.*\])(?=.*\[.*\b(%(a)s|%(b)s|%(ab)s)\b.*\])" %
65 TAGS_MAPPER)
66
67
68def verify_test_has_appropriate_tags(self):
69 if not TAGS_PATTERN.match(self.id()):
70 msg = (
71 "Required attributes either not set or set improperly. "
72 "Two test attributes are expected:\n"
73 " - one of '%(p)s' or '%(n)s' and \n"
74 " - one of '%(a)s', '%(b)s' or '%(ab)s'."
75 ) % TAGS_MAPPER
76 raise self.failureException(msg)
77
Marc Koderer0abc93b2015-07-15 09:18:35 +020078
79class handle_cleanup_exceptions(object):
80 """Handle exceptions raised with cleanup operations.
81
82 Always suppress errors when exceptions.NotFound or exceptions.Forbidden
83 are raised.
84 Suppress all other exceptions only in case config opt
85 'suppress_errors_in_cleanup' in config group 'share' is True.
86 """
87
88 def __enter__(self):
89 return self
90
91 def __exit__(self, exc_type, exc_value, exc_traceback):
92 if not (isinstance(exc_value,
93 (exceptions.NotFound, exceptions.Forbidden)) or
94 CONF.share.suppress_errors_in_cleanup):
95 return False # Do not suppress error if any
96 if exc_traceback:
97 LOG.error("Suppressed cleanup error in Manila: "
junbolib236c242017-07-18 18:12:37 +080098 "\n%s", traceback.format_exc())
Marc Koderer0abc93b2015-07-15 09:18:35 +020099 return True # Suppress error if any
100
101
102def network_synchronized(f):
103
104 def wrapped_func(self, *args, **kwargs):
Marc Koderer0abc93b2015-07-15 09:18:35 +0200105
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
130 # Will be cleaned up in tearDown method
131 method_resources = []
132
Andrea Frittoli (andreaf)369391a2016-06-27 18:59:13 +0100133 # NOTE(andreaf) Override the client manager class to be used, so that
134 # a stable class is used, which includes plugin registered services as well
135 client_manager = clients.Clients
136
Valeriy Ponomaryova14c2252015-10-29 13:34:32 +0200137 def skip_if_microversion_not_supported(self, microversion):
Valeriy Ponomaryovfcde7712015-12-14 18:06:13 +0200138 if not utils.is_microversion_supported(microversion):
Valeriy Ponomaryova14c2252015-10-29 13:34:32 +0200139 raise self.skipException(
140 "Microversion '%s' is not supported." % microversion)
141
Xing Yang69b00b52015-11-22 16:10:44 -0500142 def skip_if_microversion_lt(self, microversion):
143 if utils.is_microversion_lt(CONF.share.max_api_microversion,
144 microversion):
145 raise self.skipException(
146 "Microversion must be greater than or equal to '%s'." %
147 microversion)
148
Marc Koderer0abc93b2015-07-15 09:18:35 +0200149 @classmethod
Tom Barron4b8834a2017-02-02 11:02:20 -0500150 def _get_dynamic_creds(cls, name, network_resources=None):
Raissa Sarmento7b86b9d2017-07-21 14:32:48 +0100151 identity_version = CONF.identity.auth_version
152 if identity_version == 'v3':
153 identity_uri = CONF.identity.uri_v3
154 identity_admin_endpoint_type = CONF.identity.v3_endpoint_type
155 elif identity_version == 'v2':
156 identity_uri = CONF.identity.uri
157 identity_admin_endpoint_type = CONF.identity.v2_admin_endpoint_type
158
Tom Barron4b8834a2017-02-02 11:02:20 -0500159 return dynamic_creds.DynamicCredentialProvider(
Raissa Sarmento7b86b9d2017-07-21 14:32:48 +0100160 identity_version=identity_version,
Tom Barron4b8834a2017-02-02 11:02:20 -0500161 name=name,
162 network_resources=network_resources,
163 credentials_domain=CONF.auth.default_credentials_domain_name,
164 admin_role=CONF.identity.admin_role,
165 admin_creds=common_creds.get_configured_admin_credentials(),
166 identity_admin_domain_scope=CONF.identity.admin_domain_scope,
167 identity_admin_role=CONF.identity.admin_role,
168 extra_roles=None,
169 neutron_available=CONF.service_available.neutron,
170 create_networks=(
171 CONF.share.create_networks_when_multitenancy_enabled),
172 project_network_cidr=CONF.network.project_network_cidr,
173 project_network_mask_bits=CONF.network.project_network_mask_bits,
174 public_network_id=CONF.network.public_network_id,
ghanshyam2aea7c32017-12-11 00:03:56 +0000175 resource_prefix='tempest',
Raissa Sarmento7b86b9d2017-07-21 14:32:48 +0100176 identity_admin_endpoint_type=identity_admin_endpoint_type,
177 identity_uri=identity_uri)
Tom Barron4b8834a2017-02-02 11:02:20 -0500178
179 @classmethod
Daniel Melladoe5269142017-01-12 12:17:58 +0000180 def skip_checks(cls):
181 super(BaseSharesTest, cls).skip_checks()
182 if not CONF.service_available.manila:
183 raise cls.skipException("Manila support is required")
lkuchlana3b6f7a2020-01-07 10:45:45 +0200184 if not any(p in CONF.share.enable_protocols for p in cls.protocols):
185 skip_msg = "%s tests are disabled" % CONF.share.enable_protocols
186 raise cls.skipException(skip_msg)
Daniel Melladoe5269142017-01-12 12:17:58 +0000187
188 @classmethod
Marc Koderer0abc93b2015-07-15 09:18:35 +0200189 def verify_nonempty(cls, *args):
190 if not all(args):
191 msg = "Missing API credentials in configuration."
192 raise cls.skipException(msg)
193
194 @classmethod
Valeriy Ponomaryov39cdf722016-05-30 18:16:15 +0300195 def setup_clients(cls):
196 super(BaseSharesTest, cls).setup_clients()
197 os = getattr(cls, 'os_%s' % cls.credentials[0])
Andrea Frittoli (andreaf)369391a2016-06-27 18:59:13 +0100198 # Initialise share clients for test credentials
199 cls.shares_client = os.share_v1.SharesClient()
200 cls.shares_v2_client = os.share_v2.SharesV2Client()
debeltrami1753a592020-05-11 18:27:30 +0000201 cls.admin_nc = cls.admin_snc = cls.admin_rc = cls.admin_net_cred = None
Andrea Frittoli (andreaf)369391a2016-06-27 18:59:13 +0100202 # Initialise network clients for test credentials
203 if CONF.service_available.neutron:
204 cls.networks_client = os.network.NetworksClient()
205 cls.subnets_client = os.network.SubnetsClient()
debeltrami1753a592020-05-11 18:27:30 +0000206 if CONF.share.multitenancy_enabled and (
207 CONF.auth.use_dynamic_credentials):
208 # Get admin credentials so we can create neutron networks
209 # dynamically if/when needed
210 (cls.admin_nc, cls.admin_snc,
211 cls.admin_rc, cls.admin_net_cred) = (
212 cls.get_network_clients_with_isolated_creds())
Andrea Frittoli (andreaf)369391a2016-06-27 18:59:13 +0100213 else:
214 cls.networks_client = None
215 cls.subnets_client = None
Valeriy Ponomaryov4fb305f2016-10-21 13:46:47 +0300216
debeltrami1753a592020-05-11 18:27:30 +0000217 cls.project_network_cidr = CONF.network.project_network_cidr
218 cls.public_network_id = CONF.network.public_network_id
219
Valeriy Ponomaryov4fb305f2016-10-21 13:46:47 +0300220 if CONF.identity.auth_version == 'v3':
221 project_id = os.auth_provider.auth_data[1]['project']['id']
222 else:
223 project_id = os.auth_provider.auth_data[1]['token']['tenant']['id']
224 cls.tenant_id = project_id
225 cls.user_id = os.auth_provider.auth_data[1]['user']['id']
226
Valeriy Ponomaryov39cdf722016-05-30 18:16:15 +0300227 if CONF.share.multitenancy_enabled:
Valeriy Ponomaryovc5dae272016-06-10 18:29:24 +0300228 if (not CONF.service_available.neutron and
229 CONF.share.create_networks_when_multitenancy_enabled):
Valeriy Ponomaryov39cdf722016-05-30 18:16:15 +0300230 raise cls.skipException("Neutron support is required")
231 share_network_id = cls.provide_share_network(
Andrea Frittoli (andreaf)369391a2016-06-27 18:59:13 +0100232 cls.shares_v2_client, cls.networks_client)
Valeriy Ponomaryov39cdf722016-05-30 18:16:15 +0300233 cls.shares_client.share_network_id = share_network_id
234 cls.shares_v2_client.share_network_id = share_network_id
haobing101c7fee2018-03-09 16:33:00 +0800235 resource = {
236 "type": "share_network",
237 "id": share_network_id,
238 "client": cls.shares_v2_client,
239 }
240 cls.class_resources.insert(0, resource)
Valeriy Ponomaryov39cdf722016-05-30 18:16:15 +0300241
Marc Koderer0abc93b2015-07-15 09:18:35 +0200242 def setUp(self):
243 super(BaseSharesTest, self).setUp()
Valeriy Ponomaryovdd162cb2016-01-20 19:09:49 +0200244 self.addCleanup(self.clear_resources)
Valeriy Ponomaryov2abf5d72016-06-01 18:30:12 +0300245 verify_test_has_appropriate_tags(self)
Marc Koderer0abc93b2015-07-15 09:18:35 +0200246
247 @classmethod
248 def resource_cleanup(cls):
Marc Koderer0abc93b2015-07-15 09:18:35 +0200249 cls.clear_resources(cls.class_resources)
debeltrami1753a592020-05-11 18:27:30 +0000250 if cls.admin_net_cred:
251 cls.admin_net_cred.clear_creds()
Sam Wan241029c2016-07-26 03:37:42 -0400252 super(BaseSharesTest, cls).resource_cleanup()
Marc Koderer0abc93b2015-07-15 09:18:35 +0200253
254 @classmethod
debeltrami1753a592020-05-11 18:27:30 +0000255 def provide_and_associate_security_services(
256 cls, shares_client, share_network_id, cleanup_in_class=True):
257 """Creates a security service and associates to a share network.
258
259 This method creates security services based on the Multiopt
260 defined in tempest configuration named security_service. When this
261 configuration is not provided, the method will return None.
262 After the security service creation, this method also associates
263 the security service to a share network.
264
265 :param shares_client: shares client, which requires the provisioning
266 :param share_network_id: id of the share network to associate the
267 security service
268 :param cleanup_in_class: if the security service and the association
269 will be removed in the method teardown or class teardown
270 :returns: None -- if the security service configuration is not
271 defined
272 """
273
274 ss_configs = CONF.share.security_service
275 if not ss_configs:
276 return
277
278 for ss_config in ss_configs:
279 ss_name = "ss_autogenerated_by_tempest_%s" % (
280 ss_config.get("ss_type"))
281
282 ss_params = {
283 "name": ss_name,
284 "dns_ip": ss_config.get("ss_dns_ip"),
285 "server": ss_config.get("ss_server"),
286 "domain": ss_config.get("ss_domain"),
287 "user": ss_config.get("ss_user"),
288 "password": ss_config.get("ss_password")
289 }
290 ss_type = ss_config.get("ss_type")
291 security_service = cls.create_security_service(
292 ss_type,
293 client=shares_client,
294 cleanup_in_class=cleanup_in_class,
295 **ss_params)
296
297 cls.add_sec_service_to_share_network(
298 shares_client, share_network_id,
299 security_service["id"],
300 cleanup_in_class=cleanup_in_class)
301
302 @classmethod
303 def add_sec_service_to_share_network(
304 cls, client, share_network_id,
305 security_service_id, cleanup_in_class=True):
306 """Associates a security service to a share network.
307
308 This method associates a security service provided by
309 the security service configuration with a specific
310 share network.
311
312 :param share_network_id: the share network id to be
313 associate with a given security service
314 :param security_service_id: the security service id
315 to be associate with a given share network
316 :param cleanup_in_class: if the resources will be
317 dissociate in the method teardown or class teardown
318 """
319
320 client.add_sec_service_to_share_network(
321 share_network_id,
322 security_service_id)
323 resource = {
324 "type": "dissociate_security_service",
325 "id": security_service_id,
326 "extra_params": {
327 "share_network_id": share_network_id
328 },
329 "client": client,
330 }
331
332 if cleanup_in_class:
333 cls.class_resources.insert(0, resource)
334 else:
335 cls.method_resources.insert(0, resource)
336
337 @classmethod
Marc Koderer0abc93b2015-07-15 09:18:35 +0200338 @network_synchronized
Valeriy Ponomaryov48a2bd72015-11-05 13:22:44 +0200339 def provide_share_network(cls, shares_client, networks_client,
Rodrigo Barbieri58d9de32016-09-06 13:16:47 -0300340 ignore_multitenancy_config=False):
Marc Koderer0abc93b2015-07-15 09:18:35 +0200341 """Used for finding/creating share network for multitenant driver.
342
343 This method creates/gets entity share-network for one tenant. This
344 share-network will be used for creation of service vm.
345
346 :param shares_client: shares client, which requires share-network
Valeriy Ponomaryov48a2bd72015-11-05 13:22:44 +0200347 :param networks_client: network client from same tenant as shares
Rodrigo Barbieri58d9de32016-09-06 13:16:47 -0300348 :param ignore_multitenancy_config: provide a share network regardless
349 of 'multitenancy_enabled' configuration value.
Marc Koderer0abc93b2015-07-15 09:18:35 +0200350 :returns: str -- share network id for shares_client tenant
351 :returns: None -- if single-tenant driver used
352 """
353
354 sc = shares_client
debeltrami1753a592020-05-11 18:27:30 +0000355 sn_name = "autogenerated_by_tempest"
Marc Koderer0abc93b2015-07-15 09:18:35 +0200356
Rodrigo Barbieri58d9de32016-09-06 13:16:47 -0300357 if (not ignore_multitenancy_config and
358 not CONF.share.multitenancy_enabled):
Marc Koderer0abc93b2015-07-15 09:18:35 +0200359 # Assumed usage of a single-tenant driver
debeltrami1753a592020-05-11 18:27:30 +0000360 return None
Marc Koderer0abc93b2015-07-15 09:18:35 +0200361 else:
Rodrigo Barbieri58d9de32016-09-06 13:16:47 -0300362 if sc.share_network_id:
363 # Share-network already exists, use it
debeltrami1753a592020-05-11 18:27:30 +0000364 return sc.share_network_id
Rodrigo Barbieri58d9de32016-09-06 13:16:47 -0300365 elif not CONF.share.create_networks_when_multitenancy_enabled:
debeltrami1753a592020-05-11 18:27:30 +0000366 # We need a new share network, but don't need to associate
367 # any neutron networks to it - this configuration is used
368 # when manila is configured with "StandaloneNetworkPlugin"
369 # or "NeutronSingleNetworkPlugin" where all tenants share
370 # a single backend network where shares are exported.
371 sn_desc = "This share-network was created by tempest"
372 sn = cls.create_share_network(cleanup_in_class=True,
373 add_security_services=True,
374 name=sn_name,
375 description=sn_desc)
376 return sn['id']
Rodrigo Barbieri58d9de32016-09-06 13:16:47 -0300377 else:
debeltrami1753a592020-05-11 18:27:30 +0000378 net_id = subnet_id = None
379 # Retrieve non-public network list owned by the tenant
380 search_opts = {'tenant_id': sc.tenant_id, 'shared': False}
381 tenant_networks = (
382 networks_client.list_networks(
383 **search_opts).get('networks', [])
384 )
385 tenant_networks_with_subnet = (
386 [n for n in tenant_networks if n['subnets']]
387 )
Goutham Pacha Raviaf448262020-06-29 14:24:13 -0700388
debeltrami1753a592020-05-11 18:27:30 +0000389 if tenant_networks_with_subnet:
390 net_id = tenant_networks_with_subnet[0]['id']
391 subnet_id = tenant_networks_with_subnet[0]['subnets'][0]
392
Goutham Pacha Raviaf448262020-06-29 14:24:13 -0700393 if net_id is None or subnet_id is None:
debeltrami1753a592020-05-11 18:27:30 +0000394 network, subnet, router = (
395 cls.provide_network_resources_for_tenant_id(
396 sc.tenant_id)
397 )
398 net_id = network['network']['id']
399 subnet_id = subnet['subnet']['id']
Rodrigo Barbieri58d9de32016-09-06 13:16:47 -0300400
401 # Create suitable share-network
debeltrami1753a592020-05-11 18:27:30 +0000402 sn_desc = "This share-network was created by tempest"
403 sn = cls.create_share_network(cleanup_in_class=True,
404 add_security_services=True,
405 name=sn_name,
406 description=sn_desc,
407 neutron_net_id=net_id,
408 neutron_subnet_id=subnet_id)
Marc Koderer0abc93b2015-07-15 09:18:35 +0200409
debeltrami1753a592020-05-11 18:27:30 +0000410 return sn['id']
411
412 @classmethod
413 def provide_network_resources_for_tenant_id(cls, tenant_id):
414 """Used for creating neutron network resources.
415
416 This method creates a suitable network, subnet and router
417 to be used when providing a new share network in the tempest.
418 The tempest conf project_network_cidr is very important
419 in order to create a reachable network. Also, this method will
420 cleanup the neutron resources in the class teardown.
421
422 :param tenant_id: tenant_id to be used for network resources creation
423 :returns network, subnet, router: the neutron resources created
424 """
425
426 network = cls.admin_nc.create_network(
427 tenant_id=tenant_id,
428 name="tempest-net")
429 cls.addClassResourceCleanup(
430 test_utils.call_and_ignore_notfound_exc,
431 cls.admin_nc.delete_network,
432 network['network']['id'])
433
434 subnet = cls.admin_snc.create_subnet(
435 network_id=network['network']['id'],
436 tenant_id=tenant_id,
437 cidr=str(cls.project_network_cidr),
438 name="tempest-subnet",
439 ip_version=(ipaddress.ip_network(
440 six.text_type(cls.project_network_cidr)).version))
441 cls.addClassResourceCleanup(
442 test_utils.call_and_ignore_notfound_exc,
443 cls.admin_snc.delete_subnet,
444 subnet['subnet']['id'])
445
446 router = None
447 if cls.public_network_id:
448 kwargs = {'name': "tempest-router",
449 'tenant_id': tenant_id,
450 'external_gateway_info': cls.public_network_id}
451 body = cls.routers_client.create_router(**kwargs)
452 router = body['router']
453
454 cls.admin_rc.add_router_interface(
455 router['id'],
456 subnet_id=subnet['subnet']['id'])
457 cls.addClassResourceCleanup(
458 test_utils.call_and_ignore_notfound_exc,
459 cls.admin_rc.delete_router, router)
460 cls.addClassResourceCleanup(
461 test_utils.call_and_ignore_notfound_exc,
462 cls.admin_rc.remove_router_interface,
463 router['id'],
464 subnet_id=subnet['subnet']['id'])
465
466 return network, subnet, router
467
468 @classmethod
469 def get_network_clients_with_isolated_creds(cls,
470 name=None,
471 type_of_creds='admin'):
472 """Creates isolated creds and provide network clients.
473
474 :param name: name, will be used for naming ic and related stuff
475 :param type_of_creds: defines the type of creds to be created
476 :returns: NetworksClient, SubnetsClient, RoutersClient,
477 Isolated Credentials
478 """
479
480 if name is None:
481 # Get name of test method
482 name = inspect.stack()[1][3]
483 if len(name) > 32:
484 name = name[0:32]
485 # Choose type of isolated creds
486 ic = cls._get_dynamic_creds(name)
487 if "admin" in type_of_creds:
488 creds = ic.get_admin_creds().credentials
489 elif "alt" in type_of_creds:
490 creds = ic.get_alt_creds().credentials
491 else:
492 creds = ic.get_credentials(type_of_creds).credentials
493 ic.type_of_creds = type_of_creds
494 # create client with isolated creds
495 os = clients.Clients(creds)
496
497 net_client = os.network.NetworksClient()
498 subnet_client = os.network.SubnetsClient()
499 router_client = os.network.RoutersClient()
500
501 return net_client, subnet_client, router_client, ic
Marc Koderer0abc93b2015-07-15 09:18:35 +0200502
503 @classmethod
marcusvrne0d7cfd2016-06-24 12:27:55 -0300504 def _create_share(cls, share_protocol=None, size=None, name=None,
Marc Koderer0abc93b2015-07-15 09:18:35 +0200505 snapshot_id=None, description=None, metadata=None,
506 share_network_id=None, share_type_id=None,
Andrew Kerrb8436922016-06-01 15:32:43 -0400507 share_group_id=None, client=None,
Clinton Knighte5c8f092015-08-27 15:00:23 -0400508 cleanup_in_class=True, is_public=False, **kwargs):
Valeriy Ponomaryov1aaa72d2015-09-08 12:59:41 +0300509 client = client or cls.shares_v2_client
Marc Koderer0abc93b2015-07-15 09:18:35 +0200510 description = description or "Tempest's share"
yogesh06f519f2017-06-26 13:16:12 -0400511 share_network_id = (share_network_id or
512 CONF.share.share_network_id or
513 client.share_network_id or None)
Marc Koderer0abc93b2015-07-15 09:18:35 +0200514 metadata = metadata or {}
marcusvrne0d7cfd2016-06-24 12:27:55 -0300515 size = size or CONF.share.share_size
Clinton Knighte5c8f092015-08-27 15:00:23 -0400516 kwargs.update({
Marc Koderer0abc93b2015-07-15 09:18:35 +0200517 'share_protocol': share_protocol,
518 'size': size,
519 'name': name,
520 'snapshot_id': snapshot_id,
521 'description': description,
522 'metadata': metadata,
523 'share_network_id': share_network_id,
524 'share_type_id': share_type_id,
525 'is_public': is_public,
Clinton Knighte5c8f092015-08-27 15:00:23 -0400526 })
Andrew Kerrb8436922016-06-01 15:32:43 -0400527 if share_group_id:
528 kwargs['share_group_id'] = share_group_id
Andrew Kerrbf31e912015-07-29 10:39:38 -0400529
Marc Koderer0abc93b2015-07-15 09:18:35 +0200530 share = client.create_share(**kwargs)
Andrew Kerrbf31e912015-07-29 10:39:38 -0400531 resource = {"type": "share", "id": share["id"], "client": client,
Andrew Kerrb8436922016-06-01 15:32:43 -0400532 "share_group_id": share_group_id}
Marc Koderer0abc93b2015-07-15 09:18:35 +0200533 cleanup_list = (cls.class_resources if cleanup_in_class else
534 cls.method_resources)
535 cleanup_list.insert(0, resource)
536 return share
537
538 @classmethod
Rodrigo Barbieri427bc052016-06-06 17:10:06 -0300539 def migrate_share(
540 cls, share_id, dest_host, wait_for_status, client=None,
Rodrigo Barbieri027df982016-11-24 15:52:03 -0200541 force_host_assisted_migration=False, writable=False,
542 nondisruptive=False, preserve_metadata=False,
543 preserve_snapshots=False, new_share_network_id=None,
Rodrigo Barbierid38d2f52016-07-19 22:24:56 -0300544 new_share_type_id=None, **kwargs):
Clinton Knighte5c8f092015-08-27 15:00:23 -0400545 client = client or cls.shares_v2_client
Rodrigo Barbieri427bc052016-06-06 17:10:06 -0300546 client.migrate_share(
547 share_id, dest_host,
548 force_host_assisted_migration=force_host_assisted_migration,
Rodrigo Barbieri027df982016-11-24 15:52:03 -0200549 writable=writable, preserve_metadata=preserve_metadata,
550 nondisruptive=nondisruptive, preserve_snapshots=preserve_snapshots,
Rodrigo Barbieri427bc052016-06-06 17:10:06 -0300551 new_share_network_id=new_share_network_id,
Rodrigo Barbierid38d2f52016-07-19 22:24:56 -0300552 new_share_type_id=new_share_type_id, **kwargs)
Rodrigo Barbierie3305122016-02-03 14:32:24 -0200553 share = client.wait_for_migration_status(
Rodrigo Barbieri427bc052016-06-06 17:10:06 -0300554 share_id, dest_host, wait_for_status, **kwargs)
Rodrigo Barbierie3305122016-02-03 14:32:24 -0200555 return share
556
557 @classmethod
558 def migration_complete(cls, share_id, dest_host, client=None, **kwargs):
559 client = client or cls.shares_v2_client
560 client.migration_complete(share_id, **kwargs)
561 share = client.wait_for_migration_status(
Rodrigo Barbieri427bc052016-06-06 17:10:06 -0300562 share_id, dest_host, 'migration_success', **kwargs)
Rodrigo Barbierib7137ad2015-09-06 22:53:16 -0300563 return share
564
565 @classmethod
Rodrigo Barbieric9abf282016-08-24 22:01:31 -0300566 def migration_cancel(cls, share_id, dest_host, client=None, **kwargs):
567 client = client or cls.shares_v2_client
568 client.migration_cancel(share_id, **kwargs)
569 share = client.wait_for_migration_status(
570 share_id, dest_host, 'migration_cancelled', **kwargs)
571 return share
572
573 @classmethod
Marc Koderer0abc93b2015-07-15 09:18:35 +0200574 def create_share(cls, *args, **kwargs):
575 """Create one share and wait for available state. Retry if allowed."""
576 result = cls.create_shares([{"args": args, "kwargs": kwargs}])
577 return result[0]
578
579 @classmethod
580 def create_shares(cls, share_data_list):
581 """Creates several shares in parallel with retries.
582
583 Use this method when you want to create more than one share at same
584 time. Especially if config option 'share.share_creation_retry_number'
585 has value more than zero (0).
586 All shares will be expected to have 'available' status with or without
587 recreation else error will be raised.
588
589 :param share_data_list: list -- list of dictionaries with 'args' and
590 'kwargs' for '_create_share' method of this base class.
591 example of data:
592 share_data_list=[{'args': ['quuz'], 'kwargs': {'foo': 'bar'}}}]
593 :returns: list -- list of shares created using provided data.
594 """
595
Valeriy Ponomaryov39cdf722016-05-30 18:16:15 +0300596 for d in share_data_list:
Marc Koderer0abc93b2015-07-15 09:18:35 +0200597 if not isinstance(d, dict):
598 raise exceptions.TempestException(
599 "Expected 'dict', got '%s'" % type(d))
600 if "args" not in d:
601 d["args"] = []
602 if "kwargs" not in d:
603 d["kwargs"] = {}
604 if len(d) > 2:
605 raise exceptions.TempestException(
606 "Expected only 'args' and 'kwargs' keys. "
607 "Provided %s" % list(d))
Valeriy Ponomaryov39cdf722016-05-30 18:16:15 +0300608
609 data = []
610 for d in share_data_list:
611 client = d["kwargs"].pop("client", cls.shares_v2_client)
yogeshdb32f462016-09-28 15:09:50 -0400612 wait_for_status = d["kwargs"].pop("wait_for_status", True)
Valeriy Ponomaryov39cdf722016-05-30 18:16:15 +0300613 local_d = {
614 "args": d["args"],
615 "kwargs": copy.deepcopy(d["kwargs"]),
616 }
617 local_d["kwargs"]["client"] = client
618 local_d["share"] = cls._create_share(
619 *local_d["args"], **local_d["kwargs"])
620 local_d["cnt"] = 0
621 local_d["available"] = False
yogeshdb32f462016-09-28 15:09:50 -0400622 local_d["wait_for_status"] = wait_for_status
Valeriy Ponomaryov39cdf722016-05-30 18:16:15 +0300623 data.append(local_d)
Marc Koderer0abc93b2015-07-15 09:18:35 +0200624
625 while not all(d["available"] for d in data):
626 for d in data:
yogeshdb32f462016-09-28 15:09:50 -0400627 if not d["wait_for_status"]:
628 d["available"] = True
Marc Koderer0abc93b2015-07-15 09:18:35 +0200629 if d["available"]:
630 continue
Valeriy Ponomaryov1a3e3382016-06-08 15:17:16 +0300631 client = d["kwargs"]["client"]
632 share_id = d["share"]["id"]
Marc Koderer0abc93b2015-07-15 09:18:35 +0200633 try:
Valeriy Ponomaryov1a3e3382016-06-08 15:17:16 +0300634 client.wait_for_share_status(share_id, "available")
Marc Koderer0abc93b2015-07-15 09:18:35 +0200635 d["available"] = True
636 except (share_exceptions.ShareBuildErrorException,
637 exceptions.TimeoutException) as e:
638 if CONF.share.share_creation_retry_number > d["cnt"]:
639 d["cnt"] += 1
640 msg = ("Share '%s' failed to be built. "
Valeriy Ponomaryov1a3e3382016-06-08 15:17:16 +0300641 "Trying create another." % share_id)
Marc Koderer0abc93b2015-07-15 09:18:35 +0200642 LOG.error(msg)
643 LOG.error(e)
Valeriy Ponomaryov1a3e3382016-06-08 15:17:16 +0300644 cg_id = d["kwargs"].get("consistency_group_id")
645 if cg_id:
646 # NOTE(vponomaryov): delete errored share
647 # immediately in case share is part of CG.
648 client.delete_share(
649 share_id,
650 params={"consistency_group_id": cg_id})
651 client.wait_for_resource_deletion(
652 share_id=share_id)
Marc Koderer0abc93b2015-07-15 09:18:35 +0200653 d["share"] = cls._create_share(
654 *d["args"], **d["kwargs"])
655 else:
gecong197358663802016-08-25 11:08:45 +0800656 raise
Marc Koderer0abc93b2015-07-15 09:18:35 +0200657
658 return [d["share"] for d in data]
659
660 @classmethod
Andrew Kerrb8436922016-06-01 15:32:43 -0400661 def create_share_group(cls, client=None, cleanup_in_class=True,
662 share_network_id=None, **kwargs):
Clinton Knighte5c8f092015-08-27 15:00:23 -0400663 client = client or cls.shares_v2_client
Andrew Kerrb8436922016-06-01 15:32:43 -0400664 if kwargs.get('source_share_group_snapshot_id') is None:
Goutham Pacha Ravi9221f5e2016-04-21 13:17:49 -0400665 kwargs['share_network_id'] = (share_network_id or
666 client.share_network_id or None)
Andrew Kerrb8436922016-06-01 15:32:43 -0400667 share_group = client.create_share_group(**kwargs)
Andrew Kerrbf31e912015-07-29 10:39:38 -0400668 resource = {
Andrew Kerrb8436922016-06-01 15:32:43 -0400669 "type": "share_group",
670 "id": share_group["id"],
671 "client": client,
672 }
Andrew Kerrbf31e912015-07-29 10:39:38 -0400673 if cleanup_in_class:
674 cls.class_resources.insert(0, resource)
675 else:
676 cls.method_resources.insert(0, resource)
677
Andrew Kerrb8436922016-06-01 15:32:43 -0400678 if kwargs.get('source_share_group_snapshot_id'):
679 new_share_group_shares = client.list_shares(
Andrew Kerrbf31e912015-07-29 10:39:38 -0400680 detailed=True,
silvacarloss6e575682020-02-18 19:52:35 -0300681 params={'share_group_id': share_group['id']})
Andrew Kerrbf31e912015-07-29 10:39:38 -0400682
Andrew Kerrb8436922016-06-01 15:32:43 -0400683 for share in new_share_group_shares:
Andrew Kerrbf31e912015-07-29 10:39:38 -0400684 resource = {"type": "share",
685 "id": share["id"],
686 "client": client,
Andrew Kerrb8436922016-06-01 15:32:43 -0400687 "share_group_id": share.get("share_group_id")}
Andrew Kerrbf31e912015-07-29 10:39:38 -0400688 if cleanup_in_class:
689 cls.class_resources.insert(0, resource)
690 else:
691 cls.method_resources.insert(0, resource)
692
Andrew Kerrb8436922016-06-01 15:32:43 -0400693 client.wait_for_share_group_status(share_group['id'], 'available')
694 return share_group
695
696 @classmethod
697 def create_share_group_type(cls, name=None, share_types=(), is_public=None,
698 group_specs=None, client=None,
699 cleanup_in_class=True, **kwargs):
700 client = client or cls.shares_v2_client
Valeriy Ponomaryove92f09f2017-03-16 17:25:47 +0300701 if (group_specs is None and
702 CONF.share.capability_sg_consistent_snapshot_support):
Valeriy Ponomaryov3c188932017-03-15 19:06:23 +0300703 group_specs = {
704 'consistent_snapshot_support': (
705 CONF.share.capability_sg_consistent_snapshot_support),
706 }
Andrew Kerrb8436922016-06-01 15:32:43 -0400707 share_group_type = client.create_share_group_type(
708 name=name,
709 share_types=share_types,
710 is_public=is_public,
711 group_specs=group_specs,
712 **kwargs)
713 resource = {
714 "type": "share_group_type",
715 "id": share_group_type["id"],
716 "client": client,
717 }
718 if cleanup_in_class:
719 cls.class_resources.insert(0, resource)
720 else:
721 cls.method_resources.insert(0, resource)
722 return share_group_type
Andrew Kerrbf31e912015-07-29 10:39:38 -0400723
724 @classmethod
Marc Koderer0abc93b2015-07-15 09:18:35 +0200725 def create_snapshot_wait_for_active(cls, share_id, name=None,
726 description=None, force=False,
727 client=None, cleanup_in_class=True):
728 if client is None:
Yogesh1f931ff2015-09-29 23:41:02 -0400729 client = cls.shares_v2_client
Marc Koderer0abc93b2015-07-15 09:18:35 +0200730 if description is None:
731 description = "Tempest's snapshot"
732 snapshot = client.create_snapshot(share_id, name, description, force)
733 resource = {
734 "type": "snapshot",
735 "id": snapshot["id"],
736 "client": client,
737 }
738 if cleanup_in_class:
739 cls.class_resources.insert(0, resource)
740 else:
741 cls.method_resources.insert(0, resource)
742 client.wait_for_snapshot_status(snapshot["id"], "available")
743 return snapshot
744
745 @classmethod
Andrew Kerrb8436922016-06-01 15:32:43 -0400746 def create_share_group_snapshot_wait_for_active(
747 cls, share_group_id, name=None, description=None, client=None,
748 cleanup_in_class=True, **kwargs):
Clinton Knighte5c8f092015-08-27 15:00:23 -0400749 client = client or cls.shares_v2_client
Andrew Kerrbf31e912015-07-29 10:39:38 -0400750 if description is None:
Andrew Kerrb8436922016-06-01 15:32:43 -0400751 description = "Tempest's share group snapshot"
752 sg_snapshot = client.create_share_group_snapshot(
753 share_group_id, name=name, description=description, **kwargs)
Andrew Kerrbf31e912015-07-29 10:39:38 -0400754 resource = {
Andrew Kerrb8436922016-06-01 15:32:43 -0400755 "type": "share_group_snapshot",
756 "id": sg_snapshot["id"],
Andrew Kerrbf31e912015-07-29 10:39:38 -0400757 "client": client,
758 }
759 if cleanup_in_class:
760 cls.class_resources.insert(0, resource)
761 else:
762 cls.method_resources.insert(0, resource)
Andrew Kerrb8436922016-06-01 15:32:43 -0400763 client.wait_for_share_group_snapshot_status(
764 sg_snapshot["id"], "available")
765 return sg_snapshot
Andrew Kerrbf31e912015-07-29 10:39:38 -0400766
767 @classmethod
Goutham Pacha Ravi839c98b2019-01-14 23:16:23 -0800768 def get_availability_zones(cls, client=None, backends=None):
Yogeshbdb88102015-09-29 23:41:02 -0400769 """List the availability zones for "manila-share" services
770
771 that are currently in "up" state.
772 """
Goutham Pacha Ravi839c98b2019-01-14 23:16:23 -0800773 client = client or cls.admin_shares_v2_client
774 backends = (
775 '|'.join(['^%s$' % backend for backend in backends])
776 if backends else '.*'
777 )
Yogeshbdb88102015-09-29 23:41:02 -0400778 cls.services = client.list_services()
779 zones = [service['zone'] for service in cls.services if
Goutham Pacha Ravi839c98b2019-01-14 23:16:23 -0800780 service['binary'] == 'manila-share' and
781 service['state'] == 'up' and
782 re.search(backends, service['host'])]
Douglas Viroel161f1802020-04-25 17:18:14 -0300783 return list(set(zones))
Yogeshbdb88102015-09-29 23:41:02 -0400784
Goutham Pacha Ravi839c98b2019-01-14 23:16:23 -0800785 @classmethod
786 def get_pools_matching_share_type(cls, share_type, client=None):
787 client = client or cls.admin_shares_v2_client
788 if utils.is_microversion_supported('2.23'):
789 return client.list_pools(
andrebeltrami3b4d4852020-02-04 19:11:54 +0000790 detail=True,
Goutham Pacha Ravi839c98b2019-01-14 23:16:23 -0800791 search_opts={'share_type': share_type['id']})['pools']
792
793 pools = client.list_pools(detail=True)['pools']
794 share_type = client.get_share_type(share_type['id'])['share_type']
795 extra_specs = {}
796 for k, v in share_type['extra_specs'].items():
797 extra_specs[k] = (
798 True if six.text_type(v).lower() == 'true'
799 else False if six.text_type(v).lower() == 'false' else v
800 )
801 return [
802 pool for pool in pools if all(y in pool['capabilities'].items()
803 for y in extra_specs.items())
804 ]
805
806 @classmethod
807 def get_availability_zones_matching_share_type(cls, share_type,
808 client=None):
809
810 client = client or cls.admin_shares_v2_client
811 pools_matching_share_type = cls.get_pools_matching_share_type(
812 share_type, client=client)
813 backends_matching_share_type = set(
814 [pool['name'].split("#")[0] for pool in pools_matching_share_type]
815 )
816 azs = cls.get_availability_zones(backends=backends_matching_share_type)
817 return azs
818
Yogesh1f931ff2015-09-29 23:41:02 -0400819 def get_pools_for_replication_domain(self):
820 # Get the list of pools for the replication domain
821 pools = self.admin_client.list_pools(detail=True)['pools']
Ben Swartzlander7150c652017-02-13 22:31:18 -0500822 instance_host = self.admin_client.get_share(
823 self.shares[0]['id'])['host']
Yogesh1f931ff2015-09-29 23:41:02 -0400824 host_pool = [p for p in pools if p['name'] == instance_host][0]
825 rep_domain = host_pool['capabilities']['replication_domain']
826 pools_in_rep_domain = [p for p in pools if p['capabilities'][
827 'replication_domain'] == rep_domain]
828 return rep_domain, pools_in_rep_domain
829
Yogeshbdb88102015-09-29 23:41:02 -0400830 @classmethod
831 def create_share_replica(cls, share_id, availability_zone, client=None,
832 cleanup_in_class=False, cleanup=True):
833 client = client or cls.shares_v2_client
Douglas Viroelbd4e78c2019-09-02 17:16:30 -0300834 replica = client.create_share_replica(
835 share_id, availability_zone=availability_zone)
Yogeshbdb88102015-09-29 23:41:02 -0400836 resource = {
837 "type": "share_replica",
838 "id": replica["id"],
839 "client": client,
840 "share_id": share_id,
841 }
842 # NOTE(Yogi1): Cleanup needs to be disabled during promotion tests.
843 if cleanup:
844 if cleanup_in_class:
845 cls.class_resources.insert(0, resource)
846 else:
847 cls.method_resources.insert(0, resource)
848 client.wait_for_share_replica_status(
849 replica["id"], constants.STATUS_AVAILABLE)
850 return replica
851
852 @classmethod
853 def delete_share_replica(cls, replica_id, client=None):
854 client = client or cls.shares_v2_client
Yogesh1f931ff2015-09-29 23:41:02 -0400855 try:
856 client.delete_share_replica(replica_id)
857 client.wait_for_resource_deletion(replica_id=replica_id)
858 except exceptions.NotFound:
859 pass
Yogeshbdb88102015-09-29 23:41:02 -0400860
861 @classmethod
862 def promote_share_replica(cls, replica_id, client=None):
863 client = client or cls.shares_v2_client
864 replica = client.promote_share_replica(replica_id)
865 client.wait_for_share_replica_status(
866 replica["id"],
867 constants.REPLICATION_STATE_ACTIVE,
868 status_attr="replica_state")
869 return replica
870
Goutham Pacha Ravi1727f7a2020-05-22 13:41:40 -0700871 @classmethod
872 def _get_access_rule_data_from_config(cls):
yogeshdb32f462016-09-28 15:09:50 -0400873 """Get the first available access type/to combination from config.
874
875 This method opportunistically picks the first configured protocol
876 to create the share. Do not use this method in tests where you need
877 to test depth and breadth in the access types and access recipients.
878 """
Goutham Pacha Ravi1727f7a2020-05-22 13:41:40 -0700879 protocol = cls.shares_v2_client.share_protocol
yogeshdb32f462016-09-28 15:09:50 -0400880
881 if protocol in CONF.share.enable_ip_rules_for_protocols:
882 access_type = "ip"
883 access_to = utils.rand_ip()
884 elif protocol in CONF.share.enable_user_rules_for_protocols:
885 access_type = "user"
886 access_to = CONF.share.username_for_user_rules
887 elif protocol in CONF.share.enable_cert_rules_for_protocols:
888 access_type = "cert"
889 access_to = "client3.com"
890 elif protocol in CONF.share.enable_cephx_rules_for_protocols:
891 access_type = "cephx"
892 access_to = "eve"
893 else:
894 message = "Unrecognized protocol and access rules configuration."
Goutham Pacha Ravi1727f7a2020-05-22 13:41:40 -0700895 raise cls.skipException(message)
yogeshdb32f462016-09-28 15:09:50 -0400896
897 return access_type, access_to
898
Yogeshbdb88102015-09-29 23:41:02 -0400899 @classmethod
Marc Koderer0abc93b2015-07-15 09:18:35 +0200900 def create_share_network(cls, client=None,
debeltrami1753a592020-05-11 18:27:30 +0000901 cleanup_in_class=False,
902 add_security_services=True, **kwargs):
903
Marc Koderer0abc93b2015-07-15 09:18:35 +0200904 if client is None:
905 client = cls.shares_client
906 share_network = client.create_share_network(**kwargs)
907 resource = {
908 "type": "share_network",
909 "id": share_network["id"],
910 "client": client,
911 }
debeltrami1753a592020-05-11 18:27:30 +0000912
Marc Koderer0abc93b2015-07-15 09:18:35 +0200913 if cleanup_in_class:
914 cls.class_resources.insert(0, resource)
915 else:
916 cls.method_resources.insert(0, resource)
debeltrami1753a592020-05-11 18:27:30 +0000917
918 if add_security_services:
919 cls.provide_and_associate_security_services(
920 client, share_network["id"], cleanup_in_class=cleanup_in_class)
921
Marc Koderer0abc93b2015-07-15 09:18:35 +0200922 return share_network
923
924 @classmethod
debeltrami1753a592020-05-11 18:27:30 +0000925 def create_share_network_subnet(cls,
926 client=None,
927 cleanup_in_class=False,
928 **kwargs):
Douglas Viroelb7e27e72019-08-06 19:40:37 -0300929 if client is None:
930 client = cls.shares_v2_client
931 share_network_subnet = client.create_subnet(**kwargs)
932 resource = {
933 "type": "share-network-subnet",
934 "id": share_network_subnet["id"],
935 "extra_params": {
936 "share_network_id": share_network_subnet["share_network_id"]
937 },
938 "client": client,
939 }
940 if cleanup_in_class:
941 cls.class_resources.insert(0, resource)
942 else:
943 cls.method_resources.insert(0, resource)
944 return share_network_subnet
945
946 @classmethod
Marc Koderer0abc93b2015-07-15 09:18:35 +0200947 def create_security_service(cls, ss_type="ldap", client=None,
948 cleanup_in_class=False, **kwargs):
949 if client is None:
950 client = cls.shares_client
951 security_service = client.create_security_service(ss_type, **kwargs)
952 resource = {
953 "type": "security_service",
954 "id": security_service["id"],
955 "client": client,
956 }
957 if cleanup_in_class:
958 cls.class_resources.insert(0, resource)
959 else:
960 cls.method_resources.insert(0, resource)
961 return security_service
962
963 @classmethod
964 def create_share_type(cls, name, is_public=True, client=None,
965 cleanup_in_class=True, **kwargs):
966 if client is None:
Valeriy Ponomaryova14c2252015-10-29 13:34:32 +0200967 client = cls.shares_v2_client
Marc Koderer0abc93b2015-07-15 09:18:35 +0200968 share_type = client.create_share_type(name, is_public, **kwargs)
969 resource = {
970 "type": "share_type",
971 "id": share_type["share_type"]["id"],
972 "client": client,
973 }
974 if cleanup_in_class:
975 cls.class_resources.insert(0, resource)
976 else:
977 cls.method_resources.insert(0, resource)
978 return share_type
979
haixin0d1d29f2019-08-02 16:50:45 +0800980 @classmethod
981 def update_share_type(cls, share_type_id, name=None,
982 is_public=None, description=None,
983 client=None):
984 if client is None:
985 client = cls.shares_v2_client
986 share_type = client.update_share_type(share_type_id, name,
987 is_public, description)
988 return share_type
989
Goutham Pacha Raviaf448262020-06-29 14:24:13 -0700990 @classmethod
991 def update_quotas(cls, project_id, user_id=None, cleanup=True,
992 client=None, **kwargs):
993 client = client or cls.shares_v2_client
994 updated_quotas = client.update_quotas(project_id,
995 user_id=user_id,
996 **kwargs)
997 resource = {
998 "type": "quotas",
999 "id": project_id,
1000 "client": client,
1001 "user_id": user_id,
1002 }
1003 if cleanup:
1004 cls.method_resources.insert(0, resource)
1005 return updated_quotas
1006
Marc Koderer0abc93b2015-07-15 09:18:35 +02001007 @staticmethod
Clinton Knight4699a8c2016-08-16 22:36:13 -04001008 def add_extra_specs_to_dict(extra_specs=None):
1009 """Add any required extra-specs to share type dictionary"""
Valeriy Ponomaryovad55dc52015-09-23 13:54:00 +03001010 dhss = six.text_type(CONF.share.multitenancy_enabled)
1011 snapshot_support = six.text_type(
1012 CONF.share.capability_snapshot_support)
Clinton Knight4699a8c2016-08-16 22:36:13 -04001013 create_from_snapshot_support = six.text_type(
1014 CONF.share.capability_create_share_from_snapshot_support)
1015
1016 extra_specs_dict = {
Valeriy Ponomaryovad55dc52015-09-23 13:54:00 +03001017 "driver_handles_share_servers": dhss,
Marc Koderer0abc93b2015-07-15 09:18:35 +02001018 }
Clinton Knight4699a8c2016-08-16 22:36:13 -04001019
1020 optional = {
1021 "snapshot_support": snapshot_support,
1022 "create_share_from_snapshot_support": create_from_snapshot_support,
1023 }
1024 # NOTE(gouthamr): In micro-versions < 2.24, snapshot_support is a
1025 # required extra-spec
1026 extra_specs_dict.update(optional)
1027
Marc Koderer0abc93b2015-07-15 09:18:35 +02001028 if extra_specs:
Clinton Knight4699a8c2016-08-16 22:36:13 -04001029 extra_specs_dict.update(extra_specs)
1030
1031 return extra_specs_dict
Marc Koderer0abc93b2015-07-15 09:18:35 +02001032
1033 @classmethod
Yogesh1f931ff2015-09-29 23:41:02 -04001034 def clear_share_replicas(cls, share_id, client=None):
1035 client = client or cls.shares_v2_client
1036 share_replicas = client.list_share_replicas(
1037 share_id=share_id)
1038
1039 for replica in share_replicas:
1040 try:
1041 cls.delete_share_replica(replica['id'])
1042 except exceptions.BadRequest:
1043 # Ignore the exception due to deletion of last active replica
1044 pass
1045
1046 @classmethod
Marc Koderer0abc93b2015-07-15 09:18:35 +02001047 def clear_resources(cls, resources=None):
1048 """Deletes resources, that were created in test suites.
1049
1050 This method tries to remove resources from resource list,
1051 if it is not found, assumed it was deleted in test itself.
1052 It is expected, that all resources were added as LIFO
1053 due to restriction of deletion resources, that is in the chain.
1054
1055 :param resources: dict with keys 'type','id','client' and 'deleted'
1056 """
Marc Koderer0abc93b2015-07-15 09:18:35 +02001057 if resources is None:
1058 resources = cls.method_resources
1059 for res in resources:
1060 if "deleted" not in res.keys():
1061 res["deleted"] = False
1062 if "client" not in res.keys():
1063 res["client"] = cls.shares_client
1064 if not(res["deleted"]):
1065 res_id = res['id']
1066 client = res["client"]
1067 with handle_cleanup_exceptions():
Andreas Jaeger0cb685b2020-04-01 13:38:38 +02001068 if res["type"] == "share":
Yogesh1f931ff2015-09-29 23:41:02 -04001069 cls.clear_share_replicas(res_id)
Andrew Kerrb8436922016-06-01 15:32:43 -04001070 share_group_id = res.get('share_group_id')
1071 if share_group_id:
1072 params = {'share_group_id': share_group_id}
Clinton Knighte5c8f092015-08-27 15:00:23 -04001073 client.delete_share(res_id, params=params)
1074 else:
1075 client.delete_share(res_id)
Marc Koderer0abc93b2015-07-15 09:18:35 +02001076 client.wait_for_resource_deletion(share_id=res_id)
Andreas Jaeger0cb685b2020-04-01 13:38:38 +02001077 elif res["type"] == "snapshot":
Marc Koderer0abc93b2015-07-15 09:18:35 +02001078 client.delete_snapshot(res_id)
1079 client.wait_for_resource_deletion(snapshot_id=res_id)
Andreas Jaeger0cb685b2020-04-01 13:38:38 +02001080 elif (res["type"] == "share_network" and
yogesh06f519f2017-06-26 13:16:12 -04001081 res_id != CONF.share.share_network_id):
Victoria Martinez de la Cruzcad92012018-06-08 14:46:35 -04001082 client.delete_share_network(res_id)
1083 client.wait_for_resource_deletion(sn_id=res_id)
debeltrami1753a592020-05-11 18:27:30 +00001084 elif res["type"] == "dissociate_security_service":
1085 sn_id = res["extra_params"]["share_network_id"]
1086 client.remove_sec_service_from_share_network(
1087 sn_id=sn_id, ss_id=res_id
1088 )
Andreas Jaeger0cb685b2020-04-01 13:38:38 +02001089 elif res["type"] == "security_service":
Marc Koderer0abc93b2015-07-15 09:18:35 +02001090 client.delete_security_service(res_id)
1091 client.wait_for_resource_deletion(ss_id=res_id)
Andreas Jaeger0cb685b2020-04-01 13:38:38 +02001092 elif res["type"] == "share_type":
Marc Koderer0abc93b2015-07-15 09:18:35 +02001093 client.delete_share_type(res_id)
1094 client.wait_for_resource_deletion(st_id=res_id)
Andreas Jaeger0cb685b2020-04-01 13:38:38 +02001095 elif res["type"] == "share_group":
Andrew Kerrb8436922016-06-01 15:32:43 -04001096 client.delete_share_group(res_id)
1097 client.wait_for_resource_deletion(
1098 share_group_id=res_id)
Andreas Jaeger0cb685b2020-04-01 13:38:38 +02001099 elif res["type"] == "share_group_type":
Andrew Kerrb8436922016-06-01 15:32:43 -04001100 client.delete_share_group_type(res_id)
1101 client.wait_for_resource_deletion(
1102 share_group_type_id=res_id)
Andreas Jaeger0cb685b2020-04-01 13:38:38 +02001103 elif res["type"] == "share_group_snapshot":
Andrew Kerrb8436922016-06-01 15:32:43 -04001104 client.delete_share_group_snapshot(res_id)
1105 client.wait_for_resource_deletion(
1106 share_group_snapshot_id=res_id)
Andreas Jaeger0cb685b2020-04-01 13:38:38 +02001107 elif res["type"] == "share_replica":
Yogeshbdb88102015-09-29 23:41:02 -04001108 client.delete_share_replica(res_id)
1109 client.wait_for_resource_deletion(replica_id=res_id)
Andreas Jaeger0cb685b2020-04-01 13:38:38 +02001110 elif res["type"] == "share_network_subnet":
Douglas Viroelb7e27e72019-08-06 19:40:37 -03001111 sn_id = res["extra_params"]["share_network_id"]
1112 client.delete_subnet(sn_id, res_id)
1113 client.wait_for_resource_deletion(
1114 share_network_subnet_id=res_id,
1115 sn_id=sn_id)
Goutham Pacha Raviaf448262020-06-29 14:24:13 -07001116 elif res["type"] == "quotas":
1117 user_id = res.get('user_id')
1118 client.reset_quotas(res_id, user_id=user_id)
Marc Koderer0abc93b2015-07-15 09:18:35 +02001119 else:
huayue97bacbf2016-01-04 09:57:39 +08001120 LOG.warning("Provided unsupported resource type for "
junbolib236c242017-07-18 18:12:37 +08001121 "cleanup '%s'. Skipping.", res["type"])
Marc Koderer0abc93b2015-07-15 09:18:35 +02001122 res["deleted"] = True
1123
1124 @classmethod
1125 def generate_share_network_data(self):
1126 data = {
1127 "name": data_utils.rand_name("sn-name"),
1128 "description": data_utils.rand_name("sn-desc"),
1129 "neutron_net_id": data_utils.rand_name("net-id"),
1130 "neutron_subnet_id": data_utils.rand_name("subnet-id"),
1131 }
1132 return data
1133
1134 @classmethod
Douglas Viroelb7e27e72019-08-06 19:40:37 -03001135 def generate_subnet_data(self):
1136 data = {
1137 "neutron_net_id": data_utils.rand_name("net-id"),
1138 "neutron_subnet_id": data_utils.rand_name("subnet-id"),
1139 }
1140 return data
1141
1142 @classmethod
Maurice Schreiber5ac37172018-02-01 15:17:31 +01001143 def generate_security_service_data(self, set_ou=False):
Marc Koderer0abc93b2015-07-15 09:18:35 +02001144 data = {
1145 "name": data_utils.rand_name("ss-name"),
1146 "description": data_utils.rand_name("ss-desc"),
Valeriy Ponomaryovfcde7712015-12-14 18:06:13 +02001147 "dns_ip": utils.rand_ip(),
1148 "server": utils.rand_ip(),
Marc Koderer0abc93b2015-07-15 09:18:35 +02001149 "domain": data_utils.rand_name("ss-domain"),
1150 "user": data_utils.rand_name("ss-user"),
1151 "password": data_utils.rand_name("ss-password"),
1152 }
Maurice Schreiber5ac37172018-02-01 15:17:31 +01001153 if set_ou:
1154 data["ou"] = data_utils.rand_name("ss-ou")
1155
Marc Koderer0abc93b2015-07-15 09:18:35 +02001156 return data
1157
1158 # Useful assertions
1159 def assertDictMatch(self, d1, d2, approx_equal=False, tolerance=0.001):
1160 """Assert two dicts are equivalent.
1161
1162 This is a 'deep' match in the sense that it handles nested
1163 dictionaries appropriately.
1164
1165 NOTE:
1166
1167 If you don't care (or don't know) a given value, you can specify
1168 the string DONTCARE as the value. This will cause that dict-item
1169 to be skipped.
1170
1171 """
1172 def raise_assertion(msg):
1173 d1str = str(d1)
1174 d2str = str(d2)
1175 base_msg = ('Dictionaries do not match. %(msg)s d1: %(d1str)s '
1176 'd2: %(d2str)s' %
1177 {"msg": msg, "d1str": d1str, "d2str": d2str})
1178 raise AssertionError(base_msg)
1179
1180 d1keys = set(d1.keys())
1181 d2keys = set(d2.keys())
1182 if d1keys != d2keys:
1183 d1only = d1keys - d2keys
1184 d2only = d2keys - d1keys
1185 raise_assertion('Keys in d1 and not d2: %(d1only)s. '
1186 'Keys in d2 and not d1: %(d2only)s' %
1187 {"d1only": d1only, "d2only": d2only})
1188
1189 for key in d1keys:
1190 d1value = d1[key]
1191 d2value = d2[key]
1192 try:
1193 error = abs(float(d1value) - float(d2value))
1194 within_tolerance = error <= tolerance
1195 except (ValueError, TypeError):
daiki kato6914b1a2016-03-16 17:16:57 +09001196 # If both values aren't convertible to float, just ignore
Marc Koderer0abc93b2015-07-15 09:18:35 +02001197 # ValueError if arg is a str, TypeError if it's something else
1198 # (like None)
1199 within_tolerance = False
1200
1201 if hasattr(d1value, 'keys') and hasattr(d2value, 'keys'):
1202 self.assertDictMatch(d1value, d2value)
1203 elif 'DONTCARE' in (d1value, d2value):
1204 continue
1205 elif approx_equal and within_tolerance:
1206 continue
1207 elif d1value != d2value:
1208 raise_assertion("d1['%(key)s']=%(d1value)s != "
1209 "d2['%(key)s']=%(d2value)s" %
1210 {
1211 "key": key,
1212 "d1value": d1value,
1213 "d2value": d2value
1214 })
1215
Alex Meadeba8a1602016-05-06 09:33:09 -04001216 def create_user_message(self):
1217 """Trigger a 'no valid host' situation to generate a message."""
1218 extra_specs = {
1219 'vendor_name': 'foobar',
1220 'driver_handles_share_servers': CONF.share.multitenancy_enabled,
1221 }
1222 share_type_name = data_utils.rand_name("share-type")
1223
1224 bogus_type = self.create_share_type(
Goutham Pacha Raviaf448262020-06-29 14:24:13 -07001225 client=self.admin_shares_v2_client,
Alex Meadeba8a1602016-05-06 09:33:09 -04001226 name=share_type_name,
1227 extra_specs=extra_specs)['share_type']
1228
1229 params = {'share_type_id': bogus_type['id'],
1230 'share_network_id': self.shares_v2_client.share_network_id}
1231 share = self.shares_v2_client.create_share(**params)
1232 self.addCleanup(self.shares_v2_client.delete_share, share['id'])
1233 self.shares_v2_client.wait_for_share_status(share['id'], "error")
1234 return self.shares_v2_client.wait_for_message(share['id'])
1235
Marc Koderer0abc93b2015-07-15 09:18:35 +02001236
1237class BaseSharesAltTest(BaseSharesTest):
1238 """Base test case class for all Shares Alt API tests."""
Valeriy Ponomaryov39cdf722016-05-30 18:16:15 +03001239 credentials = ('alt', )
Marc Koderer0abc93b2015-07-15 09:18:35 +02001240
1241
1242class BaseSharesAdminTest(BaseSharesTest):
1243 """Base test case class for all Shares Admin API tests."""
Valeriy Ponomaryov39cdf722016-05-30 18:16:15 +03001244 credentials = ('admin', )
1245
Victoria Martinez de la Cruzf6bc6fa2018-02-01 11:27:00 -05001246 @classmethod
1247 def setup_clients(cls):
1248 super(BaseSharesAdminTest, cls).setup_clients()
1249 # Initialise share clients
1250 cls.admin_shares_v2_client = cls.os_admin.share_v2.SharesV2Client()
1251
1252 @classmethod
Goutham Pacha Raviaf448262020-06-29 14:24:13 -07001253 def _create_share_type(cls, is_public=True, specs=None):
Victoria Martinez de la Cruzf6bc6fa2018-02-01 11:27:00 -05001254 name = data_utils.rand_name("unique_st_name")
1255 extra_specs = cls.add_extra_specs_to_dict(specs)
1256 return cls.create_share_type(
Goutham Pacha Raviaf448262020-06-29 14:24:13 -07001257 name, extra_specs=extra_specs, is_public=is_public,
Victoria Martinez de la Cruzf6bc6fa2018-02-01 11:27:00 -05001258 client=cls.admin_shares_v2_client)['share_type']
1259
1260 @classmethod
1261 def _create_share_group_type(cls):
1262 share_group_type_name = data_utils.rand_name("unique_sgtype_name")
1263 return cls.create_share_group_type(
1264 name=share_group_type_name, share_types=[cls.share_type_id],
1265 client=cls.admin_shares_v2_client)
1266
Lucio Seki37056942019-01-24 15:40:20 -02001267 def _create_share_for_manage(self):
1268 creation_data = {
1269 'share_type_id': self.st['share_type']['id'],
1270 'share_protocol': self.protocol,
1271 }
1272
1273 share = self.create_share(**creation_data)
1274 share = self.shares_v2_client.get_share(share['id'])
1275
1276 if utils.is_microversion_ge(CONF.share.max_api_microversion, "2.9"):
1277 el = self.shares_v2_client.list_share_export_locations(share["id"])
1278 share["export_locations"] = el
1279
1280 return share
1281
1282 def _unmanage_share_and_wait(self, share):
1283 self.shares_v2_client.unmanage_share(share['id'])
1284 self.shares_v2_client.wait_for_resource_deletion(share_id=share['id'])
1285
1286 def _reset_state_and_delete_share(self, share):
1287 self.shares_v2_client.reset_state(share['id'])
1288 self._delete_share_and_wait(share)
1289
1290 def _delete_snapshot_and_wait(self, snap):
1291 self.shares_v2_client.delete_snapshot(snap['id'])
1292 self.shares_v2_client.wait_for_resource_deletion(
1293 snapshot_id=snap['id']
1294 )
1295 self.assertRaises(exceptions.NotFound,
1296 self.shares_v2_client.get_snapshot,
1297 snap['id'])
1298
1299 def _delete_share_and_wait(self, share):
1300 self.shares_v2_client.delete_share(share['id'])
1301 self.shares_v2_client.wait_for_resource_deletion(share_id=share['id'])
1302 self.assertRaises(exceptions.NotFound,
1303 self.shares_v2_client.get_share,
1304 share['id'])
1305
1306 def _manage_share(self, share, name, description, share_server_id):
1307 managed_share = self.shares_v2_client.manage_share(
1308 service_host=share['host'],
1309 export_path=share['export_locations'][0],
1310 protocol=share['share_proto'],
1311 share_type_id=self.share_type['share_type']['id'],
1312 name=name,
1313 description=description,
1314 share_server_id=share_server_id
1315 )
1316 self.shares_v2_client.wait_for_share_status(
1317 managed_share['id'], constants.STATUS_AVAILABLE
1318 )
1319
1320 return managed_share
1321
1322 def _unmanage_share_server_and_wait(self, server):
1323 self.shares_v2_client.unmanage_share_server(server['id'])
1324 self.shares_v2_client.wait_for_resource_deletion(
1325 server_id=server['id']
1326 )
1327
1328 def _manage_share_server(self, share_server, fields=None):
1329 params = fields or {}
Douglas Viroelb7e27e72019-08-06 19:40:37 -03001330 subnet_id = params.get('share_network_subnet_id', None)
Lucio Seki37056942019-01-24 15:40:20 -02001331 managed_share_server = self.shares_v2_client.manage_share_server(
1332 params.get('host', share_server['host']),
1333 params.get('share_network_id', share_server['share_network_id']),
1334 params.get('identifier', share_server['identifier']),
Douglas Viroelb7e27e72019-08-06 19:40:37 -03001335 share_network_subnet_id=subnet_id,
Lucio Seki37056942019-01-24 15:40:20 -02001336 )
1337 self.shares_v2_client.wait_for_share_server_status(
1338 managed_share_server['id'],
1339 constants.SERVER_STATE_ACTIVE,
1340 )
1341
1342 return managed_share_server
1343
1344 def _delete_share_server_and_wait(self, share_server_id):
1345 self.shares_v2_client.delete_share_server(
1346 share_server_id
1347 )
1348 self.shares_v2_client.wait_for_resource_deletion(
1349 server_id=share_server_id)
1350
Valeriy Ponomaryov39cdf722016-05-30 18:16:15 +03001351
1352class BaseSharesMixedTest(BaseSharesTest):
1353 """Base test case class for all Shares API tests with all user roles."""
1354 credentials = ('primary', 'alt', 'admin')
Marc Koderer0abc93b2015-07-15 09:18:35 +02001355
Goutham Pacha Ravic678e212020-03-20 11:13:47 -07001356 # Will be cleaned up in resource_cleanup if the class
1357 class_project_users_created = []
1358
1359 @classmethod
1360 def resource_cleanup(cls):
1361 cls.clear_project_users(cls.class_project_users_created)
1362 super(BaseSharesMixedTest, cls).resource_cleanup()
1363
1364 @classmethod
1365 def clear_project_users(cls, users=None):
1366 users = users or cls.class_project_users_created
1367 for user in users:
1368 with handle_cleanup_exceptions():
1369 cls.os_admin.creds_client.delete_user(user['id'])
1370
Marc Koderer0abc93b2015-07-15 09:18:35 +02001371 @classmethod
Valeriy Ponomaryov39cdf722016-05-30 18:16:15 +03001372 def setup_clients(cls):
1373 super(BaseSharesMixedTest, cls).setup_clients()
Andrea Frittoli (andreaf)369391a2016-06-27 18:59:13 +01001374 # Initialise share clients
1375 cls.admin_shares_client = cls.os_admin.share_v1.SharesClient()
1376 cls.admin_shares_v2_client = cls.os_admin.share_v2.SharesV2Client()
1377 cls.alt_shares_client = cls.os_alt.share_v1.SharesClient()
1378 cls.alt_shares_v2_client = cls.os_alt.share_v2.SharesV2Client()
1379 # Initialise network clients
1380 cls.os_admin.networks_client = cls.os_admin.network.NetworksClient()
1381 cls.os_alt.networks_client = cls.os_alt.network.NetworksClient()
Goutham Pacha Ravic678e212020-03-20 11:13:47 -07001382 # Initialise identity clients
1383 cls.admin_project = cls.os_admin.auth_provider.auth_data[1]['project']
1384 identity_clients = getattr(
1385 cls.os_admin, 'identity_%s' % CONF.identity.auth_version)
1386 cls.os_admin.identity_client = identity_clients.IdentityClient()
1387 cls.os_admin.projects_client = identity_clients.ProjectsClient()
1388 cls.os_admin.users_client = identity_clients.UsersClient()
1389 cls.os_admin.roles_client = identity_clients.RolesClient()
1390 cls.os_admin.domains_client = (
1391 cls.os_admin.identity_v3.DomainsClient() if
1392 CONF.identity.auth_version == 'v3' else None)
1393 cls.admin_project_member_client = cls.create_user_and_get_client()
Valeriy Ponomaryov39cdf722016-05-30 18:16:15 +03001394
1395 if CONF.share.multitenancy_enabled:
1396 admin_share_network_id = cls.provide_share_network(
1397 cls.admin_shares_v2_client, cls.os_admin.networks_client)
1398 cls.admin_shares_client.share_network_id = admin_share_network_id
1399 cls.admin_shares_v2_client.share_network_id = (
1400 admin_share_network_id)
1401
1402 alt_share_network_id = cls.provide_share_network(
1403 cls.alt_shares_v2_client, cls.os_alt.networks_client)
1404 cls.alt_shares_client.share_network_id = alt_share_network_id
1405 cls.alt_shares_v2_client.share_network_id = alt_share_network_id
haobing101c7fee2018-03-09 16:33:00 +08001406 resource = {
1407 "type": "share_network",
1408 "id": alt_share_network_id,
1409 "client": cls.alt_shares_v2_client,
1410 }
1411 cls.class_resources.insert(0, resource)
Victoria Martinez de la Cruzf6bc6fa2018-02-01 11:27:00 -05001412
1413 @classmethod
Goutham Pacha Ravic678e212020-03-20 11:13:47 -07001414 def create_user_and_get_client(cls, project=None):
1415 """Create a user in specified project & set share clients for user
1416
1417 The user will have all roles specified in tempest.conf
1418 :param: project: a dictionary with project ID and name, if not
1419 specified, the value will be cls.admin_project
1420 """
1421 project_domain_name = (
1422 cls.os_admin.identity_client.auth_provider.credentials.get(
1423 'project_domain_name', 'Default'))
1424 cls.os_admin.creds_client = cred_client.get_creds_client(
1425 cls.os_admin.identity_client, cls.os_admin.projects_client,
1426 cls.os_admin.users_client, cls.os_admin.roles_client,
1427 cls.os_admin.domains_client, project_domain_name)
1428
1429 # User info
1430 project = project or cls.admin_project
1431 username = data_utils.rand_name('manila_%s' % project['id'])
1432 password = data_utils.rand_password()
1433 email = '%s@example.org' % username
1434
1435 user = cls.os_admin.creds_client.create_user(
1436 username, password, project, email)
1437 cls.class_project_users_created.append(user)
1438
1439 for conf_role in CONF.auth.tempest_roles:
1440 cls.os_admin.creds_client.assign_user_role(
1441 user, project, conf_role)
1442
1443 user_creds = cls.os_admin.creds_client.get_credentials(
1444 user, project, password)
1445 os = clients.Clients(user_creds)
1446 os.shares_v1_client = os.share_v1.SharesClient()
1447 os.shares_v2_client = os.share_v2.SharesV2Client()
1448 return os
1449
1450 @classmethod
Goutham Pacha Raviaf448262020-06-29 14:24:13 -07001451 def _create_share_type(cls, is_public=True, specs=None):
Victoria Martinez de la Cruzf6bc6fa2018-02-01 11:27:00 -05001452 name = data_utils.rand_name("unique_st_name")
1453 extra_specs = cls.add_extra_specs_to_dict(specs)
1454 return cls.create_share_type(
Goutham Pacha Raviaf448262020-06-29 14:24:13 -07001455 name, extra_specs=extra_specs, is_public=is_public,
Victoria Martinez de la Cruzf6bc6fa2018-02-01 11:27:00 -05001456 client=cls.admin_shares_v2_client)['share_type']
1457
1458 @classmethod
1459 def _create_share_group_type(cls):
1460 share_group_type_name = data_utils.rand_name("unique_sgtype_name")
1461 return cls.create_share_group_type(
1462 name=share_group_type_name, share_types=[cls.share_type_id],
1463 client=cls.admin_shares_v2_client)