| 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, | 
| Raissa Sarmento | 7b86b9d | 2017-07-21 14:32:48 +0100 | [diff] [blame] | 180 |             resource_prefix=CONF.resources_prefix, | 
 | 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 | 
 | 293 |  | 
 | 294 |     @classmethod | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 295 |     def resource_setup(cls): | 
 | 296 |         if not (any(p in CONF.share.enable_protocols | 
 | 297 |                     for p in cls.protocols) and | 
 | 298 |                 CONF.service_available.manila): | 
 | 299 |             skip_msg = "Manila is disabled" | 
 | 300 |             raise cls.skipException(skip_msg) | 
 | 301 |         super(BaseSharesTest, cls).resource_setup() | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 302 |  | 
 | 303 |     def setUp(self): | 
 | 304 |         super(BaseSharesTest, self).setUp() | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 305 |         self.addCleanup(self.clear_isolated_creds) | 
| Valeriy Ponomaryov | dd162cb | 2016-01-20 19:09:49 +0200 | [diff] [blame] | 306 |         self.addCleanup(self.clear_resources) | 
| Valeriy Ponomaryov | 2abf5d7 | 2016-06-01 18:30:12 +0300 | [diff] [blame] | 307 |         verify_test_has_appropriate_tags(self) | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 308 |  | 
 | 309 |     @classmethod | 
 | 310 |     def resource_cleanup(cls): | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 311 |         cls.clear_resources(cls.class_resources) | 
 | 312 |         cls.clear_isolated_creds(cls.class_isolated_creds) | 
| Sam Wan | 241029c | 2016-07-26 03:37:42 -0400 | [diff] [blame] | 313 |         super(BaseSharesTest, cls).resource_cleanup() | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 314 |  | 
 | 315 |     @classmethod | 
 | 316 |     @network_synchronized | 
| Valeriy Ponomaryov | 48a2bd7 | 2015-11-05 13:22:44 +0200 | [diff] [blame] | 317 |     def provide_share_network(cls, shares_client, networks_client, | 
| Rodrigo Barbieri | 58d9de3 | 2016-09-06 13:16:47 -0300 | [diff] [blame] | 318 |                               isolated_creds_client=None, | 
 | 319 |                               ignore_multitenancy_config=False): | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 320 |         """Used for finding/creating share network for multitenant driver. | 
 | 321 |  | 
 | 322 |         This method creates/gets entity share-network for one tenant. This | 
 | 323 |         share-network will be used for creation of service vm. | 
 | 324 |  | 
 | 325 |         :param shares_client: shares client, which requires share-network | 
| Valeriy Ponomaryov | 48a2bd7 | 2015-11-05 13:22:44 +0200 | [diff] [blame] | 326 |         :param networks_client: network client from same tenant as shares | 
 | 327 |         :param isolated_creds_client: DynamicCredentialProvider instance | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 328 |             If provided, then its networking will be used if needed. | 
 | 329 |             If not provided, then common network will be used if needed. | 
| Rodrigo Barbieri | 58d9de3 | 2016-09-06 13:16:47 -0300 | [diff] [blame] | 330 |         :param ignore_multitenancy_config: provide a share network regardless | 
 | 331 |             of 'multitenancy_enabled' configuration value. | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 332 |         :returns: str -- share network id for shares_client tenant | 
 | 333 |         :returns: None -- if single-tenant driver used | 
 | 334 |         """ | 
 | 335 |  | 
 | 336 |         sc = shares_client | 
| Valeriy Ponomaryov | c5dae27 | 2016-06-10 18:29:24 +0300 | [diff] [blame] | 337 |         search_word = "reusable" | 
 | 338 |         sn_name = "autogenerated_by_tempest_%s" % search_word | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 339 |  | 
| Rodrigo Barbieri | 58d9de3 | 2016-09-06 13:16:47 -0300 | [diff] [blame] | 340 |         if (not ignore_multitenancy_config and | 
 | 341 |                 not CONF.share.multitenancy_enabled): | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 342 |             # Assumed usage of a single-tenant driver | 
 | 343 |             share_network_id = None | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 344 |         else: | 
| Rodrigo Barbieri | 58d9de3 | 2016-09-06 13:16:47 -0300 | [diff] [blame] | 345 |             if sc.share_network_id: | 
 | 346 |                 # Share-network already exists, use it | 
 | 347 |                 share_network_id = sc.share_network_id | 
 | 348 |             elif not CONF.share.create_networks_when_multitenancy_enabled: | 
 | 349 |                 share_network_id = None | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 350 |  | 
 | 351 |                 # Try get suitable share-network | 
 | 352 |                 share_networks = sc.list_share_networks_with_detail() | 
 | 353 |                 for sn in share_networks: | 
| Rodrigo Barbieri | 58d9de3 | 2016-09-06 13:16:47 -0300 | [diff] [blame] | 354 |                     if (sn["neutron_net_id"] is None and | 
 | 355 |                             sn["neutron_subnet_id"] is None and | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 356 |                             sn["name"] and search_word in sn["name"]): | 
 | 357 |                         share_network_id = sn["id"] | 
 | 358 |                         break | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 359 |  | 
| Rodrigo Barbieri | 58d9de3 | 2016-09-06 13:16:47 -0300 | [diff] [blame] | 360 |                 # Create new share-network if one was not found | 
 | 361 |                 if share_network_id is None: | 
 | 362 |                     sn_desc = "This share-network was created by tempest" | 
 | 363 |                     sn = sc.create_share_network(name=sn_name, | 
 | 364 |                                                  description=sn_desc) | 
 | 365 |                     share_network_id = sn["id"] | 
 | 366 |             else: | 
 | 367 |                 net_id = subnet_id = share_network_id = None | 
 | 368 |  | 
 | 369 |                 if not isolated_creds_client: | 
 | 370 |                     # Search for networks, created in previous runs | 
 | 371 |                     service_net_name = "share-service" | 
 | 372 |                     networks = networks_client.list_networks() | 
 | 373 |                     if "networks" in networks.keys(): | 
 | 374 |                         networks = networks["networks"] | 
 | 375 |                     for network in networks: | 
 | 376 |                         if (service_net_name in network["name"] and | 
 | 377 |                                 sc.tenant_id == network['tenant_id']): | 
 | 378 |                             net_id = network["id"] | 
 | 379 |                             if len(network["subnets"]) > 0: | 
 | 380 |                                 subnet_id = network["subnets"][0] | 
 | 381 |                                 break | 
 | 382 |  | 
 | 383 |                     # Create suitable network | 
 | 384 |                     if net_id is None or subnet_id is None: | 
| Tom Barron | 4b8834a | 2017-02-02 11:02:20 -0500 | [diff] [blame] | 385 |                         ic = cls._get_dynamic_creds(service_net_name) | 
| Rodrigo Barbieri | 58d9de3 | 2016-09-06 13:16:47 -0300 | [diff] [blame] | 386 |                         net_data = ic._create_network_resources(sc.tenant_id) | 
 | 387 |                         network, subnet, router = net_data | 
 | 388 |                         net_id = network["id"] | 
 | 389 |                         subnet_id = subnet["id"] | 
 | 390 |  | 
 | 391 |                     # Try get suitable share-network | 
 | 392 |                     share_networks = sc.list_share_networks_with_detail() | 
 | 393 |                     for sn in share_networks: | 
 | 394 |                         if (net_id == sn["neutron_net_id"] and | 
 | 395 |                                 subnet_id == sn["neutron_subnet_id"] and | 
 | 396 |                                 sn["name"] and search_word in sn["name"]): | 
 | 397 |                             share_network_id = sn["id"] | 
 | 398 |                             break | 
 | 399 |                 else: | 
 | 400 |                     sn_name = "autogenerated_by_tempest_for_isolated_creds" | 
 | 401 |                     # Use precreated network and subnet from isolated creds | 
 | 402 |                     net_id = isolated_creds_client.get_credentials( | 
 | 403 |                         isolated_creds_client.type_of_creds).network['id'] | 
 | 404 |                     subnet_id = isolated_creds_client.get_credentials( | 
 | 405 |                         isolated_creds_client.type_of_creds).subnet['id'] | 
 | 406 |  | 
 | 407 |                 # Create suitable share-network | 
 | 408 |                 if share_network_id is None: | 
 | 409 |                     sn_desc = "This share-network was created by tempest" | 
 | 410 |                     sn = sc.create_share_network(name=sn_name, | 
 | 411 |                                                  description=sn_desc, | 
 | 412 |                                                  neutron_net_id=net_id, | 
 | 413 |                                                  neutron_subnet_id=subnet_id) | 
 | 414 |                     share_network_id = sn["id"] | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 415 |  | 
 | 416 |         return share_network_id | 
 | 417 |  | 
 | 418 |     @classmethod | 
| marcusvrn | e0d7cfd | 2016-06-24 12:27:55 -0300 | [diff] [blame] | 419 |     def _create_share(cls, share_protocol=None, size=None, name=None, | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 420 |                       snapshot_id=None, description=None, metadata=None, | 
 | 421 |                       share_network_id=None, share_type_id=None, | 
| Andrew Kerr | b843692 | 2016-06-01 15:32:43 -0400 | [diff] [blame] | 422 |                       share_group_id=None, client=None, | 
| Clinton Knight | e5c8f09 | 2015-08-27 15:00:23 -0400 | [diff] [blame] | 423 |                       cleanup_in_class=True, is_public=False, **kwargs): | 
| Valeriy Ponomaryov | 1aaa72d | 2015-09-08 12:59:41 +0300 | [diff] [blame] | 424 |         client = client or cls.shares_v2_client | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 425 |         description = description or "Tempest's share" | 
 | 426 |         share_network_id = share_network_id or client.share_network_id or None | 
 | 427 |         metadata = metadata or {} | 
| marcusvrn | e0d7cfd | 2016-06-24 12:27:55 -0300 | [diff] [blame] | 428 |         size = size or CONF.share.share_size | 
| Clinton Knight | e5c8f09 | 2015-08-27 15:00:23 -0400 | [diff] [blame] | 429 |         kwargs.update({ | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 430 |             'share_protocol': share_protocol, | 
 | 431 |             'size': size, | 
 | 432 |             'name': name, | 
 | 433 |             'snapshot_id': snapshot_id, | 
 | 434 |             'description': description, | 
 | 435 |             'metadata': metadata, | 
 | 436 |             'share_network_id': share_network_id, | 
 | 437 |             'share_type_id': share_type_id, | 
 | 438 |             'is_public': is_public, | 
| Clinton Knight | e5c8f09 | 2015-08-27 15:00:23 -0400 | [diff] [blame] | 439 |         }) | 
| Andrew Kerr | b843692 | 2016-06-01 15:32:43 -0400 | [diff] [blame] | 440 |         if share_group_id: | 
 | 441 |             kwargs['share_group_id'] = share_group_id | 
| Andrew Kerr | bf31e91 | 2015-07-29 10:39:38 -0400 | [diff] [blame] | 442 |  | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 443 |         share = client.create_share(**kwargs) | 
| Andrew Kerr | bf31e91 | 2015-07-29 10:39:38 -0400 | [diff] [blame] | 444 |         resource = {"type": "share", "id": share["id"], "client": client, | 
| Andrew Kerr | b843692 | 2016-06-01 15:32:43 -0400 | [diff] [blame] | 445 |                     "share_group_id": share_group_id} | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 446 |         cleanup_list = (cls.class_resources if cleanup_in_class else | 
 | 447 |                         cls.method_resources) | 
 | 448 |         cleanup_list.insert(0, resource) | 
 | 449 |         return share | 
 | 450 |  | 
 | 451 |     @classmethod | 
| Rodrigo Barbieri | 427bc05 | 2016-06-06 17:10:06 -0300 | [diff] [blame] | 452 |     def migrate_share( | 
 | 453 |             cls, share_id, dest_host, wait_for_status, client=None, | 
| Rodrigo Barbieri | 027df98 | 2016-11-24 15:52:03 -0200 | [diff] [blame] | 454 |             force_host_assisted_migration=False, writable=False, | 
 | 455 |             nondisruptive=False, preserve_metadata=False, | 
 | 456 |             preserve_snapshots=False, new_share_network_id=None, | 
| Rodrigo Barbieri | d38d2f5 | 2016-07-19 22:24:56 -0300 | [diff] [blame] | 457 |             new_share_type_id=None, **kwargs): | 
| Clinton Knight | e5c8f09 | 2015-08-27 15:00:23 -0400 | [diff] [blame] | 458 |         client = client or cls.shares_v2_client | 
| Rodrigo Barbieri | 427bc05 | 2016-06-06 17:10:06 -0300 | [diff] [blame] | 459 |         client.migrate_share( | 
 | 460 |             share_id, dest_host, | 
 | 461 |             force_host_assisted_migration=force_host_assisted_migration, | 
| Rodrigo Barbieri | 027df98 | 2016-11-24 15:52:03 -0200 | [diff] [blame] | 462 |             writable=writable, preserve_metadata=preserve_metadata, | 
 | 463 |             nondisruptive=nondisruptive, preserve_snapshots=preserve_snapshots, | 
| Rodrigo Barbieri | 427bc05 | 2016-06-06 17:10:06 -0300 | [diff] [blame] | 464 |             new_share_network_id=new_share_network_id, | 
| Rodrigo Barbieri | d38d2f5 | 2016-07-19 22:24:56 -0300 | [diff] [blame] | 465 |             new_share_type_id=new_share_type_id, **kwargs) | 
| Rodrigo Barbieri | e330512 | 2016-02-03 14:32:24 -0200 | [diff] [blame] | 466 |         share = client.wait_for_migration_status( | 
| Rodrigo Barbieri | 427bc05 | 2016-06-06 17:10:06 -0300 | [diff] [blame] | 467 |             share_id, dest_host, wait_for_status, **kwargs) | 
| Rodrigo Barbieri | e330512 | 2016-02-03 14:32:24 -0200 | [diff] [blame] | 468 |         return share | 
 | 469 |  | 
 | 470 |     @classmethod | 
 | 471 |     def migration_complete(cls, share_id, dest_host, client=None, **kwargs): | 
 | 472 |         client = client or cls.shares_v2_client | 
 | 473 |         client.migration_complete(share_id, **kwargs) | 
 | 474 |         share = client.wait_for_migration_status( | 
| Rodrigo Barbieri | 427bc05 | 2016-06-06 17:10:06 -0300 | [diff] [blame] | 475 |             share_id, dest_host, 'migration_success', **kwargs) | 
| Rodrigo Barbieri | b7137ad | 2015-09-06 22:53:16 -0300 | [diff] [blame] | 476 |         return share | 
 | 477 |  | 
 | 478 |     @classmethod | 
| Rodrigo Barbieri | c9abf28 | 2016-08-24 22:01:31 -0300 | [diff] [blame] | 479 |     def migration_cancel(cls, share_id, dest_host, client=None, **kwargs): | 
 | 480 |         client = client or cls.shares_v2_client | 
 | 481 |         client.migration_cancel(share_id, **kwargs) | 
 | 482 |         share = client.wait_for_migration_status( | 
 | 483 |             share_id, dest_host, 'migration_cancelled', **kwargs) | 
 | 484 |         return share | 
 | 485 |  | 
 | 486 |     @classmethod | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 487 |     def create_share(cls, *args, **kwargs): | 
 | 488 |         """Create one share and wait for available state. Retry if allowed.""" | 
 | 489 |         result = cls.create_shares([{"args": args, "kwargs": kwargs}]) | 
 | 490 |         return result[0] | 
 | 491 |  | 
 | 492 |     @classmethod | 
 | 493 |     def create_shares(cls, share_data_list): | 
 | 494 |         """Creates several shares in parallel with retries. | 
 | 495 |  | 
 | 496 |         Use this method when you want to create more than one share at same | 
 | 497 |         time. Especially if config option 'share.share_creation_retry_number' | 
 | 498 |         has value more than zero (0). | 
 | 499 |         All shares will be expected to have 'available' status with or without | 
 | 500 |         recreation else error will be raised. | 
 | 501 |  | 
 | 502 |         :param share_data_list: list -- list of dictionaries with 'args' and | 
 | 503 |             'kwargs' for '_create_share' method of this base class. | 
 | 504 |             example of data: | 
 | 505 |                 share_data_list=[{'args': ['quuz'], 'kwargs': {'foo': 'bar'}}}] | 
 | 506 |         :returns: list -- list of shares created using provided data. | 
 | 507 |         """ | 
 | 508 |  | 
| Valeriy Ponomaryov | 39cdf72 | 2016-05-30 18:16:15 +0300 | [diff] [blame] | 509 |         for d in share_data_list: | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 510 |             if not isinstance(d, dict): | 
 | 511 |                 raise exceptions.TempestException( | 
 | 512 |                     "Expected 'dict', got '%s'" % type(d)) | 
 | 513 |             if "args" not in d: | 
 | 514 |                 d["args"] = [] | 
 | 515 |             if "kwargs" not in d: | 
 | 516 |                 d["kwargs"] = {} | 
 | 517 |             if len(d) > 2: | 
 | 518 |                 raise exceptions.TempestException( | 
 | 519 |                     "Expected only 'args' and 'kwargs' keys. " | 
 | 520 |                     "Provided %s" % list(d)) | 
| Valeriy Ponomaryov | 39cdf72 | 2016-05-30 18:16:15 +0300 | [diff] [blame] | 521 |  | 
 | 522 |         data = [] | 
 | 523 |         for d in share_data_list: | 
 | 524 |             client = d["kwargs"].pop("client", cls.shares_v2_client) | 
| yogesh | db32f46 | 2016-09-28 15:09:50 -0400 | [diff] [blame] | 525 |             wait_for_status = d["kwargs"].pop("wait_for_status", True) | 
| Valeriy Ponomaryov | 39cdf72 | 2016-05-30 18:16:15 +0300 | [diff] [blame] | 526 |             local_d = { | 
 | 527 |                 "args": d["args"], | 
 | 528 |                 "kwargs": copy.deepcopy(d["kwargs"]), | 
 | 529 |             } | 
 | 530 |             local_d["kwargs"]["client"] = client | 
 | 531 |             local_d["share"] = cls._create_share( | 
 | 532 |                 *local_d["args"], **local_d["kwargs"]) | 
 | 533 |             local_d["cnt"] = 0 | 
 | 534 |             local_d["available"] = False | 
| yogesh | db32f46 | 2016-09-28 15:09:50 -0400 | [diff] [blame] | 535 |             local_d["wait_for_status"] = wait_for_status | 
| Valeriy Ponomaryov | 39cdf72 | 2016-05-30 18:16:15 +0300 | [diff] [blame] | 536 |             data.append(local_d) | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 537 |  | 
 | 538 |         while not all(d["available"] for d in data): | 
 | 539 |             for d in data: | 
| yogesh | db32f46 | 2016-09-28 15:09:50 -0400 | [diff] [blame] | 540 |                 if not d["wait_for_status"]: | 
 | 541 |                     d["available"] = True | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 542 |                 if d["available"]: | 
 | 543 |                     continue | 
| Valeriy Ponomaryov | 1a3e338 | 2016-06-08 15:17:16 +0300 | [diff] [blame] | 544 |                 client = d["kwargs"]["client"] | 
 | 545 |                 share_id = d["share"]["id"] | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 546 |                 try: | 
| Valeriy Ponomaryov | 1a3e338 | 2016-06-08 15:17:16 +0300 | [diff] [blame] | 547 |                     client.wait_for_share_status(share_id, "available") | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 548 |                     d["available"] = True | 
 | 549 |                 except (share_exceptions.ShareBuildErrorException, | 
 | 550 |                         exceptions.TimeoutException) as e: | 
 | 551 |                     if CONF.share.share_creation_retry_number > d["cnt"]: | 
 | 552 |                         d["cnt"] += 1 | 
 | 553 |                         msg = ("Share '%s' failed to be built. " | 
| Valeriy Ponomaryov | 1a3e338 | 2016-06-08 15:17:16 +0300 | [diff] [blame] | 554 |                                "Trying create another." % share_id) | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 555 |                         LOG.error(msg) | 
 | 556 |                         LOG.error(e) | 
| Valeriy Ponomaryov | 1a3e338 | 2016-06-08 15:17:16 +0300 | [diff] [blame] | 557 |                         cg_id = d["kwargs"].get("consistency_group_id") | 
 | 558 |                         if cg_id: | 
 | 559 |                             # NOTE(vponomaryov): delete errored share | 
 | 560 |                             # immediately in case share is part of CG. | 
 | 561 |                             client.delete_share( | 
 | 562 |                                 share_id, | 
 | 563 |                                 params={"consistency_group_id": cg_id}) | 
 | 564 |                             client.wait_for_resource_deletion( | 
 | 565 |                                 share_id=share_id) | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 566 |                         d["share"] = cls._create_share( | 
 | 567 |                             *d["args"], **d["kwargs"]) | 
 | 568 |                     else: | 
| gecong1973 | 5866380 | 2016-08-25 11:08:45 +0800 | [diff] [blame] | 569 |                         raise | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 570 |  | 
 | 571 |         return [d["share"] for d in data] | 
 | 572 |  | 
 | 573 |     @classmethod | 
| Andrew Kerr | b843692 | 2016-06-01 15:32:43 -0400 | [diff] [blame] | 574 |     def create_share_group(cls, client=None, cleanup_in_class=True, | 
 | 575 |                            share_network_id=None, **kwargs): | 
| Clinton Knight | e5c8f09 | 2015-08-27 15:00:23 -0400 | [diff] [blame] | 576 |         client = client or cls.shares_v2_client | 
| Andrew Kerr | b843692 | 2016-06-01 15:32:43 -0400 | [diff] [blame] | 577 |         if kwargs.get('source_share_group_snapshot_id') is None: | 
| Goutham Pacha Ravi | 9221f5e | 2016-04-21 13:17:49 -0400 | [diff] [blame] | 578 |             kwargs['share_network_id'] = (share_network_id or | 
 | 579 |                                           client.share_network_id or None) | 
| Andrew Kerr | b843692 | 2016-06-01 15:32:43 -0400 | [diff] [blame] | 580 |         share_group = client.create_share_group(**kwargs) | 
| Andrew Kerr | bf31e91 | 2015-07-29 10:39:38 -0400 | [diff] [blame] | 581 |         resource = { | 
| Andrew Kerr | b843692 | 2016-06-01 15:32:43 -0400 | [diff] [blame] | 582 |             "type": "share_group", | 
 | 583 |             "id": share_group["id"], | 
 | 584 |             "client": client, | 
 | 585 |         } | 
| Andrew Kerr | bf31e91 | 2015-07-29 10:39:38 -0400 | [diff] [blame] | 586 |         if cleanup_in_class: | 
 | 587 |             cls.class_resources.insert(0, resource) | 
 | 588 |         else: | 
 | 589 |             cls.method_resources.insert(0, resource) | 
 | 590 |  | 
| Andrew Kerr | b843692 | 2016-06-01 15:32:43 -0400 | [diff] [blame] | 591 |         if kwargs.get('source_share_group_snapshot_id'): | 
 | 592 |             new_share_group_shares = client.list_shares( | 
| Andrew Kerr | bf31e91 | 2015-07-29 10:39:38 -0400 | [diff] [blame] | 593 |                 detailed=True, | 
| Andrew Kerr | b843692 | 2016-06-01 15:32:43 -0400 | [diff] [blame] | 594 |                 params={'share_group_id': share_group['id']}, | 
 | 595 |                 experimental=True) | 
| Andrew Kerr | bf31e91 | 2015-07-29 10:39:38 -0400 | [diff] [blame] | 596 |  | 
| Andrew Kerr | b843692 | 2016-06-01 15:32:43 -0400 | [diff] [blame] | 597 |             for share in new_share_group_shares: | 
| Andrew Kerr | bf31e91 | 2015-07-29 10:39:38 -0400 | [diff] [blame] | 598 |                 resource = {"type": "share", | 
 | 599 |                             "id": share["id"], | 
 | 600 |                             "client": client, | 
| Andrew Kerr | b843692 | 2016-06-01 15:32:43 -0400 | [diff] [blame] | 601 |                             "share_group_id": share.get("share_group_id")} | 
| Andrew Kerr | bf31e91 | 2015-07-29 10:39:38 -0400 | [diff] [blame] | 602 |                 if cleanup_in_class: | 
 | 603 |                     cls.class_resources.insert(0, resource) | 
 | 604 |                 else: | 
 | 605 |                     cls.method_resources.insert(0, resource) | 
 | 606 |  | 
| Andrew Kerr | b843692 | 2016-06-01 15:32:43 -0400 | [diff] [blame] | 607 |         client.wait_for_share_group_status(share_group['id'], 'available') | 
 | 608 |         return share_group | 
 | 609 |  | 
 | 610 |     @classmethod | 
 | 611 |     def create_share_group_type(cls, name=None, share_types=(), is_public=None, | 
 | 612 |                                 group_specs=None, client=None, | 
 | 613 |                                 cleanup_in_class=True, **kwargs): | 
 | 614 |         client = client or cls.shares_v2_client | 
| Valeriy Ponomaryov | e92f09f | 2017-03-16 17:25:47 +0300 | [diff] [blame] | 615 |         if (group_specs is None and | 
 | 616 |                 CONF.share.capability_sg_consistent_snapshot_support): | 
| Valeriy Ponomaryov | 3c18893 | 2017-03-15 19:06:23 +0300 | [diff] [blame] | 617 |             group_specs = { | 
 | 618 |                 'consistent_snapshot_support': ( | 
 | 619 |                     CONF.share.capability_sg_consistent_snapshot_support), | 
 | 620 |             } | 
| Andrew Kerr | b843692 | 2016-06-01 15:32:43 -0400 | [diff] [blame] | 621 |         share_group_type = client.create_share_group_type( | 
 | 622 |             name=name, | 
 | 623 |             share_types=share_types, | 
 | 624 |             is_public=is_public, | 
 | 625 |             group_specs=group_specs, | 
 | 626 |             **kwargs) | 
 | 627 |         resource = { | 
 | 628 |             "type": "share_group_type", | 
 | 629 |             "id": share_group_type["id"], | 
 | 630 |             "client": client, | 
 | 631 |         } | 
 | 632 |         if cleanup_in_class: | 
 | 633 |             cls.class_resources.insert(0, resource) | 
 | 634 |         else: | 
 | 635 |             cls.method_resources.insert(0, resource) | 
 | 636 |         return share_group_type | 
| Andrew Kerr | bf31e91 | 2015-07-29 10:39:38 -0400 | [diff] [blame] | 637 |  | 
 | 638 |     @classmethod | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 639 |     def create_snapshot_wait_for_active(cls, share_id, name=None, | 
 | 640 |                                         description=None, force=False, | 
 | 641 |                                         client=None, cleanup_in_class=True): | 
 | 642 |         if client is None: | 
| Yogesh | 1f931ff | 2015-09-29 23:41:02 -0400 | [diff] [blame] | 643 |             client = cls.shares_v2_client | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 644 |         if description is None: | 
 | 645 |             description = "Tempest's snapshot" | 
 | 646 |         snapshot = client.create_snapshot(share_id, name, description, force) | 
 | 647 |         resource = { | 
 | 648 |             "type": "snapshot", | 
 | 649 |             "id": snapshot["id"], | 
 | 650 |             "client": client, | 
 | 651 |         } | 
 | 652 |         if cleanup_in_class: | 
 | 653 |             cls.class_resources.insert(0, resource) | 
 | 654 |         else: | 
 | 655 |             cls.method_resources.insert(0, resource) | 
 | 656 |         client.wait_for_snapshot_status(snapshot["id"], "available") | 
 | 657 |         return snapshot | 
 | 658 |  | 
 | 659 |     @classmethod | 
| Andrew Kerr | b843692 | 2016-06-01 15:32:43 -0400 | [diff] [blame] | 660 |     def create_share_group_snapshot_wait_for_active( | 
 | 661 |             cls, share_group_id, name=None, description=None, client=None, | 
 | 662 |             cleanup_in_class=True, **kwargs): | 
| Clinton Knight | e5c8f09 | 2015-08-27 15:00:23 -0400 | [diff] [blame] | 663 |         client = client or cls.shares_v2_client | 
| Andrew Kerr | bf31e91 | 2015-07-29 10:39:38 -0400 | [diff] [blame] | 664 |         if description is None: | 
| Andrew Kerr | b843692 | 2016-06-01 15:32:43 -0400 | [diff] [blame] | 665 |             description = "Tempest's share group snapshot" | 
 | 666 |         sg_snapshot = client.create_share_group_snapshot( | 
 | 667 |             share_group_id, name=name, description=description, **kwargs) | 
| Andrew Kerr | bf31e91 | 2015-07-29 10:39:38 -0400 | [diff] [blame] | 668 |         resource = { | 
| Andrew Kerr | b843692 | 2016-06-01 15:32:43 -0400 | [diff] [blame] | 669 |             "type": "share_group_snapshot", | 
 | 670 |             "id": sg_snapshot["id"], | 
| Andrew Kerr | bf31e91 | 2015-07-29 10:39:38 -0400 | [diff] [blame] | 671 |             "client": client, | 
 | 672 |         } | 
 | 673 |         if cleanup_in_class: | 
 | 674 |             cls.class_resources.insert(0, resource) | 
 | 675 |         else: | 
 | 676 |             cls.method_resources.insert(0, resource) | 
| Andrew Kerr | b843692 | 2016-06-01 15:32:43 -0400 | [diff] [blame] | 677 |         client.wait_for_share_group_snapshot_status( | 
 | 678 |             sg_snapshot["id"], "available") | 
 | 679 |         return sg_snapshot | 
| Andrew Kerr | bf31e91 | 2015-07-29 10:39:38 -0400 | [diff] [blame] | 680 |  | 
 | 681 |     @classmethod | 
| Yogesh | bdb8810 | 2015-09-29 23:41:02 -0400 | [diff] [blame] | 682 |     def get_availability_zones(cls, client=None): | 
 | 683 |         """List the availability zones for "manila-share" services | 
 | 684 |  | 
 | 685 |          that are currently in "up" state. | 
 | 686 |          """ | 
 | 687 |         client = client or cls.shares_v2_client | 
 | 688 |         cls.services = client.list_services() | 
 | 689 |         zones = [service['zone'] for service in cls.services if | 
 | 690 |                  service['binary'] == "manila-share" and | 
 | 691 |                  service['state'] == 'up'] | 
 | 692 |         return zones | 
 | 693 |  | 
| Yogesh | 1f931ff | 2015-09-29 23:41:02 -0400 | [diff] [blame] | 694 |     def get_pools_for_replication_domain(self): | 
 | 695 |         # Get the list of pools for the replication domain | 
 | 696 |         pools = self.admin_client.list_pools(detail=True)['pools'] | 
| Ben Swartzlander | 7150c65 | 2017-02-13 22:31:18 -0500 | [diff] [blame] | 697 |         instance_host = self.admin_client.get_share( | 
 | 698 |             self.shares[0]['id'])['host'] | 
| Yogesh | 1f931ff | 2015-09-29 23:41:02 -0400 | [diff] [blame] | 699 |         host_pool = [p for p in pools if p['name'] == instance_host][0] | 
 | 700 |         rep_domain = host_pool['capabilities']['replication_domain'] | 
 | 701 |         pools_in_rep_domain = [p for p in pools if p['capabilities'][ | 
 | 702 |             'replication_domain'] == rep_domain] | 
 | 703 |         return rep_domain, pools_in_rep_domain | 
 | 704 |  | 
| Yogesh | bdb8810 | 2015-09-29 23:41:02 -0400 | [diff] [blame] | 705 |     @classmethod | 
 | 706 |     def create_share_replica(cls, share_id, availability_zone, client=None, | 
 | 707 |                              cleanup_in_class=False, cleanup=True): | 
 | 708 |         client = client or cls.shares_v2_client | 
 | 709 |         replica = client.create_share_replica(share_id, availability_zone) | 
 | 710 |         resource = { | 
 | 711 |             "type": "share_replica", | 
 | 712 |             "id": replica["id"], | 
 | 713 |             "client": client, | 
 | 714 |             "share_id": share_id, | 
 | 715 |         } | 
 | 716 |         # NOTE(Yogi1): Cleanup needs to be disabled during promotion tests. | 
 | 717 |         if cleanup: | 
 | 718 |             if cleanup_in_class: | 
 | 719 |                 cls.class_resources.insert(0, resource) | 
 | 720 |             else: | 
 | 721 |                 cls.method_resources.insert(0, resource) | 
 | 722 |         client.wait_for_share_replica_status( | 
 | 723 |             replica["id"], constants.STATUS_AVAILABLE) | 
 | 724 |         return replica | 
 | 725 |  | 
 | 726 |     @classmethod | 
 | 727 |     def delete_share_replica(cls, replica_id, client=None): | 
 | 728 |         client = client or cls.shares_v2_client | 
| Yogesh | 1f931ff | 2015-09-29 23:41:02 -0400 | [diff] [blame] | 729 |         try: | 
 | 730 |             client.delete_share_replica(replica_id) | 
 | 731 |             client.wait_for_resource_deletion(replica_id=replica_id) | 
 | 732 |         except exceptions.NotFound: | 
 | 733 |             pass | 
| Yogesh | bdb8810 | 2015-09-29 23:41:02 -0400 | [diff] [blame] | 734 |  | 
 | 735 |     @classmethod | 
 | 736 |     def promote_share_replica(cls, replica_id, client=None): | 
 | 737 |         client = client or cls.shares_v2_client | 
 | 738 |         replica = client.promote_share_replica(replica_id) | 
 | 739 |         client.wait_for_share_replica_status( | 
 | 740 |             replica["id"], | 
 | 741 |             constants.REPLICATION_STATE_ACTIVE, | 
 | 742 |             status_attr="replica_state") | 
 | 743 |         return replica | 
 | 744 |  | 
| yogesh | db32f46 | 2016-09-28 15:09:50 -0400 | [diff] [blame] | 745 |     def _get_access_rule_data_from_config(self): | 
 | 746 |         """Get the first available access type/to combination from config. | 
 | 747 |  | 
 | 748 |         This method opportunistically picks the first configured protocol | 
 | 749 |         to create the share. Do not use this method in tests where you need | 
 | 750 |         to test depth and breadth in the access types and access recipients. | 
 | 751 |         """ | 
 | 752 |         protocol = self.shares_v2_client.share_protocol | 
 | 753 |  | 
 | 754 |         if protocol in CONF.share.enable_ip_rules_for_protocols: | 
 | 755 |             access_type = "ip" | 
 | 756 |             access_to = utils.rand_ip() | 
 | 757 |         elif protocol in CONF.share.enable_user_rules_for_protocols: | 
 | 758 |             access_type = "user" | 
 | 759 |             access_to = CONF.share.username_for_user_rules | 
 | 760 |         elif protocol in CONF.share.enable_cert_rules_for_protocols: | 
 | 761 |             access_type = "cert" | 
 | 762 |             access_to = "client3.com" | 
 | 763 |         elif protocol in CONF.share.enable_cephx_rules_for_protocols: | 
 | 764 |             access_type = "cephx" | 
 | 765 |             access_to = "eve" | 
 | 766 |         else: | 
 | 767 |             message = "Unrecognized protocol and access rules configuration." | 
 | 768 |             raise self.skipException(message) | 
 | 769 |  | 
 | 770 |         return access_type, access_to | 
 | 771 |  | 
| Yogesh | bdb8810 | 2015-09-29 23:41:02 -0400 | [diff] [blame] | 772 |     @classmethod | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 773 |     def create_share_network(cls, client=None, | 
 | 774 |                              cleanup_in_class=False, **kwargs): | 
 | 775 |         if client is None: | 
 | 776 |             client = cls.shares_client | 
 | 777 |         share_network = client.create_share_network(**kwargs) | 
 | 778 |         resource = { | 
 | 779 |             "type": "share_network", | 
 | 780 |             "id": share_network["id"], | 
 | 781 |             "client": client, | 
 | 782 |         } | 
 | 783 |         if cleanup_in_class: | 
 | 784 |             cls.class_resources.insert(0, resource) | 
 | 785 |         else: | 
 | 786 |             cls.method_resources.insert(0, resource) | 
 | 787 |         return share_network | 
 | 788 |  | 
 | 789 |     @classmethod | 
 | 790 |     def create_security_service(cls, ss_type="ldap", client=None, | 
 | 791 |                                 cleanup_in_class=False, **kwargs): | 
 | 792 |         if client is None: | 
 | 793 |             client = cls.shares_client | 
 | 794 |         security_service = client.create_security_service(ss_type, **kwargs) | 
 | 795 |         resource = { | 
 | 796 |             "type": "security_service", | 
 | 797 |             "id": security_service["id"], | 
 | 798 |             "client": client, | 
 | 799 |         } | 
 | 800 |         if cleanup_in_class: | 
 | 801 |             cls.class_resources.insert(0, resource) | 
 | 802 |         else: | 
 | 803 |             cls.method_resources.insert(0, resource) | 
 | 804 |         return security_service | 
 | 805 |  | 
 | 806 |     @classmethod | 
 | 807 |     def create_share_type(cls, name, is_public=True, client=None, | 
 | 808 |                           cleanup_in_class=True, **kwargs): | 
 | 809 |         if client is None: | 
| Valeriy Ponomaryov | a14c225 | 2015-10-29 13:34:32 +0200 | [diff] [blame] | 810 |             client = cls.shares_v2_client | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 811 |         share_type = client.create_share_type(name, is_public, **kwargs) | 
 | 812 |         resource = { | 
 | 813 |             "type": "share_type", | 
 | 814 |             "id": share_type["share_type"]["id"], | 
 | 815 |             "client": client, | 
 | 816 |         } | 
 | 817 |         if cleanup_in_class: | 
 | 818 |             cls.class_resources.insert(0, resource) | 
 | 819 |         else: | 
 | 820 |             cls.method_resources.insert(0, resource) | 
 | 821 |         return share_type | 
 | 822 |  | 
 | 823 |     @staticmethod | 
| Clinton Knight | 4699a8c | 2016-08-16 22:36:13 -0400 | [diff] [blame] | 824 |     def add_extra_specs_to_dict(extra_specs=None): | 
 | 825 |         """Add any required extra-specs to share type dictionary""" | 
| Valeriy Ponomaryov | ad55dc5 | 2015-09-23 13:54:00 +0300 | [diff] [blame] | 826 |         dhss = six.text_type(CONF.share.multitenancy_enabled) | 
 | 827 |         snapshot_support = six.text_type( | 
 | 828 |             CONF.share.capability_snapshot_support) | 
| Clinton Knight | 4699a8c | 2016-08-16 22:36:13 -0400 | [diff] [blame] | 829 |         create_from_snapshot_support = six.text_type( | 
 | 830 |             CONF.share.capability_create_share_from_snapshot_support) | 
 | 831 |  | 
 | 832 |         extra_specs_dict = { | 
| Valeriy Ponomaryov | ad55dc5 | 2015-09-23 13:54:00 +0300 | [diff] [blame] | 833 |             "driver_handles_share_servers": dhss, | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 834 |         } | 
| Clinton Knight | 4699a8c | 2016-08-16 22:36:13 -0400 | [diff] [blame] | 835 |  | 
 | 836 |         optional = { | 
 | 837 |             "snapshot_support": snapshot_support, | 
 | 838 |             "create_share_from_snapshot_support": create_from_snapshot_support, | 
 | 839 |         } | 
 | 840 |         # NOTE(gouthamr): In micro-versions < 2.24, snapshot_support is a | 
 | 841 |         # required extra-spec | 
 | 842 |         extra_specs_dict.update(optional) | 
 | 843 |  | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 844 |         if extra_specs: | 
| Clinton Knight | 4699a8c | 2016-08-16 22:36:13 -0400 | [diff] [blame] | 845 |             extra_specs_dict.update(extra_specs) | 
 | 846 |  | 
 | 847 |         return extra_specs_dict | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 848 |  | 
 | 849 |     @classmethod | 
 | 850 |     def clear_isolated_creds(cls, creds=None): | 
 | 851 |         if creds is None: | 
 | 852 |             creds = cls.method_isolated_creds | 
 | 853 |         for ic in creds: | 
 | 854 |             if "deleted" not in ic.keys(): | 
 | 855 |                 ic["deleted"] = False | 
 | 856 |             if not ic["deleted"]: | 
 | 857 |                 with handle_cleanup_exceptions(): | 
 | 858 |                     ic["method"]() | 
 | 859 |                 ic["deleted"] = True | 
 | 860 |  | 
 | 861 |     @classmethod | 
| Yogesh | 1f931ff | 2015-09-29 23:41:02 -0400 | [diff] [blame] | 862 |     def clear_share_replicas(cls, share_id, client=None): | 
 | 863 |         client = client or cls.shares_v2_client | 
 | 864 |         share_replicas = client.list_share_replicas( | 
 | 865 |             share_id=share_id) | 
 | 866 |  | 
 | 867 |         for replica in share_replicas: | 
 | 868 |             try: | 
 | 869 |                 cls.delete_share_replica(replica['id']) | 
 | 870 |             except exceptions.BadRequest: | 
 | 871 |                 # Ignore the exception due to deletion of last active replica | 
 | 872 |                 pass | 
 | 873 |  | 
 | 874 |     @classmethod | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 875 |     def clear_resources(cls, resources=None): | 
 | 876 |         """Deletes resources, that were created in test suites. | 
 | 877 |  | 
 | 878 |         This method tries to remove resources from resource list, | 
 | 879 |         if it is not found, assumed it was deleted in test itself. | 
 | 880 |         It is expected, that all resources were added as LIFO | 
 | 881 |         due to restriction of deletion resources, that is in the chain. | 
 | 882 |  | 
 | 883 |         :param resources: dict with keys 'type','id','client' and 'deleted' | 
 | 884 |         """ | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 885 |         if resources is None: | 
 | 886 |             resources = cls.method_resources | 
 | 887 |         for res in resources: | 
 | 888 |             if "deleted" not in res.keys(): | 
 | 889 |                 res["deleted"] = False | 
 | 890 |             if "client" not in res.keys(): | 
 | 891 |                 res["client"] = cls.shares_client | 
 | 892 |             if not(res["deleted"]): | 
 | 893 |                 res_id = res['id'] | 
 | 894 |                 client = res["client"] | 
 | 895 |                 with handle_cleanup_exceptions(): | 
 | 896 |                     if res["type"] is "share": | 
| Yogesh | 1f931ff | 2015-09-29 23:41:02 -0400 | [diff] [blame] | 897 |                         cls.clear_share_replicas(res_id) | 
| Andrew Kerr | b843692 | 2016-06-01 15:32:43 -0400 | [diff] [blame] | 898 |                         share_group_id = res.get('share_group_id') | 
 | 899 |                         if share_group_id: | 
 | 900 |                             params = {'share_group_id': share_group_id} | 
| Clinton Knight | e5c8f09 | 2015-08-27 15:00:23 -0400 | [diff] [blame] | 901 |                             client.delete_share(res_id, params=params) | 
 | 902 |                         else: | 
 | 903 |                             client.delete_share(res_id) | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 904 |                         client.wait_for_resource_deletion(share_id=res_id) | 
 | 905 |                     elif res["type"] is "snapshot": | 
 | 906 |                         client.delete_snapshot(res_id) | 
 | 907 |                         client.wait_for_resource_deletion(snapshot_id=res_id) | 
 | 908 |                     elif res["type"] is "share_network": | 
 | 909 |                         client.delete_share_network(res_id) | 
 | 910 |                         client.wait_for_resource_deletion(sn_id=res_id) | 
 | 911 |                     elif res["type"] is "security_service": | 
 | 912 |                         client.delete_security_service(res_id) | 
 | 913 |                         client.wait_for_resource_deletion(ss_id=res_id) | 
 | 914 |                     elif res["type"] is "share_type": | 
 | 915 |                         client.delete_share_type(res_id) | 
 | 916 |                         client.wait_for_resource_deletion(st_id=res_id) | 
| Andrew Kerr | b843692 | 2016-06-01 15:32:43 -0400 | [diff] [blame] | 917 |                     elif res["type"] is "share_group": | 
 | 918 |                         client.delete_share_group(res_id) | 
 | 919 |                         client.wait_for_resource_deletion( | 
 | 920 |                             share_group_id=res_id) | 
 | 921 |                     elif res["type"] is "share_group_type": | 
 | 922 |                         client.delete_share_group_type(res_id) | 
 | 923 |                         client.wait_for_resource_deletion( | 
 | 924 |                             share_group_type_id=res_id) | 
 | 925 |                     elif res["type"] is "share_group_snapshot": | 
 | 926 |                         client.delete_share_group_snapshot(res_id) | 
 | 927 |                         client.wait_for_resource_deletion( | 
 | 928 |                             share_group_snapshot_id=res_id) | 
| Yogesh | bdb8810 | 2015-09-29 23:41:02 -0400 | [diff] [blame] | 929 |                     elif res["type"] is "share_replica": | 
 | 930 |                         client.delete_share_replica(res_id) | 
 | 931 |                         client.wait_for_resource_deletion(replica_id=res_id) | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 932 |                     else: | 
| huayue | 97bacbf | 2016-01-04 09:57:39 +0800 | [diff] [blame] | 933 |                         LOG.warning("Provided unsupported resource type for " | 
| junboli | b236c24 | 2017-07-18 18:12:37 +0800 | [diff] [blame] | 934 |                                     "cleanup '%s'. Skipping.", res["type"]) | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 935 |                 res["deleted"] = True | 
 | 936 |  | 
 | 937 |     @classmethod | 
 | 938 |     def generate_share_network_data(self): | 
 | 939 |         data = { | 
 | 940 |             "name": data_utils.rand_name("sn-name"), | 
 | 941 |             "description": data_utils.rand_name("sn-desc"), | 
 | 942 |             "neutron_net_id": data_utils.rand_name("net-id"), | 
 | 943 |             "neutron_subnet_id": data_utils.rand_name("subnet-id"), | 
 | 944 |         } | 
 | 945 |         return data | 
 | 946 |  | 
 | 947 |     @classmethod | 
 | 948 |     def generate_security_service_data(self): | 
 | 949 |         data = { | 
 | 950 |             "name": data_utils.rand_name("ss-name"), | 
 | 951 |             "description": data_utils.rand_name("ss-desc"), | 
| Valeriy Ponomaryov | fcde771 | 2015-12-14 18:06:13 +0200 | [diff] [blame] | 952 |             "dns_ip": utils.rand_ip(), | 
 | 953 |             "server": utils.rand_ip(), | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 954 |             "domain": data_utils.rand_name("ss-domain"), | 
 | 955 |             "user": data_utils.rand_name("ss-user"), | 
 | 956 |             "password": data_utils.rand_name("ss-password"), | 
 | 957 |         } | 
 | 958 |         return data | 
 | 959 |  | 
 | 960 |     # Useful assertions | 
 | 961 |     def assertDictMatch(self, d1, d2, approx_equal=False, tolerance=0.001): | 
 | 962 |         """Assert two dicts are equivalent. | 
 | 963 |  | 
 | 964 |         This is a 'deep' match in the sense that it handles nested | 
 | 965 |         dictionaries appropriately. | 
 | 966 |  | 
 | 967 |         NOTE: | 
 | 968 |  | 
 | 969 |             If you don't care (or don't know) a given value, you can specify | 
 | 970 |             the string DONTCARE as the value. This will cause that dict-item | 
 | 971 |             to be skipped. | 
 | 972 |  | 
 | 973 |         """ | 
 | 974 |         def raise_assertion(msg): | 
 | 975 |             d1str = str(d1) | 
 | 976 |             d2str = str(d2) | 
 | 977 |             base_msg = ('Dictionaries do not match. %(msg)s d1: %(d1str)s ' | 
 | 978 |                         'd2: %(d2str)s' % | 
 | 979 |                         {"msg": msg, "d1str": d1str, "d2str": d2str}) | 
 | 980 |             raise AssertionError(base_msg) | 
 | 981 |  | 
 | 982 |         d1keys = set(d1.keys()) | 
 | 983 |         d2keys = set(d2.keys()) | 
 | 984 |         if d1keys != d2keys: | 
 | 985 |             d1only = d1keys - d2keys | 
 | 986 |             d2only = d2keys - d1keys | 
 | 987 |             raise_assertion('Keys in d1 and not d2: %(d1only)s. ' | 
 | 988 |                             'Keys in d2 and not d1: %(d2only)s' % | 
 | 989 |                             {"d1only": d1only, "d2only": d2only}) | 
 | 990 |  | 
 | 991 |         for key in d1keys: | 
 | 992 |             d1value = d1[key] | 
 | 993 |             d2value = d2[key] | 
 | 994 |             try: | 
 | 995 |                 error = abs(float(d1value) - float(d2value)) | 
 | 996 |                 within_tolerance = error <= tolerance | 
 | 997 |             except (ValueError, TypeError): | 
| daiki kato | 6914b1a | 2016-03-16 17:16:57 +0900 | [diff] [blame] | 998 |                 # If both values aren't convertible to float, just ignore | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 999 |                 # ValueError if arg is a str, TypeError if it's something else | 
 | 1000 |                 # (like None) | 
 | 1001 |                 within_tolerance = False | 
 | 1002 |  | 
 | 1003 |             if hasattr(d1value, 'keys') and hasattr(d2value, 'keys'): | 
 | 1004 |                 self.assertDictMatch(d1value, d2value) | 
 | 1005 |             elif 'DONTCARE' in (d1value, d2value): | 
 | 1006 |                 continue | 
 | 1007 |             elif approx_equal and within_tolerance: | 
 | 1008 |                 continue | 
 | 1009 |             elif d1value != d2value: | 
 | 1010 |                 raise_assertion("d1['%(key)s']=%(d1value)s != " | 
 | 1011 |                                 "d2['%(key)s']=%(d2value)s" % | 
 | 1012 |                                 { | 
 | 1013 |                                     "key": key, | 
 | 1014 |                                     "d1value": d1value, | 
 | 1015 |                                     "d2value": d2value | 
 | 1016 |                                 }) | 
 | 1017 |  | 
| Alex Meade | ba8a160 | 2016-05-06 09:33:09 -0400 | [diff] [blame] | 1018 |     def create_user_message(self): | 
 | 1019 |         """Trigger a 'no valid host' situation to generate a message.""" | 
 | 1020 |         extra_specs = { | 
 | 1021 |             'vendor_name': 'foobar', | 
 | 1022 |             'driver_handles_share_servers': CONF.share.multitenancy_enabled, | 
 | 1023 |         } | 
 | 1024 |         share_type_name = data_utils.rand_name("share-type") | 
 | 1025 |  | 
 | 1026 |         bogus_type = self.create_share_type( | 
 | 1027 |             name=share_type_name, | 
 | 1028 |             extra_specs=extra_specs)['share_type'] | 
 | 1029 |  | 
 | 1030 |         params = {'share_type_id': bogus_type['id'], | 
 | 1031 |                   'share_network_id': self.shares_v2_client.share_network_id} | 
 | 1032 |         share = self.shares_v2_client.create_share(**params) | 
 | 1033 |         self.addCleanup(self.shares_v2_client.delete_share, share['id']) | 
 | 1034 |         self.shares_v2_client.wait_for_share_status(share['id'], "error") | 
 | 1035 |         return self.shares_v2_client.wait_for_message(share['id']) | 
 | 1036 |  | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 1037 |  | 
 | 1038 | class BaseSharesAltTest(BaseSharesTest): | 
 | 1039 |     """Base test case class for all Shares Alt API tests.""" | 
| Valeriy Ponomaryov | 39cdf72 | 2016-05-30 18:16:15 +0300 | [diff] [blame] | 1040 |     credentials = ('alt', ) | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 1041 |  | 
 | 1042 |  | 
 | 1043 | class BaseSharesAdminTest(BaseSharesTest): | 
 | 1044 |     """Base test case class for all Shares Admin API tests.""" | 
| Valeriy Ponomaryov | 39cdf72 | 2016-05-30 18:16:15 +0300 | [diff] [blame] | 1045 |     credentials = ('admin', ) | 
 | 1046 |  | 
 | 1047 |  | 
 | 1048 | class BaseSharesMixedTest(BaseSharesTest): | 
 | 1049 |     """Base test case class for all Shares API tests with all user roles.""" | 
 | 1050 |     credentials = ('primary', 'alt', 'admin') | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 1051 |  | 
 | 1052 |     @classmethod | 
| Valeriy Ponomaryov | 39cdf72 | 2016-05-30 18:16:15 +0300 | [diff] [blame] | 1053 |     def setup_clients(cls): | 
 | 1054 |         super(BaseSharesMixedTest, cls).setup_clients() | 
| Andrea Frittoli (andreaf) | 369391a | 2016-06-27 18:59:13 +0100 | [diff] [blame] | 1055 |         # Initialise share clients | 
 | 1056 |         cls.admin_shares_client = cls.os_admin.share_v1.SharesClient() | 
 | 1057 |         cls.admin_shares_v2_client = cls.os_admin.share_v2.SharesV2Client() | 
 | 1058 |         cls.alt_shares_client = cls.os_alt.share_v1.SharesClient() | 
 | 1059 |         cls.alt_shares_v2_client = cls.os_alt.share_v2.SharesV2Client() | 
 | 1060 |         # Initialise network clients | 
 | 1061 |         cls.os_admin.networks_client = cls.os_admin.network.NetworksClient() | 
 | 1062 |         cls.os_alt.networks_client = cls.os_alt.network.NetworksClient() | 
| Valeriy Ponomaryov | 39cdf72 | 2016-05-30 18:16:15 +0300 | [diff] [blame] | 1063 |  | 
 | 1064 |         if CONF.share.multitenancy_enabled: | 
 | 1065 |             admin_share_network_id = cls.provide_share_network( | 
 | 1066 |                 cls.admin_shares_v2_client, cls.os_admin.networks_client) | 
 | 1067 |             cls.admin_shares_client.share_network_id = admin_share_network_id | 
 | 1068 |             cls.admin_shares_v2_client.share_network_id = ( | 
 | 1069 |                 admin_share_network_id) | 
 | 1070 |  | 
 | 1071 |             alt_share_network_id = cls.provide_share_network( | 
 | 1072 |                 cls.alt_shares_v2_client, cls.os_alt.networks_client) | 
 | 1073 |             cls.alt_shares_client.share_network_id = alt_share_network_id | 
 | 1074 |             cls.alt_shares_v2_client.share_network_id = alt_share_network_id |