| 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 | 
| Valeriy Ponomaryov | 48a2bd7 | 2015-11-05 13:22:44 +0200 | [diff] [blame] | 25 | from tempest.common import dynamic_creds | 
 | 26 | from tempest import config | 
| Ben Swartzlander | 1c4ff52 | 2016-03-02 22:16:23 -0500 | [diff] [blame] | 27 | from tempest.lib.common.utils import data_utils | 
 | 28 | from tempest.lib import exceptions | 
| Valeriy Ponomaryov | 48a2bd7 | 2015-11-05 13:22:44 +0200 | [diff] [blame] | 29 | from tempest import test | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 30 |  | 
 | 31 | from manila_tempest_tests import clients_share as clients | 
| Yogesh | bdb8810 | 2015-09-29 23:41:02 -0400 | [diff] [blame] | 32 | from manila_tempest_tests.common import constants | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 33 | from manila_tempest_tests import share_exceptions | 
| Valeriy Ponomaryov | fcde771 | 2015-12-14 18:06:13 +0200 | [diff] [blame] | 34 | from manila_tempest_tests import utils | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 35 |  | 
 | 36 | CONF = config.CONF | 
 | 37 | LOG = log.getLogger(__name__) | 
 | 38 |  | 
| Valeriy Ponomaryov | 2abf5d7 | 2016-06-01 18:30:12 +0300 | [diff] [blame^] | 39 | # Test tags related to test direction | 
 | 40 | TAG_POSITIVE = "positive" | 
 | 41 | TAG_NEGATIVE = "negative" | 
 | 42 |  | 
 | 43 | # Test tags related to service involvement | 
 | 44 | TAG_API = "api" | 
 | 45 | TAG_BACKEND = "backend" | 
 | 46 | TAG_API_WITH_BACKEND = "api_with_backend" | 
 | 47 |  | 
 | 48 | TAGS_MAPPER = { | 
 | 49 |     "p": TAG_POSITIVE, | 
 | 50 |     "n": TAG_NEGATIVE, | 
 | 51 |     "a": TAG_API, | 
 | 52 |     "b": TAG_BACKEND, | 
 | 53 |     "ab": TAG_API_WITH_BACKEND, | 
 | 54 | } | 
 | 55 | TAGS_PATTERN = re.compile( | 
 | 56 |     r"(?=.*\[.*\b(%(p)s|%(n)s)\b.*\])(?=.*\[.*\b(%(a)s|%(b)s|%(ab)s)\b.*\])" % | 
 | 57 |     TAGS_MAPPER) | 
 | 58 |  | 
 | 59 |  | 
 | 60 | def verify_test_has_appropriate_tags(self): | 
 | 61 |     if not TAGS_PATTERN.match(self.id()): | 
 | 62 |         msg = ( | 
 | 63 |             "Required attributes either not set or set improperly. " | 
 | 64 |             "Two test attributes are expected:\n" | 
 | 65 |             " - one of '%(p)s' or '%(n)s' and \n" | 
 | 66 |             " - one of '%(a)s', '%(b)s' or '%(ab)s'." | 
 | 67 |         ) % TAGS_MAPPER | 
 | 68 |         raise self.failureException(msg) | 
 | 69 |  | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 70 |  | 
 | 71 | class handle_cleanup_exceptions(object): | 
 | 72 |     """Handle exceptions raised with cleanup operations. | 
 | 73 |  | 
 | 74 |     Always suppress errors when exceptions.NotFound or exceptions.Forbidden | 
 | 75 |     are raised. | 
 | 76 |     Suppress all other exceptions only in case config opt | 
 | 77 |     'suppress_errors_in_cleanup' in config group 'share' is True. | 
 | 78 |     """ | 
 | 79 |  | 
 | 80 |     def __enter__(self): | 
 | 81 |         return self | 
 | 82 |  | 
 | 83 |     def __exit__(self, exc_type, exc_value, exc_traceback): | 
 | 84 |         if not (isinstance(exc_value, | 
 | 85 |                            (exceptions.NotFound, exceptions.Forbidden)) or | 
 | 86 |                 CONF.share.suppress_errors_in_cleanup): | 
 | 87 |             return False  # Do not suppress error if any | 
 | 88 |         if exc_traceback: | 
 | 89 |             LOG.error("Suppressed cleanup error in Manila: " | 
 | 90 |                       "\n%s" % traceback.format_exc()) | 
 | 91 |         return True  # Suppress error if any | 
 | 92 |  | 
 | 93 |  | 
 | 94 | def network_synchronized(f): | 
 | 95 |  | 
 | 96 |     def wrapped_func(self, *args, **kwargs): | 
 | 97 |         with_isolated_creds = True if len(args) > 2 else False | 
 | 98 |         no_lock_required = kwargs.get( | 
 | 99 |             "isolated_creds_client", with_isolated_creds) | 
 | 100 |         if no_lock_required: | 
 | 101 |             # Usage of not reusable network. No need in lock. | 
 | 102 |             return f(self, *args, **kwargs) | 
 | 103 |  | 
 | 104 |         # Use lock assuming reusage of common network. | 
 | 105 |         @lockutils.synchronized("manila_network_lock", external=True) | 
 | 106 |         def source_func(self, *args, **kwargs): | 
 | 107 |             return f(self, *args, **kwargs) | 
 | 108 |  | 
 | 109 |         return source_func(self, *args, **kwargs) | 
 | 110 |  | 
 | 111 |     return wrapped_func | 
 | 112 |  | 
 | 113 |  | 
| Valeriy Ponomaryov | fcde771 | 2015-12-14 18:06:13 +0200 | [diff] [blame] | 114 | skip_if_microversion_not_supported = utils.skip_if_microversion_not_supported | 
| Xing Yang | 69b00b5 | 2015-11-22 16:10:44 -0500 | [diff] [blame] | 115 | skip_if_microversion_lt = utils.skip_if_microversion_lt | 
| Valeriy Ponomaryov | a14c225 | 2015-10-29 13:34:32 +0200 | [diff] [blame] | 116 |  | 
 | 117 |  | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 118 | class BaseSharesTest(test.BaseTestCase): | 
 | 119 |     """Base test case class for all Manila API tests.""" | 
 | 120 |  | 
 | 121 |     force_tenant_isolation = False | 
| John Spray | 061b145 | 2015-11-18 13:15:32 +0000 | [diff] [blame] | 122 |     protocols = ["nfs", "cifs", "glusterfs", "hdfs", "cephfs"] | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 123 |  | 
 | 124 |     # Will be cleaned up in resource_cleanup | 
 | 125 |     class_resources = [] | 
 | 126 |  | 
 | 127 |     # Will be cleaned up in tearDown method | 
 | 128 |     method_resources = [] | 
 | 129 |  | 
 | 130 |     # Will be cleaned up in resource_cleanup | 
 | 131 |     class_isolated_creds = [] | 
 | 132 |  | 
 | 133 |     # Will be cleaned up in tearDown method | 
 | 134 |     method_isolated_creds = [] | 
 | 135 |  | 
| Valeriy Ponomaryov | a14c225 | 2015-10-29 13:34:32 +0200 | [diff] [blame] | 136 |     def skip_if_microversion_not_supported(self, microversion): | 
| Valeriy Ponomaryov | fcde771 | 2015-12-14 18:06:13 +0200 | [diff] [blame] | 137 |         if not utils.is_microversion_supported(microversion): | 
| Valeriy Ponomaryov | a14c225 | 2015-10-29 13:34:32 +0200 | [diff] [blame] | 138 |             raise self.skipException( | 
 | 139 |                 "Microversion '%s' is not supported." % microversion) | 
 | 140 |  | 
| Xing Yang | 69b00b5 | 2015-11-22 16:10:44 -0500 | [diff] [blame] | 141 |     def skip_if_microversion_lt(self, microversion): | 
 | 142 |         if utils.is_microversion_lt(CONF.share.max_api_microversion, | 
 | 143 |                                     microversion): | 
 | 144 |             raise self.skipException( | 
 | 145 |                 "Microversion must be greater than or equal to '%s'." % | 
 | 146 |                 microversion) | 
 | 147 |  | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 148 |     @classmethod | 
 | 149 |     def get_client_with_isolated_creds(cls, | 
 | 150 |                                        name=None, | 
 | 151 |                                        type_of_creds="admin", | 
| Clinton Knight | e5c8f09 | 2015-08-27 15:00:23 -0400 | [diff] [blame] | 152 |                                        cleanup_in_class=False, | 
 | 153 |                                        client_version='1'): | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 154 |         """Creates isolated creds. | 
 | 155 |  | 
 | 156 |         :param name: name, will be used for naming ic and related stuff | 
 | 157 |         :param type_of_creds: admin, alt or primary | 
 | 158 |         :param cleanup_in_class: defines place where to delete | 
 | 159 |         :returns: SharesClient -- shares client with isolated creds. | 
 | 160 |         :returns: To client added dict attr 'creds' with | 
 | 161 |         :returns: key elements 'tenant' and 'user'. | 
 | 162 |         """ | 
 | 163 |         if name is None: | 
 | 164 |             # Get name of test method | 
 | 165 |             name = inspect.stack()[1][3] | 
 | 166 |             if len(name) > 32: | 
 | 167 |                 name = name[0:32] | 
 | 168 |  | 
 | 169 |         # Choose type of isolated creds | 
| Valeriy Ponomaryov | 48a2bd7 | 2015-11-05 13:22:44 +0200 | [diff] [blame] | 170 |         ic = dynamic_creds.DynamicCredentialProvider( | 
 | 171 |             identity_version=CONF.identity.auth_version, | 
 | 172 |             name=name, | 
| Sam Wan | c7b7f1f | 2015-11-25 00:22:28 -0500 | [diff] [blame] | 173 |             admin_role=CONF.identity.admin_role, | 
 | 174 |             admin_creds=common_creds.get_configured_credentials( | 
 | 175 |                 'identity_admin')) | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 176 |         if "admin" in type_of_creds: | 
 | 177 |             creds = ic.get_admin_creds() | 
 | 178 |         elif "alt" in type_of_creds: | 
 | 179 |             creds = ic.get_alt_creds() | 
 | 180 |         else: | 
 | 181 |             creds = ic.self.get_credentials(type_of_creds) | 
 | 182 |         ic.type_of_creds = type_of_creds | 
 | 183 |  | 
 | 184 |         # create client with isolated creds | 
 | 185 |         os = clients.Manager(credentials=creds) | 
| Clinton Knight | e5c8f09 | 2015-08-27 15:00:23 -0400 | [diff] [blame] | 186 |         if client_version == '1': | 
 | 187 |             client = os.shares_client | 
 | 188 |         elif client_version == '2': | 
 | 189 |             client = os.shares_v2_client | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 190 |  | 
 | 191 |         # Set place where will be deleted isolated creds | 
 | 192 |         ic_res = { | 
| Valeriy Ponomaryov | 48a2bd7 | 2015-11-05 13:22:44 +0200 | [diff] [blame] | 193 |             "method": ic.clear_creds, | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 194 |             "deleted": False, | 
 | 195 |         } | 
 | 196 |         if cleanup_in_class: | 
 | 197 |             cls.class_isolated_creds.insert(0, ic_res) | 
 | 198 |         else: | 
 | 199 |             cls.method_isolated_creds.insert(0, ic_res) | 
 | 200 |  | 
 | 201 |         # Provide share network | 
 | 202 |         if CONF.share.multitenancy_enabled: | 
 | 203 |             if not CONF.service_available.neutron: | 
 | 204 |                 raise cls.skipException("Neutron support is required") | 
| Valeriy Ponomaryov | 48a2bd7 | 2015-11-05 13:22:44 +0200 | [diff] [blame] | 205 |             nc = os.networks_client | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 206 |             share_network_id = cls.provide_share_network(client, nc, ic) | 
 | 207 |             client.share_network_id = share_network_id | 
 | 208 |             resource = { | 
 | 209 |                 "type": "share_network", | 
 | 210 |                 "id": client.share_network_id, | 
 | 211 |                 "client": client, | 
 | 212 |             } | 
 | 213 |             if cleanup_in_class: | 
 | 214 |                 cls.class_resources.insert(0, resource) | 
 | 215 |             else: | 
 | 216 |                 cls.method_resources.insert(0, resource) | 
 | 217 |         return client | 
 | 218 |  | 
 | 219 |     @classmethod | 
 | 220 |     def verify_nonempty(cls, *args): | 
 | 221 |         if not all(args): | 
 | 222 |             msg = "Missing API credentials in configuration." | 
 | 223 |             raise cls.skipException(msg) | 
 | 224 |  | 
 | 225 |     @classmethod | 
 | 226 |     def resource_setup(cls): | 
 | 227 |         if not (any(p in CONF.share.enable_protocols | 
 | 228 |                     for p in cls.protocols) and | 
 | 229 |                 CONF.service_available.manila): | 
 | 230 |             skip_msg = "Manila is disabled" | 
 | 231 |             raise cls.skipException(skip_msg) | 
 | 232 |         super(BaseSharesTest, cls).resource_setup() | 
 | 233 |         if not hasattr(cls, "os"): | 
 | 234 |             cls.username = CONF.identity.username | 
 | 235 |             cls.password = CONF.identity.password | 
| Valeriy Ponomaryov | 1950cb8 | 2016-04-11 14:02:29 +0300 | [diff] [blame] | 236 |             cls.project_name = CONF.identity.project_name | 
 | 237 |             cls.verify_nonempty(cls.username, cls.password, cls.project_name) | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 238 |             cls.os = clients.Manager() | 
 | 239 |         if CONF.share.multitenancy_enabled: | 
 | 240 |             if not CONF.service_available.neutron: | 
 | 241 |                 raise cls.skipException("Neutron support is required") | 
 | 242 |             sc = cls.os.shares_client | 
| Valeriy Ponomaryov | 48a2bd7 | 2015-11-05 13:22:44 +0200 | [diff] [blame] | 243 |             nc = cls.os.networks_client | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 244 |             share_network_id = cls.provide_share_network(sc, nc) | 
 | 245 |             cls.os.shares_client.share_network_id = share_network_id | 
| Clinton Knight | e5c8f09 | 2015-08-27 15:00:23 -0400 | [diff] [blame] | 246 |             cls.os.shares_v2_client.share_network_id = share_network_id | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 247 |         cls.shares_client = cls.os.shares_client | 
| Clinton Knight | e5c8f09 | 2015-08-27 15:00:23 -0400 | [diff] [blame] | 248 |         cls.shares_v2_client = cls.os.shares_v2_client | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 249 |  | 
 | 250 |     def setUp(self): | 
 | 251 |         super(BaseSharesTest, self).setUp() | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 252 |         self.addCleanup(self.clear_isolated_creds) | 
| Valeriy Ponomaryov | dd162cb | 2016-01-20 19:09:49 +0200 | [diff] [blame] | 253 |         self.addCleanup(self.clear_resources) | 
| Valeriy Ponomaryov | 2abf5d7 | 2016-06-01 18:30:12 +0300 | [diff] [blame^] | 254 |         verify_test_has_appropriate_tags(self) | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 255 |  | 
 | 256 |     @classmethod | 
 | 257 |     def resource_cleanup(cls): | 
 | 258 |         super(BaseSharesTest, cls).resource_cleanup() | 
 | 259 |         cls.clear_resources(cls.class_resources) | 
 | 260 |         cls.clear_isolated_creds(cls.class_isolated_creds) | 
 | 261 |  | 
 | 262 |     @classmethod | 
 | 263 |     @network_synchronized | 
| Valeriy Ponomaryov | 48a2bd7 | 2015-11-05 13:22:44 +0200 | [diff] [blame] | 264 |     def provide_share_network(cls, shares_client, networks_client, | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 265 |                               isolated_creds_client=None): | 
 | 266 |         """Used for finding/creating share network for multitenant driver. | 
 | 267 |  | 
 | 268 |         This method creates/gets entity share-network for one tenant. This | 
 | 269 |         share-network will be used for creation of service vm. | 
 | 270 |  | 
 | 271 |         :param shares_client: shares client, which requires share-network | 
| Valeriy Ponomaryov | 48a2bd7 | 2015-11-05 13:22:44 +0200 | [diff] [blame] | 272 |         :param networks_client: network client from same tenant as shares | 
 | 273 |         :param isolated_creds_client: DynamicCredentialProvider instance | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 274 |             If provided, then its networking will be used if needed. | 
 | 275 |             If not provided, then common network will be used if needed. | 
 | 276 |         :returns: str -- share network id for shares_client tenant | 
 | 277 |         :returns: None -- if single-tenant driver used | 
 | 278 |         """ | 
 | 279 |  | 
 | 280 |         sc = shares_client | 
 | 281 |  | 
 | 282 |         if not CONF.share.multitenancy_enabled: | 
 | 283 |             # Assumed usage of a single-tenant driver | 
 | 284 |             share_network_id = None | 
 | 285 |         elif sc.share_network_id: | 
 | 286 |             # Share-network already exists, use it | 
 | 287 |             share_network_id = sc.share_network_id | 
 | 288 |         else: | 
 | 289 |             net_id = subnet_id = share_network_id = None | 
 | 290 |  | 
 | 291 |             if not isolated_creds_client: | 
 | 292 |                 # Search for networks, created in previous runs | 
 | 293 |                 search_word = "reusable" | 
 | 294 |                 sn_name = "autogenerated_by_tempest_%s" % search_word | 
 | 295 |                 service_net_name = "share-service" | 
| Valeriy Ponomaryov | 48a2bd7 | 2015-11-05 13:22:44 +0200 | [diff] [blame] | 296 |                 networks = networks_client.list_networks() | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 297 |                 if "networks" in networks.keys(): | 
 | 298 |                     networks = networks["networks"] | 
 | 299 |                 for network in networks: | 
 | 300 |                     if (service_net_name in network["name"] and | 
 | 301 |                             sc.tenant_id == network['tenant_id']): | 
 | 302 |                         net_id = network["id"] | 
 | 303 |                         if len(network["subnets"]) > 0: | 
 | 304 |                             subnet_id = network["subnets"][0] | 
 | 305 |                             break | 
 | 306 |  | 
 | 307 |                 # Create suitable network | 
 | 308 |                 if (net_id is None or subnet_id is None): | 
| Valeriy Ponomaryov | 48a2bd7 | 2015-11-05 13:22:44 +0200 | [diff] [blame] | 309 |                     ic = dynamic_creds.DynamicCredentialProvider( | 
 | 310 |                         identity_version=CONF.identity.auth_version, | 
 | 311 |                         name=service_net_name, | 
 | 312 |                         admin_role=CONF.identity.admin_role, | 
| Sam Wan | c7b7f1f | 2015-11-25 00:22:28 -0500 | [diff] [blame] | 313 |                         admin_creds=common_creds.get_configured_credentials( | 
 | 314 |                             'identity_admin')) | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 315 |                     net_data = ic._create_network_resources(sc.tenant_id) | 
 | 316 |                     network, subnet, router = net_data | 
 | 317 |                     net_id = network["id"] | 
 | 318 |                     subnet_id = subnet["id"] | 
 | 319 |  | 
 | 320 |                 # Try get suitable share-network | 
 | 321 |                 share_networks = sc.list_share_networks_with_detail() | 
 | 322 |                 for sn in share_networks: | 
 | 323 |                     if (net_id == sn["neutron_net_id"] and | 
 | 324 |                             subnet_id == sn["neutron_subnet_id"] and | 
 | 325 |                             sn["name"] and search_word in sn["name"]): | 
 | 326 |                         share_network_id = sn["id"] | 
 | 327 |                         break | 
 | 328 |             else: | 
 | 329 |                 sn_name = "autogenerated_by_tempest_for_isolated_creds" | 
 | 330 |                 # Use precreated network and subnet from isolated creds | 
 | 331 |                 net_id = isolated_creds_client.get_credentials( | 
 | 332 |                     isolated_creds_client.type_of_creds).network['id'] | 
 | 333 |                 subnet_id = isolated_creds_client.get_credentials( | 
 | 334 |                     isolated_creds_client.type_of_creds).subnet['id'] | 
 | 335 |  | 
 | 336 |             # Create suitable share-network | 
 | 337 |             if share_network_id is None: | 
 | 338 |                 sn_desc = "This share-network was created by tempest" | 
 | 339 |                 sn = sc.create_share_network(name=sn_name, | 
 | 340 |                                              description=sn_desc, | 
 | 341 |                                              neutron_net_id=net_id, | 
 | 342 |                                              neutron_subnet_id=subnet_id) | 
 | 343 |                 share_network_id = sn["id"] | 
 | 344 |  | 
 | 345 |         return share_network_id | 
 | 346 |  | 
 | 347 |     @classmethod | 
 | 348 |     def _create_share(cls, share_protocol=None, size=1, name=None, | 
 | 349 |                       snapshot_id=None, description=None, metadata=None, | 
 | 350 |                       share_network_id=None, share_type_id=None, | 
| Andrew Kerr | bf31e91 | 2015-07-29 10:39:38 -0400 | [diff] [blame] | 351 |                       consistency_group_id=None, client=None, | 
| Clinton Knight | e5c8f09 | 2015-08-27 15:00:23 -0400 | [diff] [blame] | 352 |                       cleanup_in_class=True, is_public=False, **kwargs): | 
| Valeriy Ponomaryov | 1aaa72d | 2015-09-08 12:59:41 +0300 | [diff] [blame] | 353 |         client = client or cls.shares_v2_client | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 354 |         description = description or "Tempest's share" | 
 | 355 |         share_network_id = share_network_id or client.share_network_id or None | 
 | 356 |         metadata = metadata or {} | 
| Clinton Knight | e5c8f09 | 2015-08-27 15:00:23 -0400 | [diff] [blame] | 357 |         kwargs.update({ | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 358 |             'share_protocol': share_protocol, | 
 | 359 |             'size': size, | 
 | 360 |             'name': name, | 
 | 361 |             'snapshot_id': snapshot_id, | 
 | 362 |             'description': description, | 
 | 363 |             'metadata': metadata, | 
 | 364 |             'share_network_id': share_network_id, | 
 | 365 |             'share_type_id': share_type_id, | 
 | 366 |             'is_public': is_public, | 
| Clinton Knight | e5c8f09 | 2015-08-27 15:00:23 -0400 | [diff] [blame] | 367 |         }) | 
| Andrew Kerr | bf31e91 | 2015-07-29 10:39:38 -0400 | [diff] [blame] | 368 |         if consistency_group_id: | 
 | 369 |             kwargs['consistency_group_id'] = consistency_group_id | 
 | 370 |  | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 371 |         share = client.create_share(**kwargs) | 
| Andrew Kerr | bf31e91 | 2015-07-29 10:39:38 -0400 | [diff] [blame] | 372 |         resource = {"type": "share", "id": share["id"], "client": client, | 
 | 373 |                     "consistency_group_id": consistency_group_id} | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 374 |         cleanup_list = (cls.class_resources if cleanup_in_class else | 
 | 375 |                         cls.method_resources) | 
 | 376 |         cleanup_list.insert(0, resource) | 
 | 377 |         return share | 
 | 378 |  | 
 | 379 |     @classmethod | 
| Rodrigo Barbieri | e330512 | 2016-02-03 14:32:24 -0200 | [diff] [blame] | 380 |     def migrate_share(cls, share_id, dest_host, client=None, notify=True, | 
 | 381 |                       wait_for_status='migration_success', **kwargs): | 
| Clinton Knight | e5c8f09 | 2015-08-27 15:00:23 -0400 | [diff] [blame] | 382 |         client = client or cls.shares_v2_client | 
| Rodrigo Barbieri | e330512 | 2016-02-03 14:32:24 -0200 | [diff] [blame] | 383 |         client.migrate_share(share_id, dest_host, notify, **kwargs) | 
 | 384 |         share = client.wait_for_migration_status( | 
 | 385 |             share_id, dest_host, wait_for_status, | 
 | 386 |             version=kwargs.get('version')) | 
 | 387 |         return share | 
 | 388 |  | 
 | 389 |     @classmethod | 
 | 390 |     def migration_complete(cls, share_id, dest_host, client=None, **kwargs): | 
 | 391 |         client = client or cls.shares_v2_client | 
 | 392 |         client.migration_complete(share_id, **kwargs) | 
 | 393 |         share = client.wait_for_migration_status( | 
 | 394 |             share_id, dest_host, 'migration_success', | 
 | 395 |             version=kwargs.get('version')) | 
| Rodrigo Barbieri | b7137ad | 2015-09-06 22:53:16 -0300 | [diff] [blame] | 396 |         return share | 
 | 397 |  | 
 | 398 |     @classmethod | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 399 |     def create_share(cls, *args, **kwargs): | 
 | 400 |         """Create one share and wait for available state. Retry if allowed.""" | 
 | 401 |         result = cls.create_shares([{"args": args, "kwargs": kwargs}]) | 
 | 402 |         return result[0] | 
 | 403 |  | 
 | 404 |     @classmethod | 
 | 405 |     def create_shares(cls, share_data_list): | 
 | 406 |         """Creates several shares in parallel with retries. | 
 | 407 |  | 
 | 408 |         Use this method when you want to create more than one share at same | 
 | 409 |         time. Especially if config option 'share.share_creation_retry_number' | 
 | 410 |         has value more than zero (0). | 
 | 411 |         All shares will be expected to have 'available' status with or without | 
 | 412 |         recreation else error will be raised. | 
 | 413 |  | 
 | 414 |         :param share_data_list: list -- list of dictionaries with 'args' and | 
 | 415 |             'kwargs' for '_create_share' method of this base class. | 
 | 416 |             example of data: | 
 | 417 |                 share_data_list=[{'args': ['quuz'], 'kwargs': {'foo': 'bar'}}}] | 
 | 418 |         :returns: list -- list of shares created using provided data. | 
 | 419 |         """ | 
 | 420 |  | 
 | 421 |         data = [copy.deepcopy(d) for d in share_data_list] | 
 | 422 |         for d in data: | 
 | 423 |             if not isinstance(d, dict): | 
 | 424 |                 raise exceptions.TempestException( | 
 | 425 |                     "Expected 'dict', got '%s'" % type(d)) | 
 | 426 |             if "args" not in d: | 
 | 427 |                 d["args"] = [] | 
 | 428 |             if "kwargs" not in d: | 
 | 429 |                 d["kwargs"] = {} | 
 | 430 |             if len(d) > 2: | 
 | 431 |                 raise exceptions.TempestException( | 
 | 432 |                     "Expected only 'args' and 'kwargs' keys. " | 
 | 433 |                     "Provided %s" % list(d)) | 
 | 434 |             d["kwargs"]["client"] = d["kwargs"].get( | 
| Valeriy Ponomaryov | 1aaa72d | 2015-09-08 12:59:41 +0300 | [diff] [blame] | 435 |                 "client", cls.shares_v2_client) | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 436 |             d["share"] = cls._create_share(*d["args"], **d["kwargs"]) | 
 | 437 |             d["cnt"] = 0 | 
 | 438 |             d["available"] = False | 
 | 439 |  | 
 | 440 |         while not all(d["available"] for d in data): | 
 | 441 |             for d in data: | 
 | 442 |                 if d["available"]: | 
 | 443 |                     continue | 
 | 444 |                 try: | 
 | 445 |                     d["kwargs"]["client"].wait_for_share_status( | 
 | 446 |                         d["share"]["id"], "available") | 
 | 447 |                     d["available"] = True | 
 | 448 |                 except (share_exceptions.ShareBuildErrorException, | 
 | 449 |                         exceptions.TimeoutException) as e: | 
 | 450 |                     if CONF.share.share_creation_retry_number > d["cnt"]: | 
 | 451 |                         d["cnt"] += 1 | 
 | 452 |                         msg = ("Share '%s' failed to be built. " | 
 | 453 |                                "Trying create another." % d["share"]["id"]) | 
 | 454 |                         LOG.error(msg) | 
 | 455 |                         LOG.error(e) | 
 | 456 |                         d["share"] = cls._create_share( | 
 | 457 |                             *d["args"], **d["kwargs"]) | 
 | 458 |                     else: | 
 | 459 |                         raise e | 
 | 460 |  | 
 | 461 |         return [d["share"] for d in data] | 
 | 462 |  | 
 | 463 |     @classmethod | 
| Andrew Kerr | bf31e91 | 2015-07-29 10:39:38 -0400 | [diff] [blame] | 464 |     def create_consistency_group(cls, client=None, cleanup_in_class=True, | 
 | 465 |                                  share_network_id=None, **kwargs): | 
| Clinton Knight | e5c8f09 | 2015-08-27 15:00:23 -0400 | [diff] [blame] | 466 |         client = client or cls.shares_v2_client | 
| Goutham Pacha Ravi | 9221f5e | 2016-04-21 13:17:49 -0400 | [diff] [blame] | 467 |         if kwargs.get('source_cgsnapshot_id') is None: | 
 | 468 |             kwargs['share_network_id'] = (share_network_id or | 
 | 469 |                                           client.share_network_id or None) | 
| Andrew Kerr | bf31e91 | 2015-07-29 10:39:38 -0400 | [diff] [blame] | 470 |         consistency_group = client.create_consistency_group(**kwargs) | 
 | 471 |         resource = { | 
 | 472 |             "type": "consistency_group", | 
 | 473 |             "id": consistency_group["id"], | 
 | 474 |             "client": client} | 
 | 475 |         if cleanup_in_class: | 
 | 476 |             cls.class_resources.insert(0, resource) | 
 | 477 |         else: | 
 | 478 |             cls.method_resources.insert(0, resource) | 
 | 479 |  | 
 | 480 |         if kwargs.get('source_cgsnapshot_id'): | 
 | 481 |             new_cg_shares = client.list_shares( | 
 | 482 |                 detailed=True, | 
 | 483 |                 params={'consistency_group_id': consistency_group['id']}) | 
 | 484 |  | 
 | 485 |             for share in new_cg_shares: | 
 | 486 |                 resource = {"type": "share", | 
 | 487 |                             "id": share["id"], | 
 | 488 |                             "client": client, | 
 | 489 |                             "consistency_group_id": share.get( | 
 | 490 |                                 'consistency_group_id')} | 
 | 491 |                 if cleanup_in_class: | 
 | 492 |                     cls.class_resources.insert(0, resource) | 
 | 493 |                 else: | 
 | 494 |                     cls.method_resources.insert(0, resource) | 
 | 495 |  | 
 | 496 |         client.wait_for_consistency_group_status(consistency_group['id'], | 
 | 497 |                                                  'available') | 
 | 498 |         return consistency_group | 
 | 499 |  | 
 | 500 |     @classmethod | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 501 |     def create_snapshot_wait_for_active(cls, share_id, name=None, | 
 | 502 |                                         description=None, force=False, | 
 | 503 |                                         client=None, cleanup_in_class=True): | 
 | 504 |         if client is None: | 
| Yogesh | 1f931ff | 2015-09-29 23:41:02 -0400 | [diff] [blame] | 505 |             client = cls.shares_v2_client | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 506 |         if description is None: | 
 | 507 |             description = "Tempest's snapshot" | 
 | 508 |         snapshot = client.create_snapshot(share_id, name, description, force) | 
 | 509 |         resource = { | 
 | 510 |             "type": "snapshot", | 
 | 511 |             "id": snapshot["id"], | 
 | 512 |             "client": client, | 
 | 513 |         } | 
 | 514 |         if cleanup_in_class: | 
 | 515 |             cls.class_resources.insert(0, resource) | 
 | 516 |         else: | 
 | 517 |             cls.method_resources.insert(0, resource) | 
 | 518 |         client.wait_for_snapshot_status(snapshot["id"], "available") | 
 | 519 |         return snapshot | 
 | 520 |  | 
 | 521 |     @classmethod | 
| Andrew Kerr | bf31e91 | 2015-07-29 10:39:38 -0400 | [diff] [blame] | 522 |     def create_cgsnapshot_wait_for_active(cls, consistency_group_id, | 
 | 523 |                                           name=None, description=None, | 
| Clinton Knight | e5c8f09 | 2015-08-27 15:00:23 -0400 | [diff] [blame] | 524 |                                           client=None, cleanup_in_class=True, | 
 | 525 |                                           **kwargs): | 
 | 526 |         client = client or cls.shares_v2_client | 
| Andrew Kerr | bf31e91 | 2015-07-29 10:39:38 -0400 | [diff] [blame] | 527 |         if description is None: | 
 | 528 |             description = "Tempest's cgsnapshot" | 
| Clinton Knight | e5c8f09 | 2015-08-27 15:00:23 -0400 | [diff] [blame] | 529 |         cgsnapshot = client.create_cgsnapshot(consistency_group_id, | 
 | 530 |                                               name=name, | 
 | 531 |                                               description=description, | 
 | 532 |                                               **kwargs) | 
| Andrew Kerr | bf31e91 | 2015-07-29 10:39:38 -0400 | [diff] [blame] | 533 |         resource = { | 
 | 534 |             "type": "cgsnapshot", | 
 | 535 |             "id": cgsnapshot["id"], | 
 | 536 |             "client": client, | 
 | 537 |         } | 
 | 538 |         if cleanup_in_class: | 
 | 539 |             cls.class_resources.insert(0, resource) | 
 | 540 |         else: | 
 | 541 |             cls.method_resources.insert(0, resource) | 
 | 542 |         client.wait_for_cgsnapshot_status(cgsnapshot["id"], "available") | 
 | 543 |         return cgsnapshot | 
 | 544 |  | 
 | 545 |     @classmethod | 
| Yogesh | bdb8810 | 2015-09-29 23:41:02 -0400 | [diff] [blame] | 546 |     def get_availability_zones(cls, client=None): | 
 | 547 |         """List the availability zones for "manila-share" services | 
 | 548 |  | 
 | 549 |          that are currently in "up" state. | 
 | 550 |          """ | 
 | 551 |         client = client or cls.shares_v2_client | 
 | 552 |         cls.services = client.list_services() | 
 | 553 |         zones = [service['zone'] for service in cls.services if | 
 | 554 |                  service['binary'] == "manila-share" and | 
 | 555 |                  service['state'] == 'up'] | 
 | 556 |         return zones | 
 | 557 |  | 
| Yogesh | 1f931ff | 2015-09-29 23:41:02 -0400 | [diff] [blame] | 558 |     def get_pools_for_replication_domain(self): | 
 | 559 |         # Get the list of pools for the replication domain | 
 | 560 |         pools = self.admin_client.list_pools(detail=True)['pools'] | 
 | 561 |         instance_host = self.shares[0]['host'] | 
 | 562 |         host_pool = [p for p in pools if p['name'] == instance_host][0] | 
 | 563 |         rep_domain = host_pool['capabilities']['replication_domain'] | 
 | 564 |         pools_in_rep_domain = [p for p in pools if p['capabilities'][ | 
 | 565 |             'replication_domain'] == rep_domain] | 
 | 566 |         return rep_domain, pools_in_rep_domain | 
 | 567 |  | 
| Yogesh | bdb8810 | 2015-09-29 23:41:02 -0400 | [diff] [blame] | 568 |     @classmethod | 
 | 569 |     def create_share_replica(cls, share_id, availability_zone, client=None, | 
 | 570 |                              cleanup_in_class=False, cleanup=True): | 
 | 571 |         client = client or cls.shares_v2_client | 
 | 572 |         replica = client.create_share_replica(share_id, availability_zone) | 
 | 573 |         resource = { | 
 | 574 |             "type": "share_replica", | 
 | 575 |             "id": replica["id"], | 
 | 576 |             "client": client, | 
 | 577 |             "share_id": share_id, | 
 | 578 |         } | 
 | 579 |         # NOTE(Yogi1): Cleanup needs to be disabled during promotion tests. | 
 | 580 |         if cleanup: | 
 | 581 |             if cleanup_in_class: | 
 | 582 |                 cls.class_resources.insert(0, resource) | 
 | 583 |             else: | 
 | 584 |                 cls.method_resources.insert(0, resource) | 
 | 585 |         client.wait_for_share_replica_status( | 
 | 586 |             replica["id"], constants.STATUS_AVAILABLE) | 
 | 587 |         return replica | 
 | 588 |  | 
 | 589 |     @classmethod | 
 | 590 |     def delete_share_replica(cls, replica_id, client=None): | 
 | 591 |         client = client or cls.shares_v2_client | 
| Yogesh | 1f931ff | 2015-09-29 23:41:02 -0400 | [diff] [blame] | 592 |         try: | 
 | 593 |             client.delete_share_replica(replica_id) | 
 | 594 |             client.wait_for_resource_deletion(replica_id=replica_id) | 
 | 595 |         except exceptions.NotFound: | 
 | 596 |             pass | 
| Yogesh | bdb8810 | 2015-09-29 23:41:02 -0400 | [diff] [blame] | 597 |  | 
 | 598 |     @classmethod | 
 | 599 |     def promote_share_replica(cls, replica_id, client=None): | 
 | 600 |         client = client or cls.shares_v2_client | 
 | 601 |         replica = client.promote_share_replica(replica_id) | 
 | 602 |         client.wait_for_share_replica_status( | 
 | 603 |             replica["id"], | 
 | 604 |             constants.REPLICATION_STATE_ACTIVE, | 
 | 605 |             status_attr="replica_state") | 
 | 606 |         return replica | 
 | 607 |  | 
 | 608 |     @classmethod | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 609 |     def create_share_network(cls, client=None, | 
 | 610 |                              cleanup_in_class=False, **kwargs): | 
 | 611 |         if client is None: | 
 | 612 |             client = cls.shares_client | 
 | 613 |         share_network = client.create_share_network(**kwargs) | 
 | 614 |         resource = { | 
 | 615 |             "type": "share_network", | 
 | 616 |             "id": share_network["id"], | 
 | 617 |             "client": client, | 
 | 618 |         } | 
 | 619 |         if cleanup_in_class: | 
 | 620 |             cls.class_resources.insert(0, resource) | 
 | 621 |         else: | 
 | 622 |             cls.method_resources.insert(0, resource) | 
 | 623 |         return share_network | 
 | 624 |  | 
 | 625 |     @classmethod | 
 | 626 |     def create_security_service(cls, ss_type="ldap", client=None, | 
 | 627 |                                 cleanup_in_class=False, **kwargs): | 
 | 628 |         if client is None: | 
 | 629 |             client = cls.shares_client | 
 | 630 |         security_service = client.create_security_service(ss_type, **kwargs) | 
 | 631 |         resource = { | 
 | 632 |             "type": "security_service", | 
 | 633 |             "id": security_service["id"], | 
 | 634 |             "client": client, | 
 | 635 |         } | 
 | 636 |         if cleanup_in_class: | 
 | 637 |             cls.class_resources.insert(0, resource) | 
 | 638 |         else: | 
 | 639 |             cls.method_resources.insert(0, resource) | 
 | 640 |         return security_service | 
 | 641 |  | 
 | 642 |     @classmethod | 
 | 643 |     def create_share_type(cls, name, is_public=True, client=None, | 
 | 644 |                           cleanup_in_class=True, **kwargs): | 
 | 645 |         if client is None: | 
| Valeriy Ponomaryov | a14c225 | 2015-10-29 13:34:32 +0200 | [diff] [blame] | 646 |             client = cls.shares_v2_client | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 647 |         share_type = client.create_share_type(name, is_public, **kwargs) | 
 | 648 |         resource = { | 
 | 649 |             "type": "share_type", | 
 | 650 |             "id": share_type["share_type"]["id"], | 
 | 651 |             "client": client, | 
 | 652 |         } | 
 | 653 |         if cleanup_in_class: | 
 | 654 |             cls.class_resources.insert(0, resource) | 
 | 655 |         else: | 
 | 656 |             cls.method_resources.insert(0, resource) | 
 | 657 |         return share_type | 
 | 658 |  | 
 | 659 |     @staticmethod | 
 | 660 |     def add_required_extra_specs_to_dict(extra_specs=None): | 
| Valeriy Ponomaryov | ad55dc5 | 2015-09-23 13:54:00 +0300 | [diff] [blame] | 661 |         dhss = six.text_type(CONF.share.multitenancy_enabled) | 
 | 662 |         snapshot_support = six.text_type( | 
 | 663 |             CONF.share.capability_snapshot_support) | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 664 |         required = { | 
| Valeriy Ponomaryov | ad55dc5 | 2015-09-23 13:54:00 +0300 | [diff] [blame] | 665 |             "driver_handles_share_servers": dhss, | 
 | 666 |             "snapshot_support": snapshot_support, | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 667 |         } | 
 | 668 |         if extra_specs: | 
 | 669 |             required.update(extra_specs) | 
 | 670 |         return required | 
 | 671 |  | 
 | 672 |     @classmethod | 
 | 673 |     def clear_isolated_creds(cls, creds=None): | 
 | 674 |         if creds is None: | 
 | 675 |             creds = cls.method_isolated_creds | 
 | 676 |         for ic in creds: | 
 | 677 |             if "deleted" not in ic.keys(): | 
 | 678 |                 ic["deleted"] = False | 
 | 679 |             if not ic["deleted"]: | 
 | 680 |                 with handle_cleanup_exceptions(): | 
 | 681 |                     ic["method"]() | 
 | 682 |                 ic["deleted"] = True | 
 | 683 |  | 
 | 684 |     @classmethod | 
| Yogesh | 1f931ff | 2015-09-29 23:41:02 -0400 | [diff] [blame] | 685 |     def clear_share_replicas(cls, share_id, client=None): | 
 | 686 |         client = client or cls.shares_v2_client | 
 | 687 |         share_replicas = client.list_share_replicas( | 
 | 688 |             share_id=share_id) | 
 | 689 |  | 
 | 690 |         for replica in share_replicas: | 
 | 691 |             try: | 
 | 692 |                 cls.delete_share_replica(replica['id']) | 
 | 693 |             except exceptions.BadRequest: | 
 | 694 |                 # Ignore the exception due to deletion of last active replica | 
 | 695 |                 pass | 
 | 696 |  | 
 | 697 |     @classmethod | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 698 |     def clear_resources(cls, resources=None): | 
 | 699 |         """Deletes resources, that were created in test suites. | 
 | 700 |  | 
 | 701 |         This method tries to remove resources from resource list, | 
 | 702 |         if it is not found, assumed it was deleted in test itself. | 
 | 703 |         It is expected, that all resources were added as LIFO | 
 | 704 |         due to restriction of deletion resources, that is in the chain. | 
 | 705 |  | 
 | 706 |         :param resources: dict with keys 'type','id','client' and 'deleted' | 
 | 707 |         """ | 
 | 708 |  | 
 | 709 |         if resources is None: | 
 | 710 |             resources = cls.method_resources | 
 | 711 |         for res in resources: | 
 | 712 |             if "deleted" not in res.keys(): | 
 | 713 |                 res["deleted"] = False | 
 | 714 |             if "client" not in res.keys(): | 
 | 715 |                 res["client"] = cls.shares_client | 
 | 716 |             if not(res["deleted"]): | 
 | 717 |                 res_id = res['id'] | 
 | 718 |                 client = res["client"] | 
 | 719 |                 with handle_cleanup_exceptions(): | 
 | 720 |                     if res["type"] is "share": | 
| Yogesh | 1f931ff | 2015-09-29 23:41:02 -0400 | [diff] [blame] | 721 |                         cls.clear_share_replicas(res_id) | 
| Andrew Kerr | bf31e91 | 2015-07-29 10:39:38 -0400 | [diff] [blame] | 722 |                         cg_id = res.get('consistency_group_id') | 
 | 723 |                         if cg_id: | 
 | 724 |                             params = {'consistency_group_id': cg_id} | 
| Clinton Knight | e5c8f09 | 2015-08-27 15:00:23 -0400 | [diff] [blame] | 725 |                             client.delete_share(res_id, params=params) | 
 | 726 |                         else: | 
 | 727 |                             client.delete_share(res_id) | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 728 |                         client.wait_for_resource_deletion(share_id=res_id) | 
 | 729 |                     elif res["type"] is "snapshot": | 
 | 730 |                         client.delete_snapshot(res_id) | 
 | 731 |                         client.wait_for_resource_deletion(snapshot_id=res_id) | 
 | 732 |                     elif res["type"] is "share_network": | 
 | 733 |                         client.delete_share_network(res_id) | 
 | 734 |                         client.wait_for_resource_deletion(sn_id=res_id) | 
 | 735 |                     elif res["type"] is "security_service": | 
 | 736 |                         client.delete_security_service(res_id) | 
 | 737 |                         client.wait_for_resource_deletion(ss_id=res_id) | 
 | 738 |                     elif res["type"] is "share_type": | 
 | 739 |                         client.delete_share_type(res_id) | 
 | 740 |                         client.wait_for_resource_deletion(st_id=res_id) | 
| Andrew Kerr | bf31e91 | 2015-07-29 10:39:38 -0400 | [diff] [blame] | 741 |                     elif res["type"] is "consistency_group": | 
 | 742 |                         client.delete_consistency_group(res_id) | 
 | 743 |                         client.wait_for_resource_deletion(cg_id=res_id) | 
 | 744 |                     elif res["type"] is "cgsnapshot": | 
 | 745 |                         client.delete_cgsnapshot(res_id) | 
 | 746 |                         client.wait_for_resource_deletion(cgsnapshot_id=res_id) | 
| Yogesh | bdb8810 | 2015-09-29 23:41:02 -0400 | [diff] [blame] | 747 |                     elif res["type"] is "share_replica": | 
 | 748 |                         client.delete_share_replica(res_id) | 
 | 749 |                         client.wait_for_resource_deletion(replica_id=res_id) | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 750 |                     else: | 
| huayue | 97bacbf | 2016-01-04 09:57:39 +0800 | [diff] [blame] | 751 |                         LOG.warning("Provided unsupported resource type for " | 
 | 752 |                                     "cleanup '%s'. Skipping." % res["type"]) | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 753 |                 res["deleted"] = True | 
 | 754 |  | 
 | 755 |     @classmethod | 
 | 756 |     def generate_share_network_data(self): | 
 | 757 |         data = { | 
 | 758 |             "name": data_utils.rand_name("sn-name"), | 
 | 759 |             "description": data_utils.rand_name("sn-desc"), | 
 | 760 |             "neutron_net_id": data_utils.rand_name("net-id"), | 
 | 761 |             "neutron_subnet_id": data_utils.rand_name("subnet-id"), | 
 | 762 |         } | 
 | 763 |         return data | 
 | 764 |  | 
 | 765 |     @classmethod | 
 | 766 |     def generate_security_service_data(self): | 
 | 767 |         data = { | 
 | 768 |             "name": data_utils.rand_name("ss-name"), | 
 | 769 |             "description": data_utils.rand_name("ss-desc"), | 
| Valeriy Ponomaryov | fcde771 | 2015-12-14 18:06:13 +0200 | [diff] [blame] | 770 |             "dns_ip": utils.rand_ip(), | 
 | 771 |             "server": utils.rand_ip(), | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 772 |             "domain": data_utils.rand_name("ss-domain"), | 
 | 773 |             "user": data_utils.rand_name("ss-user"), | 
 | 774 |             "password": data_utils.rand_name("ss-password"), | 
 | 775 |         } | 
 | 776 |         return data | 
 | 777 |  | 
 | 778 |     # Useful assertions | 
 | 779 |     def assertDictMatch(self, d1, d2, approx_equal=False, tolerance=0.001): | 
 | 780 |         """Assert two dicts are equivalent. | 
 | 781 |  | 
 | 782 |         This is a 'deep' match in the sense that it handles nested | 
 | 783 |         dictionaries appropriately. | 
 | 784 |  | 
 | 785 |         NOTE: | 
 | 786 |  | 
 | 787 |             If you don't care (or don't know) a given value, you can specify | 
 | 788 |             the string DONTCARE as the value. This will cause that dict-item | 
 | 789 |             to be skipped. | 
 | 790 |  | 
 | 791 |         """ | 
 | 792 |         def raise_assertion(msg): | 
 | 793 |             d1str = str(d1) | 
 | 794 |             d2str = str(d2) | 
 | 795 |             base_msg = ('Dictionaries do not match. %(msg)s d1: %(d1str)s ' | 
 | 796 |                         'd2: %(d2str)s' % | 
 | 797 |                         {"msg": msg, "d1str": d1str, "d2str": d2str}) | 
 | 798 |             raise AssertionError(base_msg) | 
 | 799 |  | 
 | 800 |         d1keys = set(d1.keys()) | 
 | 801 |         d2keys = set(d2.keys()) | 
 | 802 |         if d1keys != d2keys: | 
 | 803 |             d1only = d1keys - d2keys | 
 | 804 |             d2only = d2keys - d1keys | 
 | 805 |             raise_assertion('Keys in d1 and not d2: %(d1only)s. ' | 
 | 806 |                             'Keys in d2 and not d1: %(d2only)s' % | 
 | 807 |                             {"d1only": d1only, "d2only": d2only}) | 
 | 808 |  | 
 | 809 |         for key in d1keys: | 
 | 810 |             d1value = d1[key] | 
 | 811 |             d2value = d2[key] | 
 | 812 |             try: | 
 | 813 |                 error = abs(float(d1value) - float(d2value)) | 
 | 814 |                 within_tolerance = error <= tolerance | 
 | 815 |             except (ValueError, TypeError): | 
| daiki kato | 6914b1a | 2016-03-16 17:16:57 +0900 | [diff] [blame] | 816 |                 # If both values aren't convertible to float, just ignore | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 817 |                 # ValueError if arg is a str, TypeError if it's something else | 
 | 818 |                 # (like None) | 
 | 819 |                 within_tolerance = False | 
 | 820 |  | 
 | 821 |             if hasattr(d1value, 'keys') and hasattr(d2value, 'keys'): | 
 | 822 |                 self.assertDictMatch(d1value, d2value) | 
 | 823 |             elif 'DONTCARE' in (d1value, d2value): | 
 | 824 |                 continue | 
 | 825 |             elif approx_equal and within_tolerance: | 
 | 826 |                 continue | 
 | 827 |             elif d1value != d2value: | 
 | 828 |                 raise_assertion("d1['%(key)s']=%(d1value)s != " | 
 | 829 |                                 "d2['%(key)s']=%(d2value)s" % | 
 | 830 |                                 { | 
 | 831 |                                     "key": key, | 
 | 832 |                                     "d1value": d1value, | 
 | 833 |                                     "d2value": d2value | 
 | 834 |                                 }) | 
 | 835 |  | 
 | 836 |  | 
 | 837 | class BaseSharesAltTest(BaseSharesTest): | 
 | 838 |     """Base test case class for all Shares Alt API tests.""" | 
 | 839 |  | 
 | 840 |     @classmethod | 
 | 841 |     def resource_setup(cls): | 
 | 842 |         cls.username = CONF.identity.alt_username | 
 | 843 |         cls.password = CONF.identity.alt_password | 
| Valeriy Ponomaryov | 1950cb8 | 2016-04-11 14:02:29 +0300 | [diff] [blame] | 844 |         cls.project_name = CONF.identity.alt_project_name | 
 | 845 |         cls.verify_nonempty(cls.username, cls.password, cls.project_name) | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 846 |         cls.os = clients.AltManager() | 
 | 847 |         alt_share_network_id = CONF.share.alt_share_network_id | 
 | 848 |         cls.os.shares_client.share_network_id = alt_share_network_id | 
| Clinton Knight | e5c8f09 | 2015-08-27 15:00:23 -0400 | [diff] [blame] | 849 |         cls.os.shares_v2_client.share_network_id = alt_share_network_id | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 850 |         super(BaseSharesAltTest, cls).resource_setup() | 
 | 851 |  | 
 | 852 |  | 
 | 853 | class BaseSharesAdminTest(BaseSharesTest): | 
 | 854 |     """Base test case class for all Shares Admin API tests.""" | 
 | 855 |  | 
 | 856 |     @classmethod | 
 | 857 |     def resource_setup(cls): | 
| Sam Wan | b5047aa | 2015-10-08 05:37:43 -0400 | [diff] [blame] | 858 |         if hasattr(CONF.identity, 'admin_username'): | 
 | 859 |             cls.username = CONF.identity.admin_username | 
 | 860 |             cls.password = CONF.identity.admin_password | 
| Valeriy Ponomaryov | 1950cb8 | 2016-04-11 14:02:29 +0300 | [diff] [blame] | 861 |             cls.project_name = CONF.identity.admin_project_name | 
| Sam Wan | b5047aa | 2015-10-08 05:37:43 -0400 | [diff] [blame] | 862 |         else: | 
 | 863 |             cls.username = CONF.auth.admin_username | 
 | 864 |             cls.password = CONF.auth.admin_password | 
| Valeriy Ponomaryov | 1950cb8 | 2016-04-11 14:02:29 +0300 | [diff] [blame] | 865 |             cls.project_name = CONF.auth.admin_project_name | 
 | 866 |         cls.verify_nonempty(cls.username, cls.password, cls.project_name) | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 867 |         cls.os = clients.AdminManager() | 
 | 868 |         admin_share_network_id = CONF.share.admin_share_network_id | 
 | 869 |         cls.os.shares_client.share_network_id = admin_share_network_id | 
| Clinton Knight | e5c8f09 | 2015-08-27 15:00:23 -0400 | [diff] [blame] | 870 |         cls.os.shares_v2_client.share_network_id = admin_share_network_id | 
| Marc Koderer | 0abc93b | 2015-07-15 09:18:35 +0200 | [diff] [blame] | 871 |         super(BaseSharesAdminTest, cls).resource_setup() |