"Fossies" - the Fresh Open Source Software Archive

Member "cinder-17.1.0/cinder/tests/unit/volume/drivers/solidfire/test_solidfire.py" (8 Mar 2021, 190221 Bytes) of package /linux/misc/openstack/cinder-17.1.0.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. See also the latest Fossies "Diffs" side-by-side code changes report for "test_solidfire.py": 17.0.1_vs_17.1.0.

    1 #
    2 # Copyright 2012 OpenStack Foundation
    3 # All Rights Reserved.
    4 #
    5 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
    6 #    not use this file except in compliance with the License. You may obtain
    7 #    a copy of the License at
    8 #
    9 #         http://www.apache.org/licenses/LICENSE-2.0
   10 #
   11 #    Unless required by applicable law or agreed to in writing, software
   12 #    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
   13 #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
   14 #    License for the specific language governing permissions and limitations
   15 #    under the License.
   16 
   17 from copy import deepcopy
   18 import datetime
   19 import re
   20 from unittest import mock
   21 from unittest.mock import call
   22 from unittest.mock import MagicMock
   23 
   24 from ddt import data
   25 from ddt import ddt
   26 from ddt import file_data
   27 from ddt import unpack
   28 from oslo_service import loopingcall
   29 from oslo_utils import timeutils
   30 from oslo_utils import units
   31 import six
   32 
   33 from cinder import context
   34 from cinder import exception
   35 from cinder.objects import fields
   36 from cinder.tests.unit.api import fakes
   37 from cinder.tests.unit import fake_group_snapshot
   38 from cinder.tests.unit import fake_snapshot
   39 from cinder.tests.unit import fake_volume
   40 from cinder.tests.unit.image import fake as fake_image
   41 from cinder.tests.unit import test
   42 from cinder.tests.unit import utils as test_utils
   43 from cinder.volume import configuration as conf
   44 from cinder.volume.drivers import solidfire
   45 from cinder.volume import qos_specs
   46 from cinder.volume import volume_types
   47 
   48 
   49 class mock_vref(object):
   50     def __init__(self):
   51         self._name_id = None
   52         self.admin_metadata = {}
   53         self.attach_status = 'detached'
   54         self.id = '262b9ce2-a71a-4fbe-830c-c20c5596caea'
   55         self.project_id = '52423d9394ad4c67b3b9034da58cedbc'
   56         self.provider_id = '5 4 6ecebf5d-5521-4ce1-80f3-358ebc1b9cdc'
   57         self.size = 20
   58 
   59     def __setitem__(self, item, value):
   60         self.__dict__[item] = value
   61 
   62     def __getitem__(self, item):
   63         return self.__dict__[item]
   64 
   65     def get(self, item, arg2 = None):
   66         return self.__dict__[item]
   67 
   68 
   69 f_uuid = ['262b9ce2-a71a-4fbe-830c-c20c5596caea',
   70           '362b9ce2-a71a-4fbe-830c-c20c5596caea']
   71 
   72 
   73 @ddt
   74 class SolidFireVolumeTestCase(test.TestCase):
   75 
   76     EXPECTED_QOS = {'minIOPS': 110, 'burstIOPS': 1530, 'maxIOPS': 1020}
   77 
   78     def setUp(self):
   79         self.ctxt = context.get_admin_context()
   80         self.configuration = conf.BackendGroupConfiguration(
   81             [], conf.SHARED_CONF_GROUP)
   82         self.configuration.sf_allow_tenant_qos = True
   83         self.configuration.san_is_local = True
   84         self.configuration.sf_emulate_512 = True
   85         self.configuration.sf_account_prefix = 'cinder'
   86         self.configuration.reserved_percentage = 25
   87         self.configuration.target_helper = None
   88         self.configuration.sf_template_account_name = 'openstack-vtemplate'
   89         self.configuration.sf_allow_template_caching = False
   90         self.configuration.sf_svip = None
   91         self.configuration.sf_volume_prefix = 'UUID-'
   92         self.configuration.sf_enable_vag = False
   93         self.configuration.replication_device = []
   94         self.configuration.max_over_subscription_ratio = 2
   95 
   96         super(SolidFireVolumeTestCase, self).setUp()
   97         self.mock_object(solidfire.SolidFireDriver,
   98                          '_issue_api_request',
   99                          self.fake_issue_api_request)
  100 
  101         self.mock_object(solidfire.SolidFireDriver,
  102                          '_get_provisioned_capacity_iops',
  103                          return_value=(0, 0))
  104 
  105         self.expected_qos_results = {'minIOPS': 1000,
  106                                      'maxIOPS': 10000,
  107                                      'burstIOPS': 20000}
  108         self.mock_stats_data =\
  109             {'result':
  110                 {'clusterCapacity': {'maxProvisionedSpace': 107374182400,
  111                                      'usedSpace': 1073741824,
  112                                      'compressionPercent': 100,
  113                                      'deDuplicationPercent': 100,
  114                                      'thinProvisioningPercent': 100}}}
  115         vol_updates = {'project_id': 'testprjid',
  116                        'name': 'testvol',
  117                        'size': 1,
  118                        'id': 'a720b3c0-d1f0-11e1-9b23-0800200c9a66',
  119                        'volume_type_id': 'fast',
  120                        'created_at': timeutils.utcnow(),
  121                        'attributes':
  122                            {'uuid': '262b9ce2-a71a-4fbe-830c-c20c5596caea'}}
  123         ctx = context.get_admin_context()
  124         self.mock_volume = fake_volume.fake_volume_obj(ctx, **vol_updates)
  125 
  126         self.fake_image_meta = {'id': '17c550bb-a411-44c0-9aaf-0d96dd47f501',
  127                                 'updated_at': datetime.datetime(2013, 9,
  128                                                                 28, 15,
  129                                                                 27, 36,
  130                                                                 325355),
  131                                 'is_public': True,
  132                                 'owner': 'testprjid'}
  133         self.fake_image_service = fake_image.FakeImageService()
  134 
  135         self.vol = test_utils.create_volume(
  136             self.ctxt, volume_id='b831c4d1-d1f0-11e1-9b23-0800200c9a66')
  137         self.snap = test_utils.create_snapshot(
  138             self.ctxt, volume_id=self.vol.id)
  139 
  140         self.fake_sfaccount = {'accountID': 25,
  141                                'targetSecret': 'shhhh',
  142                                'username': 'prefix-testprjid',
  143                                'volumes': [6, 7, 20]}
  144 
  145         self.fake_sfvol = {'volumeID': 6,
  146                            'name': 'test_volume',
  147                            'accountID': 25,
  148                            'sliceCount': 1,
  149                            'totalSize': 1 * units.Gi,
  150                            'enable512e': True,
  151                            'access': "readWrite",
  152                            'status': "active",
  153                            'attributes': {'uuid': f_uuid[0]},
  154                            'qos': None,
  155                            'iqn': 'super_fake_iqn'}
  156 
  157         self.fake_primary_cluster = (
  158             {'endpoint': {'passwd': 'admin', 'port': 443,
  159                           'url': 'https://192.168.139.11:443',
  160                           'svip': '10.10.8.11',
  161                           'mvip': '10.10.8.12',
  162                           'login': 'admin'},
  163              'name': 'volume-f0632d53-d836-474c-a5bc-478ef18daa32',
  164              'clusterPairID': 33,
  165              'uuid': 'f0632d53-d836-474c-a5bc-478ef18daa32',
  166              'svip': '10.10.8.11',
  167              'mvipNodeID': 1,
  168              'repCount': 1,
  169              'encryptionAtRestState': 'disabled',
  170              'attributes': {},
  171              'mvip': '10.10.8.12',
  172              'ensemble': ['10.10.5.130'],
  173              'svipNodeID': 1})
  174 
  175         self.fake_secondary_cluster = (
  176             {'endpoint': {'passwd': 'admin', 'port': 443,
  177                           'url': 'https://192.168.139.102:443',
  178                           'svip': '10.10.8.134',
  179                           'mvip': '192.168.139.102',
  180                           'login': 'admin'},
  181              'name': 'AutoTest2-6AjG-FOR-TEST-ONLY',
  182              'clusterPairID': 331,
  183              'clusterAPIVersion': '9.4',
  184              'uuid': '9c499d4b-8fff-48b4-b875-27601d5d9889',
  185              'svip': '10.10.23.2',
  186              'mvipNodeID': 1,
  187              'repCount': 1,
  188              'encryptionAtRestState': 'disabled',
  189              'attributes': {},
  190              'mvip': '192.168.139.102',
  191              'ensemble': ['10.10.5.130'],
  192              'svipNodeID': 1})
  193 
  194         self.cluster_pairs = (
  195             [{'uniqueID': 'lu9f',
  196               'endpoint': {'passwd': 'admin', 'port': 443,
  197                            'url': 'https://192.168.139.102:443',
  198                            'svip': '10.10.8.134',
  199                            'mvip': '192.168.139.102',
  200                            'login': 'admin'},
  201               'name': 'AutoTest2-6AjG-FOR-TEST-ONLY',
  202               'clusterPairID': 33,
  203               'clusterAPIVersion': '9.4',
  204               'uuid': '9c499d4b-8fff-48b4-b875-27601d5d9889',
  205               'svip': '10.10.23.2',
  206               'mvipNodeID': 1,
  207               'repCount': 1,
  208               'encryptionAtRestState': 'disabled',
  209               'attributes': {},
  210               'mvip': '192.168.139.102',
  211               'ensemble': ['10.10.5.130'],
  212               'svipNodeID': 1}])
  213 
  214         self.mvip = '192.168.139.102'
  215         self.svip = '10.10.8.134'
  216 
  217         self.fake_sfsnap_name = '%s%s' % (self.configuration.sf_volume_prefix,
  218                                           self.snap.id)
  219         self.fake_sfsnaps = [{'snapshotID': '5',
  220                               'name': self.fake_sfsnap_name,
  221                               'volumeID': 6}]
  222 
  223     def fake_issue_api_request(self, method, params, version='1.0',
  224                                endpoint=None, timeout=None):
  225         if method == 'GetClusterCapacity':
  226             data = {}
  227             if version == '1.0':
  228                 data = {'result': {'clusterCapacity': {
  229                         'maxProvisionedSpace': 107374182400,
  230                         'usedSpace': 1073741824,
  231                         'compressionPercent': 100,
  232                         'deduplicationPercent': 100,
  233                         'thinProvisioningPercent': 100,
  234                         'maxUsedSpace': 53687091200}}}
  235             elif version == '8.0':
  236                 data = {'result': {'clusterCapacity': {
  237                         'usedMetadataSpaceInSnapshots': 16476454912,
  238                         'maxUsedMetadataSpace': 432103337164,
  239                         'activeBlockSpace': 616690857535,
  240                         'uniqueBlocksUsedSpace': 628629229316,
  241                         'totalOps': 7092186135,
  242                         'peakActiveSessions': 0,
  243                         'uniqueBlocks': 519489473,
  244                         'maxOverProvisionableSpace': 276546135777280,
  245                         'zeroBlocks': 8719571984,
  246                         'provisionedSpace': 19938551005184,
  247                         'maxUsedSpace': 8402009333760,
  248                         'peakIOPS': 0,
  249                         'timestamp': '2019-04-24T12:08:22Z',
  250                         'currentIOPS': 0,
  251                         'usedSpace': 628629229316,
  252                         'activeSessions': 0,
  253                         'nonZeroBlocks': 1016048624,
  254                         'maxProvisionedSpace': 55309227155456,
  255                         'usedMetadataSpace': 16476946432,
  256                         'averageIOPS': 0,
  257                         'snapshotNonZeroBlocks': 1606,
  258                         'maxIOPS': 200000,
  259                         'clusterRecentIOSize': 0}}}
  260             return data
  261 
  262         elif method == 'GetClusterInfo':
  263             results = {
  264                 'result':
  265                     {'clusterInfo':
  266                         {'name': 'fake-cluster',
  267                          'mvip': '1.1.1.1',
  268                          'svip': '1.1.1.1',
  269                          'uniqueID': 'unqid',
  270                          'repCount': 2,
  271                          'uuid': '53c8be1e-89e2-4f7f-a2e3-7cb84c47e0ec',
  272                          'attributes': {}}}}
  273             return results
  274 
  275         elif method == 'GetClusterVersionInfo':
  276             return {'id': None, 'result': {'softwareVersionInfo':
  277                                            {'pendingVersion': '8.2.1.4',
  278                                             'packageName': '',
  279                                             'currentVersion': '8.2.1.4',
  280                                             'nodeID': 0, 'startTime': ''},
  281                                            'clusterVersion': '8.2.1.4',
  282                                            'clusterAPIVersion': '8.2'}}
  283 
  284         elif method == 'AddAccount' and version == '1.0':
  285             return {'result': {'accountID': 25}, 'id': 1}
  286 
  287         elif method == 'GetAccountByName' and version == '1.0':
  288             results = {'result': {'account':
  289                                   {'accountID': 25,
  290                                    'username': params['username'],
  291                                    'status': 'active',
  292                                    'initiatorSecret': '123456789012',
  293                                    'targetSecret': '123456789012',
  294                                    'attributes': {},
  295                                    'volumes': [6, 7, 20]}},
  296                        "id": 1}
  297             return results
  298 
  299         elif method == 'CreateVolume' and version == '1.0':
  300             return {'result': {'volumeID': 5}, 'id': 1}
  301 
  302         elif method == 'CreateSnapshot' and version == '6.0':
  303             return {'result': {'snapshotID': 5}, 'id': 1}
  304 
  305         elif method == 'DeleteVolume' and version == '1.0':
  306             return {'result': {}, 'id': 1}
  307 
  308         elif method == 'ModifyVolume' and version == '5.0':
  309             return {'result': {}, 'id': 1}
  310 
  311         elif method == 'CloneVolume':
  312             return {'result': {'volumeID': 6}, 'id': 2}
  313 
  314         elif method == 'ModifyVolume':
  315             return {'result': {}, 'id': 1}
  316 
  317         elif method == 'ListVolumesForAccount' and version == '1.0':
  318             test_name = 'OS-VOLID-a720b3c0-d1f0-11e1-9b23-0800200c9a66'
  319             result = {'result': {
  320                 'volumes': [{'volumeID': 5,
  321                              'name': test_name,
  322                              'accountID': 25,
  323                              'sliceCount': 1,
  324                              'totalSize': 1 * units.Gi,
  325                              'enable512e': True,
  326                              'access': "readWrite",
  327                              'status': "active",
  328                              'attributes': {'uuid': f_uuid[0]},
  329                              'qos': None,
  330                              'iqn': test_name}]}}
  331             return result
  332 
  333         elif method == 'ListActiveVolumes':
  334             test_name = "existing_volume"
  335             result = {'result': {
  336                 'volumes': [{'volumeID': 5,
  337                              'name': test_name,
  338                              'accountID': 8,
  339                              'sliceCount': 1,
  340                              'totalSize': int(1.75 * units.Gi),
  341                              'enable512e': True,
  342                              'access': "readWrite",
  343                              'status': "active",
  344                              'attributes': {},
  345                              'qos': None,
  346                              'iqn': test_name}]}}
  347             return result
  348         elif method == 'ListVolumes':
  349             test_name = "get_sfvol_by_cinder"
  350             result = {'result': {
  351                 'volumes': [{'volumeID': 5,
  352                              'name': test_name,
  353                              'accountID': 8,
  354                              'sliceCount': 1,
  355                              'totalSize': int(1.75 * units.Gi),
  356                              'enable512e': True,
  357                              'access': "readWrite",
  358                              'status': "active",
  359                              'attributes': {'uuid': f_uuid[0]},
  360                              'qos': None,
  361                              'iqn': test_name},
  362                             {'volumeID': 15,
  363                              'name': test_name,
  364                              'accountID': 8,
  365                              'sliceCount': 1,
  366                              'totalSize': int(1.75 * units.Gi),
  367                              'enable512e': True,
  368                              'access': "readWrite",
  369                              'status': "active",
  370                              'attributes': {'uuid': f_uuid[1]},
  371                              'qos': None,
  372                              'iqn': test_name}]}}
  373             if params and params.get('startVolumeID', None):
  374                 volumes = result['result']['volumes']
  375                 selected_volumes = [v for v in volumes if v.get('volumeID') !=
  376                                     params['startVolumeID']]
  377                 result['result']['volumes'] = selected_volumes
  378             else:
  379                 result = {'result': {'volumes': []}}
  380 
  381             return result
  382         elif method == 'DeleteSnapshot':
  383             return {'result': {}}
  384         elif method == 'GetClusterVersionInfo':
  385             return {'result': {'clusterAPIVersion': '8.0'}}
  386         elif method == 'StartVolumePairing':
  387             return {'result': {'volumePairingKey': 'fake-pairing-key'}}
  388         elif method == 'RollbackToSnapshot':
  389             return {
  390                 "id": 1,
  391                 "result": {
  392                     "checksum": "0x0",
  393                     "snapshot": {
  394                         "attributes": {},
  395                         "checksum": "0x0",
  396                         "createTime": "2016-04-04T17:27:32Z",
  397                         "enableRemoteReplication": "false",
  398                         "expirationReason": "None",
  399                         "expirationTime": "null",
  400                         "groupID": 0,
  401                         "groupSnapshotUUID": f_uuid[0],
  402                         "name": "test1-copy",
  403                         "snapshotID": 1,
  404                         "snapshotUUID": f_uuid[1],
  405                         "status": "done",
  406                         "totalSize": 5000658944,
  407                         "virtualVolumeID": "null",
  408                         "volumeID": 1
  409                     },
  410                     "snapshotID": 1
  411                 }
  412             }
  413         elif method == 'ListAccounts':
  414             return {
  415                 'result': {
  416                     'accounts': [{
  417                         'accountID': 5,
  418                         'targetSecret': 'shhhh',
  419                         'username': 'prefix-testprjid'
  420                     }]
  421                 }
  422             }
  423         elif method == 'ListSnapshots':
  424             raise exception.VolumeNotFound('test clone unconfigured image')
  425         else:
  426             # Crap, unimplemented API call in Fake
  427             return None
  428 
  429     def fake_issue_api_request_fails(self, method,
  430                                      params, version='1.0',
  431                                      endpoint=None):
  432         response = {'error': {'code': 000,
  433                               'name': 'DummyError',
  434                               'message': 'This is a fake error response'},
  435                     'id': 1}
  436         msg = ('Error (%s) encountered during '
  437                'SolidFire API call.' % response['error']['name'])
  438         raise solidfire.SolidFireAPIException(message=msg)
  439 
  440     def fake_set_qos_by_volume_type(self, type_id, ctxt):
  441         return {'minIOPS': 500,
  442                 'maxIOPS': 1000,
  443                 'burstIOPS': 1000}
  444 
  445     def fake_volume_get(self, key, default=None):
  446         return {'qos': 'fast'}
  447 
  448     def fake_update_cluster_status(self):
  449         return
  450 
  451     def fake_get_cluster_version_info(self):
  452         return
  453 
  454     def fake_get_model_info(self, account, vid, endpoint=None):
  455         return {'fake': 'fake-model'}
  456 
  457     @mock.patch.object(solidfire.SolidFireDriver, '_issue_api_request')
  458     def test_create_volume_with_qos_type(self,
  459                                          _mock_issue_api_request):
  460         _mock_issue_api_request.side_effect = self.fake_issue_api_request
  461         testvol = {'project_id': 'testprjid',
  462                    'name': 'testvol',
  463                    'size': 1,
  464                    'id': 'a720b3c0-d1f0-11e1-9b23-0800200c9a66',
  465                    'volume_type_id': 'fast',
  466                    'created_at': timeutils.utcnow()}
  467 
  468         fake_sfaccounts = [{'accountID': 5,
  469                             'targetSecret': 'shhhh',
  470                             'username': 'prefix-testprjid'}]
  471 
  472         test_type = {'name': 'sf-1',
  473                      'qos_specs_id': 'fb0576d7-b4b5-4cad-85dc-ca92e6a497d1',
  474                      'deleted': False,
  475                      'created_at': '2014-02-06 04:58:11',
  476                      'updated_at': None,
  477                      'extra_specs': {},
  478                      'deleted_at': None,
  479                      'id': 'e730e97b-bc7d-4af3-934a-32e59b218e81'}
  480 
  481         test_qos_spec = {'id': 'asdfafdasdf',
  482                          'specs': {'minIOPS': '1000',
  483                                    'maxIOPS': '2000',
  484                                    'burstIOPS': '3000'}}
  485 
  486         ctx = context.get_admin_context()
  487         testvol = fake_volume.fake_volume_obj(ctx, **testvol)
  488 
  489         def _fake_get_volume_type(ctxt, type_id):
  490             return test_type
  491 
  492         def _fake_get_qos_spec(ctxt, spec_id):
  493             return test_qos_spec
  494 
  495         def _fake_do_volume_create(account, params):
  496             params['provider_location'] = '1.1.1.1 iqn 0'
  497             return params
  498 
  499         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
  500         with mock.patch.object(sfv,
  501                                '_get_sfaccounts_for_tenant',
  502                                return_value=fake_sfaccounts), \
  503                 mock.patch.object(sfv,
  504                                   '_get_account_create_availability',
  505                                   return_value=fake_sfaccounts[0]), \
  506                 mock.patch.object(sfv,
  507                                   '_do_volume_create',
  508                                   side_effect=_fake_do_volume_create), \
  509                 mock.patch.object(volume_types,
  510                                   'get_volume_type',
  511                                   side_effect=_fake_get_volume_type), \
  512                 mock.patch.object(qos_specs,
  513                                   'get_qos_specs',
  514                                   side_effect=_fake_get_qos_spec):
  515 
  516             self.assertEqual({'burstIOPS': 3000,
  517                               'minIOPS': 1000,
  518                               'maxIOPS': 2000},
  519                              sfv.create_volume(testvol)['qos'])
  520 
  521     @mock.patch.object(solidfire.SolidFireDriver, '_issue_api_request')
  522     def test_create_volume(self,
  523                            _mock_issue_api_request):
  524         _mock_issue_api_request.side_effect = self.fake_issue_api_request
  525         testvol = {'project_id': 'testprjid',
  526                    'name': 'testvol',
  527                    'size': 1,
  528                    'id': 'a720b3c0-d1f0-11e1-9b23-0800200c9a66',
  529                    'volume_type_id': None,
  530                    'created_at': timeutils.utcnow()}
  531         fake_sfaccounts = [{'accountID': 5,
  532                             'targetSecret': 'shhhh',
  533                             'username': 'prefix-testprjid'}]
  534 
  535         ctx = context.get_admin_context()
  536         testvol = fake_volume.fake_volume_obj(ctx, **testvol)
  537 
  538         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
  539         with mock.patch.object(sfv,
  540                                '_get_sfaccounts_for_tenant',
  541                                return_value=fake_sfaccounts), \
  542             mock.patch.object(sfv,
  543                               '_get_account_create_availability',
  544                               return_value=fake_sfaccounts[0]):
  545 
  546             model_update = sfv.create_volume(testvol)
  547             self.assertIsNotNone(model_update)
  548             self.assertNotIn('provider_geometry', model_update)
  549 
  550     @mock.patch.object(solidfire.SolidFireDriver, '_issue_api_request')
  551     def test_create_volume_non_512e(self,
  552                                     _mock_issue_api_request):
  553         _mock_issue_api_request.side_effect = self.fake_issue_api_request
  554         testvol = {'project_id': 'testprjid',
  555                    'name': 'testvol',
  556                    'size': 1,
  557                    'id': 'a720b3c0-d1f0-11e1-9b23-0800200c9a66',
  558                    'volume_type_id': None,
  559                    'created_at': timeutils.utcnow()}
  560 
  561         ctx = context.get_admin_context()
  562         testvol = fake_volume.fake_volume_obj(ctx, **testvol)
  563 
  564         fake_sfaccounts = [{'accountID': 5,
  565                             'targetSecret': 'shhhh',
  566                             'username': 'prefix-testprjid'}]
  567 
  568         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
  569         with mock.patch.object(sfv,
  570                                '_get_sfaccounts_for_tenant',
  571                                return_value=fake_sfaccounts), \
  572             mock.patch.object(sfv,
  573                               '_issue_api_request',
  574                               side_effect=self.fake_issue_api_request), \
  575             mock.patch.object(sfv,
  576                               '_get_account_create_availability',
  577                               return_value=fake_sfaccounts[0]):
  578 
  579             self.configuration.sf_emulate_512 = False
  580             model_update = sfv.create_volume(testvol)
  581             self.configuration.sf_emulate_512 = True
  582             self.assertEqual('4096 4096',
  583                              model_update.get('provider_geometry', None))
  584 
  585     def test_create_delete_snapshot(self):
  586         ctx = context.get_admin_context()
  587         testvol = fake_volume.fake_volume_obj(ctx)
  588 
  589         testsnap_dict = {'project_id': 'testprjid',
  590                          'name': testvol.name,
  591                          'volume_size': testvol.size,
  592                          'id': 'b831c4d1-d1f0-11e1-9b23-0800200c9a66',
  593                          'volume_id': testvol.id,
  594                          'volume_type_id': None,
  595                          'created_at': timeutils.utcnow(),
  596                          'provider_id': '8 99 None',
  597                          'volume': testvol}
  598         testsnap = fake_snapshot.fake_snapshot_obj(ctx, **testsnap_dict)
  599 
  600         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
  601         fake_uuid = 'UUID-b831c4d1-d1f0-11e1-9b23-0800200c9a66'
  602         with mock.patch.object(
  603                 solidfire.SolidFireDriver,
  604                 '_get_sf_snapshots',
  605                 return_value=[{'snapshotID': '5',
  606                                'name': fake_uuid,
  607                                'volumeID': 5}]), \
  608                 mock.patch.object(sfv,
  609                                   '_get_sfaccounts_for_tenant',
  610                                   return_value=[{'accountID': 5,
  611                                                  'username':
  612                                                  'prefix-testprjid'}]),\
  613                 mock.patch.object(sfv, '_retrieve_replication_settings',
  614                                   return_value=["Async", {}]),\
  615                 mock.patch.object(sfv, '_get_sf_volume',
  616                                   return_value={'volumeID': 33}):
  617             sfv.create_snapshot(testsnap)
  618             sfv.delete_snapshot(testsnap)
  619 
  620     @mock.patch.object(solidfire.SolidFireDriver, '_issue_api_request')
  621     def test_create_clone(self,
  622                           _mock_issue_api_request):
  623         _mock_issue_api_request.side_effect = self.fake_issue_api_request
  624         _fake_get_snaps = [{'snapshotID': 5, 'name': 'testvol'}]
  625         _fake_get_volume = (
  626             {'volumeID': 99,
  627              'name': 'UUID-a720b3c0-d1f0-11e1-9b23-0800200c9a66',
  628              'attributes': {}})
  629 
  630         updates_vol_a = {'project_id': 'testprjid',
  631                          'name': 'testvol',
  632                          'size': 1,
  633                          'id': 'a720b3c0-d1f0-11e1-9b23-0800200c9a66',
  634                          'volume_type_id': None,
  635                          'created_at': timeutils.utcnow()}
  636 
  637         updates_vol_b = {'project_id': 'testprjid',
  638                          'name': 'testvol',
  639                          'size': 1,
  640                          'id': 'b831c4d1-d1f0-11e1-9b23-0800200c9a66',
  641                          'volume_type_id': None,
  642                          'created_at': timeutils.utcnow()}
  643 
  644         fake_model_info = {
  645             'provider_id': '%s %s cluster-id-01' % (
  646                 self.fake_sfvol['volumeID'],
  647                 self.fake_sfaccount['accountID'])
  648         }
  649 
  650         ctx = context.get_admin_context()
  651         testvol = fake_volume.fake_volume_obj(ctx, **updates_vol_a)
  652         testvol_b = fake_volume.fake_volume_obj(ctx, **updates_vol_b)
  653 
  654         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
  655         with mock.patch.object(sfv,
  656                                '_get_sf_snapshots',
  657                                return_value=_fake_get_snaps), \
  658                 mock.patch.object(sfv,
  659                                   '_get_sf_volume',
  660                                   return_value=_fake_get_volume), \
  661                 mock.patch.object(sfv,
  662                                   '_issue_api_request',
  663                                   side_effect=self.fake_issue_api_request), \
  664                 mock.patch.object(sfv,
  665                                   '_get_sfaccounts_for_tenant',
  666                                   return_value=[]), \
  667                 mock.patch.object(sfv,
  668                                   '_get_model_info',
  669                                   return_value=fake_model_info):
  670             sfv.create_cloned_volume(testvol_b, testvol)
  671 
  672     def test_initialize_connector_with_blocksizes(self):
  673         connector = {'initiator': 'iqn.2012-07.org.fake:01'}
  674         testvol = {'project_id': 'testprjid',
  675                    'name': 'testvol',
  676                    'size': 1,
  677                    'id': 'a720b3c0-d1f0-11e1-9b23-0800200c9a66',
  678                    'volume_type_id': None,
  679                    'provider_location': '10.10.7.1:3260 iqn.2010-01.com.'
  680                                         'solidfire:87hg.uuid-2cc06226-cc'
  681                                         '74-4cb7-bd55-14aed659a0cc.4060 0',
  682                    'provider_auth': 'CHAP stack-1-a60e2611875f40199931f2'
  683                                     'c76370d66b 2FE0CQ8J196R',
  684                    'provider_geometry': '4096 4096',
  685                    'created_at': timeutils.utcnow(),
  686                    }
  687 
  688         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
  689         properties = sfv.initialize_connection(testvol, connector)
  690         self.assertEqual('4096', properties['data']['physical_block_size'])
  691         self.assertEqual('4096', properties['data']['logical_block_size'])
  692         self.assertTrue(properties['data']['discard'])
  693 
  694     def test_create_volume_fails(self):
  695         # NOTE(JDG) This test just fakes update_cluster_status
  696         # this is inentional for this test
  697         self.mock_object(solidfire.SolidFireDriver,
  698                          '_update_cluster_status',
  699                          self.fake_update_cluster_status)
  700         self.mock_object(solidfire.SolidFireDriver,
  701                          '_issue_api_request',
  702                          self.fake_issue_api_request)
  703         testvol = {'project_id': 'testprjid',
  704                    'name': 'testvol',
  705                    'size': 1,
  706                    'id': 'a720b3c0-d1f0-11e1-9b23-0800200c9a66',
  707                    'created_at': timeutils.utcnow()}
  708         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
  709         self.mock_object(solidfire.SolidFireDriver,
  710                          '_issue_api_request',
  711                          self.fake_issue_api_request_fails)
  712         try:
  713             sfv.create_volume(testvol)
  714             self.fail("Should have thrown Error")
  715         except Exception:
  716             pass
  717 
  718     def test_create_sfaccount(self):
  719         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
  720         self.mock_object(solidfire.SolidFireDriver,
  721                          '_issue_api_request',
  722                          self.fake_issue_api_request)
  723         account = sfv._create_sfaccount('some-name')
  724         self.assertIsNotNone(account)
  725 
  726     def test_create_sfaccount_fails(self):
  727         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
  728         self.mock_object(solidfire.SolidFireDriver,
  729                          '_issue_api_request',
  730                          self.fake_issue_api_request_fails)
  731         self.assertRaises(solidfire.SolidFireAPIException,
  732                           sfv._create_sfaccount, 'project-id')
  733 
  734     def test_get_sfaccounts_for_tenant(self):
  735         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
  736         self.mock_object(solidfire.SolidFireDriver,
  737                          '_issue_api_request',
  738                          self.fake_issue_api_request)
  739         accounts = sfv._get_sfaccounts_for_tenant('some-name')
  740         self.assertIsNotNone(accounts)
  741 
  742     def test_get_sfaccounts_for_tenant_fails(self):
  743         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
  744         self.mock_object(solidfire.SolidFireDriver,
  745                          '_issue_api_request',
  746                          self.fake_issue_api_request_fails)
  747         self.assertRaises(solidfire.SolidFireAPIException,
  748                           sfv._get_sfaccounts_for_tenant, 'some-name')
  749 
  750     def test_get_sfaccount_by_name(self):
  751         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
  752         self.mock_object(solidfire.SolidFireDriver,
  753                          '_issue_api_request',
  754                          self.fake_issue_api_request)
  755         account = sfv._get_sfaccount_by_name('some-name')
  756         self.assertIsNotNone(account)
  757 
  758     def test_get_account_create_availability_no_account(self):
  759         fake_sfaccounts = []
  760         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
  761         sfaccount = sfv._get_account_create_availability(fake_sfaccounts)
  762         self.assertIsNone(sfaccount)
  763 
  764     def test_get_account_create_availability(self):
  765         fake_sfaccounts = [{'accountID': 29,
  766                             'targetSecret': 'shhhh',
  767                             'username': 'prefix-testprjid',
  768                             'volumes': [6, 7, 20]}]
  769         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
  770         sfaccount = sfv._get_account_create_availability(fake_sfaccounts)
  771         self.assertIsNotNone(sfaccount)
  772         self.assertEqual(sfaccount['accountID'],
  773                          fake_sfaccounts[0]['accountID'])
  774 
  775     def test_get_account_create_availability_primary_full(self):
  776         fake_sfaccounts = [{'accountID': 30,
  777                             'targetSecret': 'shhhh',
  778                             'username': 'prefix-testprjid'}]
  779         get_sfaccount_result = {'accountID': 31,
  780                                 'targetSecret': 'shhhh',
  781                                 'username': 'prefix-testprjid_'}
  782         get_vol_result = list(range(1, 2001))
  783         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
  784         with mock.patch.object(sfv,
  785                                '_get_sfaccounts_for_tenant',
  786                                return_value=fake_sfaccounts), \
  787                 mock.patch.object(sfv,
  788                                   '_get_volumes_for_account',
  789                                   return_value=get_vol_result):
  790             sfaccount = sfv._get_account_create_availability(fake_sfaccounts)
  791             self.assertIsNotNone(sfaccount)
  792             self.assertEqual(sfaccount['username'],
  793                              get_sfaccount_result['username'])
  794 
  795     def test_get_account_create_availability_both_full(self):
  796         fake_sfaccounts = [{'accountID': 32,
  797                             'targetSecret': 'shhhh',
  798                             'username': 'prefix-testprjid'},
  799                            {'accountID': 33,
  800                             'targetSecret': 'shhhh',
  801                             'username': 'prefix-testprjid_'}]
  802         get_vol_result = list(range(1, 2001))
  803         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
  804         with mock.patch.object(sfv,
  805                                '_get_sfaccounts_for_tenant',
  806                                return_value=fake_sfaccounts), \
  807                 mock.patch.object(sfv,
  808                                   '_get_volumes_for_account',
  809                                   return_value=get_vol_result):
  810             sfaccount = sfv._get_account_create_availability(fake_sfaccounts)
  811             self.assertIsNone(sfaccount)
  812 
  813     def test_get_create_account(self):
  814         fake_sfaccounts = [{'accountID': 34,
  815                             'targetSecret': 'shhhh',
  816                             'username': 'prefix-testprjid'},
  817                            {'accountID': 35,
  818                             'targetSecret': 'shhhh',
  819                             'username': 'prefix-testprjid_'}]
  820         get_vol_result = list(range(1, 2001))
  821         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
  822         with mock.patch.object(sfv,
  823                                '_get_sfaccounts_for_tenant',
  824                                return_value=fake_sfaccounts), \
  825                 mock.patch.object(sfv,
  826                                   '_get_volumes_for_account',
  827                                   return_value=get_vol_result):
  828             sfaccount = sfv._get_account_create_availability(fake_sfaccounts)
  829             self.assertRaises(solidfire.SolidFireDriverException,
  830                               sfv._get_create_account, sfaccount)
  831 
  832     def test_get_sfaccount_by_name_fails(self):
  833         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
  834         self.mock_object(solidfire.SolidFireDriver,
  835                          '_issue_api_request',
  836                          self.fake_issue_api_request_fails)
  837         self.assertRaises(solidfire.SolidFireAPIException,
  838                           sfv._get_sfaccount_by_name, 'some-name')
  839 
  840     def test_get_sfvol_by_cinder_vref_no_provider_id(self):
  841         fake_sfaccounts = [{'accountID': 25,
  842                             'targetSecret': 'shhhh',
  843                             'username': 'prefix-testprjid',
  844                             'volumes': [6, 7, 20]}]
  845         self.mock_vref = mock_vref()
  846 
  847         vol_result = {'volumeID': 5,
  848                       'name': 'test_volume',
  849                       'accountID': 25,
  850                       'sliceCount': 1,
  851                       'totalSize': 1 * units.Gi,
  852                       'enable512e': True,
  853                       'access': "readWrite",
  854                       'status': "active",
  855                       'attributes': {'uuid': f_uuid[0]},
  856                       'qos': None,
  857                       'iqn': 'super_fake_iqn'}
  858 
  859         mod_conf = self.configuration
  860         mod_conf.sf_enable_vag = True
  861         sfv = solidfire.SolidFireDriver(configuration=mod_conf)
  862         with mock.patch.object(sfv,
  863                                '_get_sfaccounts_for_tenant',
  864                                return_value = fake_sfaccounts), \
  865                 mock.patch.object(sfv, '_issue_api_request',
  866                                   side_effect = self.fake_issue_api_request):
  867             self.mock_vref['provider_id'] = None
  868             sfvol = sfv._get_sfvol_by_cinder_vref(self.mock_vref)
  869             self.assertIsNotNone(sfvol)
  870             self.assertEqual(sfvol['attributes']['uuid'],
  871                              vol_result['attributes']['uuid'])
  872             self.assertEqual(sfvol['volumeID'], vol_result['volumeID'])
  873 
  874     def test_get_sfvol_by_cinder_vref_no_provider_id_nomatch(self):
  875         fake_sfaccounts = [{'accountID': 5,
  876                             'targetSecret': 'shhhh',
  877                             'username': 'prefix-testprjid',
  878                             'volumes': [5, 6, 7, 8]}]
  879 
  880         self.mock_vref = mock_vref()
  881         mod_conf = self.configuration
  882         mod_conf.sf_enable_vag = True
  883 
  884         sfv = solidfire.SolidFireDriver(configuration=mod_conf)
  885         with mock.patch.object(sfv,
  886                                '_get_sfaccounts_for_tenant',
  887                                return_value = fake_sfaccounts), \
  888                 mock.patch.object(sfv, '_issue_api_request',
  889                                   side_effect = self.fake_issue_api_request):
  890             self.mock_vref['provider_id'] = None
  891             self.mock_vref['id'] = '142b9c32-a71A-4fbe-830c-c20c5596caea'
  892             sfvol = sfv._get_sfvol_by_cinder_vref(self.mock_vref)
  893             self.assertIsNone(sfvol)
  894 
  895     def test_get_sfvol_by_cinder_vref_nomatch(self):
  896         fake_sfaccounts = [{'accountID': 5,
  897                             'targetSecret': 'shhhh',
  898                             'username': 'prefix-testprjid',
  899                             'volumes': [5, 6, 7, 8]}]
  900 
  901         self.mock_vref = mock_vref()
  902         mod_conf = self.configuration
  903         mod_conf.sf_enable_vag = True
  904         sfv = solidfire.SolidFireDriver(configuration=mod_conf)
  905         with mock.patch.object(sfv,
  906                                '_get_sfaccounts_for_tenant',
  907                                return_value = fake_sfaccounts), \
  908                 mock.patch.object(sfv, '_issue_api_request',
  909                                   side_effect = self.fake_issue_api_request):
  910             p_i = '324 8 6ecebf5d-5521-4ce1-80f3-358ebc1b9cdc'
  911             self.mock_vref['provider_id'] = p_i
  912             self.mock_vref['id'] = '142b9c32-a71A-4fbe-830c-c20c5596caea'
  913             sfvol = sfv._get_sfvol_by_cinder_vref(self.mock_vref)
  914             self.assertIsNone(sfvol)
  915 
  916     def test_get_sfvol_by_cinder_vref(self):
  917         fake_sfaccounts = [{'accountID': 5,
  918                             'targetSecret': 'shhhh',
  919                             'username': 'prefix-testprjid',
  920                             'volumes': [5, 6, 7, 8]}]
  921 
  922         self.mock_vref = mock_vref()
  923 
  924         get_vol_result = {'volumeID': 5,
  925                           'name': 'test_volume',
  926                           'accountID': 25,
  927                           'sliceCount': 1,
  928                           'totalSize': 1 * units.Gi,
  929                           'enable512e': True,
  930                           'access': "readWrite",
  931                           'status': "active",
  932                           'attributes': {'uuid': f_uuid[0]},
  933                           'qos': None,
  934                           'iqn': 'super_fake_iqn'}
  935 
  936         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
  937         with mock.patch.object(sfv, '_get_sfaccounts_for_tenant',
  938                                return_value = fake_sfaccounts), \
  939                 mock.patch.object(sfv, '_issue_api_request',
  940                                   side_effect = self.fake_issue_api_request):
  941 
  942             sfvol = sfv._get_sfvol_by_cinder_vref(self.mock_vref)
  943             self.assertIsNotNone(sfvol)
  944             self.assertEqual(get_vol_result['volumeID'], sfvol['volumeID'])
  945 
  946     def test_delete_volume(self):
  947         vol_id = 'a720b3c0-d1f0-11e1-9b23-0800200c9a66'
  948         testvol = test_utils.create_volume(
  949             self.ctxt,
  950             id=vol_id,
  951             display_name='test_volume',
  952             provider_id='1 5 None',
  953             multiattach=False)
  954 
  955         fake_sfaccounts = [{'accountID': 5,
  956                             'name': 'testprjid',
  957                             'targetSecret': 'shhhh',
  958                             'username': 'john-wayne'}]
  959 
  960         get_vol_result = {'volumeID': 5,
  961                           'name': 'test_volume',
  962                           'accountID': 25,
  963                           'sliceCount': 1,
  964                           'totalSize': 1 * units.Gi,
  965                           'enable512e': True,
  966                           'access': "readWrite",
  967                           'status': "active",
  968                           'attributes': {},
  969                           'qos': None,
  970                           'iqn': 'super_fake_iqn'}
  971 
  972         mod_conf = self.configuration
  973         mod_conf.sf_enable_vag = True
  974         sfv = solidfire.SolidFireDriver(configuration=mod_conf)
  975         with mock.patch.object(sfv,
  976                                '_get_sfaccounts_for_tenant',
  977                                return_value=fake_sfaccounts), \
  978             mock.patch.object(sfv,
  979                               '_get_sfvol_by_cinder_vref',
  980                               return_value=get_vol_result), \
  981             mock.patch.object(sfv,
  982                               '_issue_api_request'), \
  983             mock.patch.object(sfv,
  984                               '_remove_volume_from_vags') as rem_vol:
  985 
  986             sfv.delete_volume(testvol)
  987             rem_vol.not_called(get_vol_result['volumeID'])
  988 
  989     def test_delete_multiattach_volume(self):
  990         vol_id = 'a720b3c0-d1f0-11e1-9b23-0800200c9a66'
  991         testvol = test_utils.create_volume(
  992             self.ctxt,
  993             id=vol_id,
  994             display_name='test_volume',
  995             provider_id='1 5 None',
  996             multiattach=True)
  997 
  998         fake_sfaccounts = [{'accountID': 5,
  999                             'targetSecret': 'shhhh',
 1000                             'username': 'prefix-testprjid'}]
 1001 
 1002         get_vol_result = {'volumeID': 5,
 1003                           'name': 'test_volume',
 1004                           'accountID': 25,
 1005                           'sliceCount': 1,
 1006                           'totalSize': 1 * units.Gi,
 1007                           'enable512e': True,
 1008                           'access': "readWrite",
 1009                           'status': "active",
 1010                           'attributes': {},
 1011                           'qos': None,
 1012                           'iqn': 'super_fake_iqn'}
 1013 
 1014         mod_conf = self.configuration
 1015         mod_conf.sf_enable_vag = True
 1016         sfv = solidfire.SolidFireDriver(configuration=mod_conf)
 1017         with mock.patch.object(sfv,
 1018                                '_get_sfaccounts_for_tenant',
 1019                                return_value=fake_sfaccounts), \
 1020             mock.patch.object(sfv,
 1021                               '_get_sfvol_by_cinder_vref',
 1022                               return_value=get_vol_result), \
 1023             mock.patch.object(sfv,
 1024                               '_issue_api_request'), \
 1025             mock.patch.object(sfv,
 1026                               '_remove_volume_from_vags') as rem_vol:
 1027 
 1028             sfv.delete_volume(testvol)
 1029             rem_vol.assert_called_with(get_vol_result['volumeID'])
 1030 
 1031     def test_delete_volume_no_volume_on_backend(self):
 1032         fake_sfaccounts = [{'accountID': 5,
 1033                             'targetSecret': 'shhhh',
 1034                             'username': 'prefix-testprjid'}]
 1035         fake_no_volumes = []
 1036         testvol = test_utils.create_volume(self.ctxt)
 1037 
 1038         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 1039         with mock.patch.object(sfv,
 1040                                '_get_sfaccounts_for_tenant',
 1041                                return_value=fake_sfaccounts), \
 1042             mock.patch.object(sfv,
 1043                               '_get_volumes_for_account',
 1044                               return_value=fake_no_volumes):
 1045             sfv.delete_volume(testvol)
 1046 
 1047     def test_delete_snapshot_no_snapshot_on_backend(self):
 1048         fake_sfaccounts = [{'accountID': 5,
 1049                             'targetSecret': 'shhhh',
 1050                             'username': 'prefix-testprjid'}]
 1051         fake_no_volumes = []
 1052         testvol = test_utils.create_volume(
 1053             self.ctxt,
 1054             volume_id='b831c4d1-d1f0-11e1-9b23-0800200c9a66')
 1055         testsnap = test_utils.create_snapshot(
 1056             self.ctxt,
 1057             volume_id=testvol.id)
 1058 
 1059         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 1060         with mock.patch.object(sfv,
 1061                                '_get_sfaccounts_for_tenant',
 1062                                return_value=fake_sfaccounts), \
 1063             mock.patch.object(sfv,
 1064                               '_get_volumes_for_account',
 1065                               return_value=fake_no_volumes):
 1066             sfv.delete_snapshot(testsnap)
 1067 
 1068     def fake_ext_qos_issue_api_request(self, method, params, version='1.0',
 1069                                        endpoint=None):
 1070         EXPECTED_SIZE = 2 << 30  # 2147483648 size + increase
 1071 
 1072         if method == 'ModifyVolume':
 1073             response = {'error': {'code': 0,
 1074                                   'name': 'Extend Volume',
 1075                                   'message': 'extend fail, size/scale-iops'},
 1076                         'id': 1}
 1077             if params.get('totalSize', None) != EXPECTED_SIZE:
 1078                 msg = ('Error (%s) encountered during '
 1079                        'SolidFire API call.' % response['error']['name'])
 1080                 raise solidfire.SolidFireAPIException(message=msg)
 1081 
 1082             if params.get('qos', None) != SolidFireVolumeTestCase.EXPECTED_QOS:
 1083                 msg = ('Error (%s) encountered during '
 1084                        'SolidFire API call.' % response['error']['name'])
 1085                 raise solidfire.SolidFireAPIException(message=msg)
 1086 
 1087             return {'result': {}, 'id': 1}
 1088 
 1089         elif method == 'GetAccountByName' and version == '1.0':
 1090             results = {'result': {'account':
 1091                                   {'accountID': 25,
 1092                                    'username': params['username'],
 1093                                    'status': 'active',
 1094                                    'initiatorSecret': '123456789012',
 1095                                    'targetSecret': '123456789012',
 1096                                    'attributes': {},
 1097                                    'volumes': [6, 7, 20]}},
 1098                        "id": 1}
 1099             return results
 1100 
 1101         elif method == 'ListVolumesForAccount' and version == '1.0':
 1102             test_name = 'OS-VOLID-a720b3c0-d1f0-11e1-9b23-0800200c9a66'
 1103             result = {'result': {
 1104                 'volumes': [{'volumeID': 5,
 1105                              'name': test_name,
 1106                              'accountID': 25,
 1107                              'sliceCount': 1,
 1108                              'totalSize': 1 * units.Gi,
 1109                              'enable512e': True,
 1110                              'access': "readWrite",
 1111                              'status': "active",
 1112                              'attributes': {},
 1113                              'qos': None,
 1114                              'iqn': test_name}]}}
 1115             return result
 1116 
 1117         else:
 1118             return None
 1119 
 1120     def test_extend_volume(self):
 1121         self.mock_object(solidfire.SolidFireDriver,
 1122                          '_issue_api_request',
 1123                          self.fake_issue_api_request)
 1124         testvol = {'project_id': 'testprjid',
 1125                    'name': 'test_volume',
 1126                    'size': 1,
 1127                    'id': 'a720b3c0-d1f0-11e1-9b23-0800200c9a66',
 1128                    'created_at': timeutils.utcnow()}
 1129 
 1130         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 1131         sfv.extend_volume(testvol, 2)
 1132 
 1133     def test_extend_volume_with_scaled_qos(self):
 1134         size = 1
 1135         self.mock_object(solidfire.SolidFireDriver,
 1136                          '_issue_api_request',
 1137                          self.fake_issue_api_request)
 1138         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 1139         qos_ref = qos_specs.create(self.ctxt,
 1140                                    'qos-specs-1', {'minIOPS': '100',
 1141                                                    'maxIOPS': '1000',
 1142                                                    'burstIOPS': '1500',
 1143                                                    'scaledIOPS': 'True',
 1144                                                    'scaleMin': '10',
 1145                                                    'scaleMax': '20',
 1146                                                    'scaleBurst': '30'})
 1147         type_ref = volume_types.create(self.ctxt, "type1",
 1148                                        {'qos:minIOPS': '1000',
 1149                                         'qos:maxIOPS': '10000',
 1150                                         'qos:burstIOPS': '20000'})
 1151         qos_specs.associate_qos_with_type(self.ctxt,
 1152                                           qos_ref['id'],
 1153                                           type_ref['id'])
 1154         qos = sfv._set_qos_by_volume_type(self.ctxt, type_ref['id'], size + 1)
 1155         self.assertEqual(SolidFireVolumeTestCase.EXPECTED_QOS, qos)
 1156 
 1157     def test_extend_volume_fails_no_volume(self):
 1158         self.mock_object(solidfire.SolidFireDriver,
 1159                          '_issue_api_request',
 1160                          self.fake_issue_api_request)
 1161         testvol = {'project_id': 'testprjid',
 1162                    'name': 'no-name',
 1163                    'size': 1,
 1164                    'id': 'not-found'}
 1165         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 1166         self.assertRaises(exception.VolumeNotFound,
 1167                           sfv.extend_volume,
 1168                           testvol, 2)
 1169 
 1170     def test_extend_volume_fails_account_lookup(self):
 1171         # NOTE(JDG) This test just fakes update_cluster_status
 1172         # this is intentional for this test
 1173         self.mock_object(solidfire.SolidFireDriver,
 1174                          '_update_cluster_status',
 1175                          self.fake_update_cluster_status)
 1176         self.mock_object(solidfire.SolidFireDriver,
 1177                          '_issue_api_request',
 1178                          self.fake_issue_api_request)
 1179         testvol = {'project_id': 'testprjid',
 1180                    'name': 'no-name',
 1181                    'size': 1,
 1182                    'id': 'a720b3c0-d1f0-11e1-9b23-0800200c9a66',
 1183                    'created_at': timeutils.utcnow()}
 1184 
 1185         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 1186         self.mock_object(solidfire.SolidFireDriver,
 1187                          '_issue_api_request',
 1188                          self.fake_issue_api_request_fails)
 1189         self.assertRaises(solidfire.SolidFireAPIException,
 1190                           sfv.extend_volume,
 1191                           testvol, 2)
 1192 
 1193     @mock.patch.object(solidfire.SolidFireDriver, '_get_sfaccount')
 1194     @mock.patch.object(solidfire.SolidFireDriver, '_get_sf_volume')
 1195     @mock.patch.object(solidfire.SolidFireDriver, '_retrieve_qos_setting')
 1196     @mock.patch.object(solidfire.SolidFireDriver, '_issue_api_request')
 1197     @mock.patch.object(solidfire.SolidFireDriver,
 1198                        '_retrieve_replication_settings')
 1199     @mock.patch.object(solidfire.SolidFireDriver, '_create_cluster_reference')
 1200     def test_extend_replicated_volume(self, mock_create_cluster_reference,
 1201                                       mock_retrieve_replication_settings,
 1202                                       mock_issue_api_request,
 1203                                       mock_retrieve_qos_setting,
 1204                                       mock_get_sf_volume,
 1205                                       mock_get_sfaccount):
 1206 
 1207         mock_create_cluster_reference.return_value = {
 1208             'mvip': self.mvip,
 1209             'svip': self.svip}
 1210 
 1211         mock_retrieve_replication_settings.return_value = "Async"
 1212         mock_retrieve_qos_setting.return_value = None
 1213         self.fake_sfvol['volumePairs'] = [{'remoteVolumeID': 26}]
 1214         mock_get_sf_volume.return_value = self.fake_sfvol
 1215         mock_get_sfaccount.return_value = self.fake_sfaccount
 1216 
 1217         ctx = context.get_admin_context()
 1218         utc_now = timeutils.utcnow().isoformat()
 1219         vol_fields = {
 1220             'id': f_uuid,
 1221             'created_at': utc_now
 1222         }
 1223         vol = fake_volume.fake_volume_obj(ctx, **vol_fields)
 1224 
 1225         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 1226         sfv.replication_enabled = True
 1227         sfv.cluster_pairs = self.cluster_pairs
 1228         sfv.active_cluster['mvip'] = self.mvip
 1229         sfv.active_cluster['svip'] = self.svip
 1230 
 1231         mock_issue_api_request.reset_mock()
 1232         # pylint: disable=assignment-from-no-return
 1233         updates = sfv.extend_volume(vol, vol.size + 10)
 1234         # pylint: enable=assignment-from-no-return
 1235         self.assertIsNone(updates)
 1236 
 1237         modify_params = {
 1238             'volumeID': self.fake_sfvol['volumeID'],
 1239             'totalSize': int((vol.size + 10) * units.Gi),
 1240             'qos': None
 1241         }
 1242         modify_params2 = modify_params.copy()
 1243         modify_params2['volumeID'] = 26
 1244 
 1245         expected_calls = [
 1246             mock.call("ModifyVolume", modify_params, version='5.0'),
 1247             mock.call("ModifyVolume", modify_params2, version='5.0',
 1248                       endpoint=self.cluster_pairs[0]['endpoint'])
 1249         ]
 1250 
 1251         mock_issue_api_request.assert_has_calls(expected_calls)
 1252         mock_create_cluster_reference.assert_called()
 1253         mock_retrieve_replication_settings.assert_called_with(vol)
 1254         mock_retrieve_qos_setting.assert_called_with(vol, vol.size + 10)
 1255         mock_get_sf_volume.assert_called_with(
 1256             vol.id, {'accountID': self.fake_sfaccount['accountID']})
 1257         mock_get_sfaccount.assert_called_with(vol.project_id)
 1258 
 1259     def test_set_by_qos_spec_with_scoping(self):
 1260         size = 1
 1261         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 1262         qos_ref = qos_specs.create(self.ctxt,
 1263                                    'qos-specs-1', {'qos:minIOPS': '1000',
 1264                                                    'qos:maxIOPS': '10000',
 1265                                                    'qos:burstIOPS': '20000'})
 1266         type_ref = volume_types.create(self.ctxt,
 1267                                        "type1", {"qos:minIOPS": "100",
 1268                                                  "qos:burstIOPS": "300",
 1269                                                  "qos:maxIOPS": "200"})
 1270         qos_specs.associate_qos_with_type(self.ctxt,
 1271                                           qos_ref['id'],
 1272                                           type_ref['id'])
 1273         qos = sfv._set_qos_by_volume_type(self.ctxt, type_ref['id'], size)
 1274         self.assertEqual(self.expected_qos_results, qos)
 1275 
 1276     def test_set_by_qos_spec(self):
 1277         size = 1
 1278         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 1279         qos_ref = qos_specs.create(self.ctxt,
 1280                                    'qos-specs-1', {'minIOPS': '1000',
 1281                                                    'maxIOPS': '10000',
 1282                                                    'burstIOPS': '20000'})
 1283         type_ref = volume_types.create(self.ctxt,
 1284                                        "type1", {"qos:minIOPS": "100",
 1285                                                  "qos:burstIOPS": "300",
 1286                                                  "qos:maxIOPS": "200"})
 1287         qos_specs.associate_qos_with_type(self.ctxt,
 1288                                           qos_ref['id'],
 1289                                           type_ref['id'])
 1290         qos = sfv._set_qos_by_volume_type(self.ctxt, type_ref['id'], size)
 1291         self.assertEqual(self.expected_qos_results, qos)
 1292 
 1293     @file_data("scaled_iops_test_data.json")
 1294     @unpack
 1295     def test_scaled_qos_spec_by_type(self, argument):
 1296         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 1297         size = argument[0].pop('size')
 1298         type_ref = volume_types.create(self.ctxt, "type1", argument[0])
 1299         qos = sfv._set_qos_by_volume_type(self.ctxt, type_ref['id'], size)
 1300         self.assertEqual(argument[1], qos)
 1301 
 1302     @file_data("scaled_iops_invalid_data.json")
 1303     @unpack
 1304     def test_set_scaled_qos_by_type_invalid(self, inputs):
 1305         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 1306         size = inputs[0].pop('size')
 1307         type_ref = volume_types.create(self.ctxt, "type1", inputs[0])
 1308         self.assertRaises(exception.InvalidQoSSpecs,
 1309                           sfv._set_qos_by_volume_type,
 1310                           self.ctxt,
 1311                           type_ref['id'],
 1312                           size)
 1313 
 1314     def test_accept_transfer(self):
 1315         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 1316         self.mock_object(solidfire.SolidFireDriver,
 1317                          '_issue_api_request',
 1318                          self.fake_issue_api_request)
 1319         testvol = {'project_id': 'testprjid',
 1320                    'name': 'test_volume',
 1321                    'size': 1,
 1322                    'id': 'a720b3c0-d1f0-11e1-9b23-0800200c9a66',
 1323                    'created_at': timeutils.utcnow()}
 1324         expected = {'provider_auth': 'CHAP cinder-new_project 123456789012'}
 1325         self.assertEqual(expected,
 1326                          sfv.accept_transfer(self.ctxt,
 1327                                              testvol,
 1328                                              'new_user', 'new_project'))
 1329 
 1330     def test_accept_transfer_volume_not_found_raises(self):
 1331         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 1332         self.mock_object(solidfire.SolidFireDriver,
 1333                          '_issue_api_request',
 1334                          self.fake_issue_api_request)
 1335         testvol = {'project_id': 'testprjid',
 1336                    'name': 'test_volume',
 1337                    'size': 1,
 1338                    'id': 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa',
 1339                    'created_at': timeutils.utcnow()}
 1340         self.assertRaises(exception.VolumeNotFound,
 1341                           sfv.accept_transfer,
 1342                           self.ctxt,
 1343                           testvol,
 1344                           'new_user',
 1345                           'new_project')
 1346 
 1347     def test_retype(self):
 1348         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 1349         self.mock_object(solidfire.SolidFireDriver,
 1350                          '_issue_api_request',
 1351                          self.fake_issue_api_request)
 1352         type_ref = volume_types.create(self.ctxt,
 1353                                        "type1", {"qos:minIOPS": "500",
 1354                                                  "qos:burstIOPS": "2000",
 1355                                                  "qos:maxIOPS": "1000"})
 1356         diff = {'encryption': {}, 'qos_specs': {},
 1357                 'extra_specs': {'qos:burstIOPS': ('10000', u'2000'),
 1358                                 'qos:minIOPS': ('1000', u'500'),
 1359                                 'qos:maxIOPS': ('10000', u'1000')}}
 1360         host = None
 1361         updates = {'project_id': 'testprjid',
 1362                    'name': 'test_volume',
 1363                    'size': 1,
 1364                    'id': 'a720b3c0-d1f0-11e1-9b23-0800200c9a66',
 1365                    'created_at': timeutils.utcnow()}
 1366 
 1367         ctx = context.get_admin_context()
 1368         testvol = fake_volume.fake_volume_obj(ctx, **updates)
 1369 
 1370         migrated, updates = sfv.retype(self.ctxt, testvol, type_ref,
 1371                                        diff, host)
 1372         self.assertTrue(migrated)
 1373         self.assertEqual({}, updates)
 1374 
 1375     @data(None, 'Success', 'Error', f'target:{f_uuid[0]}')
 1376     @mock.patch.object(solidfire.SolidFireDriver, '_get_sf_volume')
 1377     @mock.patch.object(solidfire.SolidFireDriver, '_get_sfaccount')
 1378     def test_attach_volume(self, mig_status, mock_get_sfaccount,
 1379                            mock_get_sf_volume):
 1380         mock_get_sfaccount.return_value = self.fake_sfaccount
 1381         i_uuid = 'fake_instance_uuid'
 1382         ctx = context.get_admin_context()
 1383         type_fields = {}
 1384         vol_type = fake_volume.fake_volume_type_obj(ctx, **type_fields)
 1385         utc_now = timeutils.utcnow().isoformat()
 1386         vol_fields = {
 1387             'id': f_uuid[0],
 1388             'created_at': utc_now,
 1389             'volume_type': vol_type,
 1390             'volume_type_id': vol_type.id,
 1391             'migration_status': mig_status,
 1392         }
 1393         vol = fake_volume.fake_volume_obj(ctx, **vol_fields)
 1394         sf_vol = self.fake_sfvol
 1395         mock_get_sf_volume.return_value = sf_vol
 1396 
 1397         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 1398         sfv.attach_volume(ctx, vol, i_uuid, 'fake_host', '/dev/sdf')
 1399         self.assertEqual(sf_vol['attributes']['attached_to'],
 1400                          i_uuid)
 1401         mock_get_sfaccount.assert_called()
 1402         mock_get_sf_volume.assert_called()
 1403 
 1404     def test_retype_with_qos_spec(self):
 1405         test_type = {'name': 'sf-1',
 1406                      'qos_specs_id': 'fb0576d7-b4b5-4cad-85dc-ca92e6a497d1',
 1407                      'deleted': False,
 1408                      'created_at': '2014-02-06 04:58:11',
 1409                      'updated_at': None,
 1410                      'extra_specs': {},
 1411                      'deleted_at': None,
 1412                      'id': 'e730e97b-bc7d-4af3-934a-32e59b218e81'}
 1413 
 1414         test_qos_spec = {'id': 'asdfafdasdf',
 1415                          'specs': {'minIOPS': '1000',
 1416                                    'maxIOPS': '2000',
 1417                                    'burstIOPS': '3000'}}
 1418 
 1419         def _fake_get_volume_type(ctxt, type_id):
 1420             return test_type
 1421 
 1422         def _fake_get_qos_spec(ctxt, spec_id):
 1423             return test_qos_spec
 1424 
 1425         self.mock_object(solidfire.SolidFireDriver,
 1426                          '_issue_api_request',
 1427                          self.fake_issue_api_request)
 1428         self.mock_object(volume_types, 'get_volume_type',
 1429                          _fake_get_volume_type)
 1430         self.mock_object(qos_specs, 'get_qos_specs',
 1431                          _fake_get_qos_spec)
 1432 
 1433         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 1434 
 1435         diff = {'encryption': {}, 'extra_specs': {},
 1436                 'qos_specs': {'burstIOPS': ('10000', '2000'),
 1437                               'minIOPS': ('1000', '500'),
 1438                               'maxIOPS': ('10000', '1000')}}
 1439         host = None
 1440         updates = {'project_id': 'testprjid',
 1441                    'name': 'test_volume',
 1442                    'size': 1,
 1443                    'id': 'a720b3c0-d1f0-11e1-9b23-0800200c9a66',
 1444                    'created_at': timeutils.utcnow()}
 1445         ctx = context.get_admin_context()
 1446         testvol = fake_volume.fake_volume_obj(ctx, **updates)
 1447 
 1448         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 1449         migrated, updates = sfv.retype(self.ctxt, testvol, test_type,
 1450                                        diff, host)
 1451         self.assertTrue(migrated)
 1452         self.assertEqual({}, updates)
 1453 
 1454     @mock.patch.object(solidfire.SolidFireDriver, '_get_sfaccount')
 1455     @mock.patch.object(solidfire.SolidFireDriver, '_get_sf_volume')
 1456     @mock.patch.object(solidfire.SolidFireDriver, '_set_rep_by_volume_type')
 1457     @mock.patch.object(solidfire.SolidFireDriver,
 1458                        '_retrieve_replication_settings')
 1459     @mock.patch.object(solidfire.SolidFireDriver, '_get_default_volume_params')
 1460     @mock.patch.object(solidfire.SolidFireDriver, '_replicate_volume')
 1461     @mock.patch.object(solidfire.SolidFireDriver, '_disable_replication')
 1462     @mock.patch.object(solidfire.SolidFireDriver, '_set_qos_by_volume_type')
 1463     def test_retype_replicated(self,
 1464                                mock_set_qos_by_volume_type,
 1465                                mock_disable_replication,
 1466                                mock_replicate_volume,
 1467                                mock_get_default_volume_params,
 1468                                mock_retrieve_replication_settings,
 1469                                mock_set_rep_by_volume_type,
 1470                                mock_get_sf_volume,
 1471                                mock_get_sfaccount):
 1472 
 1473         all_mocks = locals()
 1474         mock_get_sf_volume.return_value = None
 1475         mock_get_sfaccount.return_value = self.fake_sfaccount
 1476         mock_retrieve_replication_settings.return_value = 'Async'
 1477 
 1478         ctx = context.get_admin_context()
 1479         type_fields = {'extra_specs': {'replication_enabled': '<is> True'},
 1480                        'id': fakes.get_fake_uuid()}
 1481         src_vol_type = fake_volume.fake_volume_type_obj(ctx, **type_fields)
 1482 
 1483         fake_provider_id = "%s %s %s" % (
 1484             self.fake_sfvol['volumeID'],
 1485             fakes.FAKE_UUID,
 1486             self.cluster_pairs[0]['uuid'])
 1487         utc_now = timeutils.utcnow().isoformat()
 1488         vol_fields = {
 1489             'id': fakes.FAKE_UUID,
 1490             'created_at': utc_now,
 1491             'volume_type': src_vol_type,
 1492             'volume_type_id': src_vol_type.id,
 1493             'provider_id': fake_provider_id
 1494         }
 1495 
 1496         vol = fake_volume.fake_volume_obj(ctx, **vol_fields)
 1497         dst_vol_type = fake_volume.fake_volume_type_obj(ctx)
 1498 
 1499         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 1500         sfv.replication_enabled = True
 1501         sfv.cluster_pairs = self.cluster_pairs
 1502         sfv.active_cluster['mvip'] = self.mvip
 1503         sfv.active_cluster['svip'] = self.svip
 1504 
 1505         self.assertRaises(exception.VolumeNotFound,
 1506                           sfv.retype, ctx, vol, dst_vol_type, None, None)
 1507         mock_get_sfaccount.assert_called_once_with(vol.project_id)
 1508         mock_get_sf_volume.assert_called_once_with(
 1509             vol.id, {'accountID': self.fake_sfaccount['accountID']})
 1510 
 1511         mock_get_sfaccount.reset_mock()
 1512         mock_get_sf_volume.reset_mock()
 1513         expected = {"key": "value"}
 1514         mock_get_sf_volume.return_value = self.fake_sfvol
 1515         mock_replicate_volume.return_value = expected
 1516         mock_set_rep_by_volume_type.side_effect = [src_vol_type, dst_vol_type]
 1517 
 1518         retyped, updates = sfv.retype(ctx, vol, dst_vol_type, None, None)
 1519         self.assertDictEqual(expected, updates)
 1520 
 1521         mock_get_sfaccount.assert_called_once_with(vol.project_id)
 1522         mock_get_sf_volume.assert_called_once_with(
 1523             vol.id, {'accountID': self.fake_sfaccount['accountID']})
 1524         mock_get_default_volume_params.assert_called()
 1525         mock_disable_replication.assert_not_called()
 1526         mock_replicate_volume.assert_called_once()
 1527         mock_retrieve_replication_settings.assert_called_once()
 1528         mock_set_qos_by_volume_type.assert_called_once()
 1529 
 1530         expected = {}
 1531         for mk in all_mocks.values():
 1532             if isinstance(mk, mock.MagicMock):
 1533                 mk.reset_mock()
 1534 
 1535         mock_set_rep_by_volume_type.side_effect = [src_vol_type, None]
 1536         retyped, updates = sfv.retype(ctx, vol, dst_vol_type, None, None)
 1537         self.assertDictEqual(expected, updates)
 1538         mock_get_sfaccount.assert_called_once_with(vol.project_id)
 1539         mock_get_sf_volume.assert_called_once_with(
 1540             vol.id, {'accountID': self.fake_sfaccount['accountID']})
 1541         mock_get_default_volume_params.assert_not_called()
 1542         mock_disable_replication.assert_called_with(vol)
 1543         mock_replicate_volume.assert_not_called()
 1544         mock_retrieve_replication_settings.assert_not_called()
 1545         mock_set_qos_by_volume_type.assert_called_once()
 1546 
 1547     @mock.patch.object(solidfire.SolidFireDriver, '_issue_api_request')
 1548     @mock.patch.object(solidfire.SolidFireDriver, '_create_cluster_reference')
 1549     def test_update_cluster_status(self, mock_create_cluster_reference,
 1550                                    mock_issue_api_request):
 1551         mock_create_cluster_reference.return_value = {
 1552             'mvip': self.mvip,
 1553             'svip': self.svip}
 1554         fake_results = {'result': {'clusterCapacity': {
 1555             'usedMetadataSpaceInSnapshots': 16476454912,
 1556             'maxUsedMetadataSpace': 432103337164,
 1557             'activeBlockSpace': 616690857535,
 1558             'uniqueBlocksUsedSpace': 628629229316,
 1559             'totalOps': 7092186135,
 1560             'peakActiveSessions': 0,
 1561             'uniqueBlocks': 519489473,
 1562             'maxOverProvisionableSpace': 276546135777280,
 1563             'zeroBlocks': 8719571984,
 1564             'provisionedSpace': 19938551005184,
 1565             'maxUsedSpace': 8402009333760,
 1566             'peakIOPS': 0,
 1567             'timestamp': '2019-04-24T12:08:22Z',
 1568             'currentIOPS': 0,
 1569             'usedSpace': 628629229316,
 1570             'activeSessions': 0,
 1571             'nonZeroBlocks': 1016048624,
 1572             'maxProvisionedSpace': 55309227155456,
 1573             'usedMetadataSpace': 16476946432,
 1574             'averageIOPS': 0,
 1575             'snapshotNonZeroBlocks': 1606,
 1576             'maxIOPS': 200000,
 1577             'clusterRecentIOSize': 0}}}
 1578         results_with_zero = fake_results.copy()
 1579         results_with_zero['result']['clusterCapacity']['nonZeroBlocks'] = 0
 1580         mock_issue_api_request.return_value = fake_results
 1581         driver_defined_stats = ['volume_backend_name', 'vendor_name',
 1582                                 'driver_version', 'storage_protocol',
 1583                                 'consistencygroup_support',
 1584                                 'consistent_group_snapshot_enabled',
 1585                                 'replication_enabled', 'active_cluster_mvip',
 1586                                 'reserved_percentage', 'QoS_support',
 1587                                 'multiattach', 'total_capacity_gb',
 1588                                 'free_capacity_gb', 'compression_percent',
 1589                                 'deduplication_percent',
 1590                                 'thin_provision_percent', 'provisioned_iops',
 1591                                 'current_iops', 'average_iops', 'max_iops',
 1592                                 'peak_iops', 'thin_provisioning_support',
 1593                                 'provisioned_capacity_gb',
 1594                                 'max_over_subscription_ratio']
 1595         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 1596         sfv.configuration.sf_provisioning_calc = 'usedSpace'
 1597         sfv.active_cluster['mvip'] = self.mvip
 1598         sfv.active_cluster['svip'] = self.svip
 1599         sfv._update_cluster_status()
 1600 
 1601         for key in driver_defined_stats:
 1602             if sfv.cluster_stats.get(key, None) is None:
 1603                 msg = 'Key %s should be present at driver stats.' % key
 1604                 raise exception.CinderException(message=msg)
 1605 
 1606         for key in driver_defined_stats:
 1607             self.assertIn(key, driver_defined_stats)
 1608 
 1609         mock_create_cluster_reference.assert_called()
 1610         mock_issue_api_request.assert_called_with('GetClusterCapacity',
 1611                                                   {}, version='8.0')
 1612 
 1613         mock_issue_api_request.reset_mock()
 1614         mock_issue_api_request.return_value = results_with_zero
 1615         sfv._update_cluster_status()
 1616 
 1617         self.assertEqual(100, sfv.cluster_stats['compression_percent'])
 1618         self.assertEqual(100, sfv.cluster_stats['deduplication_percent'])
 1619         self.assertEqual(100, sfv.cluster_stats['thin_provision_percent'])
 1620 
 1621         mock_create_cluster_reference.assert_called()
 1622         mock_issue_api_request.assert_called_with('GetClusterCapacity',
 1623                                                   {}, version='8.0')
 1624 
 1625     def test_update_cluster_status_mvip_unreachable(self):
 1626         self.mock_object(solidfire.SolidFireDriver,
 1627                          '_issue_api_request',
 1628                          self.fake_issue_api_request)
 1629 
 1630         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 1631         with mock.patch.object(sfv,
 1632                                '_issue_api_request',
 1633                                side_effect=self.fake_issue_api_request_fails):
 1634             sfv._update_cluster_status()
 1635             self.assertEqual(0, sfv.cluster_stats['free_capacity_gb'])
 1636             self.assertEqual(0, sfv.cluster_stats['total_capacity_gb'])
 1637 
 1638     def test_manage_existing_volume(self):
 1639         external_ref = {'name': 'existing volume', 'source-id': 5}
 1640         updates = {'project_id': 'testprjid',
 1641                    'name': 'testvol',
 1642                    'size': 1,
 1643                    'id': 'a720b3c0-d1f0-11e1-9b23-0800200c9a66',
 1644                    'created_at': timeutils.utcnow()}
 1645         ctx = context.get_admin_context()
 1646         testvol = fake_volume.fake_volume_obj(ctx, **updates)
 1647 
 1648         self.mock_object(solidfire.SolidFireDriver,
 1649                          '_issue_api_request',
 1650                          self.fake_issue_api_request)
 1651         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 1652         model_update = sfv.manage_existing(testvol, external_ref)
 1653         self.assertIsNotNone(model_update)
 1654         self.assertNotIn('provider_geometry', model_update)
 1655 
 1656     def test_manage_existing_get_size(self):
 1657         external_ref = {'name': 'existing volume', 'source-id': 5}
 1658         testvol = {'project_id': 'testprjid',
 1659                    'name': 'testvol',
 1660                    'size': 1,
 1661                    'id': 'a720b3c0-d1f0-11e1-9b23-0800200c9a66',
 1662                    'created_at': timeutils.utcnow()}
 1663         mock_issue_api_request = self.mock_object(solidfire.SolidFireDriver,
 1664                                                   '_issue_api_request')
 1665         mock_issue_api_request.side_effect = self.fake_issue_api_request
 1666         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 1667         size = sfv.manage_existing_get_size(testvol, external_ref)
 1668         self.assertEqual(2, size)
 1669 
 1670     @mock.patch.object(solidfire.SolidFireDriver, '_issue_api_request')
 1671     @mock.patch.object(solidfire.SolidFireDriver, '_get_create_account')
 1672     @mock.patch.object(solidfire.SolidFireDriver, '_get_default_volume_params')
 1673     @mock.patch.object(solidfire.SolidFireDriver,
 1674                        '_retrieve_replication_settings')
 1675     @mock.patch.object(solidfire.SolidFireDriver, '_replicate_volume')
 1676     @mock.patch.object(solidfire.SolidFireDriver, '_get_model_info')
 1677     @mock.patch.object(solidfire.SolidFireDriver, '_update_cluster_status')
 1678     @mock.patch.object(solidfire.SolidFireDriver, '_create_cluster_reference')
 1679     def test_manage_existing_replicated_fail(
 1680             self,
 1681             mock_create_cluster_reference,
 1682             mock_update_cluster_status,
 1683             mock_get_model_info,
 1684             mock_replicate_volume,
 1685             mock_retrieve_replication_settings,
 1686             mock_get_default_volume_params,
 1687             mock_get_create_account,
 1688             mock_issue_api_request):
 1689 
 1690         mock_retrieve_replication_settings.return_value = 'Async'
 1691         mock_get_default_volume_params.return_value = {'totalSize': 50}
 1692         mock_get_create_account.return_value = self.fake_sfaccount
 1693         mock_replicate_volume.side_effect = solidfire.SolidFireAPIException
 1694 
 1695         ctx = context.get_admin_context()
 1696         type_fields = {'extra_specs': {'replication_enabled': '<is> True'},
 1697                        'id': fakes.get_fake_uuid()}
 1698         vol_type = fake_volume.fake_volume_type_obj(ctx, **type_fields)
 1699 
 1700         fake_provider_id = "%s %s %s" % (
 1701             self.fake_sfvol['volumeID'],
 1702             fakes.FAKE_UUID,
 1703             self.cluster_pairs[0]['uuid'])
 1704         utc_now = timeutils.utcnow().isoformat()
 1705         vol_fields = {
 1706             'id': fakes.FAKE_UUID,
 1707             'created_at': utc_now,
 1708             'volume_type': vol_type,
 1709             'volume_type_id': vol_type.id,
 1710             'provider_id': fake_provider_id
 1711         }
 1712 
 1713         vol = fake_volume.fake_volume_obj(ctx, **vol_fields)
 1714         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 1715         sfv.replication_enabled = True
 1716         sfv.active_cluster['mvip'] = self.mvip
 1717         sfv.active_cluster['svip'] = self.svip
 1718 
 1719         external_ref = {}
 1720         self.assertRaises(solidfire.SolidFireAPIException,
 1721                           sfv.manage_existing, vol, external_ref)
 1722 
 1723         self.fake_sfvol['volumePairs'] = [{'remoteVolumeID': 26}]
 1724         mock_issue_api_request.return_value = {
 1725             'result': {'volumes': [self.fake_sfvol]}}
 1726         external_ref = {'source-id': 6, 'name': 'new-being-managed'}
 1727         self.assertRaises(solidfire.SolidFireDriverException,
 1728                           sfv.manage_existing, vol, external_ref)
 1729 
 1730         mock_get_default_volume_params.return_value = {'totalSize': 50}
 1731         self.fake_sfvol['volumePairs'] = []
 1732         mock_issue_api_request.return_value = {
 1733             'result': {'volumes': [self.fake_sfvol]}}
 1734         self.assertRaises(solidfire.SolidFireAPIException,
 1735                           sfv.manage_existing, vol, external_ref)
 1736 
 1737         modify_attributes = {'uuid': vol.id,
 1738                              'is_clone': 'False',
 1739                              'os_imported_at': utc_now + "+00:00",
 1740                              'old_name': 'new-being-managed'}
 1741         modify_params1 = {'volumeID': self.fake_sfvol['volumeID'],
 1742                           'attributes': modify_attributes}
 1743         modify_params2 = {'volumeID': self.fake_sfvol['volumeID'],
 1744                           'attributes': self.fake_sfvol['attributes']}
 1745         calls = [mock.call('ListActiveVolumes',
 1746                            {'startVolumeID': self.fake_sfvol['volumeID'],
 1747                             'limit': 1}),
 1748                  mock.call('ModifyVolume', modify_params1, version='5.0'),
 1749                  mock.call('ModifyVolume', modify_params2, version='5.0')]
 1750 
 1751         mock_issue_api_request.assert_has_calls(calls)
 1752         mock_get_model_info.assert_not_called()
 1753         mock_create_cluster_reference.assert_called_once()
 1754         mock_update_cluster_status.assert_called_once()
 1755         mock_replicate_volume.assert_called()
 1756         mock_retrieve_replication_settings.assert_called_with(vol)
 1757         mock_get_default_volume_params.assert_called_with(vol)
 1758         mock_get_create_account.assert_called_with(vol.project_id)
 1759 
 1760     @mock.patch.object(solidfire.SolidFireDriver, '_get_sfaccount')
 1761     @mock.patch.object(solidfire.SolidFireDriver, '_get_sf_volume')
 1762     @mock.patch.object(solidfire.SolidFireDriver, '_set_rep_by_volume_type')
 1763     @mock.patch.object(solidfire.SolidFireDriver,
 1764                        '_retrieve_replication_settings')
 1765     @mock.patch.object(solidfire.SolidFireDriver, '_get_default_volume_params')
 1766     @mock.patch.object(solidfire.SolidFireDriver, '_replicate_volume')
 1767     @mock.patch.object(solidfire.SolidFireDriver, '_disable_replication')
 1768     @mock.patch.object(solidfire.SolidFireDriver, '_set_qos_by_volume_type')
 1769     def test_manage_existing_replicated(
 1770             self,
 1771             mock_set_qos_by_volume_type,
 1772             mock_disable_replication,
 1773             mock_replicate_volume,
 1774             mock_get_default_volume_params,
 1775             mock_retrieve_replication_settings,
 1776             mock_set_rep_by_volume_type,
 1777             mock_get_sf_volume,
 1778             mock_get_sfaccount):
 1779 
 1780         mock_get_sf_volume.return_value = None
 1781         mock_get_sfaccount.return_value = self.fake_sfaccount
 1782         mock_retrieve_replication_settings.return_value = 'Async'
 1783 
 1784         ctx = context.get_admin_context()
 1785         type_fields = {'extra_specs': {'replication_enabled': '<is> True'},
 1786                        'id': fakes.get_fake_uuid()}
 1787         src_vol_type = fake_volume.fake_volume_type_obj(ctx, **type_fields)
 1788 
 1789         fake_provider_id = "%s %s %s" % (
 1790             self.fake_sfvol['volumeID'],
 1791             fakes.FAKE_UUID,
 1792             self.cluster_pairs[0]['uuid'])
 1793         utc_now = timeutils.utcnow().isoformat()
 1794         vol_fields = {
 1795             'id': fakes.FAKE_UUID,
 1796             'created_at': utc_now,
 1797             'volume_type': src_vol_type,
 1798             'volume_type_id': src_vol_type.id,
 1799             'provider_id': fake_provider_id
 1800         }
 1801 
 1802         vol = fake_volume.fake_volume_obj(ctx, **vol_fields)
 1803         dst_vol_type = fake_volume.fake_volume_type_obj(ctx)
 1804 
 1805         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 1806         sfv.replication_enabled = True
 1807         sfv.cluster_pairs = self.cluster_pairs
 1808         sfv.active_cluster['mvip'] = self.mvip
 1809         sfv.active_cluster['svip'] = self.svip
 1810 
 1811         self.assertRaises(exception.VolumeNotFound,
 1812                           sfv.retype, ctx, vol, dst_vol_type, None, None)
 1813         mock_get_sfaccount.assert_called_once_with(vol.project_id)
 1814         mock_get_sf_volume.assert_called_once_with(
 1815             vol.id, {'accountID': self.fake_sfaccount['accountID']})
 1816 
 1817         mock_get_sfaccount.reset_mock()
 1818         mock_get_sf_volume.reset_mock()
 1819         expected = {"key": "value"}
 1820         mock_get_sf_volume.return_value = self.fake_sfvol
 1821         mock_replicate_volume.return_value = expected
 1822         mock_set_rep_by_volume_type.side_effect = [src_vol_type, dst_vol_type]
 1823 
 1824         retyped, updates = sfv.retype(ctx, vol, dst_vol_type, None, None)
 1825         self.assertDictEqual(expected, updates)
 1826 
 1827         mock_get_sfaccount.assert_called_once_with(vol.project_id)
 1828         mock_get_sf_volume.assert_called_once_with(
 1829             vol.id, {'accountID': self.fake_sfaccount['accountID']})
 1830         mock_get_default_volume_params.assert_called()
 1831         mock_disable_replication.assert_not_called()
 1832         mock_replicate_volume.assert_called_once()
 1833         mock_retrieve_replication_settings.assert_called_once()
 1834         mock_set_qos_by_volume_type.assert_called_once()
 1835         mock_set_rep_by_volume_type.assert_called()
 1836 
 1837     @mock.patch.object(solidfire.SolidFireDriver, '_issue_api_request')
 1838     def test_create_volume_for_migration(self,
 1839                                          _mock_issue_api_request):
 1840         _mock_issue_api_request.side_effect = self.fake_issue_api_request
 1841         testvol = {'project_id': 'testprjid',
 1842                    'name': 'testvol',
 1843                    'size': 1,
 1844                    'id': 'b830b3c0-d1f0-11e1-9b23-1900200c9a77',
 1845                    'volume_type_id': None,
 1846                    'created_at': timeutils.utcnow(),
 1847                    'migration_status': 'target:'
 1848                                        'a720b3c0-d1f0-11e1-9b23-0800200c9a66'}
 1849         ctx = context.get_admin_context()
 1850         testvol = fake_volume.fake_volume_obj(ctx, **testvol)
 1851         fake_sfaccounts = [{'accountID': 5,
 1852                             'targetSecret': 'shhhh',
 1853                             'username': 'prefix-testprjid'}]
 1854 
 1855         def _fake_do_v_create(project_id, params):
 1856             cvol = {
 1857                 'name': 'UUID-a720b3c0-d1f0-11e1-9b23-0800200c9a66',
 1858                 'attributes': {
 1859                     'uuid': 'a720b3c0-d1f0-11e1-9b23-0800200c9a66',
 1860                     'migration_uuid': 'b830b3c0-d1f0-11e1-9b23-1900200c9a77'
 1861                 }
 1862             }
 1863             return cvol
 1864 
 1865         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 1866         with mock.patch.object(sfv,
 1867                                '_get_sfaccounts_for_tenant',
 1868                                return_value=fake_sfaccounts), \
 1869                 mock.patch.object(sfv,
 1870                                   '_get_account_create_availability',
 1871                                   return_value=fake_sfaccounts[0]), \
 1872                 mock.patch.object(sfv,
 1873                                   '_do_volume_create',
 1874                                   side_effect=_fake_do_v_create):
 1875 
 1876             sf_vol_object = sfv.create_volume(testvol)
 1877             self.assertEqual('a720b3c0-d1f0-11e1-9b23-0800200c9a66',
 1878                              sf_vol_object['attributes']['uuid'])
 1879             self.assertEqual('b830b3c0-d1f0-11e1-9b23-1900200c9a77',
 1880                              sf_vol_object['attributes']['migration_uuid'])
 1881             self.assertEqual('UUID-a720b3c0-d1f0-11e1-9b23-0800200c9a66',
 1882                              sf_vol_object['name'])
 1883 
 1884     @mock.patch.object(solidfire.SolidFireDriver, '_issue_api_request')
 1885     def test_clone_image_not_configured(self, _mock_issue_api_request):
 1886         _mock_issue_api_request.side_effect = self.fake_issue_api_request
 1887 
 1888         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 1889         self.assertEqual((None, False),
 1890                          sfv.clone_image(self.ctxt,
 1891                                          self.mock_volume,
 1892                                          'fake',
 1893                                          self.fake_image_meta,
 1894                                          'fake'))
 1895 
 1896     def test_init_volume_mappings(self):
 1897         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 1898 
 1899         vid_1 = 'c9125d6d-22ff-4cc3-974d-d4e350df9c91'
 1900         vid_2 = '79883868-6933-47a1-a362-edfbf8d55a18'
 1901         sid_1 = 'e3caa4fa-485e-45ca-970e-1d3e693a2520'
 1902         project_1 = 'e6fb073c-11f0-4f4c-897c-90e7c7c4bcf8'
 1903         project_2 = '4ff32607-305c-4a6b-a51a-0dd33124eecf'
 1904 
 1905         vrefs = [{'id': vid_1,
 1906                   'project_id': project_1,
 1907                   'provider_id': None},
 1908                  {'id': vid_2,
 1909                   'project_id': project_2,
 1910                   'provider_id': 22}]
 1911         snaprefs = [{'id': sid_1,
 1912                      'project_id': project_1,
 1913                      'provider_id': None,
 1914                      'volume_id': vid_1}]
 1915         sf_vols = [{'volumeID': 99,
 1916                     'name': 'UUID-' + vid_1,
 1917                     'accountID': 100},
 1918                    {'volumeID': 22,
 1919                     'name': 'UUID-' + vid_2,
 1920                     'accountID': 200}]
 1921         sf_snaps = [{'snapshotID': 1,
 1922                      'name': 'UUID-' + sid_1,
 1923                      'volumeID': 99}]
 1924 
 1925         def _fake_issue_api_req(method, params, version=0):
 1926             if 'ListActiveVolumes' in method:
 1927                 return {'result': {'volumes': sf_vols}}
 1928             if 'ListSnapshots' in method:
 1929                 return {'result': {'snapshots': sf_snaps}}
 1930 
 1931         with mock.patch.object(sfv, '_issue_api_request',
 1932                                side_effect=_fake_issue_api_req):
 1933             volume_updates, snapshot_updates = sfv.update_provider_info(
 1934                 vrefs, snaprefs)
 1935             self.assertEqual('99 100 53c8be1e-89e2-4f7f-a2e3-7cb84c47e0ec',
 1936                              volume_updates[0]['provider_id'])
 1937             self.assertEqual(1, len(volume_updates))
 1938 
 1939             self.assertEqual('1 99 53c8be1e-89e2-4f7f-a2e3-7cb84c47e0ec',
 1940                              snapshot_updates[0]['provider_id'])
 1941             self.assertEqual(1, len(snapshot_updates))
 1942 
 1943     def test_get_sf_volume_missing_attributes(self):
 1944         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 1945         test_name = "existing_volume"
 1946         fake_response = {'result': {
 1947             'volumes': [{'volumeID': 5,
 1948                          'name': test_name,
 1949                          'accountID': 8,
 1950                          'sliceCount': 1,
 1951                          'totalSize': 1 * units.Gi,
 1952                          'enable512e': True,
 1953                          'access': "readWrite",
 1954                          'status': "active",
 1955                          'qos': None,
 1956                          'iqn': test_name}]}}
 1957 
 1958         def _fake_issue_api_req(method, params, version=0, endpoint=None):
 1959             return fake_response
 1960 
 1961         with mock.patch.object(
 1962                 sfv, '_issue_api_request', side_effect=_fake_issue_api_req):
 1963             self.assertEqual(5, sfv._get_sf_volume(test_name, 8)['volumeID'])
 1964 
 1965     def test_sf_init_conn_with_vag(self):
 1966         # Verify with the _enable_vag conf set that we correctly create a VAG.
 1967         mod_conf = self.configuration
 1968         mod_conf.sf_enable_vag = True
 1969         sfv = solidfire.SolidFireDriver(configuration=mod_conf)
 1970         testvol = {'project_id': 'testprjid',
 1971                    'name': 'testvol',
 1972                    'size': 1,
 1973                    'id': 'a720b3c0-d1f0-11e1-9b23-0800200c9a66',
 1974                    'volume_type_id': None,
 1975                    'provider_location': '10.10.7.1:3260 iqn.2010-01.com.'
 1976                                         'solidfire:87hg.uuid-2cc06226-cc'
 1977                                         '74-4cb7-bd55-14aed659a0cc.4060 0',
 1978                    'provider_auth': 'CHAP stack-1-a60e2611875f40199931f2'
 1979                                     'c76370d66b 2FE0CQ8J196R',
 1980                    'provider_geometry': '4096 4096',
 1981                    'created_at': timeutils.utcnow(),
 1982                    'provider_id': "1 1 1"
 1983                    }
 1984         connector = {'initiator': 'iqn.2012-07.org.fake:01'}
 1985         provider_id = testvol['provider_id']
 1986         vol_id = int(provider_id.split()[0])
 1987         vag_id = 1
 1988 
 1989         with mock.patch.object(sfv,
 1990                                '_safe_create_vag',
 1991                                return_value=vag_id) as create_vag, \
 1992             mock.patch.object(sfv,
 1993                               '_add_volume_to_vag') as add_vol:
 1994             sfv._sf_initialize_connection(testvol, connector)
 1995             create_vag.assert_called_with(connector['initiator'],
 1996                                           vol_id)
 1997             add_vol.assert_called_with(vol_id,
 1998                                        connector['initiator'],
 1999                                        vag_id)
 2000 
 2001     def test_sf_term_conn_with_vag_rem_vag(self):
 2002         # Verify we correctly remove an empty VAG on detach.
 2003         mod_conf = self.configuration
 2004         mod_conf.sf_enable_vag = True
 2005         sfv = solidfire.SolidFireDriver(configuration=mod_conf)
 2006         testvol = {'project_id': 'testprjid',
 2007                    'name': 'testvol',
 2008                    'size': 1,
 2009                    'id': 'a720b3c0-d1f0-11e1-9b23-0800200c9a66',
 2010                    'volume_type_id': None,
 2011                    'provider_location': '10.10.7.1:3260 iqn.2010-01.com.'
 2012                                         'solidfire:87hg.uuid-2cc06226-cc'
 2013                                         '74-4cb7-bd55-14aed659a0cc.4060 0',
 2014                    'provider_auth': 'CHAP stack-1-a60e2611875f40199931f2'
 2015                                     'c76370d66b 2FE0CQ8J196R',
 2016                    'provider_geometry': '4096 4096',
 2017                    'created_at': timeutils.utcnow(),
 2018                    'provider_id': "1 1 1",
 2019                    'multiattach': False
 2020                    }
 2021         connector = {'initiator': 'iqn.2012-07.org.fake:01'}
 2022         vag_id = 1
 2023         vags = [{'attributes': {},
 2024                  'deletedVolumes': [],
 2025                  'initiators': [connector['initiator']],
 2026                  'name': 'fakeiqn',
 2027                  'volumeAccessGroupID': vag_id,
 2028                  'volumes': [1],
 2029                  'virtualNetworkIDs': []}]
 2030 
 2031         with mock.patch.object(sfv,
 2032                                '_get_vags_by_name',
 2033                                return_value=vags), \
 2034             mock.patch.object(sfv,
 2035                               '_remove_vag') as rem_vag:
 2036             sfv._sf_terminate_connection(testvol, connector, False)
 2037             rem_vag.assert_called_with(vag_id)
 2038 
 2039     def test_sf_term_conn_with_vag_rem_vol(self):
 2040         # Verify we correctly remove a the volume from a non-empty VAG.
 2041         mod_conf = self.configuration
 2042         mod_conf.sf_enable_vag = True
 2043         sfv = solidfire.SolidFireDriver(configuration=mod_conf)
 2044         testvol = {'project_id': 'testprjid',
 2045                    'name': 'testvol',
 2046                    'size': 1,
 2047                    'id': 'a720b3c0-d1f0-11e1-9b23-0800200c9a66',
 2048                    'volume_type_id': None,
 2049                    'provider_location': '10.10.7.1:3260 iqn.2010-01.com.'
 2050                                         'solidfire:87hg.uuid-2cc06226-cc'
 2051                                         '74-4cb7-bd55-14aed659a0cc.4060 0',
 2052                    'provider_auth': 'CHAP stack-1-a60e2611875f40199931f2'
 2053                                     'c76370d66b 2FE0CQ8J196R',
 2054                    'provider_geometry': '4096 4096',
 2055                    'created_at': timeutils.utcnow(),
 2056                    'provider_id': "1 1 1",
 2057                    'multiattach': False
 2058                    }
 2059         provider_id = testvol['provider_id']
 2060         vol_id = int(provider_id.split()[0])
 2061         connector = {'initiator': 'iqn.2012-07.org.fake:01'}
 2062         vag_id = 1
 2063         vags = [{'attributes': {},
 2064                  'deletedVolumes': [],
 2065                  'initiators': [connector['initiator']],
 2066                  'name': 'fakeiqn',
 2067                  'volumeAccessGroupID': vag_id,
 2068                  'volumes': [1, 2],
 2069                  'virtualNetworkIDs': []}]
 2070 
 2071         with mock.patch.object(sfv,
 2072                                '_get_vags_by_name',
 2073                                return_value=vags), \
 2074             mock.patch.object(sfv,
 2075                               '_remove_volume_from_vag') as rem_vag:
 2076             sfv._sf_terminate_connection(testvol, connector, False)
 2077             rem_vag.assert_called_with(vol_id, vag_id)
 2078 
 2079     def test_sf_term_conn_without_connector(self):
 2080         # Verify we correctly force the deletion of a volume.
 2081         mod_conf = self.configuration
 2082         mod_conf.sf_enable_vag = True
 2083         sfv = solidfire.SolidFireDriver(configuration=mod_conf)
 2084         testvol = {'project_id': 'testprjid',
 2085                    'name': 'testvol',
 2086                    'size': 1,
 2087                    'id': 'a720b3c0-d1f0-11e1-9b23-0800200c9a66',
 2088                    'volume_type_id': None,
 2089                    'provider_location': '10.10.7.1:3260 iqn.2010-01.com.'
 2090                                         'solidfire:87hg.uuid-2cc06226-cc'
 2091                                         '74-4cb7-bd55-14aed659a0cc.4060 0',
 2092                    'provider_auth': 'CHAP stack-1-a60e2611875f40199931f2'
 2093                                     'c76370d66b 2FE0CQ8J196R',
 2094                    'provider_geometry': '4096 4096',
 2095                    'created_at': timeutils.utcnow(),
 2096                    'provider_id': "1 1 1",
 2097                    'multiattach': False
 2098                    }
 2099         provider_id = testvol['provider_id']
 2100         vol_id = int(provider_id.split()[0])
 2101         vag_id = 1
 2102         vags = [{'attributes': {},
 2103                  'deletedVolumes': [],
 2104                  'initiators': ['iqn.2012-07.org.fake:01'],
 2105                  'name': 'fakeiqn',
 2106                  'volumeAccessGroupID': vag_id,
 2107                  'volumes': [1, 2],
 2108                  'virtualNetworkIDs': []}]
 2109 
 2110         with mock.patch.object(sfv,
 2111                                '_get_vags_by_volume',
 2112                                return_value=vags), \
 2113             mock.patch.object(sfv,
 2114                               '_remove_volume_from_vags') as rem_vags:
 2115             sfv._sf_terminate_connection(testvol, None, False)
 2116             rem_vags.assert_called_with(vol_id)
 2117 
 2118     def test_safe_create_vag_simple(self):
 2119         # Test the sunny day call straight into _create_vag.
 2120         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 2121         iqn = 'fake_iqn'
 2122         vol_id = 1
 2123 
 2124         with mock.patch.object(sfv,
 2125                                '_get_vags_by_name',
 2126                                return_value=[]), \
 2127             mock.patch.object(sfv,
 2128                               '_create_vag') as mock_create_vag:
 2129             sfv._safe_create_vag(iqn, vol_id)
 2130             mock_create_vag.assert_called_with(iqn, vol_id)
 2131 
 2132     def test_safe_create_vag_matching_vag(self):
 2133         # Vag exists, resuse.
 2134         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 2135         iqn = 'TESTIQN'
 2136         vags = [{'attributes': {},
 2137                  'deletedVolumes': [],
 2138                  'initiators': [iqn],
 2139                  'name': iqn,
 2140                  'volumeAccessGroupID': 1,
 2141                  'volumes': [1, 2],
 2142                  'virtualNetworkIDs': []}]
 2143 
 2144         with mock.patch.object(sfv,
 2145                                '_get_vags_by_name',
 2146                                return_value=vags), \
 2147             mock.patch.object(sfv,
 2148                               '_create_vag') as create_vag, \
 2149             mock.patch.object(sfv,
 2150                               '_add_initiator_to_vag') as add_iqn:
 2151             vag_id = sfv._safe_create_vag(iqn, None)
 2152             self.assertEqual(vag_id, vags[0]['volumeAccessGroupID'])
 2153             create_vag.assert_not_called()
 2154             add_iqn.assert_not_called()
 2155 
 2156     def test_safe_create_vag_reuse_vag(self):
 2157         # Reuse a matching vag.
 2158         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 2159         iqn = 'TESTIQN'
 2160         vags = [{'attributes': {},
 2161                  'deletedVolumes': [],
 2162                  'initiators': [],
 2163                  'name': iqn,
 2164                  'volumeAccessGroupID': 1,
 2165                  'volumes': [1, 2],
 2166                  'virtualNetworkIDs': []}]
 2167         vag_id = vags[0]['volumeAccessGroupID']
 2168 
 2169         with mock.patch.object(sfv,
 2170                                '_get_vags_by_name',
 2171                                return_value=vags), \
 2172             mock.patch.object(sfv,
 2173                               '_add_initiator_to_vag',
 2174                               return_value=vag_id) as add_init:
 2175             res_vag_id = sfv._safe_create_vag(iqn, None)
 2176             self.assertEqual(res_vag_id, vag_id)
 2177             add_init.assert_called_with(iqn, vag_id)
 2178 
 2179     def test_create_vag_iqn_fail(self):
 2180         # Attempt to create a VAG with an already in-use initiator.
 2181         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 2182         iqn = 'TESTIQN'
 2183         vag_id = 1
 2184         vol_id = 42
 2185 
 2186         def throw_request(method, params, version):
 2187             msg = 'xExceededLimit: {}'.format(params['initiators'][0])
 2188             raise solidfire.SolidFireAPIException(message=msg)
 2189 
 2190         with mock.patch.object(sfv,
 2191                                '_issue_api_request',
 2192                                side_effect=throw_request), \
 2193             mock.patch.object(sfv,
 2194                               '_safe_create_vag',
 2195                               return_value=vag_id) as create_vag, \
 2196             mock.patch.object(sfv,
 2197                               '_purge_vags') as purge_vags:
 2198             res_vag_id = sfv._create_vag(iqn, vol_id)
 2199             self.assertEqual(res_vag_id, vag_id)
 2200             create_vag.assert_called_with(iqn, vol_id)
 2201             purge_vags.assert_not_called()
 2202 
 2203     def test_create_vag_limit_fail(self):
 2204         # Attempt to create a VAG with VAG limit reached.
 2205         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 2206         iqn = 'TESTIQN'
 2207         vag_id = 1
 2208         vol_id = 42
 2209 
 2210         def throw_request(method, params, version):
 2211             msg = 'xExceededLimit'
 2212             raise solidfire.SolidFireAPIException(message=msg)
 2213 
 2214         with mock.patch.object(sfv,
 2215                                '_issue_api_request',
 2216                                side_effect=throw_request), \
 2217             mock.patch.object(sfv,
 2218                               '_safe_create_vag',
 2219                               return_value=vag_id) as create_vag, \
 2220             mock.patch.object(sfv,
 2221                               '_purge_vags') as purge_vags:
 2222             res_vag_id = sfv._create_vag(iqn, vol_id)
 2223             self.assertEqual(res_vag_id, vag_id)
 2224             create_vag.assert_called_with(iqn, vol_id)
 2225             purge_vags.assert_called_with()
 2226 
 2227     def test_add_initiator_duplicate(self):
 2228         # Thrown exception should yield vag_id.
 2229         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 2230         iqn = 'TESTIQN'
 2231         vag_id = 1
 2232 
 2233         def throw_request(method, params, version):
 2234             msg = 'xAlreadyInVolumeAccessGroup'
 2235             raise solidfire.SolidFireAPIException(message=msg)
 2236 
 2237         with mock.patch.object(sfv,
 2238                                '_issue_api_request',
 2239                                side_effect=throw_request):
 2240             res_vag_id = sfv._add_initiator_to_vag(iqn, vag_id)
 2241             self.assertEqual(vag_id, res_vag_id)
 2242 
 2243     def test_add_initiator_missing_vag(self):
 2244         # Thrown exception should result in create_vag call.
 2245         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 2246         iqn = 'TESTIQN'
 2247         vag_id = 1
 2248 
 2249         def throw_request(method, params, version):
 2250             msg = 'xVolumeAccessGroupIDDoesNotExist'
 2251             raise solidfire.SolidFireAPIException(message=msg)
 2252 
 2253         with mock.patch.object(sfv,
 2254                                '_issue_api_request',
 2255                                side_effect=throw_request), \
 2256             mock.patch.object(sfv,
 2257                               '_safe_create_vag',
 2258                               return_value=vag_id) as mock_create_vag:
 2259             res_vag_id = sfv._add_initiator_to_vag(iqn, vag_id)
 2260             self.assertEqual(vag_id, res_vag_id)
 2261             mock_create_vag.assert_called_with(iqn)
 2262 
 2263     def test_add_volume_to_vag_duplicate(self):
 2264         # Thrown exception should yield vag_id
 2265         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 2266         iqn = 'TESTIQN'
 2267         vag_id = 1
 2268         vol_id = 42
 2269 
 2270         def throw_request(method, params, version):
 2271             msg = 'xAlreadyInVolumeAccessGroup'
 2272             raise solidfire.SolidFireAPIException(message=msg)
 2273 
 2274         with mock.patch.object(sfv,
 2275                                '_issue_api_request',
 2276                                side_effect=throw_request):
 2277             res_vag_id = sfv._add_volume_to_vag(vol_id, iqn, vag_id)
 2278             self.assertEqual(res_vag_id, vag_id)
 2279 
 2280     def test_add_volume_to_vag_missing_vag(self):
 2281         # Thrown exception should yield vag_id
 2282         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 2283         iqn = 'TESTIQN'
 2284         vag_id = 1
 2285         vol_id = 42
 2286 
 2287         def throw_request(method, params, version):
 2288             msg = 'xVolumeAccessGroupIDDoesNotExist'
 2289             raise solidfire.SolidFireAPIException(message=msg)
 2290 
 2291         with mock.patch.object(sfv,
 2292                                '_issue_api_request',
 2293                                side_effect=throw_request), \
 2294             mock.patch.object(sfv,
 2295                               '_safe_create_vag',
 2296                               return_value=vag_id) as mock_create_vag:
 2297             res_vag_id = sfv._add_volume_to_vag(vol_id, iqn, vag_id)
 2298             self.assertEqual(res_vag_id, vag_id)
 2299             mock_create_vag.assert_called_with(iqn, vol_id)
 2300 
 2301     def test_remove_volume_from_vag_missing_volume(self):
 2302         # Volume not in VAG, throws.
 2303         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 2304         vag_id = 1
 2305         vol_id = 42
 2306 
 2307         def throw_request(method, params, version):
 2308             msg = 'xNotInVolumeAccessGroup'
 2309             raise solidfire.SolidFireAPIException(message=msg)
 2310 
 2311         with mock.patch.object(sfv,
 2312                                '_issue_api_request',
 2313                                side_effect=throw_request):
 2314             sfv._remove_volume_from_vag(vol_id, vag_id)
 2315 
 2316     def test_remove_volume_from_vag_missing_vag(self):
 2317         # Volume not in VAG, throws.
 2318         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 2319         vag_id = 1
 2320         vol_id = 42
 2321 
 2322         def throw_request(method, params, version):
 2323             msg = 'xVolumeAccessGroupIDDoesNotExist'
 2324             raise solidfire.SolidFireAPIException(message=msg)
 2325 
 2326         with mock.patch.object(sfv,
 2327                                '_issue_api_request',
 2328                                side_effect=throw_request):
 2329             sfv._remove_volume_from_vag(vol_id, vag_id)
 2330 
 2331     def test_remove_volume_from_vag_unknown_exception(self):
 2332         # Volume not in VAG, throws.
 2333         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 2334         vag_id = 1
 2335         vol_id = 42
 2336 
 2337         def throw_request(method, params, version):
 2338             msg = 'xUnknownException'
 2339             raise solidfire.SolidFireAPIException(message=msg)
 2340 
 2341         with mock.patch.object(sfv,
 2342                                '_issue_api_request',
 2343                                side_effect=throw_request):
 2344             self.assertRaises(solidfire.SolidFireAPIException,
 2345                               sfv._remove_volume_from_vag,
 2346                               vol_id,
 2347                               vag_id)
 2348 
 2349     def test_remove_volume_from_vags(self):
 2350         # Remove volume from several VAGs.
 2351         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 2352         vol_id = 42
 2353         vags = [{'volumeAccessGroupID': 1,
 2354                  'volumes': [vol_id]},
 2355                 {'volumeAccessGroupID': 2,
 2356                  'volumes': [vol_id, 43]}]
 2357 
 2358         with mock.patch.object(sfv,
 2359                                '_get_vags_by_volume',
 2360                                return_value=vags), \
 2361             mock.patch.object(sfv,
 2362                               '_remove_volume_from_vag') as rem_vol:
 2363             sfv._remove_volume_from_vags(vol_id)
 2364             self.assertEqual(len(vags), rem_vol.call_count)
 2365 
 2366     def test_purge_vags(self):
 2367         # Remove subset of VAGs.
 2368         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 2369         vags = [{'initiators': [],
 2370                  'volumeAccessGroupID': 1,
 2371                  'deletedVolumes': [],
 2372                  'volumes': [],
 2373                  'attributes': {'openstack': True}},
 2374                 {'initiators': [],
 2375                  'volumeAccessGroupID': 2,
 2376                  'deletedVolumes': [],
 2377                  'volumes': [],
 2378                  'attributes': {'openstack': False}},
 2379                 {'initiators': [],
 2380                  'volumeAccessGroupID': 3,
 2381                  'deletedVolumes': [1],
 2382                  'volumes': [],
 2383                  'attributes': {'openstack': True}},
 2384                 {'initiators': [],
 2385                  'volumeAccessGroupID': 4,
 2386                  'deletedVolumes': [],
 2387                  'volumes': [1],
 2388                  'attributes': {'openstack': True}},
 2389                 {'initiators': ['fakeiqn'],
 2390                  'volumeAccessGroupID': 5,
 2391                  'deletedVolumes': [],
 2392                  'volumes': [],
 2393                  'attributes': {'openstack': True}}]
 2394         with mock.patch.object(sfv,
 2395                                '_base_get_vags',
 2396                                return_value=vags), \
 2397             mock.patch.object(sfv,
 2398                               '_remove_vag') as rem_vag:
 2399             sfv._purge_vags()
 2400             # Of the vags provided there is only one that is valid for purge
 2401             # based on the limits of no initiators, volumes, deleted volumes,
 2402             # and features the openstack attribute.
 2403             self.assertEqual(1, rem_vag.call_count)
 2404             rem_vag.assert_called_with(1)
 2405 
 2406     def test_sf_create_group_snapshot(self):
 2407         # Sunny day group snapshot creation.
 2408         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 2409         name = 'great_gsnap_name'
 2410         sf_volumes = [{'volumeID': 1}, {'volumeID': 42}]
 2411         expected_params = {'name': name,
 2412                            'volumes': [1, 42]}
 2413         fake_result = {'result': 'contrived_test'}
 2414         with mock.patch.object(sfv,
 2415                                '_issue_api_request',
 2416                                return_value=fake_result) as fake_api:
 2417             res = sfv._sf_create_group_snapshot(name, sf_volumes)
 2418             self.assertEqual('contrived_test', res)
 2419             fake_api.assert_called_with('CreateGroupSnapshot',
 2420                                         expected_params,
 2421                                         version='7.0')
 2422 
 2423     def test_group_snapshot_creator_sunny(self):
 2424         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 2425         gsnap_name = 'great_gsnap_name'
 2426         prefix = sfv.configuration.sf_volume_prefix
 2427         vol_uuids = ['one', 'two', 'three']
 2428         active_vols = [{'name': prefix + 'one'},
 2429                        {'name': prefix + 'two'},
 2430                        {'name': prefix + 'three'}]
 2431         with mock.patch.object(sfv,
 2432                                '_get_all_active_volumes',
 2433                                return_value=active_vols),\
 2434             mock.patch.object(sfv,
 2435                               '_sf_create_group_snapshot',
 2436                               return_value=None) as create:
 2437             sfv._group_snapshot_creator(gsnap_name, vol_uuids)
 2438             create.assert_called_with(gsnap_name,
 2439                                       active_vols)
 2440 
 2441     def test_group_snapshot_creator_rainy(self):
 2442         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 2443         gsnap_name = 'great_gsnap_name'
 2444         prefix = sfv.configuration.sf_volume_prefix
 2445         vol_uuids = ['one', 'two', 'three']
 2446         active_vols = [{'name': prefix + 'one'},
 2447                        {'name': prefix + 'two'}]
 2448         with mock.patch.object(sfv,
 2449                                '_get_all_active_volumes',
 2450                                return_value=active_vols):
 2451             self.assertRaises(solidfire.SolidFireDriverException,
 2452                               sfv._group_snapshot_creator,
 2453                               gsnap_name,
 2454                               vol_uuids)
 2455 
 2456     def test_create_temp_group_snapshot(self):
 2457         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 2458         cg = {'id': 'great_gsnap_name'}
 2459         prefix = sfv.configuration.sf_volume_prefix
 2460         tmp_name = prefix + cg['id'] + '-tmp'
 2461         vols = [{'id': 'one'},
 2462                 {'id': 'two'},
 2463                 {'id': 'three'}]
 2464         with mock.patch.object(sfv,
 2465                                '_group_snapshot_creator',
 2466                                return_value=None) as create:
 2467             sfv._create_temp_group_snapshot(cg, vols)
 2468             create.assert_called_with(tmp_name, ['one', 'two', 'three'])
 2469 
 2470     def test_list_group_snapshots(self):
 2471         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 2472         res = {'result': {'groupSnapshots': 'a_thing'}}
 2473         with mock.patch.object(sfv,
 2474                                '_issue_api_request',
 2475                                return_value=res):
 2476             result = sfv._list_group_snapshots()
 2477             self.assertEqual('a_thing', result)
 2478 
 2479     def test_get_group_snapshot_by_name(self):
 2480         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 2481         fake_snaps = [{'name': 'a_fantastic_name'}]
 2482         with mock.patch.object(sfv,
 2483                                '_list_group_snapshots',
 2484                                return_value=fake_snaps):
 2485             result = sfv._get_group_snapshot_by_name('a_fantastic_name')
 2486             self.assertEqual(fake_snaps[0], result)
 2487 
 2488     def test_delete_group_snapshot(self):
 2489         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 2490         gsnap_id = 1
 2491         with mock.patch.object(sfv,
 2492                                '_issue_api_request') as api_req:
 2493             sfv._delete_group_snapshot(gsnap_id)
 2494             api_req.assert_called_with('DeleteGroupSnapshot',
 2495                                        {'groupSnapshotID': gsnap_id},
 2496                                        version='7.0')
 2497 
 2498     def test_delete_cgsnapshot_by_name(self):
 2499         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 2500         fake_gsnap = {'groupSnapshotID': 42}
 2501         with mock.patch.object(sfv,
 2502                                '_get_group_snapshot_by_name',
 2503                                return_value=fake_gsnap),\
 2504             mock.patch.object(sfv,
 2505                               '_delete_group_snapshot') as del_stuff:
 2506             sfv._delete_cgsnapshot_by_name('does not matter')
 2507             del_stuff.assert_called_with(fake_gsnap['groupSnapshotID'])
 2508 
 2509     def test_delete_cgsnapshot_by_name_rainy(self):
 2510         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 2511         with mock.patch.object(sfv, '_get_group_snapshot_by_name',
 2512                                return_value=None):
 2513             self.assertRaises(solidfire.SolidFireDriverException,
 2514                               sfv._delete_cgsnapshot_by_name,
 2515                               'does not matter')
 2516 
 2517     def test_find_linked_snapshot(self):
 2518         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 2519         group_snap = {'members': [{'volumeID': 1}, {'volumeID': 2}]}
 2520         source_vol = {'volumeID': 1}
 2521         with mock.patch.object(sfv,
 2522                                '_get_sf_volume',
 2523                                return_value=source_vol) as get_vol:
 2524             res = sfv._find_linked_snapshot('fake_uuid', group_snap)
 2525             self.assertEqual(source_vol, res)
 2526             get_vol.assert_called_with('fake_uuid')
 2527 
 2528     def test_create_consisgroup_from_src_cgsnapshot(self):
 2529         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 2530         ctxt = None
 2531         group = {}
 2532         volumes = [{'id': 'one'}, {'id': 'two'}, {'id': 'three'}]
 2533         cgsnapshot = {'id': 'great_uuid'}
 2534         snapshots = [{'id': 'snap_id_1', 'volume_id': 'one'},
 2535                      {'id': 'snap_id_2', 'volume_id': 'two'},
 2536                      {'id': 'snap_id_3', 'volume_id': 'three'}]
 2537         source_cg = None
 2538         source_vols = None
 2539         group_snap = {}
 2540         name = sfv.configuration.sf_volume_prefix + cgsnapshot['id']
 2541         kek = (None, None, {})
 2542         with mock.patch.object(sfv,
 2543                                '_get_group_snapshot_by_name',
 2544                                return_value=group_snap) as get_snap,\
 2545             mock.patch.object(sfv,
 2546                               '_find_linked_snapshot'),\
 2547             mock.patch.object(sfv,
 2548                               '_do_clone_volume',
 2549                               return_value=kek):
 2550             model, vol_models = sfv._create_consistencygroup_from_src(
 2551                 ctxt, group, volumes,
 2552                 cgsnapshot, snapshots,
 2553                 source_cg, source_vols)
 2554             get_snap.assert_called_with(name)
 2555             self.assertEqual(
 2556                 {'status': fields.GroupStatus.AVAILABLE}, model)
 2557 
 2558     def test_create_consisgroup_from_src_source_cg(self):
 2559         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 2560         ctxt = None
 2561         group = {}
 2562         volumes = [{'id': 'one', 'source_volid': 'source_one'},
 2563                    {'id': 'two', 'source_volid': 'source_two'},
 2564                    {'id': 'three', 'source_volid': 'source_three'}]
 2565         cgsnapshot = {'id': 'great_uuid'}
 2566         snapshots = None
 2567         source_cg = {'id': 'fantastic_cg'}
 2568         source_vols = [1, 2, 3]
 2569         source_snap = None
 2570         group_snap = {}
 2571         kek = (None, None, {})
 2572         with mock.patch.object(sfv,
 2573                                '_create_temp_group_snapshot',
 2574                                return_value=source_cg['id']),\
 2575             mock.patch.object(sfv,
 2576                               '_get_group_snapshot_by_name',
 2577                               return_value=group_snap) as get_snap,\
 2578             mock.patch.object(sfv,
 2579                               '_find_linked_snapshot',
 2580                               return_value=source_snap),\
 2581             mock.patch.object(sfv,
 2582                               '_do_clone_volume',
 2583                               return_value=kek),\
 2584             mock.patch.object(sfv,
 2585                               '_delete_cgsnapshot_by_name'):
 2586             model, vol_models = sfv._create_consistencygroup_from_src(
 2587                 ctxt, group, volumes,
 2588                 cgsnapshot, snapshots,
 2589                 source_cg,
 2590                 source_vols)
 2591             get_snap.assert_called_with(source_cg['id'])
 2592             self.assertEqual(
 2593                 {'status': fields.GroupStatus.AVAILABLE}, model)
 2594 
 2595     def test_create_cgsnapshot(self):
 2596         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 2597         ctxt = None
 2598         cgsnapshot = {'id': 'acceptable_cgsnap_id'}
 2599         snapshots = [{'volume_id': 'one'},
 2600                      {'volume_id': 'two'}]
 2601         pfx = sfv.configuration.sf_volume_prefix
 2602         active_vols = [{'name': pfx + 'one'},
 2603                        {'name': pfx + 'two'}]
 2604         with mock.patch.object(sfv,
 2605                                '_get_all_active_volumes',
 2606                                return_value=active_vols),\
 2607             mock.patch.object(sfv,
 2608                               '_sf_create_group_snapshot') as create_gsnap:
 2609             sfv._create_cgsnapshot(ctxt, cgsnapshot, snapshots)
 2610             create_gsnap.assert_called_with(pfx + cgsnapshot['id'],
 2611                                             active_vols)
 2612 
 2613     def test_create_cgsnapshot_rainy(self):
 2614         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 2615         ctxt = None
 2616         cgsnapshot = {'id': 'acceptable_cgsnap_id'}
 2617         snapshots = [{'volume_id': 'one'},
 2618                      {'volume_id': 'two'}]
 2619         pfx = sfv.configuration.sf_volume_prefix
 2620         active_vols = [{'name': pfx + 'one'}]
 2621         with mock.patch.object(sfv,
 2622                                '_get_all_active_volumes',
 2623                                return_value=active_vols),\
 2624             mock.patch.object(sfv,
 2625                               '_sf_create_group_snapshot'):
 2626             self.assertRaises(solidfire.SolidFireDriverException,
 2627                               sfv._create_cgsnapshot,
 2628                               ctxt,
 2629                               cgsnapshot,
 2630                               snapshots)
 2631 
 2632     def test_create_vol_from_cgsnap(self):
 2633         # cgsnaps on the backend yield numerous identically named snapshots.
 2634         # create_volume_from_snapshot now searches for the correct snapshot.
 2635         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 2636         source = {'group_snapshot_id': 'typical_cgsnap_id',
 2637                   'volume_id': 'typical_vol_id',
 2638                   'id': 'no_id_4_u'}
 2639         name = (self.configuration.sf_volume_prefix +
 2640                 source.get('group_snapshot_id'))
 2641         with mock.patch.object(sfv,
 2642                                '_get_group_snapshot_by_name',
 2643                                return_value={}) as get,\
 2644             mock.patch.object(sfv,
 2645                               '_create_clone_from_sf_snapshot',
 2646                               return_value='model'):
 2647             result = sfv.create_volume_from_snapshot({}, source)
 2648             get.assert_called_once_with(name)
 2649             self.assertEqual('model', result)
 2650 
 2651     @mock.patch('cinder.volume.volume_utils.is_group_a_cg_snapshot_type')
 2652     def test_create_group_cg(self, group_cg_test):
 2653         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 2654         group_cg_test.return_value = True
 2655         group = mock.MagicMock()
 2656         result = sfv.create_group(self.ctxt, group)
 2657         self.assertEqual(result,
 2658                          {'status': fields.GroupStatus.AVAILABLE})
 2659         group_cg_test.assert_called_once_with(group)
 2660 
 2661     @mock.patch('cinder.volume.volume_utils.is_group_a_cg_snapshot_type')
 2662     def test_delete_group_snap_cg(self, group_cg_test):
 2663         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 2664         group_cg_test.return_value = True
 2665         cgsnapshot = fake_group_snapshot.fake_group_snapshot_obj(
 2666             mock.MagicMock())
 2667         snapshots = fake_snapshot.fake_snapshot_obj(mock.MagicMock())
 2668 
 2669         with mock.patch.object(sfv, '_delete_cgsnapshot',
 2670                                return_value={}) as _del_mock:
 2671             model_update = sfv.delete_group_snapshot(self.ctxt,
 2672                                                      cgsnapshot, snapshots)
 2673             _del_mock.assert_called_once_with(self.ctxt, cgsnapshot, snapshots)
 2674             self.assertEqual({}, model_update)
 2675 
 2676     @mock.patch('cinder.volume.volume_utils.is_group_a_cg_snapshot_type')
 2677     def test_delete_group_snap(self, group_cg_test):
 2678         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 2679         group_cg_test.return_value = False
 2680         cgsnapshot = fake_group_snapshot.fake_group_snapshot_obj(
 2681             mock.MagicMock())
 2682         snapshots = fake_snapshot.fake_snapshot_obj(mock.MagicMock())
 2683 
 2684         with mock.patch.object(sfv, '_delete_cgsnapshot',
 2685                                return_value={}) as _del_mock:
 2686 
 2687             self.assertRaises(NotImplementedError, sfv.delete_group_snapshot,
 2688                               self.ctxt, cgsnapshot, snapshots)
 2689             _del_mock.assert_not_called()
 2690 
 2691     @mock.patch('cinder.volume.volume_utils.is_group_a_cg_snapshot_type')
 2692     def test_create_group_rainy(self, group_cg_test):
 2693         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 2694         group_cg_test.return_value = False
 2695         group = mock.MagicMock()
 2696         self.assertRaises(NotImplementedError,
 2697                           sfv.create_group,
 2698                           self.ctxt, group)
 2699         group_cg_test.assert_called_once_with(group)
 2700 
 2701     @mock.patch('cinder.volume.volume_utils.is_group_a_cg_snapshot_type')
 2702     def test_create_group_from_src_rainy(self, group_cg_test):
 2703         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 2704         group_cg_test.return_value = False
 2705         group = mock.MagicMock()
 2706         volumes = [mock.MagicMock()]
 2707         self.assertRaises(NotImplementedError,
 2708                           sfv.create_group_from_src,
 2709                           self.ctxt, group, volumes)
 2710         group_cg_test.assert_called_once_with(group)
 2711 
 2712     @mock.patch('cinder.volume.volume_utils.is_group_a_cg_snapshot_type')
 2713     def test_create_group_from_src_cg(self, group_cg_test):
 2714         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 2715         group_cg_test.return_value = True
 2716         group = mock.MagicMock()
 2717         volumes = [mock.MagicMock()]
 2718         ret = 'things'
 2719         with mock.patch.object(sfv,
 2720                                '_create_consistencygroup_from_src',
 2721                                return_value=ret):
 2722             result = sfv.create_group_from_src(self.ctxt,
 2723                                                group,
 2724                                                volumes)
 2725             self.assertEqual(ret, result)
 2726             group_cg_test.assert_called_once_with(group)
 2727 
 2728     @mock.patch('cinder.volume.volume_utils.is_group_a_cg_snapshot_type')
 2729     def test_create_group_snapshot_rainy(self, group_cg_test):
 2730         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 2731         group_cg_test.return_value = False
 2732         group_snapshot = mock.MagicMock()
 2733         snapshots = [mock.MagicMock()]
 2734         self.assertRaises(NotImplementedError,
 2735                           sfv.create_group_snapshot,
 2736                           self.ctxt,
 2737                           group_snapshot,
 2738                           snapshots)
 2739         group_cg_test.assert_called_once_with(group_snapshot)
 2740 
 2741     @mock.patch('cinder.volume.volume_utils.is_group_a_cg_snapshot_type')
 2742     def test_create_group_snapshot(self, group_cg_test):
 2743         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 2744         group_cg_test.return_value = True
 2745         group_snapshot = mock.MagicMock()
 2746         snapshots = [mock.MagicMock()]
 2747         ret = 'things'
 2748         with mock.patch.object(sfv,
 2749                                '_create_cgsnapshot',
 2750                                return_value=ret):
 2751             result = sfv.create_group_snapshot(self.ctxt,
 2752                                                group_snapshot,
 2753                                                snapshots)
 2754             self.assertEqual(ret, result)
 2755         group_cg_test.assert_called_once_with(group_snapshot)
 2756 
 2757     @mock.patch('cinder.volume.volume_utils.is_group_a_cg_snapshot_type')
 2758     def test_delete_group_rainy(self, group_cg_test):
 2759         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 2760         group_cg_test.return_value = False
 2761         group = mock.MagicMock()
 2762         volumes = [mock.MagicMock()]
 2763         self.assertRaises(NotImplementedError,
 2764                           sfv.delete_group,
 2765                           self.ctxt,
 2766                           group,
 2767                           volumes)
 2768         group_cg_test.assert_called_once_with(group)
 2769 
 2770     @mock.patch('cinder.volume.volume_utils.is_group_a_cg_snapshot_type')
 2771     def test_delete_group(self, group_cg_test):
 2772         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 2773         group_cg_test.return_value = True
 2774         group = mock.MagicMock()
 2775         volumes = [mock.MagicMock()]
 2776         ret = 'things'
 2777         with mock.patch.object(sfv,
 2778                                '_delete_consistencygroup',
 2779                                return_value=ret):
 2780             result = sfv.delete_group(self.ctxt,
 2781                                       group,
 2782                                       volumes)
 2783             self.assertEqual(ret, result)
 2784         group_cg_test.assert_called_once_with(group)
 2785 
 2786     @mock.patch('cinder.volume.volume_utils.is_group_a_cg_snapshot_type')
 2787     def test_update_group_rainy(self, group_cg_test):
 2788         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 2789         group_cg_test.return_value = False
 2790         group = mock.MagicMock()
 2791         self.assertRaises(NotImplementedError,
 2792                           sfv.update_group,
 2793                           self.ctxt,
 2794                           group)
 2795         group_cg_test.assert_called_once_with(group)
 2796 
 2797     @mock.patch('cinder.volume.volume_utils.is_group_a_cg_snapshot_type')
 2798     def test_update_group(self, group_cg_test):
 2799         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 2800         group_cg_test.return_value = True
 2801         group = mock.MagicMock()
 2802         ret = 'things'
 2803         with mock.patch.object(sfv,
 2804                                '_update_consistencygroup',
 2805                                return_value=ret):
 2806             result = sfv.update_group(self.ctxt,
 2807                                       group)
 2808             self.assertEqual(ret, result)
 2809         group_cg_test.assert_called_once_with(group)
 2810 
 2811     def test_getattr_failure(self):
 2812         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 2813         try:
 2814             sfv.foo()
 2815             self.fail("Should have thrown Error")
 2816         except Exception:
 2817             pass
 2818 
 2819     @data('Async', 'Sync', 'SnapshotsOnly')
 2820     @mock.patch.object(volume_types, 'get_volume_type')
 2821     def test_set_rep_by_volume_type(self, mode, mock_get_volume_type):
 2822         mock_get_volume_type.return_value = {
 2823             'name': 'sf-1', 'deleted': False,
 2824             'created_at': '2014-02-06 04:58:11',
 2825             'updated_at': None, 'extra_specs':
 2826                 {'replication_enabled': '<is> True',
 2827                  'solidfire:replication_mode': mode},
 2828             'deleted_at': None,
 2829             'id': '290edb2a-f5ea-11e5-9ce9-5e5517507c66'}
 2830         rep_opts = {}
 2831         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 2832         sfv.cluster_pairs = self.cluster_pairs
 2833         ctxt = None
 2834         type_id = '290edb2a-f5ea-11e5-9ce9-5e5517507c66'
 2835         rep_opts['rep_type'] = mode
 2836         self.assertEqual(rep_opts, sfv._set_rep_by_volume_type(ctxt, type_id))
 2837         mock_get_volume_type.assert_called()
 2838 
 2839     def test_replicate_volume(self):
 2840         replication_status = fields.ReplicationStatus.ENABLED
 2841         fake_vol = {'project_id': 1, 'volumeID': 1, 'size': 1}
 2842         params = {'attributes': {}}
 2843         rep_info = {'rep_type': 'Async'}
 2844         sf_account = {'initiatorSecret': 'shhh', 'targetSecret': 'dont-tell'}
 2845         model_update = {'provider_id': '1 2 xxxx'}
 2846         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 2847         sfv.cluster_pairs = self.cluster_pairs
 2848 
 2849         with mock.patch.object(sfv,
 2850                                '_issue_api_request',
 2851                                self.fake_issue_api_request),\
 2852                 mock.patch.object(sfv,
 2853                                   '_get_sfaccount_by_name',
 2854                                   return_value={'accountID': 1}),\
 2855                 mock.patch.object(sfv,
 2856                                   '_do_volume_create',
 2857                                   return_value=model_update):
 2858             self.assertEqual({'replication_status': replication_status},
 2859                              sfv._replicate_volume(fake_vol, params,
 2860                                                    sf_account, rep_info))
 2861 
 2862     def test_pythons_try_except(self):
 2863         def _fake_retrieve_rep(vol):
 2864             raise solidfire.SolidFireAPIException
 2865 
 2866         fake_type = {'extra_specs': {}}
 2867         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 2868         with mock.patch.object(sfv,
 2869                                '_get_create_account',
 2870                                return_value={'accountID': 5}),\
 2871                 mock.patch.object(sfv,
 2872                                   '_retrieve_qos_setting',
 2873                                   return_value=None), \
 2874                 mock.patch.object(sfv,
 2875                                   '_do_volume_create',
 2876                                   return_value={'provider_id': '1 2 xxxx'}),\
 2877                 mock.patch.object(volume_types,
 2878                                   'get_volume_type',
 2879                                   return_value=fake_type), \
 2880                 mock.patch.object(sfv,
 2881                                   '_retrieve_replication_settings',
 2882                                   side_effect=_fake_retrieve_rep):
 2883             self.assertRaises(solidfire.SolidFireAPIException,
 2884                               sfv.create_volume,
 2885                               self.mock_volume)
 2886 
 2887     def test_extract_sf_attributes_from_extra_specs(self):
 2888         type_id = '290edb2a-f5ea-11e5-9ce9-5e5517507c66'
 2889         fake_type = {'extra_specs': {'SFAttribute:foo': 'bar',
 2890                                      'SFAttribute:biz': 'baz'}}
 2891         expected = [{'foo': 'bar'}, {'biz': 'baz'}]
 2892         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 2893         with mock.patch.object(volume_types, 'get_volume_type',
 2894                                return_value=fake_type):
 2895             res = sfv._extract_sf_attributes_from_extra_specs(type_id)
 2896             six.assertCountEqual(self, expected, res)
 2897 
 2898     def test_build_endpoint_with_kwargs(self):
 2899         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 2900         expected_ep = {'passwd': 'nunyabiz',
 2901                        'port': 888,
 2902                        'url': 'https://1.2.3.4:888',
 2903                        'svip': None,
 2904                        'mvip': '1.2.3.4',
 2905                        'login': 'JohnWayne'}
 2906         ep = sfv._build_endpoint_info(mvip='1.2.3.4', login='JohnWayne',
 2907                                       password='nunyabiz', port=888)
 2908         self.assertEqual(expected_ep, ep)
 2909 
 2910         # Make sure we pick up defaults for those not specified
 2911         expected_ep = {'passwd': 'nunyabiz',
 2912                        'url': 'https://1.2.3.4:443',
 2913                        'svip': None,
 2914                        'mvip': '1.2.3.4',
 2915                        'login': 'admin',
 2916                        'port': 443}
 2917         ep = sfv._build_endpoint_info(mvip='1.2.3.4', password='nunyabiz')
 2918         self.assertEqual(expected_ep, ep)
 2919 
 2920         # Make sure we add brackets for IPv6 MVIP
 2921         expected_ep = {'passwd': 'nunyabiz',
 2922                        'url': 'https://[ff00::00]:443',
 2923                        'svip': None,
 2924                        'mvip': 'ff00::00',
 2925                        'login': 'admin',
 2926                        'port': 443}
 2927         ep = sfv._build_endpoint_info(mvip='ff00::00', password='nunyabiz')
 2928         self.assertEqual(expected_ep, ep)
 2929 
 2930     def test_generate_random_string(self):
 2931         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 2932         a = sfv._generate_random_string(12)
 2933         self.assertEqual(len(a), 12)
 2934         self.assertIsNotNone(re.match(r'[A-Z0-9]{12}', a), a)
 2935 
 2936     @mock.patch.object(solidfire.SolidFireDriver, '_get_sfaccount')
 2937     @mock.patch.object(solidfire.SolidFireDriver, '_get_sf_volume')
 2938     @mock.patch.object(solidfire.SolidFireDriver, '_get_sf_snapshots')
 2939     @mock.patch.object(solidfire.SolidFireDriver, '_issue_api_request')
 2940     def test_revert_to_snapshot_success(self, mock_issue_api_request,
 2941                                         mock_get_sf_snapshots,
 2942                                         mock_get_sf_volume,
 2943                                         mock_get_sfaccount):
 2944         mock_issue_api_request.side_effect = self.fake_issue_api_request
 2945 
 2946         mock_get_sfaccount.return_value = self.fake_sfaccount
 2947         mock_get_sf_volume.return_value = self.fake_sfvol
 2948         mock_get_sf_snapshots.return_value = self.fake_sfsnaps
 2949 
 2950         expected_params = {'accountID': 25,
 2951                            'volumeID': 6,
 2952                            'snapshotID': '5',
 2953                            'saveCurrentState': 'false'}
 2954 
 2955         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 2956 
 2957         # Success path
 2958         sfv.revert_to_snapshot(self.ctxt, self.vol, self.snap)
 2959         mock_issue_api_request.assert_called_with(
 2960             'RollbackToSnapshot', expected_params, version='6.0')
 2961 
 2962     @mock.patch.object(solidfire.SolidFireDriver, '_get_sfaccount')
 2963     @mock.patch.object(solidfire.SolidFireDriver, '_get_sf_volume')
 2964     @mock.patch.object(solidfire.SolidFireDriver, '_get_sf_snapshots')
 2965     @mock.patch.object(solidfire.SolidFireDriver, '_issue_api_request')
 2966     def test_revert_to_snapshot_fail_vol_not_found(
 2967             self, mock_issue_api_request, mock_get_sf_snapshots,
 2968             mock_get_sf_volume, mock_get_sfaccount):
 2969         mock_issue_api_request.side_effect = self.fake_issue_api_request
 2970 
 2971         mock_get_sfaccount.return_value = self.fake_sfaccount
 2972         mock_get_sf_volume.return_value = None
 2973         mock_get_sf_snapshots.return_value = []
 2974 
 2975         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 2976 
 2977         # Volume not found
 2978         mock_get_sf_volume.return_value = None
 2979         self.assertRaises(exception.VolumeNotFound,
 2980                           sfv.revert_to_snapshot,
 2981                           self.ctxt, self.vol, self.snap)
 2982 
 2983     @mock.patch.object(solidfire.SolidFireDriver, '_get_sfaccount')
 2984     @mock.patch.object(solidfire.SolidFireDriver, '_get_sf_volume')
 2985     @mock.patch.object(solidfire.SolidFireDriver, '_get_sf_snapshots')
 2986     @mock.patch.object(solidfire.SolidFireDriver, '_issue_api_request')
 2987     def test_revert_to_snapshot_fail_snap_not_found(
 2988             self, mock_issue_api_request, mock_get_sf_snapshots,
 2989             mock_get_sf_volume, mock_get_sfaccount):
 2990         mock_issue_api_request.side_effect = self.fake_issue_api_request
 2991 
 2992         mock_get_sfaccount.return_value = self.fake_sfaccount
 2993         mock_get_sf_volume.return_value = self.fake_sfvol
 2994         mock_get_sf_snapshots.return_value = []
 2995 
 2996         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 2997 
 2998         # Snapshot not found
 2999         mock_get_sf_snapshots.return_value = []
 3000         self.assertRaises(exception.VolumeSnapshotNotFound,
 3001                           sfv.revert_to_snapshot,
 3002                           self.ctxt, self.vol, self.snap)
 3003 
 3004     @mock.patch.object(solidfire.SolidFireDriver, '_get_create_account')
 3005     @mock.patch.object(solidfire.SolidFireDriver, '_set_cluster_pairs')
 3006     @mock.patch.object(solidfire.SolidFireDriver, '_snapshot_discovery')
 3007     @mock.patch.object(solidfire.SolidFireDriver, '_issue_api_request')
 3008     @mock.patch.object(solidfire.SolidFireDriver, '_get_model_info')
 3009     @mock.patch.object(solidfire.SolidFireDriver, '_update_attributes')
 3010     @mock.patch.object(solidfire.SolidFireDriver, '_update_cluster_status')
 3011     @mock.patch.object(solidfire.SolidFireDriver, '_set_cluster_pairs')
 3012     @mock.patch.object(solidfire.SolidFireDriver, '_get_default_volume_params')
 3013     @mock.patch.object(solidfire.SolidFireDriver,
 3014                        '_retrieve_replication_settings')
 3015     @mock.patch.object(solidfire.SolidFireDriver, '_replicate_volume')
 3016     @mock.patch.object(solidfire.SolidFireDriver, '_create_cluster_reference')
 3017     def test_do_clone_volume_rep_disabled(self,
 3018                                           mock_create_cluster_reference,
 3019                                           mock_replicate_volume,
 3020                                           mock_retrieve_replication_settings,
 3021                                           mock_get_default_volume_params,
 3022                                           mock_set_cluster_pairs,
 3023                                           mock_update_cluster_status,
 3024                                           mock_update_attributes,
 3025                                           mock_get_model_info,
 3026                                           mock_issue_api_request,
 3027                                           mock_snapshot_discovery,
 3028                                           mock_test_set_cluster_pairs,
 3029                                           mock_get_create_account):
 3030 
 3031         all_mocks = locals()
 3032 
 3033         def reset_mocks():
 3034             for mk in all_mocks.values():
 3035                 if isinstance(mk, mock.MagicMock):
 3036                     mk.reset_mock()
 3037 
 3038         sf_volume_params = {'volumeID': 1, 'snapshotID': 2, 'newSize': 3}
 3039         mock_snapshot_discovery.return_value = (sf_volume_params, True,
 3040                                                 self.fake_sfvol)
 3041         mock_get_create_account.return_value = self.fake_sfaccount
 3042 
 3043         ctx = context.get_admin_context()
 3044         vol_fields = {'updated_at': timeutils.utcnow(),
 3045                       'created_at': timeutils.utcnow()}
 3046         src_vol = fake_volume.fake_volume_obj(ctx)
 3047         dst_vol = fake_volume.fake_volume_obj(ctx, **vol_fields)
 3048 
 3049         mock_create_cluster_reference.return_value = {
 3050             'mvip': self.mvip,
 3051             'svip': self.svip}
 3052 
 3053         self.configuration.sf_volume_clone_timeout = 1
 3054         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 3055         sfv.replication_enabled = False
 3056 
 3057         reset_mocks()
 3058         mock_issue_api_request.return_value = {
 3059             'error': {'code': 000, 'name': 'DummyError',
 3060                       'message': 'This is a fake error response'},
 3061             'id': 1}
 3062 
 3063         self.assertRaises(solidfire.SolidFireAPIException,
 3064                           sfv._do_clone_volume, src_vol.id,
 3065                           dst_vol, sf_src_snap=self.fake_sfsnaps[0])
 3066 
 3067         clone_vol_params = {
 3068             'snapshotID': self.fake_sfsnaps[0]['snapshotID'],
 3069             'volumeID': self.fake_sfsnaps[0]['volumeID'],
 3070             'newSize': dst_vol.size * units.Gi,
 3071             'name': '%(prefix)s%(id)s' % {
 3072                 'prefix': self.configuration.sf_volume_prefix,
 3073                     'id': dst_vol.id},
 3074             'newAccountID': self.fake_sfaccount['accountID']}
 3075 
 3076         mock_get_create_account.assert_called_with(dst_vol.project_id)
 3077         mock_issue_api_request.assert_called_once_with(
 3078             'CloneVolume', clone_vol_params, version='6.0')
 3079         mock_test_set_cluster_pairs.assert_not_called()
 3080         mock_update_attributes.assert_not_called()
 3081         mock_get_model_info.assert_not_called()
 3082         mock_snapshot_discovery.assert_not_called()
 3083 
 3084         reset_mocks()
 3085         mock_issue_api_request.side_effect = self.fake_issue_api_request
 3086         mock_get_default_volume_params.return_value = {}
 3087         mock_get_model_info.return_value = None
 3088         self.assertRaises(solidfire.SolidFireAPIException,
 3089                           sfv._do_clone_volume, src_vol.id,
 3090                           dst_vol, sf_src_snap=self.fake_sfsnaps[0])
 3091 
 3092         mock_get_create_account.assert_called_with(dst_vol.project_id)
 3093         calls = [mock.call('CloneVolume', clone_vol_params, version='6.0'),
 3094                  mock.call('ModifyVolume', {'volumeID': 6})]
 3095         mock_issue_api_request.assert_has_calls(calls)
 3096         mock_test_set_cluster_pairs.assert_not_called()
 3097         mock_update_attributes.assert_not_called()
 3098         mock_get_model_info.assert_called()
 3099         mock_snapshot_discovery.assert_not_called()
 3100 
 3101         reset_mocks()
 3102         mock_retrieve_replication_settings.return_value = 'Async'
 3103         update = {'replication_status': fields.ReplicationStatus.ENABLED}
 3104         mock_replicate_volume.side_effect = solidfire.SolidFireDriverException
 3105         mock_update_attributes.return_value = {'result': {}, 'id': 1}
 3106         mock_get_model_info.return_value = {
 3107             'provider_location': '1.1.1.1 iqn 0',
 3108             'provider_auth': 'CHAP stack-1-a60e2611875f40199931f2c76370d66b '
 3109                              '2FE0CQ8J196R',
 3110             'provider_id': '%s %s cluster-id-01' % (
 3111                 self.fake_sfvol['volumeID'],
 3112                 self.fake_sfaccount['accountID'])
 3113         }
 3114 
 3115         data, account, updates = sfv._do_clone_volume(
 3116             src_vol.id, dst_vol, sf_src_snap=self.fake_sfsnaps[0])
 3117 
 3118         self.assertEqual({'result': {}, 'id': 1}, data)
 3119         self.assertEqual(25, account['accountID'])
 3120         self.assertEqual(self.fake_sfvol['volumeID'],
 3121                          int(updates['provider_id'].split()[0]))
 3122 
 3123         mock_get_create_account.assert_called_with(dst_vol.project_id)
 3124         calls = [mock.call('CloneVolume', clone_vol_params, version='6.0'),
 3125                  mock.call('ModifyVolume', {'volumeID': 6})]
 3126 
 3127         mock_issue_api_request.assert_has_calls(calls)
 3128         mock_test_set_cluster_pairs.assert_not_called()
 3129         mock_update_attributes.assert_not_called()
 3130         mock_get_model_info.assert_called_once()
 3131         mock_snapshot_discovery.assert_not_called()
 3132 
 3133     @mock.patch.object(solidfire.SolidFireDriver, '_get_create_account')
 3134     @mock.patch.object(solidfire.SolidFireDriver, '_retrieve_qos_setting')
 3135     @mock.patch.object(solidfire.SolidFireDriver,
 3136                        '_extract_sf_attributes_from_extra_specs')
 3137     def test_get_default_volume_params(
 3138             self, mock_extract_sf_attributes_from_extra_specs,
 3139             mock_retrieve_qos_setting, mock_get_create_account):
 3140 
 3141         mock_extract_sf_attributes_from_extra_specs.return_value = [{
 3142             'key1': 'value1',
 3143             'key2': 'value2'
 3144         }]
 3145         mock_retrieve_qos_setting.return_value = None
 3146         mock_get_create_account.return_value = self.fake_sfaccount
 3147 
 3148         ctx = context.get_admin_context()
 3149         type_fields = {'extra_specs': {'replication_enabled': '<is> True'}}
 3150         vol_type = fake_volume.fake_volume_type_obj(ctx, **type_fields)
 3151         utc_now = timeutils.utcnow().isoformat()
 3152         vol_fields = {
 3153             'id': fakes.FAKE_UUID,
 3154             'created_at': utc_now,
 3155             'volume_type': vol_type,
 3156             'volume_type_id': vol_type.id
 3157         }
 3158 
 3159         vol = fake_volume.fake_volume_obj(ctx, **vol_fields)
 3160 
 3161         vol_name = '%s%s' % (self.configuration.sf_volume_prefix, vol.id)
 3162         expected_attr = {
 3163             'uuid': vol.id,
 3164             'is_clone': False,
 3165             'created_at': utc_now + "+00:00",
 3166             'cinder-name': vol.get('display_name', ""),
 3167             'key1': 'value1',
 3168             'key2': 'value2',
 3169         }
 3170 
 3171         expected_params = {
 3172             'name': vol_name,
 3173             'accountID': self.fake_sfaccount['accountID'],
 3174             'sliceCount': 1,
 3175             'totalSize': int(vol.size * units.Gi),
 3176             'enable512e': self.configuration.sf_emulate_512,
 3177             'attributes': expected_attr,
 3178             'qos': None
 3179         }
 3180 
 3181         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 3182         sfv.replication_enabled = True
 3183 
 3184         params = sfv._get_default_volume_params(vol, False)
 3185 
 3186         self.assertDictEqual(expected_params, params)
 3187         mock_extract_sf_attributes_from_extra_specs.assert_called()
 3188         mock_retrieve_qos_setting.assert_called()
 3189         mock_get_create_account.assert_called()
 3190 
 3191     @mock.patch.object(solidfire.SolidFireDriver, '_get_sfvol_by_cinder_vref')
 3192     def test_disable_replication_fail(self, mock_get_sfvol_by_cinder_vref):
 3193 
 3194         self.fake_sfvol['volumePairs'] = []
 3195         mock_get_sfvol_by_cinder_vref.return_value = self.fake_sfvol
 3196 
 3197         ctx = context.get_admin_context()
 3198         utc_now = timeutils.utcnow().isoformat()
 3199         vol_fields = {
 3200             'id': f_uuid,
 3201             'created_at': utc_now
 3202         }
 3203         vol = fake_volume.fake_volume_obj(ctx, **vol_fields)
 3204 
 3205         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 3206         sfv.replication_enabled = True
 3207         sfv.cluster_pairs = self.cluster_pairs
 3208 
 3209         expected = {'replication_status': fields.ReplicationStatus.DISABLED}
 3210         updates = sfv._disable_replication(vol)
 3211 
 3212         self.assertDictEqual(expected, updates)
 3213 
 3214     @mock.patch.object(solidfire.SolidFireDriver, '_get_sfvol_by_cinder_vref')
 3215     @mock.patch.object(solidfire.SolidFireDriver, '_issue_api_request')
 3216     @mock.patch.object(solidfire.SolidFireDriver, '_create_cluster_reference')
 3217     def test_disable_replication(self, mock_create_cluster_reference,
 3218                                  mock_issue_api_request,
 3219                                  mock_get_sfvol_by_cinder_vref):
 3220 
 3221         mock_create_cluster_reference.return_value = {
 3222             'mvip': self.mvip,
 3223             'svip': self.svip}
 3224 
 3225         self.fake_sfvol['volumePairs'] = [{"remoteVolumeID": 26}]
 3226         mock_get_sfvol_by_cinder_vref.return_value = self.fake_sfvol
 3227 
 3228         ctx = context.get_admin_context()
 3229         utc_now = timeutils.utcnow().isoformat()
 3230         vol_fields = {
 3231             'id': f_uuid,
 3232             'created_at': utc_now
 3233         }
 3234         vol = fake_volume.fake_volume_obj(ctx, **vol_fields)
 3235 
 3236         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 3237         sfv.replication_enabled = True
 3238         sfv.cluster_pairs = self.cluster_pairs
 3239         sfv.active_cluster['mvip'] = self.mvip
 3240         sfv.active_cluster['svip'] = self.svip
 3241 
 3242         expected = {'replication_status': fields.ReplicationStatus.DISABLED}
 3243         mock_issue_api_request.reset_mock()
 3244         updates = sfv._disable_replication(vol)
 3245 
 3246         self.assertDictEqual(expected, updates)
 3247 
 3248         expected = [
 3249             mock.call("RemoveVolumePair",
 3250                       {'volumeID': self.fake_sfvol['volumeID']}, '8.0'),
 3251             mock.call("RemoveVolumePair", {'volumeID': 26}, '8.0',
 3252                       endpoint=sfv.cluster_pairs[0]['endpoint']),
 3253             mock.call("DeleteVolume", {'volumeID': 26},
 3254                       endpoint=sfv.cluster_pairs[0]['endpoint']),
 3255             mock.call("PurgeDeletedVolume", {'volumeID': 26},
 3256                       endpoint=sfv.cluster_pairs[0]['endpoint'])
 3257         ]
 3258 
 3259         mock_issue_api_request.assert_has_calls(expected)
 3260         mock_create_cluster_reference.assert_called()
 3261         mock_get_sfvol_by_cinder_vref.assert_called()
 3262 
 3263     @mock.patch.object(solidfire.SolidFireDriver, '_set_cluster_pairs')
 3264     @mock.patch.object(solidfire.SolidFireDriver, 'failover')
 3265     @mock.patch.object(solidfire.SolidFireDriver, 'failover_completed')
 3266     def test_failover_host(self, mock_failover_completed,
 3267                            mock_failover,
 3268                            mock_set_cluster_pairs):
 3269 
 3270         fake_context = None
 3271         fake_cinder_vols = [{'id': 'testvol1'}, {'id': 'testvol2'}]
 3272 
 3273         fake_failover_updates = [{'volume_id': 'testvol1',
 3274                                   'updates': {
 3275                                       'replication_status': 'failed-over'}},
 3276                                  {'volume_id': 'testvol2',
 3277                                   'updates': {
 3278                                       'replication_status': 'failed-over'}}]
 3279 
 3280         mock_failover.return_value = "secondary", fake_failover_updates, []
 3281 
 3282         drv_args = {'active_backend_id': None}
 3283         sfv = solidfire.SolidFireDriver(configuration=self.configuration,
 3284                                         **drv_args)
 3285 
 3286         cluster_id, updates, _ = sfv.failover_host(
 3287             fake_context, fake_cinder_vols, secondary_id='secondary',
 3288             groups=None)
 3289 
 3290         mock_failover.called_with(fake_context, fake_cinder_vols, "secondary",
 3291                                   None)
 3292         mock_failover_completed.called_with(fake_context, "secondary")
 3293         self.assertEqual(cluster_id, "secondary")
 3294         self.assertEqual(fake_failover_updates, updates)
 3295 
 3296     @mock.patch.object(solidfire.SolidFireDriver, '_set_cluster_pairs')
 3297     @mock.patch.object(solidfire.SolidFireDriver, '_create_cluster_reference')
 3298     def test_failover_completed(self, mock_create_cluster_reference,
 3299                                 mock_set_cluster_pairs):
 3300 
 3301         ctx = context.get_admin_context()
 3302         drv_args = {'active_backend_id': None}
 3303         sfv = solidfire.SolidFireDriver(configuration=self.configuration,
 3304                                         **drv_args)
 3305 
 3306         sfv.cluster_pairs = self.cluster_pairs
 3307 
 3308         sfv.failover_completed(ctx, "secondary")
 3309         self.assertTrue(sfv.failed_over)
 3310         self.assertDictEqual(sfv.active_cluster, sfv.cluster_pairs[0])
 3311 
 3312         mock_create_cluster_reference.return_value = self.fake_primary_cluster
 3313         sfv.failover_completed(ctx, '')
 3314         self.assertFalse(sfv.failed_over)
 3315         mock_create_cluster_reference.assert_called()
 3316         self.assertDictEqual(sfv.active_cluster, self.fake_primary_cluster)
 3317 
 3318     @mock.patch.object(solidfire.SolidFireDriver, '_issue_api_request')
 3319     @mock.patch.object(solidfire.SolidFireDriver, '_create_cluster_reference')
 3320     @mock.patch.object(solidfire.SolidFireDriver, '_set_cluster_pairs')
 3321     @mock.patch.object(solidfire.SolidFireDriver, '_update_cluster_status')
 3322     @mock.patch.object(solidfire.SolidFireDriver, '_get_cluster_info')
 3323     @mock.patch.object(solidfire.SolidFireDriver, '_map_sf_volumes')
 3324     @mock.patch.object(solidfire.SolidFireDriver, '_failover_volume')
 3325     @mock.patch.object(solidfire.SolidFireDriver, '_get_create_account')
 3326     @mock.patch.object(solidfire.SolidFireDriver, '_get_remote_info_by_id')
 3327     def test_failover(self, mock_get_remote_info_by_id,
 3328                       mock_get_create_account,
 3329                       mock_failover_volume,
 3330                       mock_map_sf_volumes,
 3331                       mock_get_cluster_info,
 3332                       mock_update_cluster_status,
 3333                       mock_set_cluster_pairs,
 3334                       mock_create_cluster_reference,
 3335                       mock_issue_api_request):
 3336 
 3337         all_mocks = locals()
 3338 
 3339         def reset_mocks():
 3340             for mk in all_mocks.values():
 3341                 if isinstance(mk, mock.MagicMock):
 3342                     mk.reset_mock()
 3343 
 3344         ctx = context.get_admin_context()
 3345         vol_fields = {'updated_at': timeutils.utcnow(),
 3346                       'created_at': timeutils.utcnow()}
 3347 
 3348         cinder_vols = []
 3349         sf_vols = []
 3350         for i in range(1, 6):
 3351             vol = fake_volume.fake_volume_obj(ctx, **vol_fields)
 3352             sf_vol = self.fake_sfvol.copy()
 3353             sf_vol['volumeID'] = i
 3354             sf_vol['name'] = '%s%s' % (self.configuration.sf_volume_prefix,
 3355                                        vol.id)
 3356             sf_vol['access'] = 'replicationTarget'
 3357             sf_vol['attributes'] = {'uuid': vol.id}
 3358             sf_vol['cinder_id'] = vol.id
 3359 
 3360             sf_vols.append(sf_vol)
 3361             cinder_vols.append(vol)
 3362 
 3363         mock_map_sf_volumes.return_value = sf_vols
 3364 
 3365         self.configuration.replication_device = []
 3366 
 3367         reset_mocks()
 3368         drv_args = {'active_backend_id': None}
 3369         sfv = solidfire.SolidFireDriver(configuration=self.configuration,
 3370                                         **drv_args)
 3371 
 3372         self.assertRaises(exception.UnableToFailOver,
 3373                           sfv.failover, ctx, cinder_vols, 'fake', None)
 3374         mock_map_sf_volumes.assert_not_called()
 3375 
 3376         fake_replication_device = {'backend_id': 'fake',
 3377                                    'mvip': '0.0.0.0',
 3378                                    'login': 'fake_login',
 3379                                    'password': 'fake_pwd'}
 3380 
 3381         self.configuration.replication_device = [fake_replication_device]
 3382 
 3383         reset_mocks()
 3384         drv_args = {'active_backend_id': ''}
 3385         sfv = solidfire.SolidFireDriver(configuration=self.configuration,
 3386                                         **drv_args)
 3387         sfv.replication_enabled = True
 3388         self.assertRaises(exception.InvalidReplicationTarget,
 3389                           sfv.failover, ctx, cinder_vols, 'default', None)
 3390         mock_map_sf_volumes.assert_not_called()
 3391 
 3392         reset_mocks()
 3393         drv_args = {'active_backend_id': None}
 3394         sfv = solidfire.SolidFireDriver(configuration=self.configuration,
 3395                                         **drv_args)
 3396         sfv.replication_enabled = True
 3397         self.assertRaises(exception.InvalidReplicationTarget,
 3398                           sfv.failover, ctx, cinder_vols,
 3399                           secondary_id='not_fake_id', groups=None)
 3400         mock_map_sf_volumes.assert_not_called()
 3401 
 3402         mock_create_cluster_reference.return_value = self.cluster_pairs[0]
 3403 
 3404         reset_mocks()
 3405         drv_args = {'active_backend_id': 'fake'}
 3406         sfv = solidfire.SolidFireDriver(configuration=self.configuration,
 3407                                         **drv_args)
 3408         sfv.cluster_pairs = self.cluster_pairs
 3409         sfv.cluster_pairs[0]['backend_id'] = 'fake'
 3410         sfv.replication_enabled = True
 3411         cluster_id, updates, _ = sfv.failover_host(
 3412             ctx, cinder_vols, secondary_id='default', groups=None)
 3413         self.assertEqual(5, len(updates))
 3414         for update in updates:
 3415             self.assertEqual(fields.ReplicationStatus.ENABLED,
 3416                              update['updates']['replication_status'])
 3417         self.assertEqual('', cluster_id)
 3418         mock_get_create_account.assert_called()
 3419         mock_failover_volume.assert_called()
 3420         mock_map_sf_volumes.assert_called()
 3421         mock_update_cluster_status.assert_called()
 3422         mock_create_cluster_reference.assert_called()
 3423 
 3424         reset_mocks()
 3425         drv_args = {'active_backend_id': None}
 3426         sfv = solidfire.SolidFireDriver(configuration=self.configuration,
 3427                                         **drv_args)
 3428         sfv.cluster_pairs = self.cluster_pairs
 3429         sfv.cluster_pairs[0]['backend_id'] = 'fake'
 3430         sfv.replication_enabled = True
 3431         cluster_id, updates, _ = sfv.failover(
 3432             ctx, cinder_vols, secondary_id='fake', groups=None)
 3433         self.assertEqual(5, len(updates))
 3434         for update in updates:
 3435             self.assertEqual(fields.ReplicationStatus.FAILED_OVER,
 3436                              update['updates']['replication_status'])
 3437 
 3438         self.assertEqual('fake', cluster_id)
 3439         mock_get_create_account.assert_called()
 3440         mock_failover_volume.assert_called()
 3441         mock_map_sf_volumes.assert_called()
 3442         mock_update_cluster_status.assert_called()
 3443         mock_create_cluster_reference.assert_called()
 3444 
 3445     @mock.patch.object(solidfire.SolidFireDriver, '_issue_api_request')
 3446     @mock.patch.object(solidfire.SolidFireDriver, '_create_cluster_reference')
 3447     @mock.patch.object(solidfire.SolidFireDriver, '_update_cluster_status')
 3448     def test_failover_volume(self, mock_update_cluster_status,
 3449                              mock_create_cluster_reference,
 3450                              mock_issue_api_request):
 3451 
 3452         all_mocks = locals()
 3453 
 3454         def reset_mocks():
 3455             for mk in all_mocks.values():
 3456                 if isinstance(mk, mock.MagicMock):
 3457                     mk.reset_mock()
 3458 
 3459         mock_issue_api_request.return_value = self.fake_sfaccount
 3460 
 3461         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 3462         sfv.replication_enabled = True
 3463 
 3464         fake_src_sfvol = {'volumeID': 600,
 3465                           'name': 'test_volume',
 3466                           'accountID': 25,
 3467                           'sliceCount': 1,
 3468                           'totalSize': 1 * units.Gi,
 3469                           'enable512e': True,
 3470                           'access': "replicationTarget",
 3471                           'status': "active",
 3472                           'attributes': {'uuid': f_uuid[0]},
 3473                           'qos': None,
 3474                           'iqn': 'super_fake_iqn'}
 3475 
 3476         expected_src_params = {'volumeID': fake_src_sfvol['volumeID'],
 3477                                'access': 'replicationTarget'}
 3478 
 3479         expected_tgt_params = {'volumeID': self.fake_sfvol['volumeID'],
 3480                                'access': 'readWrite'}
 3481 
 3482         sfv._failover_volume(self.fake_sfvol, self.cluster_pairs[0],
 3483                              fake_src_sfvol)
 3484 
 3485         mock_issue_api_request.assert_has_calls(
 3486             [mock.call("ModifyVolume", expected_src_params),
 3487              mock.call("ModifyVolume", expected_tgt_params,
 3488                        endpoint=self.cluster_pairs[0]['endpoint'])]
 3489         )
 3490         reset_mocks()
 3491 
 3492         sfv._failover_volume(self.fake_sfvol, self.cluster_pairs[0])
 3493 
 3494         mock_issue_api_request.assert_called_with(
 3495             "ModifyVolume",
 3496             expected_tgt_params,
 3497             endpoint=self.cluster_pairs[0]['endpoint']
 3498         )
 3499 
 3500     @mock.patch('oslo_service.loopingcall.FixedIntervalWithTimeoutLoopingCall')
 3501     @mock.patch.object(solidfire.SolidFireDriver, '_issue_api_request')
 3502     @mock.patch.object(solidfire.SolidFireDriver, '_create_cluster_reference')
 3503     @mock.patch.object(solidfire.SolidFireDriver, '_get_cluster_pair')
 3504     @mock.patch.object(solidfire.SolidFireDriver, '_create_remote_pairing')
 3505     def test_get_or_create_cluster_pairing(
 3506             self, mock_create_remote_pairing,
 3507             mock_get_cluster_pair,
 3508             mock_create_cluster_reference,
 3509             mock_issue_api_request,
 3510             mock_looping_call):
 3511 
 3512         fake_remote_pair_connected = {'status': 'Connected'}
 3513         mock_get_cluster_pair.side_effect = [None, fake_remote_pair_connected]
 3514 
 3515         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 3516         result = sfv._get_or_create_cluster_pairing(
 3517             self.fake_secondary_cluster, check_connected=True)
 3518 
 3519         mock_get_cluster_pair.assert_has_calls(
 3520             [call(self.fake_secondary_cluster),
 3521              call(self.fake_secondary_cluster)])
 3522 
 3523         mock_create_remote_pairing.assert_called_with(
 3524             self.fake_secondary_cluster)
 3525 
 3526         mock_looping_call.assert_not_called()
 3527         self.assertEqual(fake_remote_pair_connected, result)
 3528 
 3529     @mock.patch.object(solidfire.SolidFireDriver, '_issue_api_request')
 3530     @mock.patch.object(solidfire.SolidFireDriver, '_create_cluster_reference')
 3531     @mock.patch.object(solidfire.SolidFireDriver, '_get_cluster_pair')
 3532     @mock.patch.object(solidfire.SolidFireDriver, '_create_remote_pairing')
 3533     def test_get_or_create_cluster_pairing_check_connected_true(
 3534             self, mock_create_remote_pairing,
 3535             mock_get_cluster_pair,
 3536             mock_create_cluster_reference,
 3537             mock_issue_api_request):
 3538 
 3539         fake_remote_pair_misconfigured = {'status': 'Misconfigured'}
 3540         fake_remote_pair_connected = {'status': 'Connected'}
 3541         mock_get_cluster_pair.side_effect = [None,
 3542                                              fake_remote_pair_misconfigured,
 3543                                              fake_remote_pair_connected]
 3544 
 3545         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 3546         result = sfv._get_or_create_cluster_pairing(
 3547             self.fake_secondary_cluster, check_connected=True)
 3548 
 3549         mock_get_cluster_pair.assert_has_calls(
 3550             [call(self.fake_secondary_cluster),
 3551              call(self.fake_secondary_cluster),
 3552              call(self.fake_secondary_cluster)])
 3553 
 3554         mock_create_remote_pairing.assert_called_with(
 3555             self.fake_secondary_cluster)
 3556 
 3557         self.assertEqual(fake_remote_pair_connected, result)
 3558 
 3559     @mock.patch.object(solidfire.SolidFireDriver, '_issue_api_request')
 3560     @mock.patch.object(solidfire.SolidFireDriver, '_update_cluster_status')
 3561     @mock.patch.object(solidfire.SolidFireDriver, '_create_cluster_reference')
 3562     def test_get_cluster_pair(self, mock_create_cluster_reference,
 3563                               mock_update_cluster_status,
 3564                               mock_issue_api_request):
 3565         fake_cluster_pair = {
 3566             'result': {
 3567                 'clusterPairs': [{
 3568                     'mvip': self.fake_secondary_cluster['mvip']
 3569                 }]
 3570             }
 3571         }
 3572         mock_issue_api_request.return_value = fake_cluster_pair
 3573 
 3574         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 3575         result = sfv._get_cluster_pair(self.fake_secondary_cluster)
 3576 
 3577         mock_issue_api_request.assert_called_with('ListClusterPairs', {},
 3578                                                   version='8.0')
 3579         self.assertEqual(
 3580             fake_cluster_pair['result']['clusterPairs'][0], result)
 3581 
 3582     @mock.patch.object(solidfire.SolidFireDriver, '_issue_api_request')
 3583     @mock.patch.object(solidfire.SolidFireDriver, '_update_cluster_status')
 3584     @mock.patch.object(solidfire.SolidFireDriver, '_create_cluster_reference')
 3585     def test_get_cluster_pair_remote_not_found(self,
 3586                                                mock_create_cluster_reference,
 3587                                                mock_update_cluster_status,
 3588                                                mock_issue_api_request):
 3589         fake_cluster_pair = {
 3590             'result': {
 3591                 'clusterPairs': []
 3592             }
 3593         }
 3594         mock_issue_api_request.return_value = fake_cluster_pair
 3595 
 3596         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 3597         result = sfv._get_cluster_pair(self.fake_secondary_cluster)
 3598 
 3599         mock_issue_api_request.assert_called_with('ListClusterPairs', {},
 3600                                                   version='8.0')
 3601         self.assertIsNone(result)
 3602 
 3603     @mock.patch.object(solidfire.SolidFireDriver, '_issue_api_request')
 3604     @mock.patch.object(solidfire.SolidFireDriver, '_update_cluster_status')
 3605     @mock.patch.object(solidfire.SolidFireDriver, '_create_cluster_reference')
 3606     def _create_volume_pairing(self, mock_issue_api_request,
 3607                                mock_update_cluster_status,
 3608                                mock_create_cluster_reference):
 3609 
 3610         ctx = context.get_admin_context()
 3611         type_fields = {'id': fakes.get_fake_uuid()}
 3612         src_vol_type = fake_volume.fake_volume_type_obj(ctx, **type_fields)
 3613 
 3614         fake_src_sf_volid = 1111
 3615         vol_fields = {
 3616             'id': fakes.get_fake_uuid(),
 3617             'volume_type': src_vol_type,
 3618             'host': 'fakeHost@fakeBackend#fakePool',
 3619             'status': 'in-use',
 3620             'provider_id': "%s %s %s" % (fake_src_sf_volid,
 3621                                          fakes.get_fake_uuid(),
 3622                                          self.fake_primary_cluster['uuid'])
 3623         }
 3624 
 3625         vol = fake_volume.fake_volume_obj(ctx, **vol_fields)
 3626         fake_dst_cluster_ref = deepcopy(self.fake_secondary_cluster)
 3627         fake_dst_sf_volid = 9999
 3628         fake_dst_volume = {
 3629             'provider_id': "%s %s %s" % (fake_dst_sf_volid,
 3630                                          fakes.get_fake_uuid(),
 3631                                          fake_dst_cluster_ref['uuid'])
 3632         }
 3633 
 3634         fake_start_volume_pairing = {
 3635             {'result': {'volumePairingKey': 'CAFE'}}
 3636         }
 3637         mock_issue_api_request.side_effect = [MagicMock(),
 3638                                               fake_start_volume_pairing]
 3639 
 3640         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 3641         sfv._create_volume_pairing(vol, fake_dst_volume, fake_dst_cluster_ref)
 3642 
 3643         src_params = {'volumeID': fake_src_sf_volid, 'mode': "Sync"}
 3644         dst_params = {'volumeID': fake_dst_sf_volid,
 3645                       'volumePairingKey': 'CAFE'}
 3646 
 3647         mock_issue_api_request.assert_has_calls([
 3648             call('RemoveVolumePair', src_params, '8.0'),
 3649             call('StartVolumePairing', src_params, '8.0'),
 3650             call('CompleteVolumePairing', dst_params, '8.0',
 3651                  endpoint=fake_dst_cluster_ref['endpoint'])])
 3652 
 3653     @mock.patch('cinder.volume.drivers.solidfire.retry')
 3654     @mock.patch.object(solidfire.SolidFireDriver, '_issue_api_request')
 3655     @mock.patch.object(solidfire.SolidFireDriver, '_update_cluster_status')
 3656     @mock.patch.object(solidfire.SolidFireDriver, '_create_cluster_reference')
 3657     def _create_volume_pairing_timeout(self, mock_issue_api_request,
 3658                                        mock_update_cluster_status,
 3659                                        mock_create_cluster_reference,
 3660                                        mock_retry):
 3661 
 3662         ctx = context.get_admin_context()
 3663         fake_src_sf_volid = 1111
 3664         vol_fields = {
 3665             'provider_id': "%s %s %s" % (fake_src_sf_volid,
 3666                                          fakes.get_fake_uuid(),
 3667                                          self.fake_primary_cluster['uuid'])
 3668         }
 3669 
 3670         vol = fake_volume.fake_volume_obj(ctx, **vol_fields)
 3671         fake_dst_cluster_ref = deepcopy(self.fake_secondary_cluster)
 3672         fake_dst_sf_volid = 9999
 3673         fake_dst_volume = {
 3674             'provider_id': "%s %s %s" % (fake_dst_sf_volid,
 3675                                          fakes.get_fake_uuid(),
 3676                                          fake_dst_cluster_ref['uuid'])
 3677         }
 3678         mock_retry.side_effect = solidfire.SolidFireReplicationPairingError()
 3679         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 3680         mock_issue_api_request.reset_mock()
 3681         self.assertRaises(solidfire.SolidFireReplicationPairingError,
 3682                           sfv._create_volume_pairing, vol, fake_dst_volume,
 3683                           fake_dst_cluster_ref)
 3684 
 3685     @mock.patch.object(solidfire.SolidFireDriver,
 3686                        '_do_intercluster_volume_migration')
 3687     def test_migrate_volume_volume_is_not_available(
 3688             self, mock_do_intercluster_volume_migration):
 3689 
 3690         ctx = context.get_admin_context()
 3691 
 3692         vol_fields = {
 3693             'status': 'in-use'
 3694         }
 3695 
 3696         vol = fake_volume.fake_volume_obj(ctx, **vol_fields)
 3697         host = {'host': 'fakeHost@anotherFakeBackend#fakePool'}
 3698 
 3699         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 3700         self.assertRaises(exception.InvalidVolume,
 3701                           sfv.migrate_volume, ctx, vol, host)
 3702 
 3703         mock_do_intercluster_volume_migration.assert_not_called()
 3704 
 3705     @mock.patch.object(solidfire.SolidFireDriver,
 3706                        '_do_intercluster_volume_migration')
 3707     def test_migrate_volume_volume_is_replicated(
 3708             self, mock_do_intercluster_volume_migration):
 3709 
 3710         ctx = context.get_admin_context()
 3711         type_fields = {'extra_specs': {'replication_enabled': '<is> True'},
 3712                        'id': fakes.get_fake_uuid()}
 3713         src_vol_type = fake_volume.fake_volume_type_obj(ctx, **type_fields)
 3714 
 3715         vol_fields = {
 3716             'id': fakes.get_fake_uuid(),
 3717             'volume_type': src_vol_type
 3718         }
 3719 
 3720         vol = fake_volume.fake_volume_obj(ctx, **vol_fields)
 3721         vol.volume_type = src_vol_type
 3722         host = {'host': 'fakeHost@fakeBackend#fakePool'}
 3723 
 3724         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 3725 
 3726         self.assertRaises(exception.InvalidVolume,
 3727                           sfv.migrate_volume, ctx, vol, host)
 3728         mock_do_intercluster_volume_migration.assert_not_called()
 3729 
 3730     @mock.patch.object(solidfire.SolidFireDriver,
 3731                        '_do_intercluster_volume_migration')
 3732     def test_migrate_volume_same_host_and_backend(
 3733             self, mock_do_intercluster_volume_migration):
 3734 
 3735         ctx = context.get_admin_context()
 3736         type_fields = {'id': fakes.get_fake_uuid()}
 3737         src_vol_type = fake_volume.fake_volume_type_obj(ctx, **type_fields)
 3738 
 3739         vol_fields = {
 3740             'id': fakes.get_fake_uuid(),
 3741             'volume_type': src_vol_type,
 3742             'host': 'fakeHost@fakeBackend#fakePool'
 3743         }
 3744 
 3745         vol = fake_volume.fake_volume_obj(ctx, **vol_fields)
 3746         vol.volume_type = src_vol_type
 3747         host = {'host': 'fakeHost@fakeBackend#fakePool'}
 3748 
 3749         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 3750         result = sfv.migrate_volume(ctx, vol, host)
 3751 
 3752         mock_do_intercluster_volume_migration.assert_not_called()
 3753         self.assertEqual((True, {}), result)
 3754 
 3755     @mock.patch('cinder.volume.volume_utils.get_backend_configuration')
 3756     @mock.patch.object(solidfire.SolidFireDriver,
 3757                        '_do_intercluster_volume_migration')
 3758     def test_migrate_volume_different_host_same_backend(
 3759             self, mock_do_intercluster_volume_migration,
 3760             mock_get_backend_configuration):
 3761 
 3762         ctx = context.get_admin_context()
 3763         type_fields = {'id': fakes.get_fake_uuid()}
 3764         src_vol_type = fake_volume.fake_volume_type_obj(ctx, **type_fields)
 3765 
 3766         vol_fields = {
 3767             'id': fakes.get_fake_uuid(),
 3768             'volume_type': src_vol_type,
 3769             'host': 'fakeHost@fakeBackend#fakePool'
 3770         }
 3771 
 3772         vol = fake_volume.fake_volume_obj(ctx, **vol_fields)
 3773         vol.volume_type = src_vol_type
 3774         host = {'host': 'anotherFakeHost@fakeBackend#fakePool'}
 3775 
 3776         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 3777         result = sfv.migrate_volume(ctx, vol, host)
 3778 
 3779         mock_get_backend_configuration.assert_not_called()
 3780         mock_do_intercluster_volume_migration.assert_not_called()
 3781 
 3782         self.assertEqual((True, {}), result)
 3783 
 3784     @mock.patch('cinder.volume.volume_utils.get_backend_configuration')
 3785     @mock.patch.object(solidfire.SolidFireDriver,
 3786                        '_do_intercluster_volume_migration')
 3787     def test_migrate_volume_config_stanza_not_found(
 3788             self, mock_do_intercluster_volume_migration,
 3789             mock_get_backend_configuration):
 3790 
 3791         ctx = context.get_admin_context()
 3792         type_fields = {'id': fakes.get_fake_uuid()}
 3793         src_vol_type = fake_volume.fake_volume_type_obj(ctx, **type_fields)
 3794 
 3795         vol_fields = {
 3796             'id': fakes.get_fake_uuid(),
 3797             'volume_type': src_vol_type,
 3798             'host': 'fakeHost@fakeBackend#fakePool'
 3799         }
 3800 
 3801         vol = fake_volume.fake_volume_obj(ctx, **vol_fields)
 3802         vol.volume_type = src_vol_type
 3803         host = {'host': 'fakeHost@anotherFakeBackend#fakePool'}
 3804 
 3805         mock_get_backend_configuration.side_effect = \
 3806             exception.ConfigNotFound('error')
 3807 
 3808         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 3809         self.assertRaises(exception.VolumeMigrationFailed,
 3810                           sfv.migrate_volume, ctx, vol, host)
 3811 
 3812         mock_get_backend_configuration.assert_called_with(
 3813             'anotherFakeBackend', sfv.get_driver_options())
 3814 
 3815         mock_do_intercluster_volume_migration.assert_not_called()
 3816 
 3817     @mock.patch.object(solidfire.SolidFireDriver,
 3818                        '_do_intercluster_volume_migration')
 3819     @mock.patch('cinder.volume.volume_utils.get_backend_configuration')
 3820     def test_migrate_volume_different_backend_same_cluster(
 3821             self, mock_get_backend_configuration,
 3822             mock_do_intercluster_volume_migration):
 3823 
 3824         ctx = context.get_admin_context()
 3825         type_fields = {'id': fakes.get_fake_uuid()}
 3826         src_vol_type = fake_volume.fake_volume_type_obj(ctx, **type_fields)
 3827 
 3828         vol_fields = {
 3829             'id': fakes.get_fake_uuid(),
 3830             'volume_type': src_vol_type,
 3831             'host': 'fakeHost@fakeBackend#fakePool'
 3832         }
 3833 
 3834         vol = fake_volume.fake_volume_obj(ctx, **vol_fields)
 3835         vol.volume_type = src_vol_type
 3836         host = {'host': 'fakeHost@anotherFakeBackend#fakePool'}
 3837 
 3838         dst_config = conf.BackendGroupConfiguration(
 3839             [], conf.SHARED_CONF_GROUP)
 3840         dst_config.san_ip = '10.10.10.10'
 3841 
 3842         mock_get_backend_configuration.return_value = dst_config
 3843 
 3844         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 3845         sfv.active_cluster['mvip'] = '10.10.10.10'
 3846         result = sfv.migrate_volume(ctx, vol, host)
 3847 
 3848         mock_get_backend_configuration.assert_called_with(
 3849             'anotherFakeBackend', sfv.get_driver_options())
 3850 
 3851         mock_do_intercluster_volume_migration.assert_not_called()
 3852         self.assertEqual((True, {}), result)
 3853 
 3854     @mock.patch.object(solidfire.SolidFireDriver,
 3855                        '_do_intercluster_volume_migration')
 3856     @mock.patch('cinder.volume.volume_utils.get_backend_configuration')
 3857     def test_migrate_volume_different_cluster(
 3858             self, mock_get_backend_configuration,
 3859             mock_do_intercluster_volume_migration):
 3860 
 3861         ctx = context.get_admin_context()
 3862         type_fields = {'id': fakes.get_fake_uuid()}
 3863         src_vol_type = fake_volume.fake_volume_type_obj(ctx, **type_fields)
 3864 
 3865         vol_fields = {
 3866             'id': fakes.get_fake_uuid(),
 3867             'volume_type': src_vol_type,
 3868             'host': 'fakeHost@fakeBackend#fakePool'
 3869         }
 3870 
 3871         vol = fake_volume.fake_volume_obj(ctx, **vol_fields)
 3872         vol.volume_type = src_vol_type
 3873         host = {'host': 'fakeHost@anotherFakeBackend#fakePool'}
 3874 
 3875         dst_config = conf.BackendGroupConfiguration(
 3876             [], conf.SHARED_CONF_GROUP)
 3877         dst_config.san_ip = '10.10.10.10'
 3878 
 3879         mock_get_backend_configuration.return_value = dst_config
 3880         mock_do_intercluster_volume_migration.return_value = {}
 3881 
 3882         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 3883         sfv.active_cluster['mvip'] = '20.20.20.20'
 3884         result = sfv.migrate_volume(ctx, vol, host)
 3885 
 3886         mock_do_intercluster_volume_migration.assert_called()
 3887         self.assertEqual((True, {}), result)
 3888 
 3889     @mock.patch.object(solidfire.SolidFireDriver, '_build_endpoint_info')
 3890     @mock.patch.object(solidfire.SolidFireDriver, '_create_cluster_reference')
 3891     @mock.patch.object(solidfire.SolidFireDriver,
 3892                        '_setup_intercluster_volume_migration')
 3893     @mock.patch.object(solidfire.SolidFireDriver,
 3894                        '_do_intercluster_volume_migration_data_sync')
 3895     @mock.patch.object(solidfire.SolidFireDriver,
 3896                        '_cleanup_intercluster_volume_migration')
 3897     def test_do_intercluster_volume_migration(
 3898             self, mock_cleanup_intercluster_volume_migration,
 3899             mock_do_intercluster_volume_migration_data_sync,
 3900             mock_setup_intercluster_volume_migration,
 3901             mock_create_cluster_reference,
 3902             mock_build_endpoint_info):
 3903 
 3904         vol_fields = {
 3905             'id': fakes.get_fake_uuid()
 3906         }
 3907 
 3908         vol = fake_volume.fake_volume_obj(context.get_admin_context(),
 3909                                           **vol_fields)
 3910         host = {'host': 'fakeHost@anotherFakeBackend#fakePool'}
 3911 
 3912         dst_config = conf.BackendGroupConfiguration(
 3913             [], conf.SHARED_CONF_GROUP)
 3914 
 3915         fake_dst_endpoint = deepcopy(self.fake_secondary_cluster['endpoint'])
 3916         fake_dst_cluster_ref = deepcopy(self.fake_secondary_cluster)
 3917 
 3918         mock_build_endpoint_info.return_value = fake_dst_endpoint
 3919         mock_create_cluster_reference.return_value = fake_dst_cluster_ref
 3920 
 3921         fake_dst_volume = {
 3922             'provider_id': "%s %s %s" % (9999,
 3923                                          fakes.get_fake_uuid(),
 3924                                          fake_dst_cluster_ref['uuid'])
 3925         }
 3926 
 3927         mock_setup_intercluster_volume_migration.return_value = \
 3928             fake_dst_volume
 3929 
 3930         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 3931         result = sfv._do_intercluster_volume_migration(vol, host, dst_config)
 3932 
 3933         mock_build_endpoint_info.assert_called_once_with(
 3934             backend_conf=dst_config)
 3935 
 3936         mock_create_cluster_reference.assert_called_with(fake_dst_endpoint)
 3937         mock_setup_intercluster_volume_migration.assert_called_with(
 3938             vol, fake_dst_cluster_ref)
 3939         mock_do_intercluster_volume_migration_data_sync.assert_called_with(
 3940             vol, None, 9999, fake_dst_cluster_ref)
 3941         mock_cleanup_intercluster_volume_migration.assert_called_with(
 3942             vol, 9999, fake_dst_cluster_ref)
 3943         self.assertEqual(fake_dst_volume, result)
 3944 
 3945     @mock.patch.object(solidfire.SolidFireDriver, '_create_cluster_reference')
 3946     @mock.patch.object(solidfire.SolidFireDriver, '_get_create_account')
 3947     @mock.patch.object(solidfire.SolidFireDriver, '_get_default_volume_params')
 3948     @mock.patch.object(solidfire.SolidFireDriver, '_do_volume_create')
 3949     @mock.patch.object(solidfire.SolidFireDriver, '_create_volume_pairing')
 3950     @mock.patch.object(solidfire.SolidFireDriver, '_issue_api_request')
 3951     @mock.patch.object(solidfire.SolidFireDriver,
 3952                        '_get_or_create_cluster_pairing')
 3953     def test_setup_intercluster_volume_migration(
 3954             self, mock_get_or_create_cluster_pairing,
 3955             mock_issue_api_request,
 3956             mock_create_volume_pairing,
 3957             mock_do_volume_create,
 3958             mock_get_default_volume_params,
 3959             mock_get_create_account,
 3960             mock_create_cluster_reference):
 3961 
 3962         fake_project_id = fakes.get_fake_uuid()
 3963 
 3964         vol_fields = {
 3965             'id': fakes.get_fake_uuid(),
 3966             'project_id': fake_project_id
 3967         }
 3968 
 3969         vol = fake_volume.fake_volume_obj(context.get_admin_context(),
 3970                                           **vol_fields)
 3971 
 3972         fake_dst_cluster_ref = deepcopy(self.fake_secondary_cluster)
 3973 
 3974         fake_sfaccount = {'username': 'fakeAccount'}
 3975         mock_get_create_account.return_value = fake_sfaccount
 3976 
 3977         fake_vol_default_params = {'name': 'someFakeVolumeName'}
 3978         mock_get_default_volume_params.return_value = fake_vol_default_params
 3979 
 3980         fake_dst_volume = {'volumeID': 9999}
 3981         mock_do_volume_create.return_value = fake_dst_volume
 3982 
 3983         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 3984         mock_issue_api_request.reset_mock()
 3985         result = sfv._setup_intercluster_volume_migration(
 3986             vol, fake_dst_cluster_ref)
 3987 
 3988         mock_get_or_create_cluster_pairing.assert_called_with(
 3989             fake_dst_cluster_ref, check_connected=True)
 3990         mock_get_create_account.assert_called_with(
 3991             fake_project_id, endpoint=fake_dst_cluster_ref['endpoint'])
 3992         mock_get_default_volume_params.assert_called_with(vol, fake_sfaccount)
 3993         mock_do_volume_create.assert_called_with(
 3994             fake_sfaccount,
 3995             fake_vol_default_params,
 3996             endpoint=fake_dst_cluster_ref['endpoint'])
 3997         mock_issue_api_request.assert_not_called()
 3998         mock_create_volume_pairing.assert_called_with(
 3999             vol, fake_dst_volume, fake_dst_cluster_ref)
 4000         self.assertEqual(fake_dst_volume, result)
 4001 
 4002     @mock.patch.object(solidfire.SolidFireDriver, '_create_cluster_reference')
 4003     @mock.patch.object(solidfire.SolidFireDriver, '_get_create_account')
 4004     @mock.patch.object(solidfire.SolidFireDriver, '_get_default_volume_params')
 4005     @mock.patch.object(solidfire.SolidFireDriver, '_do_volume_create')
 4006     @mock.patch.object(solidfire.SolidFireDriver, '_create_volume_pairing')
 4007     @mock.patch.object(solidfire.SolidFireDriver, '_issue_api_request')
 4008     @mock.patch.object(solidfire.SolidFireDriver,
 4009                        '_get_or_create_cluster_pairing')
 4010     def test_setup_intercluster_volume_migration_rollback(
 4011             self, mock_get_or_create_cluster_pairing,
 4012             mock_issue_api_request,
 4013             mock_create_volume_pairing,
 4014             mock_do_volume_create,
 4015             mock_get_default_volume_params,
 4016             mock_get_create_account,
 4017             mock_create_cluster_reference):
 4018 
 4019         fake_project_id = fakes.get_fake_uuid()
 4020         fake_src_sf_volid = 1111
 4021         vol_fields = {
 4022             'id': fakes.get_fake_uuid(),
 4023             'project_id': fake_project_id,
 4024             'provider_id': "%s %s %s" % (fake_src_sf_volid,
 4025                                          fakes.get_fake_uuid(),
 4026                                          self.fake_primary_cluster['uuid'])
 4027         }
 4028 
 4029         vol = fake_volume.fake_volume_obj(context.get_admin_context(),
 4030                                           **vol_fields)
 4031 
 4032         fake_dst_cluster_ref = deepcopy(self.fake_secondary_cluster)
 4033 
 4034         fake_dst_sf_volid = 9999
 4035         fake_dst_volume = {
 4036             'provider_id': "%s %s %s" % (fake_dst_sf_volid,
 4037                                          fakes.get_fake_uuid(),
 4038                                          fake_dst_cluster_ref['uuid'])
 4039         }
 4040 
 4041         mock_do_volume_create.return_value = fake_dst_volume
 4042 
 4043         mock_create_volume_pairing.side_effect = \
 4044             solidfire.SolidFireReplicationPairingError()
 4045 
 4046         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 4047         self.assertRaises(solidfire.SolidFireReplicationPairingError,
 4048                           sfv._setup_intercluster_volume_migration, vol,
 4049                           fake_dst_cluster_ref)
 4050 
 4051         src_params = {'volumeID': fake_src_sf_volid}
 4052         dst_params = {'volumeID': fake_dst_sf_volid}
 4053         mock_issue_api_request.assert_has_calls([
 4054             call('RemoveVolumePair', src_params, '8.0'),
 4055             call('RemoveVolumePair', dst_params, '8.0',
 4056                  endpoint=fake_dst_cluster_ref["endpoint"]),
 4057             call('DeleteVolume', dst_params,
 4058                  endpoint=fake_dst_cluster_ref["endpoint"]),
 4059             call('PurgeDeletedVolume', dst_params,
 4060                  endpoint=fake_dst_cluster_ref["endpoint"])])
 4061 
 4062     @mock.patch.object(solidfire.SolidFireDriver,
 4063                        '_do_intercluster_volume_migration_complete_data_sync')
 4064     @mock.patch.object(solidfire.SolidFireDriver, '_get_sf_volume')
 4065     @mock.patch.object(solidfire.SolidFireDriver, '_create_cluster_reference')
 4066     @mock.patch.object(solidfire.SolidFireDriver, '_issue_api_request')
 4067     def test_do_intercluster_volume_migration_data_sync(
 4068             self, mock_issue_api_request,
 4069             mock_create_cluster_reference,
 4070             mock_get_sf_volume,
 4071             mock_do_intercluster_volume_migration_complete_data_sync):
 4072 
 4073         fake_src_sf_volid = 1111
 4074         vol_fields = {
 4075             'id': fakes.get_fake_uuid(),
 4076             'provider_id': "%s %s %s" % (fake_src_sf_volid,
 4077                                          fakes.get_fake_uuid(),
 4078                                          self.fake_primary_cluster['uuid'])
 4079         }
 4080         vol = fake_volume.fake_volume_obj(context.get_admin_context(),
 4081                                           **vol_fields)
 4082 
 4083         fake_dst_cluster_ref = deepcopy(self.fake_secondary_cluster)
 4084         fake_dst_sf_volid = 9999
 4085         fake_sfaccount = {'accountID': 'fakeAccountID'}
 4086 
 4087         mock_get_sf_volume.return_value = {
 4088             'volumePairs': [{'remoteReplication': {'state': 'Active'}}]
 4089         }
 4090 
 4091         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 4092         sfv._do_intercluster_volume_migration_data_sync(vol, fake_sfaccount,
 4093                                                         fake_dst_sf_volid,
 4094                                                         fake_dst_cluster_ref)
 4095 
 4096         params = {'volumeID': fake_dst_sf_volid, 'access': 'replicationTarget'}
 4097         mock_issue_api_request.assert_called_with(
 4098             'ModifyVolume', params, '8.0',
 4099             endpoint=fake_dst_cluster_ref['endpoint'])
 4100 
 4101         vol_params = {'accountID': fake_sfaccount['accountID']}
 4102         mock_get_sf_volume.assert_called_with(vol.id, vol_params)
 4103 
 4104         mock_do_intercluster_volume_migration_complete_data_sync\
 4105             .asert_called_with(fake_dst_sf_volid, fake_dst_cluster_ref)
 4106 
 4107     @mock.patch('oslo_service.loopingcall.FixedIntervalWithTimeoutLoopingCall')
 4108     @mock.patch.object(solidfire.SolidFireDriver, '_get_sf_volume')
 4109     @mock.patch.object(solidfire.SolidFireDriver,
 4110                        '_do_intercluster_volume_migration_complete_data_sync')
 4111     @mock.patch.object(solidfire.SolidFireDriver, '_create_cluster_reference')
 4112     @mock.patch.object(solidfire.SolidFireDriver, '_issue_api_request')
 4113     def test_do_intercluster_volume_migration_data_sync_timeout(
 4114             self, mock_issue_api_request, mock_create_cluster_reference,
 4115             mock_do_intercluster_volume_migration_complete_data_sync,
 4116             mock_get_sf_volume,
 4117             mock_looping_call):
 4118 
 4119         fake_src_sf_volid = 1111
 4120         vol_fields = {
 4121             'id': fakes.get_fake_uuid(),
 4122             'provider_id': "%s %s %s" % (fake_src_sf_volid,
 4123                                          fakes.get_fake_uuid(),
 4124                                          self.fake_primary_cluster['uuid'])
 4125         }
 4126         vol = fake_volume.fake_volume_obj(context.get_admin_context(),
 4127                                           **vol_fields)
 4128 
 4129         fake_dst_cluster_ref = deepcopy(self.fake_secondary_cluster)
 4130         fake_dst_sf_volid = 9999
 4131         fake_sfaccount = {'accountID': 'fakeAccountID'}
 4132 
 4133         mock_looping_call.return_value.start.return_value.wait.side_effect = (
 4134             loopingcall.LoopingCallTimeOut())
 4135 
 4136         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 4137         self.assertRaises(solidfire.SolidFireDataSyncTimeoutError,
 4138                           sfv._do_intercluster_volume_migration_data_sync,
 4139                           vol,
 4140                           fake_sfaccount,
 4141                           fake_dst_sf_volid,
 4142                           fake_dst_cluster_ref)
 4143 
 4144         mock_get_sf_volume.assert_not_called()
 4145         mock_do_intercluster_volume_migration_complete_data_sync\
 4146             .assert_not_called()
 4147 
 4148     @mock.patch.object(solidfire.SolidFireDriver, '_create_cluster_reference')
 4149     @mock.patch.object(solidfire.SolidFireDriver, '_issue_api_request')
 4150     def test_do_intercluster_volume_migration_complete_data_sync(
 4151             self, mock_issue_api_request, mock_create_cluster_reference):
 4152 
 4153         fake_src_sf_volid = 1111
 4154         fake_dst_cluster_ref = deepcopy(self.fake_secondary_cluster)
 4155 
 4156         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 4157         sfv._do_intercluster_volume_migration_complete_data_sync(
 4158             fake_src_sf_volid, fake_dst_cluster_ref)
 4159 
 4160         params = {'volumeID': fake_src_sf_volid, 'access': 'readWrite'}
 4161         mock_issue_api_request.assert_called_with(
 4162             'ModifyVolume', params, '8.0',
 4163             endpoint=fake_dst_cluster_ref['endpoint'])
 4164 
 4165     @mock.patch.object(solidfire.SolidFireDriver, '_create_cluster_reference')
 4166     @mock.patch.object(solidfire.SolidFireDriver, '_issue_api_request')
 4167     def test_cleanup_intercluster_volume_migration(
 4168             self, mock_issue_api_request, mock_create_cluster_reference):
 4169         fake_src_sf_volid = 1111
 4170         vol_fields = {
 4171             'id': fakes.get_fake_uuid(),
 4172             'provider_id': "%s %s %s" % (fake_src_sf_volid,
 4173                                          fakes.get_fake_uuid(),
 4174                                          self.fake_primary_cluster['uuid'])
 4175         }
 4176         vol = fake_volume.fake_volume_obj(context.get_admin_context(),
 4177                                           **vol_fields)
 4178 
 4179         fake_dst_cluster_ref = deepcopy(self.fake_secondary_cluster)
 4180         fake_dst_sf_volid = 9999
 4181 
 4182         sfv = solidfire.SolidFireDriver(configuration=self.configuration)
 4183         sfv._cleanup_intercluster_volume_migration(vol, fake_dst_sf_volid,
 4184                                                    fake_dst_cluster_ref)
 4185 
 4186         src_params = {'volumeID': fake_src_sf_volid}
 4187         dst_params = {'volumeID': fake_dst_sf_volid}
 4188         mock_issue_api_request.assert_has_calls([
 4189             call('RemoveVolumePair', dst_params, '8.0',
 4190                  endpoint=fake_dst_cluster_ref["endpoint"]),
 4191             call('RemoveVolumePair', src_params, '8.0'),
 4192             call('DeleteVolume', src_params),
 4193             call('PurgeDeletedVolume', src_params)])