| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 1 | # 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 |  | 
 | 16 | import copy | 
 | 17 | import inspect | 
| Valeriy Ponomaryov | 2abf5d7 | 2016-06-01 18:30:12 +0300 | [diff] [blame] | 18 | import re | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 19 | import traceback | 
 | 20 |  | 
 | 21 | from oslo_concurrency import lockutils | 
 | 22 | from oslo_log import log | 
 | 23 | import six | 
| Sam Wan | c7b7f1f | 2015-11-25 00:22:28 -0500 | [diff] [blame] | 24 | from tempest.common import credentials_factory as common_creds | 
| Raissa Sarmento | 7b86b9d | 2017-07-21 14:32:48 +0100 | [diff] [blame] | 25 |  | 
| Valeriy Ponomaryov | 48a2bd7 | 2015-11-05 13:22:44 +0200 | [diff] [blame] | 26 | from tempest import config | 
| Raissa Sarmento | 7b86b9d | 2017-07-21 14:32:48 +0100 | [diff] [blame] | 27 | from tempest.lib.common import dynamic_creds | 
| Ben Swartzlander | 1c4ff52 | 2016-03-02 22:16:23 -0500 | [diff] [blame] | 28 | from tempest.lib.common.utils import data_utils | 
 | 29 | from tempest.lib import exceptions | 
| Valeriy Ponomaryov | 48a2bd7 | 2015-11-05 13:22:44 +0200 | [diff] [blame] | 30 | from tempest import test | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 31 |  | 
| Andrea Frittoli (andreaf) | 369391a | 2016-06-27 18:59:13 +0100 | [diff] [blame] | 32 | from manila_tempest_tests import clients | 
| Yogesh | bdb8810 | 2015-09-29 23:41:02 -0400 | [diff] [blame] | 33 | from manila_tempest_tests.common import constants | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 34 | from manila_tempest_tests import share_exceptions | 
| Valeriy Ponomaryov | fcde771 | 2015-12-14 18:06:13 +0200 | [diff] [blame] | 35 | from manila_tempest_tests import utils | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 36 |  | 
 | 37 | CONF = config.CONF | 
 | 38 | LOG = log.getLogger(__name__) | 
 | 39 |  | 
| Valeriy Ponomaryov | 2abf5d7 | 2016-06-01 18:30:12 +0300 | [diff] [blame] | 40 | # Test tags related to test direction | 
 | 41 | TAG_POSITIVE = "positive" | 
 | 42 | TAG_NEGATIVE = "negative" | 
 | 43 |  | 
 | 44 | # Test tags related to service involvement | 
 | 45 | TAG_API = "api" | 
 | 46 | TAG_BACKEND = "backend" | 
 | 47 | TAG_API_WITH_BACKEND = "api_with_backend" | 
 | 48 |  | 
 | 49 | TAGS_MAPPER = { | 
 | 50 |     "p": TAG_POSITIVE, | 
 | 51 |     "n": TAG_NEGATIVE, | 
 | 52 |     "a": TAG_API, | 
 | 53 |     "b": TAG_BACKEND, | 
 | 54 |     "ab": TAG_API_WITH_BACKEND, | 
 | 55 | } | 
 | 56 | TAGS_PATTERN = re.compile( | 
 | 57 |     r"(?=.*\[.*\b(%(p)s|%(n)s)\b.*\])(?=.*\[.*\b(%(a)s|%(b)s|%(ab)s)\b.*\])" % | 
 | 58 |     TAGS_MAPPER) | 
 | 59 |  | 
 | 60 |  | 
 | 61 | def verify_test_has_appropriate_tags(self): | 
 | 62 |     if not TAGS_PATTERN.match(self.id()): | 
 | 63 |         msg = ( | 
 | 64 |             "Required attributes either not set or set improperly. " | 
 | 65 |             "Two test attributes are expected:\n" | 
 | 66 |             " - one of '%(p)s' or '%(n)s' and \n" | 
 | 67 |             " - one of '%(a)s', '%(b)s' or '%(ab)s'." | 
 | 68 |         ) % TAGS_MAPPER | 
 | 69 |         raise self.failureException(msg) | 
 | 70 |  | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 71 |  | 
 | 72 | class handle_cleanup_exceptions(object): | 
 | 73 |     """Handle exceptions raised with cleanup operations. | 
 | 74 |  | 
 | 75 |     Always suppress errors when exceptions.NotFound or exceptions.Forbidden | 
 | 76 |     are raised. | 
 | 77 |     Suppress all other exceptions only in case config opt | 
 | 78 |     'suppress_errors_in_cleanup' in config group 'share' is True. | 
 | 79 |     """ | 
 | 80 |  | 
 | 81 |     def __enter__(self): | 
 | 82 |         return self | 
 | 83 |  | 
 | 84 |     def __exit__(self, exc_type, exc_value, exc_traceback): | 
 | 85 |         if not (isinstance(exc_value, | 
 | 86 |                            (exceptions.NotFound, exceptions.Forbidden)) or | 
 | 87 |                 CONF.share.suppress_errors_in_cleanup): | 
 | 88 |             return False  # Do not suppress error if any | 
 | 89 |         if exc_traceback: | 
 | 90 |             LOG.error("Suppressed cleanup error in Manila: " | 
| junboli | b236c24 | 2017-07-18 18:12:37 +0800 | [diff] [blame] | 91 |                       "\n%s", traceback.format_exc()) | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 92 |         return True  # Suppress error if any | 
 | 93 |  | 
 | 94 |  | 
 | 95 | def network_synchronized(f): | 
 | 96 |  | 
 | 97 |     def wrapped_func(self, *args, **kwargs): | 
 | 98 |         with_isolated_creds = True if len(args) > 2 else False | 
 | 99 |         no_lock_required = kwargs.get( | 
 | 100 |             "isolated_creds_client", with_isolated_creds) | 
 | 101 |         if no_lock_required: | 
 | 102 |             # Usage of not reusable network. No need in lock. | 
 | 103 |             return f(self, *args, **kwargs) | 
 | 104 |  | 
 | 105 |         # Use lock assuming reusage of common network. | 
 | 106 |         @lockutils.synchronized("manila_network_lock", external=True) | 
 | 107 |         def source_func(self, *args, **kwargs): | 
 | 108 |             return f(self, *args, **kwargs) | 
 | 109 |  | 
 | 110 |         return source_func(self, *args, **kwargs) | 
 | 111 |  | 
 | 112 |     return wrapped_func | 
 | 113 |  | 
 | 114 |  | 
| Valeriy Ponomaryov | fcde771 | 2015-12-14 18:06:13 +0200 | [diff] [blame] | 115 | skip_if_microversion_not_supported = utils.skip_if_microversion_not_supported | 
| Xing Yang | 69b00b5 | 2015-11-22 16:10:44 -0500 | [diff] [blame] | 116 | skip_if_microversion_lt = utils.skip_if_microversion_lt | 
| Valeriy Ponomaryov | a14c225 | 2015-10-29 13:34:32 +0200 | [diff] [blame] | 117 |  | 
 | 118 |  | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 119 | class BaseSharesTest(test.BaseTestCase): | 
 | 120 |     """Base test case class for all Manila API tests.""" | 
 | 121 |  | 
| Valeriy Ponomaryov | 39cdf72 | 2016-05-30 18:16:15 +0300 | [diff] [blame] | 122 |     credentials = ('primary', ) | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 123 |     force_tenant_isolation = False | 
| Vitaliy Levitksi | cfebfff | 2016-12-15 16:16:35 +0200 | [diff] [blame] | 124 |     protocols = ["nfs", "cifs", "glusterfs", "hdfs", "cephfs", "maprfs"] | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 125 |  | 
 | 126 |     # Will be cleaned up in resource_cleanup | 
 | 127 |     class_resources = [] | 
 | 128 |  | 
 | 129 |     # Will be cleaned up in tearDown method | 
 | 130 |     method_resources = [] | 
 | 131 |  | 
 | 132 |     # Will be cleaned up in resource_cleanup | 
 | 133 |     class_isolated_creds = [] | 
 | 134 |  | 
 | 135 |     # Will be cleaned up in tearDown method | 
 | 136 |     method_isolated_creds = [] | 
 | 137 |  | 
| Andrea Frittoli (andreaf) | 369391a | 2016-06-27 18:59:13 +0100 | [diff] [blame] | 138 |     # NOTE(andreaf) Override the client manager class to be used, so that | 
 | 139 |     # a stable class is used, which includes plugin registered services as well | 
 | 140 |     client_manager = clients.Clients | 
 | 141 |  | 
| Valeriy Ponomaryov | a14c225 | 2015-10-29 13:34:32 +0200 | [diff] [blame] | 142 |     def skip_if_microversion_not_supported(self, microversion): | 
| Valeriy Ponomaryov | fcde771 | 2015-12-14 18:06:13 +0200 | [diff] [blame] | 143 |         if not utils.is_microversion_supported(microversion): | 
| Valeriy Ponomaryov | a14c225 | 2015-10-29 13:34:32 +0200 | [diff] [blame] | 144 |             raise self.skipException( | 
 | 145 |                 "Microversion '%s' is not supported." % microversion) | 
 | 146 |  | 
| Xing Yang | 69b00b5 | 2015-11-22 16:10:44 -0500 | [diff] [blame] | 147 |     def skip_if_microversion_lt(self, microversion): | 
 | 148 |         if utils.is_microversion_lt(CONF.share.max_api_microversion, | 
 | 149 |                                     microversion): | 
 | 150 |             raise self.skipException( | 
 | 151 |                 "Microversion must be greater than or equal to '%s'." % | 
 | 152 |                 microversion) | 
 | 153 |  | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 154 |     @classmethod | 
| Tom Barron | 4b8834a | 2017-02-02 11:02:20 -0500 | [diff] [blame] | 155 |     def _get_dynamic_creds(cls, name, network_resources=None): | 
| Raissa Sarmento | 7b86b9d | 2017-07-21 14:32:48 +0100 | [diff] [blame] | 156 |         identity_version = CONF.identity.auth_version | 
 | 157 |         if identity_version == 'v3': | 
 | 158 |             identity_uri = CONF.identity.uri_v3 | 
 | 159 |             identity_admin_endpoint_type = CONF.identity.v3_endpoint_type | 
 | 160 |         elif identity_version == 'v2': | 
 | 161 |             identity_uri = CONF.identity.uri | 
 | 162 |             identity_admin_endpoint_type = CONF.identity.v2_admin_endpoint_type | 
 | 163 |  | 
| Tom Barron | 4b8834a | 2017-02-02 11:02:20 -0500 | [diff] [blame] | 164 |         return dynamic_creds.DynamicCredentialProvider( | 
| Raissa Sarmento | 7b86b9d | 2017-07-21 14:32:48 +0100 | [diff] [blame] | 165 |             identity_version=identity_version, | 
| Tom Barron | 4b8834a | 2017-02-02 11:02:20 -0500 | [diff] [blame] | 166 |             name=name, | 
 | 167 |             network_resources=network_resources, | 
 | 168 |             credentials_domain=CONF.auth.default_credentials_domain_name, | 
 | 169 |             admin_role=CONF.identity.admin_role, | 
 | 170 |             admin_creds=common_creds.get_configured_admin_credentials(), | 
 | 171 |             identity_admin_domain_scope=CONF.identity.admin_domain_scope, | 
 | 172 |             identity_admin_role=CONF.identity.admin_role, | 
 | 173 |             extra_roles=None, | 
 | 174 |             neutron_available=CONF.service_available.neutron, | 
 | 175 |             create_networks=( | 
 | 176 |                 CONF.share.create_networks_when_multitenancy_enabled), | 
 | 177 |             project_network_cidr=CONF.network.project_network_cidr, | 
 | 178 |             project_network_mask_bits=CONF.network.project_network_mask_bits, | 
 | 179 |             public_network_id=CONF.network.public_network_id, | 
| ghanshyam | 2aea7c3 | 2017-12-11 00:03:56 +0000 | [diff] [blame] | 180 |             resource_prefix='tempest', | 
| Raissa Sarmento | 7b86b9d | 2017-07-21 14:32:48 +0100 | [diff] [blame] | 181 |             identity_admin_endpoint_type=identity_admin_endpoint_type, | 
 | 182 |             identity_uri=identity_uri) | 
| Tom Barron | 4b8834a | 2017-02-02 11:02:20 -0500 | [diff] [blame] | 183 |  | 
 | 184 |     @classmethod | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 185 |     def get_client_with_isolated_creds(cls, | 
 | 186 |                                        name=None, | 
 | 187 |                                        type_of_creds="admin", | 
| Clinton Knight | e5c8f09 | 2015-08-27 15:00:23 -0400 | [diff] [blame] | 188 |                                        cleanup_in_class=False, | 
 | 189 |                                        client_version='1'): | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 190 |         """Creates isolated creds. | 
 | 191 |  | 
 | 192 |         :param name: name, will be used for naming ic and related stuff | 
 | 193 |         :param type_of_creds: admin, alt or primary | 
 | 194 |         :param cleanup_in_class: defines place where to delete | 
 | 195 |         :returns: SharesClient -- shares client with isolated creds. | 
 | 196 |         :returns: To client added dict attr 'creds' with | 
 | 197 |         :returns: key elements 'tenant' and 'user'. | 
 | 198 |         """ | 
 | 199 |         if name is None: | 
 | 200 |             # Get name of test method | 
 | 201 |             name = inspect.stack()[1][3] | 
 | 202 |             if len(name) > 32: | 
 | 203 |                 name = name[0:32] | 
 | 204 |  | 
 | 205 |         # Choose type of isolated creds | 
| Tom Barron | 4b8834a | 2017-02-02 11:02:20 -0500 | [diff] [blame] | 206 |         ic = cls._get_dynamic_creds(name) | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 207 |         if "admin" in type_of_creds: | 
| Marc Koderer | 5880b36 | 2016-07-06 10:59:07 +0200 | [diff] [blame] | 208 |             creds = ic.get_admin_creds().credentials | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 209 |         elif "alt" in type_of_creds: | 
| Marc Koderer | 5880b36 | 2016-07-06 10:59:07 +0200 | [diff] [blame] | 210 |             creds = ic.get_alt_creds().credentials | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 211 |         else: | 
| Marc Koderer | 5880b36 | 2016-07-06 10:59:07 +0200 | [diff] [blame] | 212 |             creds = ic.get_credentials(type_of_creds).credentials | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 213 |         ic.type_of_creds = type_of_creds | 
 | 214 |  | 
 | 215 |         # create client with isolated creds | 
| Andrea Frittoli (andreaf) | 369391a | 2016-06-27 18:59:13 +0100 | [diff] [blame] | 216 |         os = clients.Clients(creds) | 
| Clinton Knight | e5c8f09 | 2015-08-27 15:00:23 -0400 | [diff] [blame] | 217 |         if client_version == '1': | 
| Andrea Frittoli (andreaf) | 369391a | 2016-06-27 18:59:13 +0100 | [diff] [blame] | 218 |             client = os.share_v1.SharesClient() | 
| Clinton Knight | e5c8f09 | 2015-08-27 15:00:23 -0400 | [diff] [blame] | 219 |         elif client_version == '2': | 
| Andrea Frittoli (andreaf) | 369391a | 2016-06-27 18:59:13 +0100 | [diff] [blame] | 220 |             client = os.share_v2.SharesV2Client() | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 221 |  | 
 | 222 |         # Set place where will be deleted isolated creds | 
 | 223 |         ic_res = { | 
| Valeriy Ponomaryov | 48a2bd7 | 2015-11-05 13:22:44 +0200 | [diff] [blame] | 224 |             "method": ic.clear_creds, | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 225 |             "deleted": False, | 
 | 226 |         } | 
 | 227 |         if cleanup_in_class: | 
 | 228 |             cls.class_isolated_creds.insert(0, ic_res) | 
 | 229 |         else: | 
 | 230 |             cls.method_isolated_creds.insert(0, ic_res) | 
 | 231 |  | 
 | 232 |         # Provide share network | 
 | 233 |         if CONF.share.multitenancy_enabled: | 
| Valeriy Ponomaryov | c5dae27 | 2016-06-10 18:29:24 +0300 | [diff] [blame] | 234 |             if (not CONF.service_available.neutron and | 
 | 235 |                     CONF.share.create_networks_when_multitenancy_enabled): | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 236 |                 raise cls.skipException("Neutron support is required") | 
| Andrea Frittoli (andreaf) | 369391a | 2016-06-27 18:59:13 +0100 | [diff] [blame] | 237 |             nc = os.network.NetworksClient() | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 238 |             share_network_id = cls.provide_share_network(client, nc, ic) | 
 | 239 |             client.share_network_id = share_network_id | 
 | 240 |             resource = { | 
 | 241 |                 "type": "share_network", | 
 | 242 |                 "id": client.share_network_id, | 
 | 243 |                 "client": client, | 
 | 244 |             } | 
 | 245 |             if cleanup_in_class: | 
 | 246 |                 cls.class_resources.insert(0, resource) | 
 | 247 |             else: | 
 | 248 |                 cls.method_resources.insert(0, resource) | 
 | 249 |         return client | 
 | 250 |  | 
 | 251 |     @classmethod | 
| Daniel Mellado | e526914 | 2017-01-12 12:17:58 +0000 | [diff] [blame] | 252 |     def skip_checks(cls): | 
 | 253 |         super(BaseSharesTest, cls).skip_checks() | 
 | 254 |         if not CONF.service_available.manila: | 
 | 255 |             raise cls.skipException("Manila support is required") | 
 | 256 |  | 
 | 257 |     @classmethod | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 258 |     def verify_nonempty(cls, *args): | 
 | 259 |         if not all(args): | 
 | 260 |             msg = "Missing API credentials in configuration." | 
 | 261 |             raise cls.skipException(msg) | 
 | 262 |  | 
 | 263 |     @classmethod | 
| Valeriy Ponomaryov | 39cdf72 | 2016-05-30 18:16:15 +0300 | [diff] [blame] | 264 |     def setup_clients(cls): | 
 | 265 |         super(BaseSharesTest, cls).setup_clients() | 
 | 266 |         os = getattr(cls, 'os_%s' % cls.credentials[0]) | 
| Andrea Frittoli (andreaf) | 369391a | 2016-06-27 18:59:13 +0100 | [diff] [blame] | 267 |         # Initialise share clients for test credentials | 
 | 268 |         cls.shares_client = os.share_v1.SharesClient() | 
 | 269 |         cls.shares_v2_client = os.share_v2.SharesV2Client() | 
 | 270 |         # Initialise network clients for test credentials | 
 | 271 |         if CONF.service_available.neutron: | 
 | 272 |             cls.networks_client = os.network.NetworksClient() | 
 | 273 |             cls.subnets_client = os.network.SubnetsClient() | 
 | 274 |         else: | 
 | 275 |             cls.networks_client = None | 
 | 276 |             cls.subnets_client = None | 
| Valeriy Ponomaryov | 4fb305f | 2016-10-21 13:46:47 +0300 | [diff] [blame] | 277 |  | 
 | 278 |         if CONF.identity.auth_version == 'v3': | 
 | 279 |             project_id = os.auth_provider.auth_data[1]['project']['id'] | 
 | 280 |         else: | 
 | 281 |             project_id = os.auth_provider.auth_data[1]['token']['tenant']['id'] | 
 | 282 |         cls.tenant_id = project_id | 
 | 283 |         cls.user_id = os.auth_provider.auth_data[1]['user']['id'] | 
 | 284 |  | 
| Valeriy Ponomaryov | 39cdf72 | 2016-05-30 18:16:15 +0300 | [diff] [blame] | 285 |         if CONF.share.multitenancy_enabled: | 
| Valeriy Ponomaryov | c5dae27 | 2016-06-10 18:29:24 +0300 | [diff] [blame] | 286 |             if (not CONF.service_available.neutron and | 
 | 287 |                     CONF.share.create_networks_when_multitenancy_enabled): | 
| Valeriy Ponomaryov | 39cdf72 | 2016-05-30 18:16:15 +0300 | [diff] [blame] | 288 |                 raise cls.skipException("Neutron support is required") | 
 | 289 |             share_network_id = cls.provide_share_network( | 
| Andrea Frittoli (andreaf) | 369391a | 2016-06-27 18:59:13 +0100 | [diff] [blame] | 290 |                 cls.shares_v2_client, cls.networks_client) | 
| Valeriy Ponomaryov | 39cdf72 | 2016-05-30 18:16:15 +0300 | [diff] [blame] | 291 |             cls.shares_client.share_network_id = share_network_id | 
 | 292 |             cls.shares_v2_client.share_network_id = share_network_id | 
| haobing1 | 01c7fee | 2018-03-09 16:33:00 +0800 | [diff] [blame] | 293 |             resource = { | 
 | 294 |                 "type": "share_network", | 
 | 295 |                 "id": share_network_id, | 
 | 296 |                 "client": cls.shares_v2_client, | 
 | 297 |             } | 
 | 298 |             cls.class_resources.insert(0, resource) | 
| Valeriy Ponomaryov | 39cdf72 | 2016-05-30 18:16:15 +0300 | [diff] [blame] | 299 |  | 
 | 300 |     @classmethod | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 301 |     def resource_setup(cls): | 
 | 302 |         if not (any(p in CONF.share.enable_protocols | 
 | 303 |                     for p in cls.protocols) and | 
 | 304 |                 CONF.service_available.manila): | 
 | 305 |             skip_msg = "Manila is disabled" | 
 | 306 |             raise cls.skipException(skip_msg) | 
 | 307 |         super(BaseSharesTest, cls).resource_setup() | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 308 |  | 
 | 309 |     def setUp(self): | 
 | 310 |         super(BaseSharesTest, self).setUp() | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 311 |         self.addCleanup(self.clear_isolated_creds) | 
| Valeriy Ponomaryov | dd162cb | 2016-01-20 19:09:49 +0200 | [diff] [blame] | 312 |         self.addCleanup(self.clear_resources) | 
| Valeriy Ponomaryov | 2abf5d7 | 2016-06-01 18:30:12 +0300 | [diff] [blame] | 313 |         verify_test_has_appropriate_tags(self) | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 314 |  | 
 | 315 |     @classmethod | 
 | 316 |     def resource_cleanup(cls): | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 317 |         cls.clear_resources(cls.class_resources) | 
 | 318 |         cls.clear_isolated_creds(cls.class_isolated_creds) | 
| Sam Wan | 241029c | 2016-07-26 03:37:42 -0400 | [diff] [blame] | 319 |         super(BaseSharesTest, cls).resource_cleanup() | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 320 |  | 
 | 321 |     @classmethod | 
 | 322 |     @network_synchronized | 
| Valeriy Ponomaryov | 48a2bd7 | 2015-11-05 13:22:44 +0200 | [diff] [blame] | 323 |     def provide_share_network(cls, shares_client, networks_client, | 
| Rodrigo Barbieri | 58d9de3 | 2016-09-06 13:16:47 -0300 | [diff] [blame] | 324 |                               isolated_creds_client=None, | 
 | 325 |                               ignore_multitenancy_config=False): | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 326 |         """Used for finding/creating share network for multitenant driver. | 
 | 327 |  | 
 | 328 |         This method creates/gets entity share-network for one tenant. This | 
 | 329 |         share-network will be used for creation of service vm. | 
 | 330 |  | 
 | 331 |         :param shares_client: shares client, which requires share-network | 
| Valeriy Ponomaryov | 48a2bd7 | 2015-11-05 13:22:44 +0200 | [diff] [blame] | 332 |         :param networks_client: network client from same tenant as shares | 
 | 333 |         :param isolated_creds_client: DynamicCredentialProvider instance | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 334 |             If provided, then its networking will be used if needed. | 
 | 335 |             If not provided, then common network will be used if needed. | 
| Rodrigo Barbieri | 58d9de3 | 2016-09-06 13:16:47 -0300 | [diff] [blame] | 336 |         :param ignore_multitenancy_config: provide a share network regardless | 
 | 337 |             of 'multitenancy_enabled' configuration value. | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 338 |         :returns: str -- share network id for shares_client tenant | 
 | 339 |         :returns: None -- if single-tenant driver used | 
 | 340 |         """ | 
 | 341 |  | 
 | 342 |         sc = shares_client | 
| Valeriy Ponomaryov | c5dae27 | 2016-06-10 18:29:24 +0300 | [diff] [blame] | 343 |         search_word = "reusable" | 
 | 344 |         sn_name = "autogenerated_by_tempest_%s" % search_word | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 345 |  | 
| Rodrigo Barbieri | 58d9de3 | 2016-09-06 13:16:47 -0300 | [diff] [blame] | 346 |         if (not ignore_multitenancy_config and | 
 | 347 |                 not CONF.share.multitenancy_enabled): | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 348 |             # Assumed usage of a single-tenant driver | 
 | 349 |             share_network_id = None | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 350 |         else: | 
| Rodrigo Barbieri | 58d9de3 | 2016-09-06 13:16:47 -0300 | [diff] [blame] | 351 |             if sc.share_network_id: | 
 | 352 |                 # Share-network already exists, use it | 
 | 353 |                 share_network_id = sc.share_network_id | 
 | 354 |             elif not CONF.share.create_networks_when_multitenancy_enabled: | 
 | 355 |                 share_network_id = None | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 356 |  | 
 | 357 |                 # Try get suitable share-network | 
 | 358 |                 share_networks = sc.list_share_networks_with_detail() | 
 | 359 |                 for sn in share_networks: | 
| Rodrigo Barbieri | 58d9de3 | 2016-09-06 13:16:47 -0300 | [diff] [blame] | 360 |                     if (sn["neutron_net_id"] is None and | 
 | 361 |                             sn["neutron_subnet_id"] is None and | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 362 |                             sn["name"] and search_word in sn["name"]): | 
 | 363 |                         share_network_id = sn["id"] | 
 | 364 |                         break | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 365 |  | 
| Rodrigo Barbieri | 58d9de3 | 2016-09-06 13:16:47 -0300 | [diff] [blame] | 366 |                 # Create new share-network if one was not found | 
 | 367 |                 if share_network_id is None: | 
 | 368 |                     sn_desc = "This share-network was created by tempest" | 
 | 369 |                     sn = sc.create_share_network(name=sn_name, | 
 | 370 |                                                  description=sn_desc) | 
 | 371 |                     share_network_id = sn["id"] | 
 | 372 |             else: | 
 | 373 |                 net_id = subnet_id = share_network_id = None | 
 | 374 |  | 
 | 375 |                 if not isolated_creds_client: | 
 | 376 |                     # Search for networks, created in previous runs | 
 | 377 |                     service_net_name = "share-service" | 
 | 378 |                     networks = networks_client.list_networks() | 
 | 379 |                     if "networks" in networks.keys(): | 
 | 380 |                         networks = networks["networks"] | 
 | 381 |                     for network in networks: | 
 | 382 |                         if (service_net_name in network["name"] and | 
 | 383 |                                 sc.tenant_id == network['tenant_id']): | 
 | 384 |                             net_id = network["id"] | 
 | 385 |                             if len(network["subnets"]) > 0: | 
 | 386 |                                 subnet_id = network["subnets"][0] | 
 | 387 |                                 break | 
 | 388 |  | 
 | 389 |                     # Create suitable network | 
 | 390 |                     if net_id is None or subnet_id is None: | 
| Tom Barron | 4b8834a | 2017-02-02 11:02:20 -0500 | [diff] [blame] | 391 |                         ic = cls._get_dynamic_creds(service_net_name) | 
| Rodrigo Barbieri | 58d9de3 | 2016-09-06 13:16:47 -0300 | [diff] [blame] | 392 |                         net_data = ic._create_network_resources(sc.tenant_id) | 
 | 393 |                         network, subnet, router = net_data | 
 | 394 |                         net_id = network["id"] | 
 | 395 |                         subnet_id = subnet["id"] | 
 | 396 |  | 
 | 397 |                     # Try get suitable share-network | 
 | 398 |                     share_networks = sc.list_share_networks_with_detail() | 
 | 399 |                     for sn in share_networks: | 
 | 400 |                         if (net_id == sn["neutron_net_id"] and | 
 | 401 |                                 subnet_id == sn["neutron_subnet_id"] and | 
 | 402 |                                 sn["name"] and search_word in sn["name"]): | 
 | 403 |                             share_network_id = sn["id"] | 
 | 404 |                             break | 
 | 405 |                 else: | 
 | 406 |                     sn_name = "autogenerated_by_tempest_for_isolated_creds" | 
 | 407 |                     # Use precreated network and subnet from isolated creds | 
 | 408 |                     net_id = isolated_creds_client.get_credentials( | 
 | 409 |                         isolated_creds_client.type_of_creds).network['id'] | 
 | 410 |                     subnet_id = isolated_creds_client.get_credentials( | 
 | 411 |                         isolated_creds_client.type_of_creds).subnet['id'] | 
 | 412 |  | 
 | 413 |                 # Create suitable share-network | 
 | 414 |                 if share_network_id is None: | 
 | 415 |                     sn_desc = "This share-network was created by tempest" | 
 | 416 |                     sn = sc.create_share_network(name=sn_name, | 
 | 417 |                                                  description=sn_desc, | 
 | 418 |                                                  neutron_net_id=net_id, | 
 | 419 |                                                  neutron_subnet_id=subnet_id) | 
 | 420 |                     share_network_id = sn["id"] | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 421 |  | 
 | 422 |         return share_network_id | 
 | 423 |  | 
 | 424 |     @classmethod | 
| marcusvrn | e0d7cfd | 2016-06-24 12:27:55 -0300 | [diff] [blame] | 425 |     def _create_share(cls, share_protocol=None, size=None, name=None, | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 426 |                       snapshot_id=None, description=None, metadata=None, | 
 | 427 |                       share_network_id=None, share_type_id=None, | 
| Andrew Kerr | b843692 | 2016-06-01 15:32:43 -0400 | [diff] [blame] | 428 |                       share_group_id=None, client=None, | 
| Clinton Knight | e5c8f09 | 2015-08-27 15:00:23 -0400 | [diff] [blame] | 429 |                       cleanup_in_class=True, is_public=False, **kwargs): | 
| Valeriy Ponomaryov | 1aaa72d | 2015-09-08 12:59:41 +0300 | [diff] [blame] | 430 |         client = client or cls.shares_v2_client | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 431 |         description = description or "Tempest's share" | 
| yogesh | 06f519f | 2017-06-26 13:16:12 -0400 | [diff] [blame] | 432 |         share_network_id = (share_network_id or | 
 | 433 |                             CONF.share.share_network_id or | 
 | 434 |                             client.share_network_id or None) | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 435 |         metadata = metadata or {} | 
| marcusvrn | e0d7cfd | 2016-06-24 12:27:55 -0300 | [diff] [blame] | 436 |         size = size or CONF.share.share_size | 
| Clinton Knight | e5c8f09 | 2015-08-27 15:00:23 -0400 | [diff] [blame] | 437 |         kwargs.update({ | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 438 |             'share_protocol': share_protocol, | 
 | 439 |             'size': size, | 
 | 440 |             'name': name, | 
 | 441 |             'snapshot_id': snapshot_id, | 
 | 442 |             'description': description, | 
 | 443 |             'metadata': metadata, | 
 | 444 |             'share_network_id': share_network_id, | 
 | 445 |             'share_type_id': share_type_id, | 
 | 446 |             'is_public': is_public, | 
| Clinton Knight | e5c8f09 | 2015-08-27 15:00:23 -0400 | [diff] [blame] | 447 |         }) | 
| Andrew Kerr | b843692 | 2016-06-01 15:32:43 -0400 | [diff] [blame] | 448 |         if share_group_id: | 
 | 449 |             kwargs['share_group_id'] = share_group_id | 
| Andrew Kerr | bf31e91 | 2015-07-29 10:39:38 -0400 | [diff] [blame] | 450 |  | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 451 |         share = client.create_share(**kwargs) | 
| Andrew Kerr | bf31e91 | 2015-07-29 10:39:38 -0400 | [diff] [blame] | 452 |         resource = {"type": "share", "id": share["id"], "client": client, | 
| Andrew Kerr | b843692 | 2016-06-01 15:32:43 -0400 | [diff] [blame] | 453 |                     "share_group_id": share_group_id} | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 454 |         cleanup_list = (cls.class_resources if cleanup_in_class else | 
 | 455 |                         cls.method_resources) | 
 | 456 |         cleanup_list.insert(0, resource) | 
 | 457 |         return share | 
 | 458 |  | 
 | 459 |     @classmethod | 
| Rodrigo Barbieri | 427bc05 | 2016-06-06 17:10:06 -0300 | [diff] [blame] | 460 |     def migrate_share( | 
 | 461 |             cls, share_id, dest_host, wait_for_status, client=None, | 
| Rodrigo Barbieri | 027df98 | 2016-11-24 15:52:03 -0200 | [diff] [blame] | 462 |             force_host_assisted_migration=False, writable=False, | 
 | 463 |             nondisruptive=False, preserve_metadata=False, | 
 | 464 |             preserve_snapshots=False, new_share_network_id=None, | 
| Rodrigo Barbieri | d38d2f5 | 2016-07-19 22:24:56 -0300 | [diff] [blame] | 465 |             new_share_type_id=None, **kwargs): | 
| Clinton Knight | e5c8f09 | 2015-08-27 15:00:23 -0400 | [diff] [blame] | 466 |         client = client or cls.shares_v2_client | 
| Rodrigo Barbieri | 427bc05 | 2016-06-06 17:10:06 -0300 | [diff] [blame] | 467 |         client.migrate_share( | 
 | 468 |             share_id, dest_host, | 
 | 469 |             force_host_assisted_migration=force_host_assisted_migration, | 
| Rodrigo Barbieri | 027df98 | 2016-11-24 15:52:03 -0200 | [diff] [blame] | 470 |             writable=writable, preserve_metadata=preserve_metadata, | 
 | 471 |             nondisruptive=nondisruptive, preserve_snapshots=preserve_snapshots, | 
| Rodrigo Barbieri | 427bc05 | 2016-06-06 17:10:06 -0300 | [diff] [blame] | 472 |             new_share_network_id=new_share_network_id, | 
| Rodrigo Barbieri | d38d2f5 | 2016-07-19 22:24:56 -0300 | [diff] [blame] | 473 |             new_share_type_id=new_share_type_id, **kwargs) | 
| Rodrigo Barbieri | e330512 | 2016-02-03 14:32:24 -0200 | [diff] [blame] | 474 |         share = client.wait_for_migration_status( | 
| Rodrigo Barbieri | 427bc05 | 2016-06-06 17:10:06 -0300 | [diff] [blame] | 475 |             share_id, dest_host, wait_for_status, **kwargs) | 
| Rodrigo Barbieri | e330512 | 2016-02-03 14:32:24 -0200 | [diff] [blame] | 476 |         return share | 
 | 477 |  | 
 | 478 |     @classmethod | 
 | 479 |     def migration_complete(cls, share_id, dest_host, client=None, **kwargs): | 
 | 480 |         client = client or cls.shares_v2_client | 
 | 481 |         client.migration_complete(share_id, **kwargs) | 
 | 482 |         share = client.wait_for_migration_status( | 
| Rodrigo Barbieri | 427bc05 | 2016-06-06 17:10:06 -0300 | [diff] [blame] | 483 |             share_id, dest_host, 'migration_success', **kwargs) | 
| Rodrigo Barbieri | b7137ad | 2015-09-06 22:53:16 -0300 | [diff] [blame] | 484 |         return share | 
 | 485 |  | 
 | 486 |     @classmethod | 
| Rodrigo Barbieri | c9abf28 | 2016-08-24 22:01:31 -0300 | [diff] [blame] | 487 |     def migration_cancel(cls, share_id, dest_host, client=None, **kwargs): | 
 | 488 |         client = client or cls.shares_v2_client | 
 | 489 |         client.migration_cancel(share_id, **kwargs) | 
 | 490 |         share = client.wait_for_migration_status( | 
 | 491 |             share_id, dest_host, 'migration_cancelled', **kwargs) | 
 | 492 |         return share | 
 | 493 |  | 
 | 494 |     @classmethod | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 495 |     def create_share(cls, *args, **kwargs): | 
 | 496 |         """Create one share and wait for available state. Retry if allowed.""" | 
 | 497 |         result = cls.create_shares([{"args": args, "kwargs": kwargs}]) | 
 | 498 |         return result[0] | 
 | 499 |  | 
 | 500 |     @classmethod | 
 | 501 |     def create_shares(cls, share_data_list): | 
 | 502 |         """Creates several shares in parallel with retries. | 
 | 503 |  | 
 | 504 |         Use this method when you want to create more than one share at same | 
 | 505 |         time. Especially if config option 'share.share_creation_retry_number' | 
 | 506 |         has value more than zero (0). | 
 | 507 |         All shares will be expected to have 'available' status with or without | 
 | 508 |         recreation else error will be raised. | 
 | 509 |  | 
 | 510 |         :param share_data_list: list -- list of dictionaries with 'args' and | 
 | 511 |             'kwargs' for '_create_share' method of this base class. | 
 | 512 |             example of data: | 
 | 513 |                 share_data_list=[{'args': ['quuz'], 'kwargs': {'foo': 'bar'}}}] | 
 | 514 |         :returns: list -- list of shares created using provided data. | 
 | 515 |         """ | 
 | 516 |  | 
| Valeriy Ponomaryov | 39cdf72 | 2016-05-30 18:16:15 +0300 | [diff] [blame] | 517 |         for d in share_data_list: | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 518 |             if not isinstance(d, dict): | 
 | 519 |                 raise exceptions.TempestException( | 
 | 520 |                     "Expected 'dict', got '%s'" % type(d)) | 
 | 521 |             if "args" not in d: | 
 | 522 |                 d["args"] = [] | 
 | 523 |             if "kwargs" not in d: | 
 | 524 |                 d["kwargs"] = {} | 
 | 525 |             if len(d) > 2: | 
 | 526 |                 raise exceptions.TempestException( | 
 | 527 |                     "Expected only 'args' and 'kwargs' keys. " | 
 | 528 |                     "Provided %s" % list(d)) | 
| Valeriy Ponomaryov | 39cdf72 | 2016-05-30 18:16:15 +0300 | [diff] [blame] | 529 |  | 
 | 530 |         data = [] | 
 | 531 |         for d in share_data_list: | 
 | 532 |             client = d["kwargs"].pop("client", cls.shares_v2_client) | 
| yogesh | db32f46 | 2016-09-28 15:09:50 -0400 | [diff] [blame] | 533 |             wait_for_status = d["kwargs"].pop("wait_for_status", True) | 
| Valeriy Ponomaryov | 39cdf72 | 2016-05-30 18:16:15 +0300 | [diff] [blame] | 534 |             local_d = { | 
 | 535 |                 "args": d["args"], | 
 | 536 |                 "kwargs": copy.deepcopy(d["kwargs"]), | 
 | 537 |             } | 
 | 538 |             local_d["kwargs"]["client"] = client | 
 | 539 |             local_d["share"] = cls._create_share( | 
 | 540 |                 *local_d["args"], **local_d["kwargs"]) | 
 | 541 |             local_d["cnt"] = 0 | 
 | 542 |             local_d["available"] = False | 
| yogesh | db32f46 | 2016-09-28 15:09:50 -0400 | [diff] [blame] | 543 |             local_d["wait_for_status"] = wait_for_status | 
| Valeriy Ponomaryov | 39cdf72 | 2016-05-30 18:16:15 +0300 | [diff] [blame] | 544 |             data.append(local_d) | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 545 |  | 
 | 546 |         while not all(d["available"] for d in data): | 
 | 547 |             for d in data: | 
| yogesh | db32f46 | 2016-09-28 15:09:50 -0400 | [diff] [blame] | 548 |                 if not d["wait_for_status"]: | 
 | 549 |                     d["available"] = True | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 550 |                 if d["available"]: | 
 | 551 |                     continue | 
| Valeriy Ponomaryov | 1a3e338 | 2016-06-08 15:17:16 +0300 | [diff] [blame] | 552 |                 client = d["kwargs"]["client"] | 
 | 553 |                 share_id = d["share"]["id"] | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 554 |                 try: | 
| Valeriy Ponomaryov | 1a3e338 | 2016-06-08 15:17:16 +0300 | [diff] [blame] | 555 |                     client.wait_for_share_status(share_id, "available") | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 556 |                     d["available"] = True | 
 | 557 |                 except (share_exceptions.ShareBuildErrorException, | 
 | 558 |                         exceptions.TimeoutException) as e: | 
 | 559 |                     if CONF.share.share_creation_retry_number > d["cnt"]: | 
 | 560 |                         d["cnt"] += 1 | 
 | 561 |                         msg = ("Share '%s' failed to be built. " | 
| Valeriy Ponomaryov | 1a3e338 | 2016-06-08 15:17:16 +0300 | [diff] [blame] | 562 |                                "Trying create another." % share_id) | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 563 |                         LOG.error(msg) | 
 | 564 |                         LOG.error(e) | 
| Valeriy Ponomaryov | 1a3e338 | 2016-06-08 15:17:16 +0300 | [diff] [blame] | 565 |                         cg_id = d["kwargs"].get("consistency_group_id") | 
 | 566 |                         if cg_id: | 
 | 567 |                             # NOTE(vponomaryov): delete errored share | 
 | 568 |                             # immediately in case share is part of CG. | 
 | 569 |                             client.delete_share( | 
 | 570 |                                 share_id, | 
 | 571 |                                 params={"consistency_group_id": cg_id}) | 
 | 572 |                             client.wait_for_resource_deletion( | 
 | 573 |                                 share_id=share_id) | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 574 |                         d["share"] = cls._create_share( | 
 | 575 |                             *d["args"], **d["kwargs"]) | 
 | 576 |                     else: | 
| gecong1973 | 5866380 | 2016-08-25 11:08:45 +0800 | [diff] [blame] | 577 |                         raise | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 578 |  | 
 | 579 |         return [d["share"] for d in data] | 
 | 580 |  | 
 | 581 |     @classmethod | 
| Andrew Kerr | b843692 | 2016-06-01 15:32:43 -0400 | [diff] [blame] | 582 |     def create_share_group(cls, client=None, cleanup_in_class=True, | 
 | 583 |                            share_network_id=None, **kwargs): | 
| Clinton Knight | e5c8f09 | 2015-08-27 15:00:23 -0400 | [diff] [blame] | 584 |         client = client or cls.shares_v2_client | 
| Andrew Kerr | b843692 | 2016-06-01 15:32:43 -0400 | [diff] [blame] | 585 |         if kwargs.get('source_share_group_snapshot_id') is None: | 
| Goutham Pacha Ravi | 9221f5e | 2016-04-21 13:17:49 -0400 | [diff] [blame] | 586 |             kwargs['share_network_id'] = (share_network_id or | 
 | 587 |                                           client.share_network_id or None) | 
| Andrew Kerr | b843692 | 2016-06-01 15:32:43 -0400 | [diff] [blame] | 588 |         share_group = client.create_share_group(**kwargs) | 
| Andrew Kerr | bf31e91 | 2015-07-29 10:39:38 -0400 | [diff] [blame] | 589 |         resource = { | 
| Andrew Kerr | b843692 | 2016-06-01 15:32:43 -0400 | [diff] [blame] | 590 |             "type": "share_group", | 
 | 591 |             "id": share_group["id"], | 
 | 592 |             "client": client, | 
 | 593 |         } | 
| Andrew Kerr | bf31e91 | 2015-07-29 10:39:38 -0400 | [diff] [blame] | 594 |         if cleanup_in_class: | 
 | 595 |             cls.class_resources.insert(0, resource) | 
 | 596 |         else: | 
 | 597 |             cls.method_resources.insert(0, resource) | 
 | 598 |  | 
| Andrew Kerr | b843692 | 2016-06-01 15:32:43 -0400 | [diff] [blame] | 599 |         if kwargs.get('source_share_group_snapshot_id'): | 
 | 600 |             new_share_group_shares = client.list_shares( | 
| Andrew Kerr | bf31e91 | 2015-07-29 10:39:38 -0400 | [diff] [blame] | 601 |                 detailed=True, | 
| Andrew Kerr | b843692 | 2016-06-01 15:32:43 -0400 | [diff] [blame] | 602 |                 params={'share_group_id': share_group['id']}, | 
 | 603 |                 experimental=True) | 
| Andrew Kerr | bf31e91 | 2015-07-29 10:39:38 -0400 | [diff] [blame] | 604 |  | 
| Andrew Kerr | b843692 | 2016-06-01 15:32:43 -0400 | [diff] [blame] | 605 |             for share in new_share_group_shares: | 
| Andrew Kerr | bf31e91 | 2015-07-29 10:39:38 -0400 | [diff] [blame] | 606 |                 resource = {"type": "share", | 
 | 607 |                             "id": share["id"], | 
 | 608 |                             "client": client, | 
| Andrew Kerr | b843692 | 2016-06-01 15:32:43 -0400 | [diff] [blame] | 609 |                             "share_group_id": share.get("share_group_id")} | 
| Andrew Kerr | bf31e91 | 2015-07-29 10:39:38 -0400 | [diff] [blame] | 610 |                 if cleanup_in_class: | 
 | 611 |                     cls.class_resources.insert(0, resource) | 
 | 612 |                 else: | 
 | 613 |                     cls.method_resources.insert(0, resource) | 
 | 614 |  | 
| Andrew Kerr | b843692 | 2016-06-01 15:32:43 -0400 | [diff] [blame] | 615 |         client.wait_for_share_group_status(share_group['id'], 'available') | 
 | 616 |         return share_group | 
 | 617 |  | 
 | 618 |     @classmethod | 
 | 619 |     def create_share_group_type(cls, name=None, share_types=(), is_public=None, | 
 | 620 |                                 group_specs=None, client=None, | 
 | 621 |                                 cleanup_in_class=True, **kwargs): | 
 | 622 |         client = client or cls.shares_v2_client | 
| Valeriy Ponomaryov | e92f09f | 2017-03-16 17:25:47 +0300 | [diff] [blame] | 623 |         if (group_specs is None and | 
 | 624 |                 CONF.share.capability_sg_consistent_snapshot_support): | 
| Valeriy Ponomaryov | 3c18893 | 2017-03-15 19:06:23 +0300 | [diff] [blame] | 625 |             group_specs = { | 
 | 626 |                 'consistent_snapshot_support': ( | 
 | 627 |                     CONF.share.capability_sg_consistent_snapshot_support), | 
 | 628 |             } | 
| Andrew Kerr | b843692 | 2016-06-01 15:32:43 -0400 | [diff] [blame] | 629 |         share_group_type = client.create_share_group_type( | 
 | 630 |             name=name, | 
 | 631 |             share_types=share_types, | 
 | 632 |             is_public=is_public, | 
 | 633 |             group_specs=group_specs, | 
 | 634 |             **kwargs) | 
 | 635 |         resource = { | 
 | 636 |             "type": "share_group_type", | 
 | 637 |             "id": share_group_type["id"], | 
 | 638 |             "client": client, | 
 | 639 |         } | 
 | 640 |         if cleanup_in_class: | 
 | 641 |             cls.class_resources.insert(0, resource) | 
 | 642 |         else: | 
 | 643 |             cls.method_resources.insert(0, resource) | 
 | 644 |         return share_group_type | 
| Andrew Kerr | bf31e91 | 2015-07-29 10:39:38 -0400 | [diff] [blame] | 645 |  | 
 | 646 |     @classmethod | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 647 |     def create_snapshot_wait_for_active(cls, share_id, name=None, | 
 | 648 |                                         description=None, force=False, | 
 | 649 |                                         client=None, cleanup_in_class=True): | 
 | 650 |         if client is None: | 
| Yogesh | 1f931ff | 2015-09-29 23:41:02 -0400 | [diff] [blame] | 651 |             client = cls.shares_v2_client | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 652 |         if description is None: | 
 | 653 |             description = "Tempest's snapshot" | 
 | 654 |         snapshot = client.create_snapshot(share_id, name, description, force) | 
 | 655 |         resource = { | 
 | 656 |             "type": "snapshot", | 
 | 657 |             "id": snapshot["id"], | 
 | 658 |             "client": client, | 
 | 659 |         } | 
 | 660 |         if cleanup_in_class: | 
 | 661 |             cls.class_resources.insert(0, resource) | 
 | 662 |         else: | 
 | 663 |             cls.method_resources.insert(0, resource) | 
 | 664 |         client.wait_for_snapshot_status(snapshot["id"], "available") | 
 | 665 |         return snapshot | 
 | 666 |  | 
 | 667 |     @classmethod | 
| Andrew Kerr | b843692 | 2016-06-01 15:32:43 -0400 | [diff] [blame] | 668 |     def create_share_group_snapshot_wait_for_active( | 
 | 669 |             cls, share_group_id, name=None, description=None, client=None, | 
 | 670 |             cleanup_in_class=True, **kwargs): | 
| Clinton Knight | e5c8f09 | 2015-08-27 15:00:23 -0400 | [diff] [blame] | 671 |         client = client or cls.shares_v2_client | 
| Andrew Kerr | bf31e91 | 2015-07-29 10:39:38 -0400 | [diff] [blame] | 672 |         if description is None: | 
| Andrew Kerr | b843692 | 2016-06-01 15:32:43 -0400 | [diff] [blame] | 673 |             description = "Tempest's share group snapshot" | 
 | 674 |         sg_snapshot = client.create_share_group_snapshot( | 
 | 675 |             share_group_id, name=name, description=description, **kwargs) | 
| Andrew Kerr | bf31e91 | 2015-07-29 10:39:38 -0400 | [diff] [blame] | 676 |         resource = { | 
| Andrew Kerr | b843692 | 2016-06-01 15:32:43 -0400 | [diff] [blame] | 677 |             "type": "share_group_snapshot", | 
 | 678 |             "id": sg_snapshot["id"], | 
| Andrew Kerr | bf31e91 | 2015-07-29 10:39:38 -0400 | [diff] [blame] | 679 |             "client": client, | 
 | 680 |         } | 
 | 681 |         if cleanup_in_class: | 
 | 682 |             cls.class_resources.insert(0, resource) | 
 | 683 |         else: | 
 | 684 |             cls.method_resources.insert(0, resource) | 
| Andrew Kerr | b843692 | 2016-06-01 15:32:43 -0400 | [diff] [blame] | 685 |         client.wait_for_share_group_snapshot_status( | 
 | 686 |             sg_snapshot["id"], "available") | 
 | 687 |         return sg_snapshot | 
| Andrew Kerr | bf31e91 | 2015-07-29 10:39:38 -0400 | [diff] [blame] | 688 |  | 
 | 689 |     @classmethod | 
| Goutham Pacha Ravi | 839c98b | 2019-01-14 23:16:23 -0800 | [diff] [blame^] | 690 |     def get_availability_zones(cls, client=None, backends=None): | 
| Yogesh | bdb8810 | 2015-09-29 23:41:02 -0400 | [diff] [blame] | 691 |         """List the availability zones for "manila-share" services | 
 | 692 |  | 
 | 693 |          that are currently in "up" state. | 
 | 694 |          """ | 
| Goutham Pacha Ravi | 839c98b | 2019-01-14 23:16:23 -0800 | [diff] [blame^] | 695 |         client = client or cls.admin_shares_v2_client | 
 | 696 |         backends = ( | 
 | 697 |             '|'.join(['^%s$' % backend for backend in backends]) | 
 | 698 |             if backends else '.*' | 
 | 699 |         ) | 
| Yogesh | bdb8810 | 2015-09-29 23:41:02 -0400 | [diff] [blame] | 700 |         cls.services = client.list_services() | 
 | 701 |         zones = [service['zone'] for service in cls.services if | 
| Goutham Pacha Ravi | 839c98b | 2019-01-14 23:16:23 -0800 | [diff] [blame^] | 702 |                  service['binary'] == 'manila-share' and | 
 | 703 |                  service['state'] == 'up' and | 
 | 704 |                  re.search(backends, service['host'])] | 
| Yogesh | bdb8810 | 2015-09-29 23:41:02 -0400 | [diff] [blame] | 705 |         return zones | 
 | 706 |  | 
| Goutham Pacha Ravi | 839c98b | 2019-01-14 23:16:23 -0800 | [diff] [blame^] | 707 |     @classmethod | 
 | 708 |     def get_pools_matching_share_type(cls, share_type, client=None): | 
 | 709 |         client = client or cls.admin_shares_v2_client | 
 | 710 |         if utils.is_microversion_supported('2.23'): | 
 | 711 |             return client.list_pools( | 
 | 712 |                 search_opts={'share_type': share_type['id']})['pools'] | 
 | 713 |  | 
 | 714 |         pools = client.list_pools(detail=True)['pools'] | 
 | 715 |         share_type = client.get_share_type(share_type['id'])['share_type'] | 
 | 716 |         extra_specs = {} | 
 | 717 |         for k, v in share_type['extra_specs'].items(): | 
 | 718 |             extra_specs[k] = ( | 
 | 719 |                 True if six.text_type(v).lower() == 'true' | 
 | 720 |                 else False if six.text_type(v).lower() == 'false' else v | 
 | 721 |             ) | 
 | 722 |         return [ | 
 | 723 |             pool for pool in pools if all(y in pool['capabilities'].items() | 
 | 724 |                                           for y in extra_specs.items()) | 
 | 725 |         ] | 
 | 726 |  | 
 | 727 |     @classmethod | 
 | 728 |     def get_availability_zones_matching_share_type(cls, share_type, | 
 | 729 |                                                    client=None): | 
 | 730 |  | 
 | 731 |         client = client or cls.admin_shares_v2_client | 
 | 732 |         pools_matching_share_type = cls.get_pools_matching_share_type( | 
 | 733 |             share_type, client=client) | 
 | 734 |         backends_matching_share_type = set( | 
 | 735 |             [pool['name'].split("#")[0] for pool in pools_matching_share_type] | 
 | 736 |         ) | 
 | 737 |         azs = cls.get_availability_zones(backends=backends_matching_share_type) | 
 | 738 |         return azs | 
 | 739 |  | 
| Yogesh | 1f931ff | 2015-09-29 23:41:02 -0400 | [diff] [blame] | 740 |     def get_pools_for_replication_domain(self): | 
 | 741 |         # Get the list of pools for the replication domain | 
 | 742 |         pools = self.admin_client.list_pools(detail=True)['pools'] | 
| Ben Swartzlander | 7150c65 | 2017-02-13 22:31:18 -0500 | [diff] [blame] | 743 |         instance_host = self.admin_client.get_share( | 
 | 744 |             self.shares[0]['id'])['host'] | 
| Yogesh | 1f931ff | 2015-09-29 23:41:02 -0400 | [diff] [blame] | 745 |         host_pool = [p for p in pools if p['name'] == instance_host][0] | 
 | 746 |         rep_domain = host_pool['capabilities']['replication_domain'] | 
 | 747 |         pools_in_rep_domain = [p for p in pools if p['capabilities'][ | 
 | 748 |             'replication_domain'] == rep_domain] | 
 | 749 |         return rep_domain, pools_in_rep_domain | 
 | 750 |  | 
| Yogesh | bdb8810 | 2015-09-29 23:41:02 -0400 | [diff] [blame] | 751 |     @classmethod | 
 | 752 |     def create_share_replica(cls, share_id, availability_zone, client=None, | 
 | 753 |                              cleanup_in_class=False, cleanup=True): | 
 | 754 |         client = client or cls.shares_v2_client | 
 | 755 |         replica = client.create_share_replica(share_id, availability_zone) | 
 | 756 |         resource = { | 
 | 757 |             "type": "share_replica", | 
 | 758 |             "id": replica["id"], | 
 | 759 |             "client": client, | 
 | 760 |             "share_id": share_id, | 
 | 761 |         } | 
 | 762 |         # NOTE(Yogi1): Cleanup needs to be disabled during promotion tests. | 
 | 763 |         if cleanup: | 
 | 764 |             if cleanup_in_class: | 
 | 765 |                 cls.class_resources.insert(0, resource) | 
 | 766 |             else: | 
 | 767 |                 cls.method_resources.insert(0, resource) | 
 | 768 |         client.wait_for_share_replica_status( | 
 | 769 |             replica["id"], constants.STATUS_AVAILABLE) | 
 | 770 |         return replica | 
 | 771 |  | 
 | 772 |     @classmethod | 
 | 773 |     def delete_share_replica(cls, replica_id, client=None): | 
 | 774 |         client = client or cls.shares_v2_client | 
| Yogesh | 1f931ff | 2015-09-29 23:41:02 -0400 | [diff] [blame] | 775 |         try: | 
 | 776 |             client.delete_share_replica(replica_id) | 
 | 777 |             client.wait_for_resource_deletion(replica_id=replica_id) | 
 | 778 |         except exceptions.NotFound: | 
 | 779 |             pass | 
| Yogesh | bdb8810 | 2015-09-29 23:41:02 -0400 | [diff] [blame] | 780 |  | 
 | 781 |     @classmethod | 
 | 782 |     def promote_share_replica(cls, replica_id, client=None): | 
 | 783 |         client = client or cls.shares_v2_client | 
 | 784 |         replica = client.promote_share_replica(replica_id) | 
 | 785 |         client.wait_for_share_replica_status( | 
 | 786 |             replica["id"], | 
 | 787 |             constants.REPLICATION_STATE_ACTIVE, | 
 | 788 |             status_attr="replica_state") | 
 | 789 |         return replica | 
 | 790 |  | 
| yogesh | db32f46 | 2016-09-28 15:09:50 -0400 | [diff] [blame] | 791 |     def _get_access_rule_data_from_config(self): | 
 | 792 |         """Get the first available access type/to combination from config. | 
 | 793 |  | 
 | 794 |         This method opportunistically picks the first configured protocol | 
 | 795 |         to create the share. Do not use this method in tests where you need | 
 | 796 |         to test depth and breadth in the access types and access recipients. | 
 | 797 |         """ | 
 | 798 |         protocol = self.shares_v2_client.share_protocol | 
 | 799 |  | 
 | 800 |         if protocol in CONF.share.enable_ip_rules_for_protocols: | 
 | 801 |             access_type = "ip" | 
 | 802 |             access_to = utils.rand_ip() | 
 | 803 |         elif protocol in CONF.share.enable_user_rules_for_protocols: | 
 | 804 |             access_type = "user" | 
 | 805 |             access_to = CONF.share.username_for_user_rules | 
 | 806 |         elif protocol in CONF.share.enable_cert_rules_for_protocols: | 
 | 807 |             access_type = "cert" | 
 | 808 |             access_to = "client3.com" | 
 | 809 |         elif protocol in CONF.share.enable_cephx_rules_for_protocols: | 
 | 810 |             access_type = "cephx" | 
 | 811 |             access_to = "eve" | 
 | 812 |         else: | 
 | 813 |             message = "Unrecognized protocol and access rules configuration." | 
 | 814 |             raise self.skipException(message) | 
 | 815 |  | 
 | 816 |         return access_type, access_to | 
 | 817 |  | 
| Yogesh | bdb8810 | 2015-09-29 23:41:02 -0400 | [diff] [blame] | 818 |     @classmethod | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 819 |     def create_share_network(cls, client=None, | 
 | 820 |                              cleanup_in_class=False, **kwargs): | 
 | 821 |         if client is None: | 
 | 822 |             client = cls.shares_client | 
 | 823 |         share_network = client.create_share_network(**kwargs) | 
 | 824 |         resource = { | 
 | 825 |             "type": "share_network", | 
 | 826 |             "id": share_network["id"], | 
 | 827 |             "client": client, | 
 | 828 |         } | 
 | 829 |         if cleanup_in_class: | 
 | 830 |             cls.class_resources.insert(0, resource) | 
 | 831 |         else: | 
 | 832 |             cls.method_resources.insert(0, resource) | 
 | 833 |         return share_network | 
 | 834 |  | 
 | 835 |     @classmethod | 
 | 836 |     def create_security_service(cls, ss_type="ldap", client=None, | 
 | 837 |                                 cleanup_in_class=False, **kwargs): | 
 | 838 |         if client is None: | 
 | 839 |             client = cls.shares_client | 
 | 840 |         security_service = client.create_security_service(ss_type, **kwargs) | 
 | 841 |         resource = { | 
 | 842 |             "type": "security_service", | 
 | 843 |             "id": security_service["id"], | 
 | 844 |             "client": client, | 
 | 845 |         } | 
 | 846 |         if cleanup_in_class: | 
 | 847 |             cls.class_resources.insert(0, resource) | 
 | 848 |         else: | 
 | 849 |             cls.method_resources.insert(0, resource) | 
 | 850 |         return security_service | 
 | 851 |  | 
 | 852 |     @classmethod | 
 | 853 |     def create_share_type(cls, name, is_public=True, client=None, | 
 | 854 |                           cleanup_in_class=True, **kwargs): | 
 | 855 |         if client is None: | 
| Valeriy Ponomaryov | a14c225 | 2015-10-29 13:34:32 +0200 | [diff] [blame] | 856 |             client = cls.shares_v2_client | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 857 |         share_type = client.create_share_type(name, is_public, **kwargs) | 
 | 858 |         resource = { | 
 | 859 |             "type": "share_type", | 
 | 860 |             "id": share_type["share_type"]["id"], | 
 | 861 |             "client": client, | 
 | 862 |         } | 
 | 863 |         if cleanup_in_class: | 
 | 864 |             cls.class_resources.insert(0, resource) | 
 | 865 |         else: | 
 | 866 |             cls.method_resources.insert(0, resource) | 
 | 867 |         return share_type | 
 | 868 |  | 
 | 869 |     @staticmethod | 
| Clinton Knight | 4699a8c | 2016-08-16 22:36:13 -0400 | [diff] [blame] | 870 |     def add_extra_specs_to_dict(extra_specs=None): | 
 | 871 |         """Add any required extra-specs to share type dictionary""" | 
| Valeriy Ponomaryov | ad55dc5 | 2015-09-23 13:54:00 +0300 | [diff] [blame] | 872 |         dhss = six.text_type(CONF.share.multitenancy_enabled) | 
 | 873 |         snapshot_support = six.text_type( | 
 | 874 |             CONF.share.capability_snapshot_support) | 
| Clinton Knight | 4699a8c | 2016-08-16 22:36:13 -0400 | [diff] [blame] | 875 |         create_from_snapshot_support = six.text_type( | 
 | 876 |             CONF.share.capability_create_share_from_snapshot_support) | 
 | 877 |  | 
 | 878 |         extra_specs_dict = { | 
| Valeriy Ponomaryov | ad55dc5 | 2015-09-23 13:54:00 +0300 | [diff] [blame] | 879 |             "driver_handles_share_servers": dhss, | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 880 |         } | 
| Clinton Knight | 4699a8c | 2016-08-16 22:36:13 -0400 | [diff] [blame] | 881 |  | 
 | 882 |         optional = { | 
 | 883 |             "snapshot_support": snapshot_support, | 
 | 884 |             "create_share_from_snapshot_support": create_from_snapshot_support, | 
 | 885 |         } | 
 | 886 |         # NOTE(gouthamr): In micro-versions < 2.24, snapshot_support is a | 
 | 887 |         # required extra-spec | 
 | 888 |         extra_specs_dict.update(optional) | 
 | 889 |  | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 890 |         if extra_specs: | 
| Clinton Knight | 4699a8c | 2016-08-16 22:36:13 -0400 | [diff] [blame] | 891 |             extra_specs_dict.update(extra_specs) | 
 | 892 |  | 
 | 893 |         return extra_specs_dict | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 894 |  | 
 | 895 |     @classmethod | 
 | 896 |     def clear_isolated_creds(cls, creds=None): | 
 | 897 |         if creds is None: | 
 | 898 |             creds = cls.method_isolated_creds | 
 | 899 |         for ic in creds: | 
 | 900 |             if "deleted" not in ic.keys(): | 
 | 901 |                 ic["deleted"] = False | 
 | 902 |             if not ic["deleted"]: | 
 | 903 |                 with handle_cleanup_exceptions(): | 
 | 904 |                     ic["method"]() | 
 | 905 |                 ic["deleted"] = True | 
 | 906 |  | 
 | 907 |     @classmethod | 
| Yogesh | 1f931ff | 2015-09-29 23:41:02 -0400 | [diff] [blame] | 908 |     def clear_share_replicas(cls, share_id, client=None): | 
 | 909 |         client = client or cls.shares_v2_client | 
 | 910 |         share_replicas = client.list_share_replicas( | 
 | 911 |             share_id=share_id) | 
 | 912 |  | 
 | 913 |         for replica in share_replicas: | 
 | 914 |             try: | 
 | 915 |                 cls.delete_share_replica(replica['id']) | 
 | 916 |             except exceptions.BadRequest: | 
 | 917 |                 # Ignore the exception due to deletion of last active replica | 
 | 918 |                 pass | 
 | 919 |  | 
 | 920 |     @classmethod | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 921 |     def clear_resources(cls, resources=None): | 
 | 922 |         """Deletes resources, that were created in test suites. | 
 | 923 |  | 
 | 924 |         This method tries to remove resources from resource list, | 
 | 925 |         if it is not found, assumed it was deleted in test itself. | 
 | 926 |         It is expected, that all resources were added as LIFO | 
 | 927 |         due to restriction of deletion resources, that is in the chain. | 
 | 928 |  | 
 | 929 |         :param resources: dict with keys 'type','id','client' and 'deleted' | 
 | 930 |         """ | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 931 |         if resources is None: | 
 | 932 |             resources = cls.method_resources | 
 | 933 |         for res in resources: | 
 | 934 |             if "deleted" not in res.keys(): | 
 | 935 |                 res["deleted"] = False | 
 | 936 |             if "client" not in res.keys(): | 
 | 937 |                 res["client"] = cls.shares_client | 
 | 938 |             if not(res["deleted"]): | 
 | 939 |                 res_id = res['id'] | 
 | 940 |                 client = res["client"] | 
 | 941 |                 with handle_cleanup_exceptions(): | 
 | 942 |                     if res["type"] is "share": | 
| Yogesh | 1f931ff | 2015-09-29 23:41:02 -0400 | [diff] [blame] | 943 |                         cls.clear_share_replicas(res_id) | 
| Andrew Kerr | b843692 | 2016-06-01 15:32:43 -0400 | [diff] [blame] | 944 |                         share_group_id = res.get('share_group_id') | 
 | 945 |                         if share_group_id: | 
 | 946 |                             params = {'share_group_id': share_group_id} | 
| Clinton Knight | e5c8f09 | 2015-08-27 15:00:23 -0400 | [diff] [blame] | 947 |                             client.delete_share(res_id, params=params) | 
 | 948 |                         else: | 
 | 949 |                             client.delete_share(res_id) | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 950 |                         client.wait_for_resource_deletion(share_id=res_id) | 
 | 951 |                     elif res["type"] is "snapshot": | 
 | 952 |                         client.delete_snapshot(res_id) | 
 | 953 |                         client.wait_for_resource_deletion(snapshot_id=res_id) | 
| yogesh | 06f519f | 2017-06-26 13:16:12 -0400 | [diff] [blame] | 954 |                     elif (res["type"] is "share_network" and | 
 | 955 |                             res_id != CONF.share.share_network_id): | 
| Victoria Martinez de la Cruz | cad9201 | 2018-06-08 14:46:35 -0400 | [diff] [blame] | 956 |                         client.delete_share_network(res_id) | 
 | 957 |                         client.wait_for_resource_deletion(sn_id=res_id) | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 958 |                     elif res["type"] is "security_service": | 
 | 959 |                         client.delete_security_service(res_id) | 
 | 960 |                         client.wait_for_resource_deletion(ss_id=res_id) | 
 | 961 |                     elif res["type"] is "share_type": | 
 | 962 |                         client.delete_share_type(res_id) | 
 | 963 |                         client.wait_for_resource_deletion(st_id=res_id) | 
| Andrew Kerr | b843692 | 2016-06-01 15:32:43 -0400 | [diff] [blame] | 964 |                     elif res["type"] is "share_group": | 
 | 965 |                         client.delete_share_group(res_id) | 
 | 966 |                         client.wait_for_resource_deletion( | 
 | 967 |                             share_group_id=res_id) | 
 | 968 |                     elif res["type"] is "share_group_type": | 
 | 969 |                         client.delete_share_group_type(res_id) | 
 | 970 |                         client.wait_for_resource_deletion( | 
 | 971 |                             share_group_type_id=res_id) | 
 | 972 |                     elif res["type"] is "share_group_snapshot": | 
 | 973 |                         client.delete_share_group_snapshot(res_id) | 
 | 974 |                         client.wait_for_resource_deletion( | 
 | 975 |                             share_group_snapshot_id=res_id) | 
| Yogesh | bdb8810 | 2015-09-29 23:41:02 -0400 | [diff] [blame] | 976 |                     elif res["type"] is "share_replica": | 
 | 977 |                         client.delete_share_replica(res_id) | 
 | 978 |                         client.wait_for_resource_deletion(replica_id=res_id) | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 979 |                     else: | 
| huayue | 97bacbf | 2016-01-04 09:57:39 +0800 | [diff] [blame] | 980 |                         LOG.warning("Provided unsupported resource type for " | 
| junboli | b236c24 | 2017-07-18 18:12:37 +0800 | [diff] [blame] | 981 |                                     "cleanup '%s'. Skipping.", res["type"]) | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 982 |                 res["deleted"] = True | 
 | 983 |  | 
 | 984 |     @classmethod | 
 | 985 |     def generate_share_network_data(self): | 
 | 986 |         data = { | 
 | 987 |             "name": data_utils.rand_name("sn-name"), | 
 | 988 |             "description": data_utils.rand_name("sn-desc"), | 
 | 989 |             "neutron_net_id": data_utils.rand_name("net-id"), | 
 | 990 |             "neutron_subnet_id": data_utils.rand_name("subnet-id"), | 
 | 991 |         } | 
 | 992 |         return data | 
 | 993 |  | 
 | 994 |     @classmethod | 
| Maurice Schreiber | 5ac3717 | 2018-02-01 15:17:31 +0100 | [diff] [blame] | 995 |     def generate_security_service_data(self, set_ou=False): | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 996 |         data = { | 
 | 997 |             "name": data_utils.rand_name("ss-name"), | 
 | 998 |             "description": data_utils.rand_name("ss-desc"), | 
| Valeriy Ponomaryov | fcde771 | 2015-12-14 18:06:13 +0200 | [diff] [blame] | 999 |             "dns_ip": utils.rand_ip(), | 
 | 1000 |             "server": utils.rand_ip(), | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 1001 |             "domain": data_utils.rand_name("ss-domain"), | 
 | 1002 |             "user": data_utils.rand_name("ss-user"), | 
 | 1003 |             "password": data_utils.rand_name("ss-password"), | 
 | 1004 |         } | 
| Maurice Schreiber | 5ac3717 | 2018-02-01 15:17:31 +0100 | [diff] [blame] | 1005 |         if set_ou: | 
 | 1006 |             data["ou"] = data_utils.rand_name("ss-ou") | 
 | 1007 |  | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 1008 |         return data | 
 | 1009 |  | 
 | 1010 |     # Useful assertions | 
 | 1011 |     def assertDictMatch(self, d1, d2, approx_equal=False, tolerance=0.001): | 
 | 1012 |         """Assert two dicts are equivalent. | 
 | 1013 |  | 
 | 1014 |         This is a 'deep' match in the sense that it handles nested | 
 | 1015 |         dictionaries appropriately. | 
 | 1016 |  | 
 | 1017 |         NOTE: | 
 | 1018 |  | 
 | 1019 |             If you don't care (or don't know) a given value, you can specify | 
 | 1020 |             the string DONTCARE as the value. This will cause that dict-item | 
 | 1021 |             to be skipped. | 
 | 1022 |  | 
 | 1023 |         """ | 
 | 1024 |         def raise_assertion(msg): | 
 | 1025 |             d1str = str(d1) | 
 | 1026 |             d2str = str(d2) | 
 | 1027 |             base_msg = ('Dictionaries do not match. %(msg)s d1: %(d1str)s ' | 
 | 1028 |                         'd2: %(d2str)s' % | 
 | 1029 |                         {"msg": msg, "d1str": d1str, "d2str": d2str}) | 
 | 1030 |             raise AssertionError(base_msg) | 
 | 1031 |  | 
 | 1032 |         d1keys = set(d1.keys()) | 
 | 1033 |         d2keys = set(d2.keys()) | 
 | 1034 |         if d1keys != d2keys: | 
 | 1035 |             d1only = d1keys - d2keys | 
 | 1036 |             d2only = d2keys - d1keys | 
 | 1037 |             raise_assertion('Keys in d1 and not d2: %(d1only)s. ' | 
 | 1038 |                             'Keys in d2 and not d1: %(d2only)s' % | 
 | 1039 |                             {"d1only": d1only, "d2only": d2only}) | 
 | 1040 |  | 
 | 1041 |         for key in d1keys: | 
 | 1042 |             d1value = d1[key] | 
 | 1043 |             d2value = d2[key] | 
 | 1044 |             try: | 
 | 1045 |                 error = abs(float(d1value) - float(d2value)) | 
 | 1046 |                 within_tolerance = error <= tolerance | 
 | 1047 |             except (ValueError, TypeError): | 
| daiki kato | 6914b1a | 2016-03-16 17:16:57 +0900 | [diff] [blame] | 1048 |                 # If both values aren't convertible to float, just ignore | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 1049 |                 # ValueError if arg is a str, TypeError if it's something else | 
 | 1050 |                 # (like None) | 
 | 1051 |                 within_tolerance = False | 
 | 1052 |  | 
 | 1053 |             if hasattr(d1value, 'keys') and hasattr(d2value, 'keys'): | 
 | 1054 |                 self.assertDictMatch(d1value, d2value) | 
 | 1055 |             elif 'DONTCARE' in (d1value, d2value): | 
 | 1056 |                 continue | 
 | 1057 |             elif approx_equal and within_tolerance: | 
 | 1058 |                 continue | 
 | 1059 |             elif d1value != d2value: | 
 | 1060 |                 raise_assertion("d1['%(key)s']=%(d1value)s != " | 
 | 1061 |                                 "d2['%(key)s']=%(d2value)s" % | 
 | 1062 |                                 { | 
 | 1063 |                                     "key": key, | 
 | 1064 |                                     "d1value": d1value, | 
 | 1065 |                                     "d2value": d2value | 
 | 1066 |                                 }) | 
 | 1067 |  | 
| Alex Meade | ba8a160 | 2016-05-06 09:33:09 -0400 | [diff] [blame] | 1068 |     def create_user_message(self): | 
 | 1069 |         """Trigger a 'no valid host' situation to generate a message.""" | 
 | 1070 |         extra_specs = { | 
 | 1071 |             'vendor_name': 'foobar', | 
 | 1072 |             'driver_handles_share_servers': CONF.share.multitenancy_enabled, | 
 | 1073 |         } | 
 | 1074 |         share_type_name = data_utils.rand_name("share-type") | 
 | 1075 |  | 
 | 1076 |         bogus_type = self.create_share_type( | 
 | 1077 |             name=share_type_name, | 
 | 1078 |             extra_specs=extra_specs)['share_type'] | 
 | 1079 |  | 
 | 1080 |         params = {'share_type_id': bogus_type['id'], | 
 | 1081 |                   'share_network_id': self.shares_v2_client.share_network_id} | 
 | 1082 |         share = self.shares_v2_client.create_share(**params) | 
 | 1083 |         self.addCleanup(self.shares_v2_client.delete_share, share['id']) | 
 | 1084 |         self.shares_v2_client.wait_for_share_status(share['id'], "error") | 
 | 1085 |         return self.shares_v2_client.wait_for_message(share['id']) | 
 | 1086 |  | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 1087 |  | 
 | 1088 | class BaseSharesAltTest(BaseSharesTest): | 
 | 1089 |     """Base test case class for all Shares Alt API tests.""" | 
| Valeriy Ponomaryov | 39cdf72 | 2016-05-30 18:16:15 +0300 | [diff] [blame] | 1090 |     credentials = ('alt', ) | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 1091 |  | 
 | 1092 |  | 
 | 1093 | class BaseSharesAdminTest(BaseSharesTest): | 
 | 1094 |     """Base test case class for all Shares Admin API tests.""" | 
| Valeriy Ponomaryov | 39cdf72 | 2016-05-30 18:16:15 +0300 | [diff] [blame] | 1095 |     credentials = ('admin', ) | 
 | 1096 |  | 
| Victoria Martinez de la Cruz | f6bc6fa | 2018-02-01 11:27:00 -0500 | [diff] [blame] | 1097 |     @classmethod | 
 | 1098 |     def setup_clients(cls): | 
 | 1099 |         super(BaseSharesAdminTest, cls).setup_clients() | 
 | 1100 |         # Initialise share clients | 
 | 1101 |         cls.admin_shares_v2_client = cls.os_admin.share_v2.SharesV2Client() | 
 | 1102 |  | 
 | 1103 |     @classmethod | 
 | 1104 |     def _create_share_type(cls, specs=None): | 
 | 1105 |         name = data_utils.rand_name("unique_st_name") | 
 | 1106 |         extra_specs = cls.add_extra_specs_to_dict(specs) | 
 | 1107 |         return cls.create_share_type( | 
 | 1108 |             name, extra_specs=extra_specs, | 
 | 1109 |             client=cls.admin_shares_v2_client)['share_type'] | 
 | 1110 |  | 
 | 1111 |     @classmethod | 
 | 1112 |     def _create_share_group_type(cls): | 
 | 1113 |         share_group_type_name = data_utils.rand_name("unique_sgtype_name") | 
 | 1114 |         return cls.create_share_group_type( | 
 | 1115 |             name=share_group_type_name, share_types=[cls.share_type_id], | 
 | 1116 |             client=cls.admin_shares_v2_client) | 
 | 1117 |  | 
| Valeriy Ponomaryov | 39cdf72 | 2016-05-30 18:16:15 +0300 | [diff] [blame] | 1118 |  | 
 | 1119 | class BaseSharesMixedTest(BaseSharesTest): | 
 | 1120 |     """Base test case class for all Shares API tests with all user roles.""" | 
 | 1121 |     credentials = ('primary', 'alt', 'admin') | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 1122 |  | 
 | 1123 |     @classmethod | 
| Valeriy Ponomaryov | 39cdf72 | 2016-05-30 18:16:15 +0300 | [diff] [blame] | 1124 |     def setup_clients(cls): | 
 | 1125 |         super(BaseSharesMixedTest, cls).setup_clients() | 
| Andrea Frittoli (andreaf) | 369391a | 2016-06-27 18:59:13 +0100 | [diff] [blame] | 1126 |         # Initialise share clients | 
 | 1127 |         cls.admin_shares_client = cls.os_admin.share_v1.SharesClient() | 
 | 1128 |         cls.admin_shares_v2_client = cls.os_admin.share_v2.SharesV2Client() | 
 | 1129 |         cls.alt_shares_client = cls.os_alt.share_v1.SharesClient() | 
 | 1130 |         cls.alt_shares_v2_client = cls.os_alt.share_v2.SharesV2Client() | 
 | 1131 |         # Initialise network clients | 
 | 1132 |         cls.os_admin.networks_client = cls.os_admin.network.NetworksClient() | 
 | 1133 |         cls.os_alt.networks_client = cls.os_alt.network.NetworksClient() | 
| Valeriy Ponomaryov | 39cdf72 | 2016-05-30 18:16:15 +0300 | [diff] [blame] | 1134 |  | 
 | 1135 |         if CONF.share.multitenancy_enabled: | 
 | 1136 |             admin_share_network_id = cls.provide_share_network( | 
 | 1137 |                 cls.admin_shares_v2_client, cls.os_admin.networks_client) | 
 | 1138 |             cls.admin_shares_client.share_network_id = admin_share_network_id | 
 | 1139 |             cls.admin_shares_v2_client.share_network_id = ( | 
 | 1140 |                 admin_share_network_id) | 
 | 1141 |  | 
 | 1142 |             alt_share_network_id = cls.provide_share_network( | 
 | 1143 |                 cls.alt_shares_v2_client, cls.os_alt.networks_client) | 
 | 1144 |             cls.alt_shares_client.share_network_id = alt_share_network_id | 
 | 1145 |             cls.alt_shares_v2_client.share_network_id = alt_share_network_id | 
| haobing1 | 01c7fee | 2018-03-09 16:33:00 +0800 | [diff] [blame] | 1146 |             resource = { | 
 | 1147 |                 "type": "share_network", | 
 | 1148 |                 "id": alt_share_network_id, | 
 | 1149 |                 "client": cls.alt_shares_v2_client, | 
 | 1150 |             } | 
 | 1151 |             cls.class_resources.insert(0, resource) | 
| Victoria Martinez de la Cruz | f6bc6fa | 2018-02-01 11:27:00 -0500 | [diff] [blame] | 1152 |  | 
 | 1153 |     @classmethod | 
 | 1154 |     def _create_share_type(cls, specs=None): | 
 | 1155 |         name = data_utils.rand_name("unique_st_name") | 
 | 1156 |         extra_specs = cls.add_extra_specs_to_dict(specs) | 
 | 1157 |         return cls.create_share_type( | 
 | 1158 |             name, extra_specs=extra_specs, | 
 | 1159 |             client=cls.admin_shares_v2_client)['share_type'] | 
 | 1160 |  | 
 | 1161 |     @classmethod | 
 | 1162 |     def _create_share_group_type(cls): | 
 | 1163 |         share_group_type_name = data_utils.rand_name("unique_sgtype_name") | 
 | 1164 |         return cls.create_share_group_type( | 
 | 1165 |             name=share_group_type_name, share_types=[cls.share_type_id], | 
 | 1166 |             client=cls.admin_shares_v2_client) |