]> review.fuel-infra Code Review - openstack-build/cinder-build.git/commitdiff
Remove SSH code from 3PAR drivers
authorWalter A. Boring IV <walter.boring@hp.com>
Fri, 31 Jan 2014 07:44:22 +0000 (23:44 -0800)
committerWalter A. Boring IV <walter.boring@hp.com>
Fri, 31 Jan 2014 23:13:06 +0000 (15:13 -0800)
This patch migrates all of the communication
to the 3PAR array into the client library.
Some of the calls to the array happen over ssh
and others happen over REST.  Now the drivers
don't care.

This allows us to change the external client
library to replace SSH calls to REST calls,
without the need of driver changes.

Change-Id: Ia5e94a349308055381001c373b91c444860115c7

cinder/tests/test_hp3par.py
cinder/volume/drivers/san/hp/hp_3par_common.py
cinder/volume/drivers/san/hp/hp_3par_fc.py
cinder/volume/drivers/san/hp/hp_3par_iscsi.py

index ee325c4e5a23a44f02f3fad8ba4a18cf26103f88..93915d26485eb85bf9d66ce2d3e3d017f08ef957 100644 (file)
 #    under the License.
 """Unit tests for OpenStack Cinder volume drivers."""
 
-import ast
 import mock
-import mox
-import shutil
-import tempfile
 
+from hp3parclient import client
 from hp3parclient import exceptions as hpexceptions
 
 from cinder import context
 from cinder import exception
 from cinder.openstack.common import log as logging
 from cinder import test
-from cinder.volume import configuration as conf
 from cinder.volume.drivers.san.hp import hp_3par_fc as hpfcdriver
 from cinder.volume.drivers.san.hp import hp_3par_iscsi as hpdriver
+from cinder.volume import volume_types
 
 LOG = logging.getLogger(__name__)
 
-HP3PAR_DOMAIN = 'OpenStack',
-HP3PAR_CPG = 'OpenStackCPG',
+HP3PAR_CPG = 'OpenStackCPG'
 HP3PAR_CPG_SNAP = 'OpenStackCPGSnap'
-CLI_CR = '\r\n'
-
-
-class FakeHP3ParClient(object):
-
-    PORT_MODE_TARGET = 2
-    PORT_MODE_INITIATOR = 3
-    PORT_MODE_PEER = 4
-
-    PORT_TYPE_HOST = 1
-    PORT_TYPE_DISK = 2
-    PORT_TYPE_FREE = 3
-    PORT_TYPE_RCIP = 6
-    PORT_TYPE_ISCSI = 7
-
-    PORT_PROTO_FC = 1
-    PORT_PROTO_ISCSI = 2
-    PORT_PROTO_IP = 4
-
-    PORT_STATE_READY = 4
-    PORT_STATE_SYNC = 5
-    PORT_STATE_OFFLINE = 10
-
-    HOST_EDIT_ADD = 1
-    HOST_EDIT_REMOVE = 2
-
-    api_url = None
-    debug = False
-
-    connection_count = 0
-
-    volumes = []
-    hosts = []
-    vluns = []
-    cpgs = [
-        {'SAGrowth': {'LDLayout': {'diskPatterns': [{'diskType': 2}]},
-                      'incrementMiB': 8192},
-         'SAUsage': {'rawTotalMiB': 24576,
-                     'rawUsedMiB': 768,
-                     'totalMiB': 8192,
-                     'usedMiB': 256},
-         'SDGrowth': {'LDLayout': {'RAIDType': 4,
-                      'diskPatterns': [{'diskType': 2}]},
-                      'incrementMiB': 32768},
-         'SDUsage': {'rawTotalMiB': 49152,
-                     'rawUsedMiB': 1023,
-                     'totalMiB': 36864,
-                     'usedMiB': 768},
-         'UsrUsage': {'rawTotalMiB': 57344,
-                      'rawUsedMiB': 43349,
-                      'totalMiB': 43008,
-                      'usedMiB': 32512},
-         'additionalStates': [],
-         'degradedStates': [],
-         'domain': HP3PAR_DOMAIN,
-         'failedStates': [],
-         'id': 5,
-         'name': HP3PAR_CPG,
-         'numFPVVs': 2,
-         'numTPVVs': 0,
-         'state': 1,
-         'uuid': '29c214aa-62b9-41c8-b198-543f6cf24edf'}]
-
-    def __init__(self, api_url):
-        self.api_url = api_url
-        self.volumes = []
-        self.hosts = []
-        self.vluns = []
-
-    def debug_rest(self, flag):
-        self.debug = flag
-
-    def login(self, username, password, optional=None):
-        self.connection_count += 1
-        return None
-
-    def logout(self):
-        if self.connection_count < 1:
-            raise hpexceptions.CommandError('No connection to log out.')
-        self.connection_count -= 1
-        return None
-
-    def getVolumes(self):
-        return self.volumes
-
-    def getVolume(self, name):
-        if self.volumes:
-            for volume in self.volumes:
-                if volume['name'] == name:
-                    return volume
-
-        msg = {'code': 'NON_EXISTENT_HOST',
-               'desc': "VOLUME '%s' was not found" % name}
-        raise hpexceptions.HTTPNotFound(msg)
-
-    def createVolume(self, name, cpgName, sizeMiB, optional=None):
-        new_vol = {'additionalStates': [],
-                   'adminSpace': {'freeMiB': 0,
-                                  'rawReservedMiB': 384,
-                                  'reservedMiB': 128,
-                                  'usedMiB': 128},
-                   'baseId': 115,
-                   'comment': optional['comment'],
-                   'copyType': 1,
-                   'creationTime8601': '2012-10-22T16:37:57-07:00',
-                   'creationTimeSec': 1350949077,
-                   'degradedStates': [],
-                   'domain': HP3PAR_DOMAIN,
-                   'failedStates': [],
-                   'id': 115,
-                   'name': name,
-                   'policies': {'caching': True,
-                                'oneHost': False,
-                                'staleSS': True,
-                                'system': False,
-                                'zeroDetect': False},
-                   'provisioningType': 1,
-                   'readOnly': False,
-                   'sizeMiB': sizeMiB,
-                   'snapCPG': optional['snapCPG'],
-                   'snapshotSpace': {'freeMiB': 0,
-                                     'rawReservedMiB': 683,
-                                     'reservedMiB': 512,
-                                     'usedMiB': 512},
-                   'ssSpcAllocLimitPct': 0,
-                   'ssSpcAllocWarningPct': 0,
-                   'state': 1,
-                   'userCPG': cpgName,
-                   'userSpace': {'freeMiB': 0,
-                                 'rawReservedMiB': 41984,
-                                 'reservedMiB': 31488,
-                                 'usedMiB': 31488},
-                   'usrSpcAllocLimitPct': 0,
-                   'usrSpcAllocWarningPct': 0,
-                   'uuid': '1e7daee4-49f4-4d07-9ab8-2b6a4319e243',
-                   'wwn': '50002AC00073383D'}
-        self.volumes.append(new_vol)
-        return None
-
-    def deleteVolume(self, name):
-        volume = self.getVolume(name)
-        self.volumes.remove(volume)
-
-    def createSnapshot(self, name, copyOfName, optional=None):
-        new_snap = {'additionalStates': [],
-                    'adminSpace': {'freeMiB': 0,
-                                   'rawReservedMiB': 0,
-                                   'reservedMiB': 0,
-                                   'usedMiB': 0},
-                    'baseId': 342,
-                    'comment': optional['comment'],
-                    'copyOf': copyOfName,
-                    'copyType': 3,
-                    'creationTime8601': '2012-11-09T15:13:28-08:00',
-                    'creationTimeSec': 1352502808,
-                    'degradedStates': [],
-                    'domain': HP3PAR_DOMAIN,
-                    'expirationTime8601': '2012-11-09T17:13:28-08:00',
-                    'expirationTimeSec': 1352510008,
-                    'failedStates': [],
-                    'id': 343,
-                    'name': name,
-                    'parentId': 342,
-                    'policies': {'caching': True,
-                                 'oneHost': False,
-                                 'staleSS': True,
-                                 'system': False,
-                                 'zeroDetect': False},
-                    'provisioningType': 3,
-                    'readOnly': True,
-                    'retentionTime8601': '2012-11-09T16:13:27-08:00',
-                    'retentionTimeSec': 1352506407,
-                    'sizeMiB': 256,
-                    'snapCPG': HP3PAR_CPG_SNAP,
-                    'snapshotSpace': {'freeMiB': 0,
-                                      'rawReservedMiB': 0,
-                                      'reservedMiB': 0,
-                                      'usedMiB': 0},
-                    'ssSpcAllocLimitPct': 0,
-                    'ssSpcAllocWarningPct': 0,
-                    'state': 1,
-                    'userCPG': HP3PAR_CPG,
-                    'userSpace': {'freeMiB': 0,
-                                  'rawReservedMiB': 0,
-                                  'reservedMiB': 0,
-                                  'usedMiB': 0},
-                    'usrSpcAllocLimitPct': 0,
-                    'usrSpcAllocWarningPct': 0,
-                    'uuid': 'd7a40b8f-2511-46a8-9e75-06383c826d19',
-                    'wwn': '50002AC00157383D'}
-        self.volumes.append(new_snap)
-        return None
-
-    def deleteSnapshot(self, name):
-        volume = self.getVolume(name)
-        self.volumes.remove(volume)
-
-    def createCPG(self, name, optional=None):
-        cpg = {'SAGrowth': {'LDLayout': {'diskPatterns': [{'diskType': 2}]},
-                            'incrementMiB': 8192},
-               'SAUsage': {'rawTotalMiB': 24576,
-                           'rawUsedMiB': 768,
-                           'totalMiB': 8192,
-                           'usedMiB': 256},
-               'SDGrowth': {'LDLayout': {'RAIDType': 4,
-                            'diskPatterns': [{'diskType': 2}]},
-                            'incrementMiB': 32768},
-               'SDUsage': {'rawTotalMiB': 49152,
-                           'rawUsedMiB': 1023,
-                           'totalMiB': 36864,
-                           'usedMiB': 768},
-               'UsrUsage': {'rawTotalMiB': 57344,
-                            'rawUsedMiB': 43349,
-                            'totalMiB': 43008,
-                            'usedMiB': 32512},
-               'additionalStates': [],
-               'degradedStates': [],
-               'domain': HP3PAR_DOMAIN,
-               'failedStates': [],
-               'id': 1,
-               'name': name,
-               'numFPVVs': 2,
-               'numTPVVs': 0,
-               'state': 1,
-               'uuid': '29c214aa-62b9-41c8-b198-000000000000'}
-
-        new_cpg = cpg.copy()
-        new_cpg.update(optional)
-        self.cpgs.append(new_cpg)
-
-    def getCPGs(self):
-        return self.cpgs
-
-    def getCPG(self, name):
-        if self.cpgs:
-            for cpg in self.cpgs:
-                if cpg['name'] == name:
-                    return cpg
-
-        msg = {'code': 'NON_EXISTENT_HOST',
-               'desc': "CPG '%s' was not found" % name}
-        raise hpexceptions.HTTPNotFound(msg)
-
-    def deleteCPG(self, name):
-        cpg = self.getCPG(name)
-        self.cpgs.remove(cpg)
-
-    def createVLUN(self, volumeName, lun, hostname=None,
-                   portPos=None, noVcn=None,
-                   overrideLowerPriority=None):
-
-        vlun = {'active': False,
-                'failedPathInterval': 0,
-                'failedPathPol': 1,
-                'hostname': hostname,
-                'lun': lun,
-                'multipathing': 1,
-                'portPos': portPos,
-                'type': 4,
-                'volumeName': volumeName,
-                'volumeWWN': '50002AC00077383D'}
-        self.vluns.append(vlun)
-        return None
-
-    def deleteVLUN(self, name, lunID, hostname=None, port=None):
-        vlun = self.getVLUN(name)
-        self.vluns.remove(vlun)
-
-    def getVLUNs(self):
-        return self.vluns
-
-    def getVLUN(self, volumeName):
-        for vlun in self.vluns:
-            if vlun['volumeName'] == volumeName:
-                return vlun
-
-        msg = {'code': 'NON_EXISTENT_HOST',
-               'desc': "VLUN '%s' was not found" % volumeName}
-        raise hpexceptions.HTTPNotFound(msg)
-
-    def getHost(self, hostname):
-        return None
-
-    def modifyHost(self, hostname, options):
-        return None
-
-    def getPorts(self):
-        return None
+HP3PAR_USER_NAME = 'testUser'
+HP3PAR_USER_PASS = 'testPassword'
+HP3PAR_SAN_IP = '2.2.2.2'
+HP3PAR_SAN_SSH_PORT = 999
+HP3PAR_SAN_SSH_CON_TIMEOUT = 44
+HP3PAR_SAN_SSH_PRIVATE = 'foobar'
 
 
 class HP3PARBaseDriver():
 
-    VOLUME_ID = "d03338a9-9115-48a3-8dfc-35cdfcdc15a7"
-    CLONE_ID = "d03338a9-9115-48a3-8dfc-000000000000"
-    VOLUME_NAME = "volume-d03338a9-9115-48a3-8dfc-35cdfcdc15a7"
-    SNAPSHOT_ID = "2f823bdc-e36e-4dc8-bd15-de1c7a28ff31"
-    SNAPSHOT_NAME = "snapshot-2f823bdc-e36e-4dc8-bd15-de1c7a28ff31"
-    VOLUME_3PAR_NAME = "osv-0DM4qZEVSKON-DXN-NwVpw"
-    SNAPSHOT_3PAR_NAME = "oss-L4I73ONuTci9Fd4ceij-MQ"
-    FAKE_HOST = "fakehost"
+    VOLUME_ID = 'd03338a9-9115-48a3-8dfc-35cdfcdc15a7'
+    CLONE_ID = 'd03338a9-9115-48a3-8dfc-000000000000'
+    VOLUME_NAME = 'volume-' + VOLUME_ID
+    VOLUME_NAME_3PAR = 'osv-0DM4qZEVSKON-DXN-NwVpw'
+    SNAPSHOT_ID = '2f823bdc-e36e-4dc8-bd15-de1c7a28ff31'
+    SNAPSHOT_NAME = 'snapshot-2f823bdc-e36e-4dc8-bd15-de1c7a28ff31'
+    VOLUME_3PAR_NAME = 'osv-0DM4qZEVSKON-DXN-NwVpw'
+    SNAPSHOT_3PAR_NAME = 'oss-L4I73ONuTci9Fd4ceij-MQ'
+    FAKE_HOST = 'fakehost'
     USER_ID = '2689d9a913974c008b1d859013f23607'
     PROJECT_ID = 'fac88235b9d64685a3530f73e490348f'
     VOLUME_ID_SNAP = '761fc5e5-5191-4ec7-aeba-33e36de44156'
@@ -387,11 +102,13 @@ class HP3PARBaseDriver():
                 'display_name': 'fakesnap',
                 'display_description': FAKE_DESC}
 
+    wwn = ["123456789012345", "123456789054321"]
+
     connector = {'ip': '10.0.0.2',
                  'initiator': 'iqn.1993-08.org.debian:01:222',
-                 'wwpns': ["123456789012345", "123456789054321"],
+                 'wwpns': [wwn[0], wwn[1]],
                  'wwnns': ["223456789012345", "223456789054321"],
-                 'host': 'fakehost'}
+                 'host': FAKE_HOST}
 
     volume_type = {'name': 'gold',
                    'deleted': False,
@@ -401,167 +118,153 @@ class HP3PARBaseDriver():
                    'deleted_at': None,
                    'id': 'gold'}
 
+    cpgs = [
+        {'SAGrowth': {'LDLayout': {'diskPatterns': [{'diskType': 2}]},
+                      'incrementMiB': 8192},
+         'SAUsage': {'rawTotalMiB': 24576,
+                     'rawUsedMiB': 768,
+                     'totalMiB': 8192,
+                     'usedMiB': 256},
+         'SDGrowth': {'LDLayout': {'RAIDType': 4,
+                      'diskPatterns': [{'diskType': 2}]},
+                      'incrementMiB': 32768},
+         'SDUsage': {'rawTotalMiB': 49152,
+                     'rawUsedMiB': 1023,
+                     'totalMiB': 36864,
+                     'usedMiB': 768},
+         'UsrUsage': {'rawTotalMiB': 57344,
+                      'rawUsedMiB': 43349,
+                      'totalMiB': 43008,
+                      'usedMiB': 32512},
+         'additionalStates': [],
+         'degradedStates': [],
+         'failedStates': [],
+         'id': 5,
+         'name': HP3PAR_CPG,
+         'numFPVVs': 2,
+         'numTPVVs': 0,
+         'state': 1,
+         'uuid': '29c214aa-62b9-41c8-b198-543f6cf24edf'}]
+
     def setup_configuration(self):
-        configuration = mox.MockObject(conf.Configuration)
+        configuration = mock.Mock()
         configuration.hp3par_debug = False
-        configuration.hp3par_username = 'testUser'
-        configuration.hp3par_password = 'testPassword'
+        configuration.hp3par_username = HP3PAR_USER_NAME
+        configuration.hp3par_password = HP3PAR_USER_PASS
         configuration.hp3par_api_url = 'https://1.1.1.1/api/v1'
         configuration.hp3par_cpg = HP3PAR_CPG
         configuration.hp3par_cpg_snap = HP3PAR_CPG_SNAP
         configuration.iscsi_ip_address = '1.1.1.2'
         configuration.iscsi_port = '1234'
-        configuration.san_ip = '2.2.2.2'
-        configuration.san_login = 'test'
-        configuration.san_password = 'test'
+        configuration.san_ip = HP3PAR_SAN_IP
+        configuration.san_login = HP3PAR_USER_NAME
+        configuration.san_password = HP3PAR_USER_PASS
+        configuration.san_ssh_port = HP3PAR_SAN_SSH_PORT
+        configuration.ssh_conn_timeout = HP3PAR_SAN_SSH_CON_TIMEOUT
+        configuration.san_private_key = HP3PAR_SAN_SSH_PRIVATE
         configuration.hp3par_snapshot_expiration = ""
         configuration.hp3par_snapshot_retention = ""
         configuration.hp3par_iscsi_ips = []
         return configuration
 
-    def setup_fakes(self):
-        self.stubs.Set(hpdriver.hpcommon.HP3PARCommon, "_create_client",
-                       self.fake_create_client)
-        self.stubs.Set(hpdriver.hpcommon.HP3PARCommon, "_set_connections",
-                       self.fake_set_connections)
-        self.stubs.Set(hpdriver.hpcommon.HP3PARCommon, "_get_3par_host",
-                       self.fake_get_3par_host)
-        self.stubs.Set(hpdriver.hpcommon.HP3PARCommon, "_delete_3par_host",
-                       self.fake_delete_3par_host)
-        self.stubs.Set(hpdriver.hpcommon.HP3PARCommon, "_create_3par_vlun",
-                       self.fake_create_3par_vlun)
-        self.stubs.Set(hpdriver.hpcommon.HP3PARCommon, "get_ports",
-                       self.fake_get_ports)
-        self.stubs.Set(hpdriver.hpcommon.HP3PARCommon, "get_cpg",
-                       self.fake_get_cpg)
-        self.stubs.Set(hpdriver.hpcommon.HP3PARCommon,
-                       "get_volume_settings_from_type",
-                       self.fake_get_volume_settings_from_type)
-        self.stubs.Set(hpfcdriver.hpcommon.HP3PARCommon, "get_domain",
-                       self.fake_get_domain)
-
-    def clear_mox(self):
-        self.mox.ResetAll()
-        self.stubs.UnsetAll()
-
-    def fake_create_client(self):
-        return FakeHP3ParClient(self.driver.configuration.hp3par_api_url)
-
-    def fake_get_cpg(self, volume, allowSnap=False):
-        return HP3PAR_CPG
-
-    def fake_set_connections(self):
-        return
-
-    def fake_get_domain(self, cpg):
-        return HP3PAR_DOMAIN
-
-    def fake_extend_volume(self, volume, new_size):
-        vol = self.driver.common.client.getVolume(volume['name'])
-        old_size = vol['sizeMiB']
-        option = {'comment': vol['comment'], 'snapCPG': vol['snapCPG']}
-        self.driver.common.client.deleteVolume(volume['name'])
-        self.driver.common.client.createVolume(vol['name'],
-                                               vol['userCPG'],
-                                               new_size, option)
-
-    def fake_get_3par_host(self, hostname):
-        if hostname not in self._hosts:
-            msg = {'code': 'NON_EXISTENT_HOST',
-                   'desc': "HOST '%s' was not found" % hostname}
-            raise hpexceptions.HTTPNotFound(msg)
-        else:
-            return self._hosts[hostname]
-
-    def fake_delete_3par_host(self, hostname):
-        if hostname not in self._hosts:
-            msg = {'code': 'NON_EXISTENT_HOST',
-                   'desc': "HOST '%s' was not found" % hostname}
-            raise hpexceptions.HTTPNotFound(msg)
-        else:
-            del self._hosts[hostname]
-
-    def fake_create_3par_vlun(self, volume, hostname, nsp):
-        self.driver.common.client.createVLUN(volume, 19, hostname, nsp)
-
-    def fake_get_ports(self):
-        ports = self.FAKE_FC_PORTS
-        ports.append(self.FAKE_ISCSI_PORT)
-        return {'members': ports}
-
-    def fake_get_volume_type(self, type_id):
-        return self.volume_type
-
-    def fake_get_qos_by_volume_type(self, volume_type):
-        return self.QOS
-
-    def fake_add_volume_to_volume_set(self, volume, volume_name,
-                                      cpg, vvs_name, qos):
-        return volume
-
-    def fake_copy_volume(self, src_name, dest_name, cpg=None,
-                         snap_cpg=None, tpvv=True):
-        pass
-
-    def fake_get_volume_stats(self, vol_name):
-        return "normal"
-
-    def fake_get_volume_settings_from_type(self, volume):
-        return {'cpg': HP3PAR_CPG,
+    @mock.patch(
+        'hp3parclient.client.HP3ParClient',
+        spec=True,
+        PORT_MODE_TARGET=client.HP3ParClient.PORT_MODE_TARGET,
+        PORT_STATE_READY=client.HP3ParClient.PORT_STATE_READY,
+        PORT_PROTO_ISCSI=client.HP3ParClient.PORT_PROTO_ISCSI,
+        PORT_PROTO_FC=client.HP3ParClient.PORT_PROTO_FC,
+        HOST_EDIT_ADD=client.HP3ParClient.HOST_EDIT_ADD)
+    def setup_mock_client(self, _m_client, driver, conf=None, m_conf=None):
+
+        _m_client = _m_client.return_value
+        if m_conf is not None:
+            _m_client.configure_mock(**m_conf)
+
+        if conf is None:
+            conf = self.setup_configuration()
+        self.driver = driver(configuration=conf)
+        self.driver.do_setup(None)
+        return _m_client
+
+    def test_create_volume(self):
+
+        # setup_mock_client drive with default configuration
+        # and return the mock HTTP 3PAR client
+        mock_client = self.setup_driver()
+        self.driver.create_volume(self.volume)
+        comment = (
+            '{"display_name": "Foo Volume", "type": "OpenStack",'
+            ' "name": "volume-d03338a9-9115-48a3-8dfc-35cdfcdc15a7",'
+            ' "volume_id": "d03338a9-9115-48a3-8dfc-35cdfcdc15a7"}')
+        expected = [
+            mock.call.login(HP3PAR_USER_NAME, HP3PAR_USER_PASS),
+            mock.call.createVolume(
+                self.VOLUME_3PAR_NAME,
+                HP3PAR_CPG,
+                1907, {
+                    'comment': comment,
+                    'tpvv': True,
+                    'snapCPG': HP3PAR_CPG_SNAP}),
+            mock.call.logout()]
+
+        mock_client.assert_has_calls(expected)
+
+    @mock.patch.object(volume_types, 'get_volume_type')
+    def test_create_volume_qos(self, _mock_volume_types):
+        # setup_mock_client drive with default configuration
+        # and return the mock HTTP 3PAR client
+        mock_client = self.setup_driver()
+
+        _mock_volume_types.return_value = {
+            'name': 'gold',
+            'extra_specs': {
+                'cpg': HP3PAR_CPG,
                 'snap_cpg': HP3PAR_CPG_SNAP,
                 'vvs_name': self.VVS_NAME,
                 'qos': self.QOS,
                 'tpvv': True,
-                'volume_type': self.volume_type}
-
-    def fake_get_volume_settings_from_type_noqos(self, volume):
-        return {'cpg': HP3PAR_CPG,
-                'snap_cpg': HP3PAR_CPG_SNAP,
-                'vvs_name': None,
-                'qos': None,
-                'tpvv': True,
-                'volume_type': None}
+                'volume_type': self.volume_type}}
 
-    def test_create_volume(self):
-        self.flags(lock_path=self.tempdir)
-        self.stubs.Set(hpdriver.hpcommon.HP3PARCommon,
-                       "get_volume_settings_from_type",
-                       self.fake_get_volume_settings_from_type_noqos)
-        self.driver.create_volume(self.volume)
-        volume = self.driver.common.client.getVolume(self.VOLUME_3PAR_NAME)
-        self.assertEqual(volume['name'], self.VOLUME_3PAR_NAME)
-
-    def test_create_volume_qos(self):
-        self.flags(lock_path=self.tempdir)
-        self.stubs.Set(hpdriver.hpcommon.HP3PARCommon,
-                       "get_volume_settings_from_type",
-                       self.fake_get_volume_settings_from_type)
-        self.stubs.Set(hpdriver.hpcommon.HP3PARCommon,
-                       "_add_volume_to_volume_set",
-                       self.fake_add_volume_to_volume_set)
         self.driver.create_volume(self.volume_qos)
-        volume = self.driver.common.client.getVolume(self.VOLUME_3PAR_NAME)
-
-        self.assertEqual(volume['name'], self.VOLUME_3PAR_NAME)
-        self.assertNotIn(self.QOS, dict(ast.literal_eval(volume['comment'])))
+        comment = (
+            '{"volume_type_name": "gold", "display_name": "Foo Volume"'
+            ', "name": "volume-d03338a9-9115-48a3-8dfc-35cdfcdc15a7'
+            '", "volume_type_id": "gold", "volume_id": "d03338a9-91'
+            '15-48a3-8dfc-35cdfcdc15a7", "qos": {}, "type": "OpenStack"}')
+
+        expected = [
+            mock.call.login(HP3PAR_USER_NAME, HP3PAR_USER_PASS),
+            mock.call.createVolume(
+                self.VOLUME_3PAR_NAME,
+                HP3PAR_CPG,
+                1907, {
+                    'comment': comment,
+                    'tpvv': True,
+                    'snapCPG': HP3PAR_CPG_SNAP}),
+            mock.call.logout()]
+
+        mock_client.assert_has_calls(expected)
 
     def test_delete_volume(self):
-        self.flags(lock_path=self.tempdir)
-        self.stubs.Set(hpdriver.hpcommon.HP3PARCommon,
-                       "get_volume_settings_from_type",
-                       self.fake_get_volume_settings_from_type)
+
+        # setup_mock_client drive with default configuration
+        # and return the mock HTTP 3PAR client
+        mock_client = self.setup_driver()
         self.driver.delete_volume(self.volume)
-        self.assertRaises(hpexceptions.HTTPNotFound,
-                          self.driver.common.client.getVolume,
-                          self.VOLUME_ID)
+
+        expected = [
+            mock.call.login(HP3PAR_USER_NAME, HP3PAR_USER_PASS),
+            mock.call.deleteVolume(self.VOLUME_3PAR_NAME),
+            mock.call.logout()]
+
+        mock_client.assert_has_calls(expected)
 
     def test_create_cloned_volume(self):
-        self.flags(lock_path=self.tempdir)
-        self.stubs.Set(hpdriver.hpcommon.HP3PARCommon,
-                       "get_volume_settings_from_type",
-                       self.fake_get_volume_settings_from_type)
-        self.stubs.Set(hpdriver.hpcommon.HP3PARCommon, "_copy_volume",
-                       self.fake_copy_volume)
+
+        # setup_mock_client drive with default configuration
+        # and return the mock HTTP 3PAR client
+        mock_client = self.setup_driver()
         volume = {'name': HP3PARBaseDriver.VOLUME_NAME,
                   'id': HP3PARBaseDriver.CLONE_ID,
                   'display_name': 'Foo Volume',
@@ -572,15 +275,38 @@ class HP3PARBaseDriver():
         model_update = self.driver.create_cloned_volume(volume, src_vref)
         self.assertIsNotNone(model_update)
 
-    @mock.patch.object(hpdriver.hpcommon.HP3PARCommon, '_run_ssh')
-    def test_attach_volume(self, mock_run_ssh):
-        mock_run_ssh.side_effect = [[CLI_CR, ''], Exception('Custom ex')]
+        expected = [
+            mock.call.login(HP3PAR_USER_NAME, HP3PAR_USER_PASS),
+            mock.call.copyVolume(
+                self.VOLUME_3PAR_NAME,
+                'osv-0DM4qZEVSKON-AAAAAAAAA',
+                HP3PAR_CPG,
+                HP3PAR_CPG_SNAP, True),
+            mock.call.logout()]
+
+        mock_client.assert_has_calls(expected)
+
+    def test_attach_volume(self):
+
+        # setup_mock_client drive with default configuration
+        # and return the mock HTTP 3PAR client
+        mock_client = self.setup_driver()
         self.driver.attach_volume(context.get_admin_context(),
                                   self.volume,
                                   'abcdef',
                                   'newhost',
                                   '/dev/vdb')
-        self.assertTrue(mock_run_ssh.called)
+
+        expected = [
+            mock.call.setVolumeMetaData(
+                self.VOLUME_3PAR_NAME,
+                'HPQ-CS-instance_uuid',
+                'abcdef')]
+
+        mock_client.assert_has_calls(expected)
+
+        # test the exception
+        mock_client.setVolumeMetaData.side_effect = Exception('Custom ex')
         self.assertRaises(exception.CinderException,
                           self.driver.attach_volume,
                           context.get_admin_context(),
@@ -589,46 +315,73 @@ class HP3PARBaseDriver():
                           'newhost',
                           '/dev/vdb')
 
-    @mock.patch.object(hpdriver.hpcommon.HP3PARCommon, '_run_ssh')
-    def test_detach_volume(self, mock_run_ssh):
-        mock_run_ssh.side_effect = [[CLI_CR, ''], Exception('Custom ex')]
+    def test_detach_volume(self):
+        # setup_mock_client drive with default configuration
+        # and return the mock HTTP 3PAR client
+        mock_client = self.setup_driver()
         self.driver.detach_volume(context.get_admin_context(), self.volume)
-        self.assertTrue(mock_run_ssh.called)
+        expected = [
+            mock.call.removeVolumeMetaData(
+                self.VOLUME_3PAR_NAME,
+                'HPQ-CS-instance_uuid')]
+
+        mock_client.assert_has_calls(expected)
+
+        # test the exception
+        mock_client.removeVolumeMetaData.side_effect = Exception('Custom ex')
         self.assertRaises(exception.CinderException,
                           self.driver.detach_volume,
                           context.get_admin_context(),
                           self.volume)
 
     def test_create_snapshot(self):
-        self.flags(lock_path=self.tempdir)
+        # setup_mock_client drive with default configuration
+        # and return the mock HTTP 3PAR client
+        mock_client = self.setup_driver()
         self.driver.create_snapshot(self.snapshot)
 
-        # check to see if the snapshot was created
-        snap_vol = self.driver.common.client.getVolume(self.SNAPSHOT_3PAR_NAME)
-        self.assertEqual(snap_vol['name'], self.SNAPSHOT_3PAR_NAME)
+        commet = (
+            '{"volume_id": "761fc5e5-5191-4ec7-aeba-33e36de44156",'
+            ' "display_name": "fakesnap",'
+            ' "description": "test description name",'
+            ' "volume_name": "volume-d03338a9-9115-48a3-8dfc-35cdfcdc15a7"}')
+
+        expected = [
+            mock.call.login(HP3PAR_USER_NAME, HP3PAR_USER_PASS),
+            mock.call.createSnapshot(
+                'oss-L4I73ONuTci9Fd4ceij-MQ',
+                'osv-dh-F5VGRTseuujPjbeRBVg',
+                {
+                    'comment': commet,
+                    'readOnly': True}),
+            mock.call.logout()]
+
+        mock_client.assert_has_calls(expected)
 
     def test_delete_snapshot(self):
-        self.flags(lock_path=self.tempdir)
+        # setup_mock_client drive with default configuration
+        # and return the mock HTTP 3PAR client
+        mock_client = self.setup_driver()
 
-        self.driver.create_snapshot(self.snapshot)
-        #make sure it exists first
-        vol = self.driver.common.client.getVolume(self.SNAPSHOT_3PAR_NAME)
-        self.assertEqual(vol['name'], self.SNAPSHOT_3PAR_NAME)
         self.driver.delete_snapshot(self.snapshot)
 
-        # the snapshot should be deleted now
-        self.assertRaises(hpexceptions.HTTPNotFound,
-                          self.driver.common.client.getVolume,
-                          self.SNAPSHOT_3PAR_NAME)
+        expected = [
+            mock.call.login(HP3PAR_USER_NAME, HP3PAR_USER_PASS),
+            mock.call.deleteVolume('oss-L4I73ONuTci9Fd4ceij-MQ'),
+            mock.call.logout()]
+
+        mock_client.assert_has_calls(expected)
 
     def test_delete_snapshot_in_use(self):
-        self.flags(lock_path=self.tempdir)
+        # setup_mock_client drive with default configuration
+        # and return the mock HTTP 3PAR client
+        mock_client = self.setup_driver()
 
         self.driver.create_snapshot(self.snapshot)
         self.driver.create_volume_from_snapshot(self.volume, self.snapshot)
 
         ex = hpexceptions.HTTPConflict("In use")
-        self.driver.common.client.deleteVolume = mock.Mock(side_effect=ex)
+        mock_client.deleteVolume = mock.Mock(side_effect=ex)
 
         # Deleting the snapshot that a volume is dependent on should fail
         self.assertRaises(exception.SnapshotIsBusy,
@@ -636,11 +389,27 @@ class HP3PARBaseDriver():
                           self.snapshot)
 
     def test_create_volume_from_snapshot(self):
-        self.flags(lock_path=self.tempdir)
+        # setup_mock_client drive with default configuration
+        # and return the mock HTTP 3PAR client
+        mock_client = self.setup_driver()
         self.driver.create_volume_from_snapshot(self.volume, self.snapshot)
 
-        snap_vol = self.driver.common.client.getVolume(self.VOLUME_3PAR_NAME)
-        self.assertEqual(snap_vol['name'], self.VOLUME_3PAR_NAME)
+        comment = (
+            '{"snapshot_id": "2f823bdc-e36e-4dc8-bd15-de1c7a28ff31",'
+            ' "display_name": "Foo Volume",'
+            ' "volume_id": "d03338a9-9115-48a3-8dfc-35cdfcdc15a7"}')
+
+        expected = [
+            mock.call.login(HP3PAR_USER_NAME, HP3PAR_USER_PASS),
+            mock.call.createSnapshot(
+                self.VOLUME_3PAR_NAME,
+                'oss-L4I73ONuTci9Fd4ceij-MQ',
+                {
+                    'comment': comment,
+                    'readOnly': False}),
+            mock.call.logout()]
+
+        mock_client.assert_has_calls(expected)
 
         volume = self.volume.copy()
         volume['size'] = 1
@@ -648,20 +417,37 @@ class HP3PARBaseDriver():
                           self.driver.create_volume_from_snapshot,
                           volume, self.snapshot)
 
-    def test_create_volume_from_snapshot_qos(self):
-        self.flags(lock_path=self.tempdir)
-        self.stubs.Set(hpdriver.hpcommon.HP3PARCommon, "_get_volume_type",
-                       self.fake_get_volume_type)
-        self.stubs.Set(hpdriver.hpcommon.HP3PARCommon,
-                       "_get_qos_by_volume_type",
-                       self.fake_get_qos_by_volume_type)
-        self.stubs.Set(hpdriver.hpcommon.HP3PARCommon,
-                       "_add_volume_to_volume_set",
-                       self.fake_add_volume_to_volume_set)
+    @mock.patch.object(volume_types, 'get_volume_type')
+    def test_create_volume_from_snapshot_qos(self, _mock_volume_types):
+        # setup_mock_client drive with default configuration
+        # and return the mock HTTP 3PAR client
+        mock_client = self.setup_driver()
+        _mock_volume_types.return_value = {
+            'name': 'gold',
+            'extra_specs': {
+                'cpg': HP3PAR_CPG,
+                'snap_cpg': HP3PAR_CPG_SNAP,
+                'vvs_name': self.VVS_NAME,
+                'qos': self.QOS,
+                'tpvv': True,
+                'volume_type': self.volume_type}}
         self.driver.create_volume_from_snapshot(self.volume_qos, self.snapshot)
-        snap_vol = self.driver.common.client.getVolume(self.VOLUME_3PAR_NAME)
-        self.assertEqual(snap_vol['name'], self.VOLUME_3PAR_NAME)
-        self.assertNotIn(self.QOS, dict(ast.literal_eval(snap_vol['comment'])))
+
+        comment = (
+            '{"snapshot_id": "2f823bdc-e36e-4dc8-bd15-de1c7a28ff31",'
+            ' "display_name": "Foo Volume",'
+            ' "volume_id": "d03338a9-9115-48a3-8dfc-35cdfcdc15a7"}')
+
+        expected = [
+            mock.call.login(HP3PAR_USER_NAME, HP3PAR_USER_PASS),
+            mock.call.createSnapshot(
+                self.VOLUME_3PAR_NAME,
+                'oss-L4I73ONuTci9Fd4ceij-MQ', {
+                    'comment': comment,
+                    'readOnly': False}),
+            mock.call.logout()]
+
+        mock_client.assert_has_calls(expected)
 
         volume = self.volume.copy()
         volume['size'] = 1
@@ -670,105 +456,180 @@ class HP3PARBaseDriver():
                           volume, self.snapshot)
 
     def test_terminate_connection(self):
-        self.flags(lock_path=self.tempdir)
-        #setup the connections
-        self.driver.initialize_connection(self.volume, self.connector)
-        vlun = self.driver.common.client.getVLUN(self.VOLUME_3PAR_NAME)
-        self.assertEqual(vlun['volumeName'], self.VOLUME_3PAR_NAME)
-        self.driver.terminate_connection(self.volume, self.connector,
-                                         force=True)
-        # vlun should be gone.
-        self.assertRaises(hpexceptions.HTTPNotFound,
-                          self.driver.common.client.getVLUN,
-                          self.VOLUME_3PAR_NAME)
-
-    @mock.patch.object(hpdriver.hpcommon.HP3PARCommon, '_run_ssh')
-    def test_update_volume_key_value_pair(self, mock_run_ssh):
-        mock_run_ssh.return_value = [CLI_CR, '']
-        self.assertEqual(
-            self.driver.common.update_volume_key_value_pair(self.volume,
-                                                            'a',
-                                                            'b'),
-            None)
-        update_cmd = ['setvv', '-setkv', 'a=b', self.VOLUME_3PAR_NAME]
-        mock_run_ssh.assert_called_once_with(update_cmd, False)
+        # setup_mock_client drive with default configuration
+        # and return the mock HTTP 3PAR client
+        mock_client = self.setup_driver()
+        mock_client.getVLUN.return_value = {'lun': None, 'type': 0}
+
+        self.driver.terminate_connection(
+            self.volume,
+            self.connector,
+            force=True)
+
+        expected = [
+            mock.call.login(HP3PAR_USER_NAME, HP3PAR_USER_PASS),
+            mock.call.getVLUN(self.VOLUME_3PAR_NAME),
+            mock.call.deleteVLUN(
+                self.VOLUME_3PAR_NAME,
+                None,
+                self.FAKE_HOST),
+            mock.call.deleteHost(self.FAKE_HOST),
+            mock.call.logout()]
+
+        mock_client.assert_has_calls(expected)
+
+    def test_update_volume_key_value_pair(self):
+        # setup_mock_client drive with default configuration
+        # and return the mock HTTP 3PAR client
+        mock_client = self.setup_driver()
+
+        key = 'a'
+        value = 'b'
+        self.driver.common.update_volume_key_value_pair(
+            self.volume,
+            key,
+            value)
+
+        expected = [
+            mock.call.setVolumeMetaData(self.VOLUME_3PAR_NAME, key, value)]
+
+        mock_client.assert_has_calls(expected)
+
+        # check exception
+        mock_client.setVolumeMetaData.side_effect = Exception('fake')
         self.assertRaises(exception.VolumeBackendAPIException,
                           self.driver.common.update_volume_key_value_pair,
                           self.volume,
                           None,
                           'b')
 
-    @mock.patch.object(hpdriver.hpcommon.HP3PARCommon, '_run_ssh')
-    def test_clear_volume_key_value_pair(self, mock_run_ssh):
-        mock_run_ssh.side_effect = [[CLI_CR, ''], Exception('Custom ex')]
-        self.assertEqual(
-            self.driver.common.clear_volume_key_value_pair(self.volume, 'a'),
-            None)
-        clear_cmd = ['setvv', '-clrkey', 'a', self.VOLUME_3PAR_NAME]
-        mock_run_ssh.assert_called_once_with(clear_cmd, False)
+    def test_clear_volume_key_value_pair(self):
+
+        # setup_mock_client drive with default configuration
+        # and return the mock HTTP 3PAR client
+        mock_client = self.setup_driver()
+
+        key = 'a'
+        self.driver.common.clear_volume_key_value_pair(self.volume, key)
+
+        expected = [
+            mock.call.removeVolumeMetaData(self.VOLUME_3PAR_NAME, key)]
+
+        mock_client.assert_has_calls(expected)
+
+        # check the exception
+        mock_client.removeVolumeMetaData.side_effect = Exception('fake')
         self.assertRaises(exception.VolumeBackendAPIException,
                           self.driver.common.clear_volume_key_value_pair,
                           self.volume,
                           None)
 
     def test_extend_volume(self):
-        self.flags(lock_path=self.tempdir)
-        self.stubs.UnsetAll()
-        self.stubs.Set(hpdriver.hpcommon.HP3PARCommon, "extend_volume",
-                       self.fake_extend_volume)
-        option = {'comment': '', 'snapCPG': HP3PAR_CPG_SNAP}
-        self.driver.common.client.createVolume(self.volume['name'],
-                                               HP3PAR_CPG,
-                                               self.volume['size'],
-                                               option)
+        # setup_mock_client drive with default configuration
+        # and return the mock HTTP 3PAR client
+        mock_client = self.setup_driver()
+        grow_size = 3
         old_size = self.volume['size']
-        volume = self.driver.common.client.getVolume(self.volume['name'])
-        self.driver.extend_volume(volume, str(old_size + 1))
-        vol = self.driver.common.client.getVolume(self.volume['name'])
-        self.assertEqual(vol['sizeMiB'], str(old_size + 1))
+        new_size = old_size + grow_size
+        self.driver.extend_volume(self.volume, str(new_size))
+
+        expected = [
+            mock.call.growVolume(self.VOLUME_3PAR_NAME, grow_size)]
+
+        mock_client.assert_has_calls(expected)
+
+    def test_get_ports(self):
+        # setup_mock_client drive with default configuration
+        # and return the mock HTTP 3PAR client
+        mock_client = self.setup_driver()
+        mock_client.getPorts.return_value = {
+            'members': [{
+                'portPos': {'node': 0, 'slot': 8, 'cardPort': 2},
+                'protocol': 2,
+                'IPAddr': '10.10.120.252',
+                'linkState': 4,
+                'device': [],
+                'iSCSIName': 'iqn.2000-05.com.3pardata:21810002ac00383d',
+                'mode': 2,
+                'HWAddr': '2C27D75375D2',
+                'type': 8}, {
+                    'portPos': {'node': 1, 'slot': 8, 'cardPort': 1},
+                    'protocol': 2,
+                    'IPAddr': '10.10.220.253',
+                    'linkState': 4,
+                    'device': [],
+                    'iSCSIName': 'iqn.2000-05.com.3pardata:21810002ac00383d',
+                    'mode': 2,
+                    'HWAddr': '2C27D75375D6',
+                    'type': 8}, {
+                        'portWWN': '20210002AC00383D',
+                        'protocol': 1,
+                        'linkState': 4,
+                        'mode': 2,
+                        'device': ['cage2'],
+                        'nodeWWN': '20210002AC00383D',
+                        'type': 2,
+                        'portPos': {'node': 0, 'slot': 6, 'cardPort': 3}}]}
+
+        ports = self.driver.common.get_ports()['members']
+        self.assertEqual(len(ports), 3)
 
 
 class TestHP3PARFCDriver(HP3PARBaseDriver, test.TestCase):
 
-    _hosts = {}
+    properties = {
+        'driver_volume_type': 'fibre_channel',
+        'data': {
+            'target_lun': 90,
+            'target_wwn': ['0987654321234', '123456789000987'],
+            'target_discovered': True}}
 
     def setUp(self):
-        self.tempdir = tempfile.mkdtemp()
         super(TestHP3PARFCDriver, self).setUp()
-        self.setup_driver(self.setup_configuration())
-        self.setup_fakes()
-
-    def setup_fakes(self):
-        super(TestHP3PARFCDriver, self).setup_fakes()
-        self.stubs.Set(hpfcdriver.HP3PARFCDriver,
-                       "_create_3par_fibrechan_host",
-                       self.fake_create_3par_fibrechan_host)
 
     def tearDown(self):
-        shutil.rmtree(self.tempdir)
-        self.assertEqual(0, self.driver.common.client.connection_count,
-                         'Leaked hp3parclient connection.')
         super(TestHP3PARFCDriver, self).tearDown()
 
-    def setup_driver(self, configuration):
-        self.driver = hpfcdriver.HP3PARFCDriver(configuration=configuration)
+    def setup_driver(self, config=None, mock_conf=None):
+
+        mock_client = self.setup_mock_client(
+            conf=config,
+            m_conf=mock_conf,
+            driver=hpfcdriver.HP3PARFCDriver)
+
+        expected = [
+            mock.call.setSSHOptions(
+                HP3PAR_SAN_IP,
+                HP3PAR_USER_NAME,
+                HP3PAR_USER_PASS,
+                privatekey=HP3PAR_SAN_SSH_PRIVATE,
+                port=HP3PAR_SAN_SSH_PORT,
+                conn_timeout=HP3PAR_SAN_SSH_CON_TIMEOUT),
+            mock.call.login(HP3PAR_USER_NAME, HP3PAR_USER_PASS),
+            mock.call.getCPG(HP3PAR_CPG),
+            mock.call.setHighConnections(),
+            mock.call.logout()]
+        mock_client.assert_has_calls(expected)
+        mock_client.reset_mock()
+        return mock_client
 
-        self.stubs.Set(hpdriver.hpcommon.HP3PARCommon, "_create_client",
-                       self.fake_create_client)
-        self.stubs.Set(hpdriver.hpcommon.HP3PARCommon, "_set_connections",
-                       self.fake_set_connections)
-        self.driver.do_setup(None)
-
-    def fake_create_3par_fibrechan_host(self, hostname, wwn,
-                                        domain, persona_id):
-        host = {'FCPaths': [{'driverVersion': None,
+    def test_initialize_connection(self):
+        # setup_mock_client drive with default configuration
+        # and return the mock HTTP 3PAR client
+        mock_client = self.setup_driver()
+        mock_client.getVolume.return_value = {'userCPG': HP3PAR_CPG}
+        mock_client.getCPG.return_value = {}
+        mock_client.getHost.side_effect = [
+            hpexceptions.HTTPNotFound('fake'),
+            {'name': self.FAKE_HOST,
+                'FCPaths': [{'driverVersion': None,
                              'firmwareVersion': None,
                              'hostSpeed': 0,
                              'model': None,
                              'portPos': {'cardPort': 1, 'node': 1,
                                          'slot': 2},
                              'vendor': None,
-                             'wwn': wwn[0]},
+                             'wwn': self.wwn[0]},
                             {'driverVersion': None,
                              'firmwareVersion': None,
                              'hostSpeed': 0,
@@ -776,177 +637,177 @@ class TestHP3PARFCDriver(HP3PARBaseDriver, test.TestCase):
                              'portPos': {'cardPort': 1, 'node': 0,
                                          'slot': 2},
                              'vendor': None,
-                             'wwn': wwn[1]}],
-                'descriptors': None,
-                'domain': domain,
-                'iSCSIPaths': [],
-                'id': 11,
-                'name': hostname}
-        self._hosts[hostname] = host
-        self.properties = {'data':
-                          {'target_discovered': True,
-                           'target_lun': 186,
-                           'target_portal': '1.1.1.2:1234'},
-                           'driver_volume_type': 'fibre_channel'}
-        return hostname
+                             'wwn': self.wwn[1]}]}]
+        mock_client.findHost.return_value = self.FAKE_HOST
+        mock_client.getVLUN.return_value = {'lun': 90}
+        mock_client.getPorts.return_value = {
+            'members': self.FAKE_FC_PORTS + [self.FAKE_ISCSI_PORT]}
 
-    def test_initialize_connection(self):
-        self.flags(lock_path=self.tempdir)
         result = self.driver.initialize_connection(self.volume, self.connector)
-        self.assertEqual(result['driver_volume_type'], 'fibre_channel')
 
-        # we should have a host and a vlun now.
-        host = self.fake_get_3par_host(self.FAKE_HOST)
-        self.assertEqual(self.FAKE_HOST, host['name'])
-        self.assertEqual(HP3PAR_DOMAIN, host['domain'])
-        vlun = self.driver.common.client.getVLUN(self.VOLUME_3PAR_NAME)
-
-        self.assertEqual(self.VOLUME_3PAR_NAME, vlun['volumeName'])
-        self.assertEqual(self.FAKE_HOST, vlun['hostname'])
+        expected = [
+            mock.call.login(HP3PAR_USER_NAME, HP3PAR_USER_PASS),
+            mock.call.getVolume('osv-0DM4qZEVSKON-DXN-NwVpw'),
+            mock.call.getCPG(HP3PAR_CPG),
+            mock.call.getHost(self.FAKE_HOST),
+            mock.ANY,
+            mock.call.getHost(self.FAKE_HOST),
+            mock.call.createVLUN(
+                'osv-0DM4qZEVSKON-DXN-NwVpw',
+                auto=True,
+                hostname=self.FAKE_HOST),
+            mock.call.getVLUN('osv-0DM4qZEVSKON-DXN-NwVpw'),
+            mock.call.getPorts(),
+            mock.call.logout()]
+
+        mock_client.assert_has_calls(expected)
+
+        self.assertDictMatch(result, self.properties)
 
     def test_get_volume_stats(self):
-        self.flags(lock_path=self.tempdir)
+        # setup_mock_client drive with default configuration
+        # and return the mock HTTP 3PAR client
+        mock_client = self.setup_driver()
+        mock_client.getCPG.return_value = self.cpgs[0]
+
+        stats = self.driver.get_volume_stats(True)
+        self.assertEqual(stats['storage_protocol'], 'FC')
+        self.assertEqual(stats['total_capacity_gb'], 'infinite')
+        self.assertEqual(stats['free_capacity_gb'], 'infinite')
 
-        def fake_safe_get(*args):
-            return "HP3PARFCDriver"
+        expected = [
+            mock.call.login(HP3PAR_USER_NAME, HP3PAR_USER_PASS),
+            mock.call.getCPG(HP3PAR_CPG),
+            mock.call.logout()]
 
-        self.stubs.Set(self.driver.configuration, 'safe_get', fake_safe_get)
+        mock_client.assert_has_calls(expected)
         stats = self.driver.get_volume_stats(True)
         self.assertEqual(stats['storage_protocol'], 'FC')
         self.assertEqual(stats['total_capacity_gb'], 'infinite')
         self.assertEqual(stats['free_capacity_gb'], 'infinite')
 
-        #modify the CPG to have a limit
-        old_cpg = self.driver.common.client.getCPG(HP3PAR_CPG)
-        options = {'SDGrowth': {'limitMiB': 8192}}
-        self.driver.common.client.deleteCPG(HP3PAR_CPG)
-        self.driver.common.client.createCPG(HP3PAR_CPG, options)
+        cpg2 = self.cpgs[0].copy()
+        cpg2.update({'SDGrowth': {'limitMiB': 8192}})
+        mock_client.getCPG.return_value = cpg2
 
         const = 0.0009765625
         stats = self.driver.get_volume_stats(True)
         self.assertEqual(stats['storage_protocol'], 'FC')
         total_capacity_gb = 8192 * const
         self.assertEqual(stats['total_capacity_gb'], total_capacity_gb)
-        free_capacity_gb = int((8192 - old_cpg['UsrUsage']['usedMiB']) * const)
+        free_capacity_gb = int(
+            (8192 - self.cpgs[0]['UsrUsage']['usedMiB']) * const)
         self.assertEqual(stats['free_capacity_gb'], free_capacity_gb)
         self.driver.common.client.deleteCPG(HP3PAR_CPG)
         self.driver.common.client.createCPG(HP3PAR_CPG, {})
 
     def test_create_host(self):
-        self.flags(lock_path=self.tempdir)
-
-        #record
-        self.clear_mox()
-        self.stubs.Set(hpfcdriver.hpcommon.HP3PARCommon, "get_cpg",
-                       self.fake_get_cpg)
-        self.stubs.Set(hpfcdriver.hpcommon.HP3PARCommon, "get_domain",
-                       self.fake_get_domain)
-        _run_ssh = self.mox.CreateMock(hpdriver.hpcommon.HP3PARCommon._run_ssh)
-        self.stubs.Set(hpdriver.hpcommon.HP3PARCommon, "_run_ssh", _run_ssh)
-
-        getHost = self.mox.CreateMock(FakeHP3ParClient.getHost)
-        self.stubs.Set(FakeHP3ParClient, "getHost", getHost)
-
-        ex = hpexceptions.HTTPNotFound('Host not found.')
-        getHost('fakehost').AndRaise(ex)
-
-        create_host_cmd = (['createhost', '-persona', '1', '-domain',
-                            ('OpenStack',), 'fakehost', '123456789012345',
-                            '123456789054321'])
-        _run_ssh(create_host_cmd, False).AndReturn([CLI_CR, ''])
-
-        getHost('fakehost').AndReturn({'name': self.FAKE_HOST,
-                                       'FCPaths': [{'wwn': '123456789012345'},
-                                                   {'wwn': '123456789054321'}]}
-                                      )
-        self.mox.ReplayAll()
+        # setup_mock_client drive with default configuration
+        # and return the mock HTTP 3PAR client
+        mock_client = self.setup_driver()
+
+        mock_client.getVolume.return_value = {'userCPG': HP3PAR_CPG}
+        mock_client.getCPG.return_value = {}
+        mock_client.getHost.side_effect = [
+            hpexceptions.HTTPNotFound('fake'),
+            {'name': self.FAKE_HOST,
+                'FCPaths': [{'driverVersion': None,
+                             'firmwareVersion': None,
+                             'hostSpeed': 0,
+                             'model': None,
+                             'portPos': {'cardPort': 1, 'node': 1,
+                                         'slot': 2},
+                             'vendor': None,
+                             'wwn': self.wwn[0]},
+                            {'driverVersion': None,
+                             'firmwareVersion': None,
+                             'hostSpeed': 0,
+                             'model': None,
+                             'portPos': {'cardPort': 1, 'node': 0,
+                                         'slot': 2},
+                             'vendor': None,
+                             'wwn': self.wwn[1]}]}]
+        mock_client.findHost.return_value = None
+        mock_client.getVLUN.return_value = {'lun': 186}
 
         host = self.driver._create_host(self.volume, self.connector)
+        expected = [
+            mock.call.getVolume('osv-0DM4qZEVSKON-DXN-NwVpw'),
+            mock.call.getCPG(HP3PAR_CPG),
+            mock.call.getHost(self.FAKE_HOST),
+            mock.call.findHost(wwn='123456789012345'),
+            mock.call.findHost(wwn='123456789054321'),
+            mock.call.createHost(
+                self.FAKE_HOST,
+                FCWwns=['123456789012345', '123456789054321'],
+                optional={'domain': None, 'persona': 1}),
+            mock.call.getHost(self.FAKE_HOST)]
+
+        mock_client.assert_has_calls(expected)
+
         self.assertEqual(host['name'], self.FAKE_HOST)
 
     def test_create_invalid_host(self):
-        self.flags(lock_path=self.tempdir)
-
-        #record
-        self.clear_mox()
-        self.stubs.Set(hpdriver.hpcommon.HP3PARCommon, "get_cpg",
-                       self.fake_get_cpg)
-        self.stubs.Set(hpdriver.hpcommon.HP3PARCommon, "get_domain",
-                       self.fake_get_domain)
-        _run_ssh = self.mox.CreateMock(hpdriver.hpcommon.HP3PARCommon._run_ssh)
-        self.stubs.Set(hpdriver.hpcommon.HP3PARCommon, "_run_ssh", _run_ssh)
-
-        getHost = self.mox.CreateMock(FakeHP3ParClient.getHost)
-        self.stubs.Set(FakeHP3ParClient, "getHost", getHost)
-
-        not_found_ex = hpexceptions.HTTPNotFound('Host not found.')
-        getHost('fakehost').AndRaise(not_found_ex)
-
-        create_host_cmd = (['createhost', '-persona', '1', '-domain',
-                            ('OpenStack',), 'fakehost', '123456789012345',
-                            '123456789054321'])
-        create_host_ret = pack(CLI_CR +
-                               'already used by host fakehost.foo (19)')
-        _run_ssh(create_host_cmd, False).AndReturn([create_host_ret, ''])
-
-        host_ret = {
-            'name': 'fakehost.foo',
-            'FCPaths': [{'wwn': '123456789012345'},
-                        {'wwn': '123456789054321'}]}
-        getHost('fakehost.foo').AndReturn(host_ret)
-
-        self.mox.ReplayAll()
+        # setup_mock_client drive with default configuration
+        # and return the mock HTTP 3PAR client
+        mock_client = self.setup_driver()
+
+        mock_client.getVolume.return_value = {'userCPG': HP3PAR_CPG}
+        mock_client.getCPG.return_value = {}
+        mock_client.getHost.side_effect = [
+            hpexceptions.HTTPNotFound('Host not found.'), {
+                'name': 'fakehost.foo',
+                'FCPaths': [{'wwn': '123456789012345'}, {
+                    'wwn': '123456789054321'}]}]
+        mock_client.findHost.return_value = 'fakehost.foo'
 
         host = self.driver._create_host(self.volume, self.connector)
 
-        self.assertEqual(host['name'], 'fakehost.foo')
-
-    def test_create_modify_host(self):
-        self.flags(lock_path=self.tempdir)
-
-        #record
-        self.clear_mox()
-        self.stubs.Set(hpdriver.hpcommon.HP3PARCommon, "get_cpg",
-                       self.fake_get_cpg)
-        self.stubs.Set(hpdriver.hpcommon.HP3PARCommon, "get_domain",
-                       self.fake_get_domain)
+        expected = [
+            mock.call.getVolume('osv-0DM4qZEVSKON-DXN-NwVpw'),
+            mock.call.getCPG(HP3PAR_CPG),
+            mock.call.getHost('fakehost'),
+            mock.call.findHost(wwn='123456789012345'),
+            mock.call.getHost('fakehost.foo')]
 
-        getHost = self.mox.CreateMock(FakeHP3ParClient.getHost)
-        self.stubs.Set(FakeHP3ParClient, "getHost", getHost)
+        mock_client.assert_has_calls(expected)
 
-        modifyHost = self.mox.CreateMock(FakeHP3ParClient.modifyHost)
-        self.stubs.Set(FakeHP3ParClient, "modifyHost", modifyHost)
-
-        getHost('fakehost').AndReturn(({'name': self.FAKE_HOST,
-                                        'FCPaths': []}))
-
-        modifyHost('fakehost', {'FCWWNs':
-                                ['123456789012345', '123456789054321'],
-                                'pathOperation': 1})
-
-        getHost('fakehost').AndReturn({'name': self.FAKE_HOST,
-                                       'FCPaths': [{'wwn': '123456789012345'},
-                                                   {'wwn': '123456789054321'}]}
-                                      )
+        self.assertEqual(host['name'], 'fakehost.foo')
 
-        self.mox.ReplayAll()
+    def test_create_modify_host(self):
+        # setup_mock_client drive with default configuration
+        # and return the mock HTTP 3PAR client
+        mock_client = self.setup_driver()
+        mock_client.getVolume.return_value = {'userCPG': HP3PAR_CPG}
+        mock_client.getCPG.return_value = {}
+        mock_client.getHost.side_effect = [{
+            'name': self.FAKE_HOST, 'FCPaths': []},
+            {'name': self.FAKE_HOST,
+                'FCPaths': [{'wwn': '123456789012345'}, {
+                    'wwn': '123456789054321'}]}]
 
         host = self.driver._create_host(self.volume, self.connector)
+        expected = [
+            mock.call.getVolume('osv-0DM4qZEVSKON-DXN-NwVpw'),
+            mock.call.getCPG(HP3PAR_CPG),
+            mock.call.getHost('fakehost'),
+            mock.call.modifyHost(
+                'fakehost', {
+                    'FCWWNs': ['123456789012345', '123456789054321'],
+                    'pathOperation': 1}),
+            mock.call.getHost('fakehost')]
+
+        mock_client.assert_has_calls(expected)
+
         self.assertEqual(host['name'], self.FAKE_HOST)
         self.assertEqual(len(host['FCPaths']), 2)
 
     def test_modify_host_with_new_wwn(self):
-        self.flags(lock_path=self.tempdir)
-        self.clear_mox()
-
-        hpdriver.hpcommon.HP3PARCommon.get_cpg = mock.Mock(
-            return_value=self.fake_get_cpg)
-        hpdriver.hpcommon.HP3PARCommon.get_domain = mock.Mock(
-            return_value=self.fake_get_domain)
-
-        # set up the getHost mock
-        self.driver.common.client.getHost = mock.Mock()
-        # define the return values for the 2 calls
+        # setup_mock_client drive with default configuration
+        # and return the mock HTTP 3PAR client
+        mock_client = self.setup_driver()
+        mock_client.getVolume.return_value = {'userCPG': HP3PAR_CPG}
+        mock_client.getCPG.return_value = {}
         getHost_ret1 = {
             'name': self.FAKE_HOST,
             'FCPaths': [{'wwn': '123456789054321'}]}
@@ -954,36 +815,30 @@ class TestHP3PARFCDriver(HP3PARBaseDriver, test.TestCase):
             'name': self.FAKE_HOST,
             'FCPaths': [{'wwn': '123456789012345'},
                         {'wwn': '123456789054321'}]}
-        self.driver.common.client.getHost.side_effect = [
-            getHost_ret1, getHost_ret2]
-
-        # setup the modifyHost mock
-        self.driver.common.client.modifyHost = mock.Mock()
+        mock_client.getHost.side_effect = [getHost_ret1, getHost_ret2]
 
         host = self.driver._create_host(self.volume, self.connector)
 
-        # mock assertions
-        self.driver.common.client.getHost.assert_has_calls([
-            mock.call('fakehost'),
-            mock.call('fakehost')])
-        self.driver.common.client.modifyHost.assert_called_once_with(
-            'fakehost', {'FCWWNs': ['123456789012345'], 'pathOperation': 1})
+        expected = [
+            mock.call.getVolume('osv-0DM4qZEVSKON-DXN-NwVpw'),
+            mock.call.getCPG(HP3PAR_CPG),
+            mock.call.getHost('fakehost'),
+            mock.call.modifyHost(
+                'fakehost', {
+                    'FCWWNs': ['123456789012345'], 'pathOperation': 1}),
+            mock.call.getHost('fakehost')]
+
+        mock_client.assert_has_calls(expected)
 
         self.assertEqual(host['name'], self.FAKE_HOST)
         self.assertEqual(len(host['FCPaths']), 2)
 
     def test_modify_host_with_unknown_wwn_and_new_wwn(self):
-        self.flags(lock_path=self.tempdir)
-        self.clear_mox()
-
-        hpdriver.hpcommon.HP3PARCommon.get_cpg = mock.Mock(
-            return_value=self.fake_get_cpg)
-        hpdriver.hpcommon.HP3PARCommon.get_domain = mock.Mock(
-            return_value=self.fake_get_domain)
-
-        # set up the getHost mock
-        self.driver.common.client.getHost = mock.Mock()
-        # define the return values for the 2 calls
+        # setup_mock_client drive with default configuration
+        # and return the mock HTTP 3PAR client
+        mock_client = self.setup_driver()
+        mock_client.getVolume.return_value = {'userCPG': HP3PAR_CPG}
+        mock_client.getCPG.return_value = {}
         getHost_ret1 = {
             'name': self.FAKE_HOST,
             'FCPaths': [{'wwn': '123456789054321'},
@@ -993,20 +848,20 @@ class TestHP3PARFCDriver(HP3PARBaseDriver, test.TestCase):
             'FCPaths': [{'wwn': '123456789012345'},
                         {'wwn': '123456789054321'},
                         {'wwn': 'xxxxxxxxxxxxxxx'}]}
-        self.driver.common.client.getHost.side_effect = [
-            getHost_ret1, getHost_ret2]
-
-        # setup the modifyHost mock
-        self.driver.common.client.modifyHost = mock.Mock()
+        mock_client.getHost.side_effect = [getHost_ret1, getHost_ret2]
 
         host = self.driver._create_host(self.volume, self.connector)
 
-        # mock assertions
-        self.driver.common.client.getHost.assert_has_calls([
-            mock.call('fakehost'),
-            mock.call('fakehost')])
-        self.driver.common.client.modifyHost.assert_called_once_with(
-            'fakehost', {'FCWWNs': ['123456789012345'], 'pathOperation': 1})
+        expected = [
+            mock.call.getVolume('osv-0DM4qZEVSKON-DXN-NwVpw'),
+            mock.call.getCPG(HP3PAR_CPG),
+            mock.call.getHost('fakehost'),
+            mock.call.modifyHost(
+                'fakehost', {
+                    'FCWWNs': ['123456789012345'], 'pathOperation': 1}),
+            mock.call.getHost('fakehost')]
+
+        mock_client.assert_has_calls(expected)
 
         self.assertEqual(host['name'], self.FAKE_HOST)
         self.assertEqual(len(host['FCPaths']), 3)
@@ -1014,234 +869,213 @@ class TestHP3PARFCDriver(HP3PARBaseDriver, test.TestCase):
 
 class TestHP3PARISCSIDriver(HP3PARBaseDriver, test.TestCase):
 
-    TARGET_IQN = "iqn.2000-05.com.3pardata:21810002ac00383d"
+    TARGET_IQN = 'iqn.2000-05.com.3pardata:21810002ac00383d'
+    TARGET_LUN = 186
 
-    _hosts = {}
+    properties = {
+        'driver_volume_type': 'iscsi',
+        'data':
+        {'target_discovered': True,
+            'target_iqn': TARGET_IQN,
+            'target_lun': TARGET_LUN,
+            'target_portal': '1.1.1.2:1234'}}
 
     def setUp(self):
-        self.tempdir = tempfile.mkdtemp()
         super(TestHP3PARISCSIDriver, self).setUp()
-        self.setup_driver(self.setup_configuration())
-        self.setup_fakes()
-
-    def setup_fakes(self):
-        super(TestHP3PARISCSIDriver, self).setup_fakes()
-
-        self.stubs.Set(hpdriver.HP3PARISCSIDriver, "_create_3par_iscsi_host",
-                       self.fake_create_3par_iscsi_host)
-
-        #target_iqn = 'iqn.2000-05.com.3pardata:21810002ac00383d'
-        self.properties = {'data':
-                          {'target_discovered': True,
-                           'target_iqn': self.TARGET_IQN,
-                           'target_lun': 186,
-                           'target_portal': '1.1.1.2:1234'},
-                           'driver_volume_type': 'iscsi'}
 
     def tearDown(self):
-        shutil.rmtree(self.tempdir)
-        self.assertEqual(0, self.driver.common.client.connection_count,
-                         'Leaked hp3parclient connection.')
-        self._hosts = {}
         super(TestHP3PARISCSIDriver, self).tearDown()
 
-    def setup_driver(self, configuration, set_up_fakes=True):
-        self.driver = hpdriver.HP3PARISCSIDriver(configuration=configuration)
+    def setup_driver(self, config=None, mock_conf=None):
+
+        # setup_mock_client default config, if necessary
+        if mock_conf is None:
+            mock_conf = {
+                'getPorts.return_value': {
+                    'members': self.FAKE_FC_PORTS + [self.FAKE_ISCSI_PORT]}}
+
+        mock_client = self.setup_mock_client(
+            conf=config,
+            m_conf=mock_conf,
+            driver=hpdriver.HP3PARISCSIDriver)
+
+        expected = [
+            mock.call.setSSHOptions(
+                HP3PAR_SAN_IP,
+                HP3PAR_USER_NAME,
+                HP3PAR_USER_PASS,
+                privatekey=HP3PAR_SAN_SSH_PRIVATE,
+                port=HP3PAR_SAN_SSH_PORT,
+                conn_timeout=HP3PAR_SAN_SSH_CON_TIMEOUT),
+            mock.call.login(HP3PAR_USER_NAME, HP3PAR_USER_PASS),
+            mock.call.getCPG(HP3PAR_CPG),
+            mock.call.setHighConnections(),
+            mock.call.logout(),
+            mock.call.login(HP3PAR_USER_NAME, HP3PAR_USER_PASS),
+            mock.call.getPorts(),
+            mock.call.logout()]
+        mock_client.assert_has_calls(expected)
+        mock_client.reset_mock()
+
+        return mock_client
 
-        self.stubs.Set(hpdriver.hpcommon.HP3PARCommon, "_create_client",
-                       self.fake_create_client)
+    def test_initialize_connection(self):
+        # setup_mock_client drive with default configuration
+        # and return the mock HTTP 3PAR client
+        mock_client = self.setup_driver()
+        mock_client.getVolume.return_value = {'userCPG': HP3PAR_CPG}
+        mock_client.getCPG.return_value = {}
+        mock_client.getHost.side_effect = [
+            hpexceptions.HTTPNotFound('fake'),
+            {'name': self.FAKE_HOST}]
+        mock_client.findHost.return_value = self.FAKE_HOST
+        mock_client.getVLUN.return_value = {'lun': self.TARGET_LUN}
 
-        if set_up_fakes:
-            self.stubs.Set(hpdriver.hpcommon.HP3PARCommon, "get_ports",
-                           self.fake_get_ports)
+        result = self.driver.initialize_connection(self.volume, self.connector)
 
-        self.stubs.Set(hpdriver.hpcommon.HP3PARCommon, "_set_connections",
-                       self.fake_set_connections)
-        self.driver.do_setup(None)
+        expected = [
+            mock.call.login(HP3PAR_USER_NAME, HP3PAR_USER_PASS),
+            mock.call.getVolume('osv-0DM4qZEVSKON-DXN-NwVpw'),
+            mock.call.getCPG(HP3PAR_CPG),
+            mock.call.getHost(self.FAKE_HOST),
+            mock.call.findHost(iqn='iqn.1993-08.org.debian:01:222'),
+            mock.call.getHost(self.FAKE_HOST),
+            mock.call.createVLUN(
+                'osv-0DM4qZEVSKON-DXN-NwVpw',
+                auto=True,
+                hostname='fakehost',
+                portPos={'node': 8, 'slot': 1, 'cardPort': 1}),
+            mock.call.getVLUN('osv-0DM4qZEVSKON-DXN-NwVpw'),
+            mock.call.logout()]
+
+        mock_client.assert_has_calls(expected)
+
+        self.assertDictMatch(result, self.properties)
 
-    def fake_create_3par_iscsi_host(self, hostname, iscsi_iqn,
-                                    domain, persona_id):
-        host = {'FCPaths': [],
-                'descriptors': None,
-                'domain': domain,
-                'iSCSIPaths': [{'driverVersion': None,
-                                'firmwareVersion': None,
-                                'hostSpeed': 0,
-                                'ipAddr': '10.10.221.59',
-                                'model': None,
-                                'name': iscsi_iqn,
-                                'portPos': {'cardPort': 1, 'node': 1,
-                                            'slot': 8},
-                                'vendor': None}],
-                'id': 11,
-                'name': hostname}
-        self._hosts[hostname] = host
-        return hostname
+    def test_get_volume_stats(self):
+        # setup_mock_client drive with default configuration
+        # and return the mock HTTP 3PAR client
+        mock_client = self.setup_driver()
+        mock_client.getCPG.return_value = self.cpgs[0]
 
-    def test_initialize_connection(self):
-        self.flags(lock_path=self.tempdir)
-        result = self.driver.initialize_connection(self.volume, self.connector)
-        self.assertEqual(result['driver_volume_type'], 'iscsi')
-        self.assertEqual(result['data']['target_iqn'],
-                         self.properties['data']['target_iqn'])
-        self.assertEqual(result['data']['target_portal'],
-                         self.properties['data']['target_portal'])
-        self.assertEqual(result['data']['target_discovered'],
-                         self.properties['data']['target_discovered'])
-
-        # we should have a host and a vlun now.
-        host = self.fake_get_3par_host(self.FAKE_HOST)
-        self.assertEqual(self.FAKE_HOST, host['name'])
-        self.assertEqual(HP3PAR_DOMAIN, host['domain'])
-        vlun = self.driver.common.client.getVLUN(self.VOLUME_3PAR_NAME)
-
-        self.assertEqual(self.VOLUME_3PAR_NAME, vlun['volumeName'])
-        self.assertEqual(self.FAKE_HOST, vlun['hostname'])
+        stats = self.driver.get_volume_stats(True)
+        self.assertEqual(stats['storage_protocol'], 'iSCSI')
+        self.assertEqual(stats['total_capacity_gb'], 'infinite')
+        self.assertEqual(stats['free_capacity_gb'], 'infinite')
 
-    def test_get_volume_stats(self):
-        self.flags(lock_path=self.tempdir)
+        expected = [
+            mock.call.login(HP3PAR_USER_NAME, HP3PAR_USER_PASS),
+            mock.call.getCPG(HP3PAR_CPG),
+            mock.call.logout()]
 
-        def fake_safe_get(*args):
-            return "HP3PARFCDriver"
+        mock_client.assert_has_calls(expected)
 
-        self.stubs.Set(self.driver.configuration, 'safe_get', fake_safe_get)
-        stats = self.driver.get_volume_stats(True)
         self.assertEqual(stats['storage_protocol'], 'iSCSI')
         self.assertEqual(stats['total_capacity_gb'], 'infinite')
         self.assertEqual(stats['free_capacity_gb'], 'infinite')
 
-        #modify the CPG to have a limit
-        old_cpg = self.driver.common.client.getCPG(HP3PAR_CPG)
-        options = {'SDGrowth': {'limitMiB': 8192}}
-        self.driver.common.client.deleteCPG(HP3PAR_CPG)
-        self.driver.common.client.createCPG(HP3PAR_CPG, options)
+        cpg2 = self.cpgs[0].copy()
+        cpg2.update({'SDGrowth': {'limitMiB': 8192}})
+        mock_client.getCPG.return_value = cpg2
 
         const = 0.0009765625
         stats = self.driver.get_volume_stats(True)
         self.assertEqual(stats['storage_protocol'], 'iSCSI')
         total_capacity_gb = 8192 * const
         self.assertEqual(stats['total_capacity_gb'], total_capacity_gb)
-        free_capacity_gb = int((8192 - old_cpg['UsrUsage']['usedMiB']) * const)
+        free_capacity_gb = int(
+            (8192 - self.cpgs[0]['UsrUsage']['usedMiB']) * const)
         self.assertEqual(stats['free_capacity_gb'], free_capacity_gb)
-        self.driver.common.client.deleteCPG(HP3PAR_CPG)
-        self.driver.common.client.createCPG(HP3PAR_CPG, {})
 
     def test_create_host(self):
-        self.flags(lock_path=self.tempdir)
-
-        #record
-        self.clear_mox()
-        self.stubs.Set(hpdriver.hpcommon.HP3PARCommon, "get_cpg",
-                       self.fake_get_cpg)
-        self.stubs.Set(hpdriver.hpcommon.HP3PARCommon, "get_domain",
-                       self.fake_get_domain)
-        _run_ssh = self.mox.CreateMock(hpdriver.hpcommon.HP3PARCommon._run_ssh)
-        self.stubs.Set(hpdriver.hpcommon.HP3PARCommon, "_run_ssh", _run_ssh)
-
-        getHost = self.mox.CreateMock(FakeHP3ParClient.getHost)
-        self.stubs.Set(FakeHP3ParClient, "getHost", getHost)
-
-        not_found_ex = hpexceptions.HTTPNotFound('Host not found.')
-        getHost('fakehost').AndRaise(not_found_ex)
-
-        create_host_cmd = (['createhost', '-iscsi', '-persona', '1', '-domain',
-                            ('OpenStack',), 'fakehost',
-                            'iqn.1993-08.org.debian:01:222'])
-        _run_ssh(create_host_cmd, False).AndReturn([CLI_CR, ''])
-
-        getHost('fakehost').AndReturn({'name': self.FAKE_HOST})
-        self.mox.ReplayAll()
+        # setup_mock_client drive with default configuration
+        # and return the mock HTTP 3PAR client
+        mock_client = self.setup_driver()
+
+        mock_client.getVolume.return_value = {'userCPG': HP3PAR_CPG}
+        mock_client.getCPG.return_value = {}
+        mock_client.getHost.side_effect = [
+            hpexceptions.HTTPNotFound('fake'),
+            {'name': self.FAKE_HOST}]
+        mock_client.findHost.return_value = None
+        mock_client.getVLUN.return_value = {'lun': self.TARGET_LUN}
 
         host = self.driver._create_host(self.volume, self.connector)
+        expected = [
+            mock.call.getVolume('osv-0DM4qZEVSKON-DXN-NwVpw'),
+            mock.call.getCPG(HP3PAR_CPG),
+            mock.call.getHost(self.FAKE_HOST),
+            mock.call.findHost(iqn='iqn.1993-08.org.debian:01:222'),
+            mock.call.createHost(
+                self.FAKE_HOST,
+                optional={'domain': None, 'persona': 1},
+                iscsiNames=['iqn.1993-08.org.debian:01:222']),
+            mock.call.getHost(self.FAKE_HOST)]
+
+        mock_client.assert_has_calls(expected)
+
         self.assertEqual(host['name'], self.FAKE_HOST)
 
     def test_create_invalid_host(self):
-        self.flags(lock_path=self.tempdir)
-
-        #record
-        self.clear_mox()
-        self.stubs.Set(hpdriver.hpcommon.HP3PARCommon, "get_cpg",
-                       self.fake_get_cpg)
-        self.stubs.Set(hpdriver.hpcommon.HP3PARCommon, "get_domain",
-                       self.fake_get_domain)
-        _run_ssh = self.mox.CreateMock(hpdriver.hpcommon.HP3PARCommon._run_ssh)
-        self.stubs.Set(hpdriver.hpcommon.HP3PARCommon, "_run_ssh", _run_ssh)
+        # setup_mock_client drive with default configuration
+        # and return the mock HTTP 3PAR client
+        mock_client = self.setup_driver()
+        mock_client.getVolume.return_value = {'userCPG': HP3PAR_CPG}
+        mock_client.getCPG.return_value = {}
+        mock_client.getHost.side_effect = [
+            hpexceptions.HTTPNotFound('Host not found.'),
+            {'name': 'fakehost.foo'}]
+        mock_client.findHost.return_value = 'fakehost.foo'
 
-        getHost = self.mox.CreateMock(FakeHP3ParClient.getHost)
-        self.stubs.Set(FakeHP3ParClient, "getHost", getHost)
-
-        not_found_ex = hpexceptions.HTTPNotFound('Host not found.')
-        getHost('fakehost').AndRaise(not_found_ex)
+        host = self.driver._create_host(self.volume, self.connector)
 
-        create_host_cmd = (['createhost', '-iscsi', '-persona', '1', '-domain',
-                           ('OpenStack',), 'fakehost',
-                            'iqn.1993-08.org.debian:01:222'])
-        in_use_ret = pack('\r\nalready used by host fakehost.foo ')
-        _run_ssh(create_host_cmd, False).AndReturn([in_use_ret, ''])
+        expected = [
+            mock.call.getVolume('osv-0DM4qZEVSKON-DXN-NwVpw'),
+            mock.call.getCPG(HP3PAR_CPG),
+            mock.call.getHost(self.FAKE_HOST),
+            mock.call.findHost(iqn='iqn.1993-08.org.debian:01:222'),
+            mock.call.getHost('fakehost.foo')]
 
-        getHost('fakehost.foo').AndReturn({'name': 'fakehost.foo'})
-        self.mox.ReplayAll()
-
-        host = self.driver._create_host(self.volume, self.connector)
+        mock_client.assert_has_calls(expected)
 
         self.assertEqual(host['name'], 'fakehost.foo')
 
     def test_create_modify_host(self):
-        self.flags(lock_path=self.tempdir)
-
-        #record
-        self.clear_mox()
-        self.stubs.Set(hpdriver.hpcommon.HP3PARCommon, "get_cpg",
-                       self.fake_get_cpg)
-        self.stubs.Set(hpdriver.hpcommon.HP3PARCommon, "get_domain",
-                       self.fake_get_domain)
-
-        getHost = self.mox.CreateMock(FakeHP3ParClient.getHost)
-        self.stubs.Set(FakeHP3ParClient, "getHost", getHost)
-
-        modifyHost = self.mox.CreateMock(FakeHP3ParClient.modifyHost)
-        self.stubs.Set(FakeHP3ParClient, "modifyHost", modifyHost)
-
-        getHost('fakehost').AndReturn(({'name': self.FAKE_HOST,
-                                        'iSCSIPaths': []}))
-
-        modifyHost('fakehost', {'iSCSINames':
-                                ['iqn.1993-08.org.debian:01:222'],
-                                'pathOperation': 1})
-
-        ret_value = {'name': self.FAKE_HOST,
-                     'iSCSIPaths': [{'name': 'iqn.1993-08.org.debian:01:222'}]
-                     }
-        getHost('fakehost').AndReturn(ret_value)
-        self.mox.ReplayAll()
+        # setup_mock_client drive with default configuration
+        # and return the mock HTTP 3PAR client
+        mock_client = self.setup_driver()
+        mock_client.getVolume.return_value = {'userCPG': HP3PAR_CPG}
+        mock_client.getCPG.return_value = {}
+        mock_client.getHost.side_effect = [{
+            'name': self.FAKE_HOST, 'FCPaths': []}, {
+                'name': self.FAKE_HOST,
+                'FCPaths': [{'wwn': '123456789012345'}, {
+                    'wwn': '123456789054321'}]}]
 
         host = self.driver._create_host(self.volume, self.connector)
-        self.assertEqual(host['name'], self.FAKE_HOST)
-        self.assertEqual(len(host['iSCSIPaths']), 1)
-
-    def test_get_ports(self):
-        self.flags(lock_path=self.tempdir)
 
-        #record
-        self.clear_mox()
-        getPorts = self.mox.CreateMock(FakeHP3ParClient.getPorts)
-        self.stubs.Set(FakeHP3ParClient, "getPorts", getPorts)
+        expected = [
+            mock.call.getVolume('osv-0DM4qZEVSKON-DXN-NwVpw'),
+            mock.call.getCPG(HP3PAR_CPG),
+            mock.call.getHost(self.FAKE_HOST),
+            mock.call.modifyHost(
+                self.FAKE_HOST,
+                {'pathOperation': 1,
+                    'iSCSINames': ['iqn.1993-08.org.debian:01:222']}),
+            mock.call.getHost(self.FAKE_HOST)]
 
-        getPorts().AndReturn(PORTS1_RET)
-        self.mox.ReplayAll()
+        mock_client.assert_has_calls(expected)
 
-        ports = self.driver.common.get_ports()['members']
-        self.assertEqual(len(ports), 3)
+        self.assertEqual(host['name'], self.FAKE_HOST)
+        self.assertEqual(len(host['FCPaths']), 2)
 
     def test_get_least_used_nsp_for_host_single(self):
-        self.flags(lock_path=self.tempdir)
-        self.clear_mox()
+        # setup_mock_client drive with default configuration
+        # and return the mock HTTP 3PAR client
+        mock_client = self.setup_driver()
 
-        self.driver.common.client.getPorts = mock.Mock(
-            return_value=PORTS_RET)
-
-        self.driver.common.client.getVLUNs = mock.Mock(
-            return_value=VLUNS1_RET)
+        mock_client.getPorts.return_value = PORTS_RET
+        mock_client.getVLUNs.return_value = VLUNS1_RET
 
         #Setup a single ISCSI IP
         iscsi_ips = ["10.10.220.253"]
@@ -1253,14 +1087,12 @@ class TestHP3PARISCSIDriver(HP3PARBaseDriver, test.TestCase):
         self.assertEqual(nsp, "1:8:1")
 
     def test_get_least_used_nsp_for_host_new(self):
-        self.flags(lock_path=self.tempdir)
-        self.clear_mox()
-
-        self.driver.common.client.getPorts = mock.Mock(
-            return_value=PORTS_RET)
+        # setup_mock_client drive with default configuration
+        # and return the mock HTTP 3PAR client
+        mock_client = self.setup_driver()
 
-        self.driver.common.client.getVLUNs = mock.Mock(
-            return_value=VLUNS1_RET)
+        mock_client.getPorts.return_value = PORTS_RET
+        mock_client.getVLUNs.return_value = VLUNS1_RET
 
         #Setup two ISCSI IPs
         iscsi_ips = ["10.10.220.252", "10.10.220.253"]
@@ -1274,14 +1106,12 @@ class TestHP3PARISCSIDriver(HP3PARBaseDriver, test.TestCase):
         self.assertEqual(nsp, "1:8:2")
 
     def test_get_least_used_nsp_for_host_reuse(self):
-        self.flags(lock_path=self.tempdir)
-        self.clear_mox()
-
-        self.driver.common.client.getPorts = mock.Mock(
-            return_value=PORTS_RET)
+        # setup_mock_client drive with default configuration
+        # and return the mock HTTP 3PAR client
+        mock_client = self.setup_driver()
 
-        self.driver.common.client.getVLUNs = mock.Mock(
-            return_value=VLUNS1_RET)
+        mock_client.getPorts.return_value = PORTS_RET
+        mock_client.getVLUNs.return_value = VLUNS1_RET
 
         #Setup two ISCSI IPs
         iscsi_ips = ["10.10.220.252", "10.10.220.253"]
@@ -1298,15 +1128,12 @@ class TestHP3PARISCSIDriver(HP3PARBaseDriver, test.TestCase):
         self.assertEqual(nsp, "1:8:1")
 
     def test_get_least_used_nps_for_host_fc(self):
-        # Ensure that with an active FC path setup
-        # an ISCSI path is used
-        self.flags(lock_path=self.tempdir)
-        self.clear_mox()
+        # setup_mock_client drive with default configuration
+        # and return the mock HTTP 3PAR client
+        mock_client = self.setup_driver()
 
-        self.driver.common.client.getPorts = mock.Mock(
-            return_value=PORTS1_RET)
-        self.driver.common.client.getVLUNs = mock.Mock(
-            return_value=VLUNS5_RET)
+        mock_client.getPorts.return_value = PORTS1_RET
+        mock_client.getVLUNs.return_value = VLUNS5_RET
 
         #Setup two ISCSI IPs
         iscsi_ips = ["10.10.220.252", "10.10.220.253"]
@@ -1319,62 +1146,101 @@ class TestHP3PARISCSIDriver(HP3PARBaseDriver, test.TestCase):
         self.assertEqual(nsp, "1:8:1")
 
     def test_invalid_iscsi_ip(self):
-        self.flags(lock_path=self.tempdir)
-
-        #record driver set up
-        self.clear_mox()
-        getPorts = self.mox.CreateMock(FakeHP3ParClient.getPorts)
-        self.stubs.Set(FakeHP3ParClient, "getPorts", getPorts)
-
-        getPorts().AndReturn(PORTS_RET)
-
         config = self.setup_configuration()
         config.hp3par_iscsi_ips = ['10.10.220.250', '10.10.220.251']
         config.iscsi_ip_address = '10.10.10.10'
-        self.mox.ReplayAll()
+        mock_conf = {
+            'getPorts.return_value': {
+                'members': [{
+                    'portPos': {'node': 1, 'slot': 8, 'cardPort': 2},
+                    'protocol': 2,
+                    'IPAddr': '10.10.220.252',
+                    'linkState': 4,
+                    'device': [],
+                    'iSCSIName': self.TARGET_IQN,
+                    'mode': 2,
+                    'HWAddr': '2C27D75375D2',
+                    'type': 8}, {
+                        'portPos': {'node': 1, 'slot': 8, 'cardPort': 1},
+                        'protocol': 2,
+                        'IPAddr': '10.10.220.253',
+                        'linkState': 4,
+                        'device': [],
+                        'iSCSIName': self.TARGET_IQN,
+                        'mode': 2,
+                        'HWAddr': '2C27D75375D6',
+                        'type': 8}]}}
 
         # no valid ip addr should be configured.
         self.assertRaises(exception.InvalidInput,
                           self.setup_driver,
-                          config,
-                          set_up_fakes=False)
+                          config=config,
+                          mock_conf=mock_conf)
 
     def test_get_least_used_nsp(self):
-        self.flags(lock_path=self.tempdir)
-
-        #record
-        self.clear_mox()
-        getVLUNs = self.mox.CreateMock(FakeHP3ParClient.getVLUNs)
-        self.stubs.Set(FakeHP3ParClient, "getVLUNs", getVLUNs)
+        # setup_mock_client drive with default configuration
+        # and return the mock HTTP 3PAR client
+        mock_client = self.setup_driver()
+        ports = [
+            {'portPos': {'node': 1, 'slot': 8, 'cardPort': 2}, 'active': True},
+            {'portPos': {'node': 1, 'slot': 8, 'cardPort': 1}, 'active': True},
+            {'portPos': {'node': 1, 'slot': 8, 'cardPort': 2}, 'active': True},
+            {'portPos': {'node': 0, 'slot': 2, 'cardPort': 2}, 'active': True},
+            {'portPos': {'node': 0, 'slot': 2, 'cardPort': 1}, 'active': True},
+            {'portPos': {'node': 0, 'slot': 2, 'cardPort': 1}, 'active': True},
+            {'portPos': {'node': 0, 'slot': 2, 'cardPort': 1}, 'active': True},
+            {'portPos': {'node': 0, 'slot': 2, 'cardPort': 1}, 'active': True}]
+        mock_client.getVLUNs.return_value = {'members': ports}
 
-        getVLUNs().AndReturn(VLUNS3_RET)
-        getVLUNs().AndReturn(VLUNS4_RET)
-        getVLUNs().AndReturn(VLUNS4_RET)
-
-        self.mox.ReplayAll()
         # in use count
         vluns = self.driver.common.client.getVLUNs()
         nsp = self.driver._get_least_used_nsp(vluns['members'],
                                               ['0:2:1', '1:8:1'])
         self.assertEqual(nsp, '1:8:1')
 
+        ports = [
+            {'portPos': {'node': 1, 'slot': 2, 'cardPort': 1}, 'active': True},
+            {'portPos': {'node': 1, 'slot': 2, 'cardPort': 1}, 'active': True},
+            {'portPos': {'node': 1, 'slot': 2, 'cardPort': 1}, 'active': True},
+            {'portPos': {'node': 1, 'slot': 2, 'cardPort': 1}, 'active': True},
+            {'portPos': {'node': 0, 'slot': 2, 'cardPort': 1}, 'active': True},
+            {'portPos': {'node': 0, 'slot': 2, 'cardPort': 1}, 'active': True},
+            {'portPos': {'node': 0, 'slot': 2, 'cardPort': 1}, 'active': True},
+            {'portPos': {'node': 0, 'slot': 2, 'cardPort': 1}, 'active': True},
+            {'portPos': {'node': 0, 'slot': 2, 'cardPort': 1}, 'active': True}]
+
+        mock_client.getVLUNs.return_value = {'members': ports}
+
         # in use count
         vluns = self.driver.common.client.getVLUNs()
         nsp = self.driver._get_least_used_nsp(vluns['members'],
                                               ['0:2:1', '1:2:1'])
         self.assertEqual(nsp, '1:2:1')
 
+        ports = [
+            {'portPos': {'node': 1, 'slot': 2, 'cardPort': 1}, 'active': True},
+            {'portPos': {'node': 1, 'slot': 2, 'cardPort': 1}, 'active': True},
+            {'portPos': {'node': 1, 'slot': 2, 'cardPort': 1}, 'active': True},
+            {'portPos': {'node': 1, 'slot': 2, 'cardPort': 1}, 'active': True},
+            {'portPos': {'node': 0, 'slot': 2, 'cardPort': 1}, 'active': True},
+            {'portPos': {'node': 0, 'slot': 2, 'cardPort': 1}, 'active': True},
+            {'portPos': {'node': 0, 'slot': 2, 'cardPort': 1}, 'active': True},
+            {'portPos': {'node': 0, 'slot': 2, 'cardPort': 1}, 'active': True},
+            {'portPos': {'node': 0, 'slot': 2, 'cardPort': 1}, 'active': True}]
+
+        mock_client.getVLUNs.return_value = {'members': ports}
+
         # in use count
         vluns = self.driver.common.client.getVLUNs()
         nsp = self.driver._get_least_used_nsp(vluns['members'],
                                               ['1:1:1', '1:2:1'])
         self.assertEqual(nsp, '1:1:1')
 
-
-def pack(arg):
-    header = '\r\n\r\n\r\n\r\n\r\n'
-    footer = '\r\n\r\n\r\n'
-    return header + arg + footer
+VLUNS5_RET = ({'members':
+               [{'portPos': {'node': 0, 'slot': 8, 'cardPort': 2},
+                 'active': True},
+                {'portPos': {'node': 1, 'slot': 8, 'cardPort': 1},
+                 'active': True}]})
 
 PORTS_RET = ({'members':
               [{'portPos': {'node': 1, 'slot': 8, 'cardPort': 2},
@@ -1396,6 +1262,16 @@ PORTS_RET = ({'members':
                 'HWAddr': '2C27D75375D6',
                 'type': 8}]})
 
+VLUNS1_RET = ({'members':
+               [{'portPos': {'node': 1, 'slot': 8, 'cardPort': 2},
+                 'hostname': 'foo', 'active': True},
+                {'portPos': {'node': 1, 'slot': 8, 'cardPort': 1},
+                 'hostname': 'bar', 'active': True},
+                {'portPos': {'node': 1, 'slot': 8, 'cardPort': 1},
+                 'hostname': 'bar', 'active': True},
+                {'portPos': {'node': 1, 'slot': 8, 'cardPort': 1},
+                 'hostname': 'bar', 'active': True}]})
+
 PORTS1_RET = ({'members':
                [{'portPos': {'node': 0, 'slot': 8, 'cardPort': 2},
                  'protocol': 2,
@@ -1423,66 +1299,3 @@ PORTS1_RET = ({'members':
                  'nodeWWN': '20210002AC00383D',
                  'type': 2,
                  'portPos': {'node': 0, 'slot': 6, 'cardPort': 3}}]})
-
-VLUNS1_RET = ({'members':
-               [{'portPos': {'node': 1, 'slot': 8, 'cardPort': 2},
-                 'hostname': 'foo', 'active': True},
-                {'portPos': {'node': 1, 'slot': 8, 'cardPort': 1},
-                 'hostname': 'bar', 'active': True},
-                {'portPos': {'node': 1, 'slot': 8, 'cardPort': 1},
-                 'hostname': 'bar', 'active': True},
-                {'portPos': {'node': 1, 'slot': 8, 'cardPort': 1},
-                 'hostname': 'bar', 'active': True}]})
-
-VLUNS2_RET = ({'members':
-               [{'portPos': {'node': 1, 'slot': 8, 'cardPort': 2},
-                 'hostname': 'bar', 'active': True},
-                {'portPos': {'node': 1, 'slot': 8, 'cardPort': 1},
-                 'hostname': 'bar', 'active': True},
-                {'portPos': {'node': 1, 'slot': 8, 'cardPort': 2},
-                 'hostname': 'bar', 'active': True},
-                {'portPos': {'node': 1, 'slot': 8, 'cardPort': 2},
-                 'hostname': 'fakehost', 'active': True}]})
-
-VLUNS3_RET = ({'members':
-               [{'portPos': {'node': 1, 'slot': 8, 'cardPort': 2},
-                 'active': True},
-                {'portPos': {'node': 1, 'slot': 8, 'cardPort': 1},
-                 'active': True},
-                {'portPos': {'node': 1, 'slot': 8, 'cardPort': 2},
-                 'active': True},
-                {'portPos': {'node': 0, 'slot': 2, 'cardPort': 2},
-                 'active': True},
-                {'portPos': {'node': 0, 'slot': 2, 'cardPort': 1},
-                 'active': True},
-                {'portPos': {'node': 0, 'slot': 2, 'cardPort': 1},
-                 'active': True},
-                {'portPos': {'node': 0, 'slot': 2, 'cardPort': 1},
-                 'active': True},
-                {'portPos': {'node': 0, 'slot': 2, 'cardPort': 1},
-                 'active': True}]})
-
-VLUNS4_RET = ({'members':
-               [{'portPos': {'node': 1, 'slot': 2, 'cardPort': 1},
-                 'active': True},
-                {'portPos': {'node': 1, 'slot': 2, 'cardPort': 1},
-                 'active': True},
-                {'portPos': {'node': 1, 'slot': 2, 'cardPort': 1},
-                 'active': True},
-                {'portPos': {'node': 1, 'slot': 2, 'cardPort': 1},
-                 'active': True},
-                {'portPos': {'node': 0, 'slot': 2, 'cardPort': 1},
-                 'active': True},
-                {'portPos': {'node': 0, 'slot': 2, 'cardPort': 1},
-                 'active': True},
-                {'portPos': {'node': 0, 'slot': 2, 'cardPort': 1},
-                 'active': True},
-                {'portPos': {'node': 0, 'slot': 2, 'cardPort': 1},
-                 'active': True},
-                {'portPos': {'node': 0, 'slot': 2, 'cardPort': 1},
-                 'active': True}]})
-VLUNS5_RET = ({'members':
-               [{'portPos': {'node': 0, 'slot': 8, 'cardPort': 2},
-                 'active': True},
-                {'portPos': {'node': 1, 'slot': 8, 'cardPort': 1},
-                 'active': True}]})
index d32271c8a3e4a0b8bd11a110acaaf531e07d9200..0479703856556a71117d135ebaf31174c75c3c75 100644 (file)
@@ -38,11 +38,9 @@ import ast
 import base64
 import json
 import pprint
-from random import randint
 import re
 import uuid
 
-from eventlet import greenthread
 import hp3parclient
 from hp3parclient import client
 from hp3parclient import exceptions as hpexceptions
@@ -52,14 +50,12 @@ from cinder import context
 from cinder import exception
 from cinder.openstack.common import excutils
 from cinder.openstack.common import log as logging
-from cinder.openstack.common import processutils
-from cinder import utils
 from cinder.volume import volume_types
 
 
 LOG = logging.getLogger(__name__)
 
-MIN_CLIENT_VERSION = '2.0.0'
+MIN_CLIENT_VERSION = '2.9.0'
 
 hp3par_opts = [
     cfg.StrOpt('hp3par_api_url',
@@ -113,10 +109,11 @@ class HP3PARCommon(object):
         1.2.5 - Raise Ex when deleting snapshot with dependencies bug #1250249
         1.2.6 - Allow optional specifying n:s:p for vlun creation bug #1269515
                 This update now requires 3.1.2 MU3 firmware
+        1.3.0 - Removed all SSH code.  We rely on the hp3parclient now.
 
     """
 
-    VERSION = "1.2.6"
+    VERSION = "1.3.0"
 
     stats = {}
 
@@ -143,7 +140,6 @@ class HP3PARCommon(object):
     hp3par_valid_keys = ['cpg', 'snap_cpg', 'provisioning', 'persona', 'vvs']
 
     def __init__(self, config):
-        self.sshpool = None
         self.config = config
         self.hosts_naming_dict = dict()
         self.client = None
@@ -163,11 +159,20 @@ class HP3PARCommon(object):
         client_version = hp3parclient.version
 
         if (client_version < MIN_CLIENT_VERSION):
-            ex_msg = (_('Invalid hp3parclient version. Version %s or greater '
-                        'required.') % MIN_CLIENT_VERSION)
+            ex_msg = (_('Invalid hp3parclient version found (%(found)s). '
+                        'Version %(minimum)s or greater required.')
+                      % {'found': client_version,
+                         'minimum': MIN_CLIENT_VERSION})
             LOG.error(ex_msg)
             raise exception.InvalidInput(reason=ex_msg)
 
+        cl.setSSHOptions(self.config.san_ip,
+                         self.config.san_login,
+                         self.config.san_password,
+                         port=self.config.san_ssh_port,
+                         conn_timeout=self.config.ssh_conn_timeout,
+                         privatekey=self.config.san_private_key)
+
         return cl
 
     def client_login(self):
@@ -201,7 +206,7 @@ class HP3PARCommon(object):
         try:
             # make sure the default CPG exists
             self.validate_cpg(self.config.hp3par_cpg)
-            self._set_connections()
+            self.client.setHighConnections()
         finally:
             self.client_logout()
 
@@ -213,14 +218,6 @@ class HP3PARCommon(object):
             LOG.error(err)
             raise exception.InvalidInput(reason=err)
 
-    def _set_connections(self):
-        """Set the number of concurrent connections.
-
-        The 3PAR WS API server has a limit of concurrent connections.
-        This is setting the number to the highest allowed, 15 connections.
-        """
-        self._cli_run(['setwsapi', '-sru', 'high'])
-
     def get_domain(self, cpg_name):
         try:
             cpg = self.client.getCPG(cpg_name)
@@ -236,12 +233,12 @@ class HP3PARCommon(object):
 
     def extend_volume(self, volume, new_size):
         volume_name = self._get_3par_vol_name(volume['id'])
-        old_size = volume.size
+        old_size = volume['size']
         growth_size = int(new_size) - old_size
         LOG.debug("Extending Volume %s from %s to %s, by %s GB." %
                   (volume_name, old_size, new_size, growth_size))
         try:
-            self._cli_run(['growvv', '-f', volume_name, '%dg' % growth_size])
+            self.client.growVolume(volume_name, growth_size)
         except Exception:
             with excutils.save_and_reraise_exception():
                 LOG.error(_("Error extending volume %s") % volume)
@@ -299,96 +296,6 @@ class HP3PARCommon(object):
         capacity = int(round(capacity / MiB))
         return capacity
 
-    def _cli_run(self, cmd):
-        """Runs a CLI command over SSH, without doing any result parsing."""
-        LOG.debug("SSH CMD = %s " % cmd)
-
-        (stdout, stderr) = self._run_ssh(cmd, False)
-        # we have to strip out the input and exit lines
-        tmp = stdout.split("\r\n")
-        out = tmp[5:len(tmp) - 2]
-        return out
-
-    def _ssh_execute(self, ssh, cmd, check_exit_code=True):
-        """We have to do this in order to get CSV output from the CLI command.
-
-        We first have to issue a command to tell the CLI that we want the
-        output to be formatted in CSV, then we issue the real command.
-        """
-        LOG.debug(_('Running cmd (SSH): %s'), cmd)
-
-        channel = ssh.invoke_shell()
-        stdin_stream = channel.makefile('wb')
-        stdout_stream = channel.makefile('rb')
-        stderr_stream = channel.makefile('rb')
-
-        stdin_stream.write('''setclienv csvtable 1
-%s
-exit
-''' % cmd)
-
-        # stdin.write('process_input would go here')
-        # stdin.flush()
-
-        # NOTE(justinsb): This seems suspicious...
-        # ...other SSH clients have buffering issues with this approach
-        stdout = stdout_stream.read()
-        stderr = stderr_stream.read()
-        stdin_stream.close()
-        stdout_stream.close()
-        stderr_stream.close()
-
-        exit_status = channel.recv_exit_status()
-
-        # exit_status == -1 if no exit code was returned
-        if exit_status != -1:
-            LOG.debug(_('Result was %s') % exit_status)
-            if check_exit_code and exit_status != 0:
-                msg = _("command %s failed") % cmd
-                LOG.error(msg)
-                raise processutils.ProcessExecutionError(exit_code=exit_status,
-                                                         stdout=stdout,
-                                                         stderr=stderr,
-                                                         cmd=cmd)
-        channel.close()
-        return (stdout, stderr)
-
-    def _run_ssh(self, cmd_list, check_exit=True, attempts=1):
-        utils.check_ssh_injection(cmd_list)
-        command = ' '. join(cmd_list)
-
-        if not self.sshpool:
-            self.sshpool = utils.SSHPool(self.config.san_ip,
-                                         self.config.san_ssh_port,
-                                         self.config.ssh_conn_timeout,
-                                         self.config.san_login,
-                                         password=self.config.san_password,
-                                         privatekey=
-                                         self.config.san_private_key,
-                                         min_size=
-                                         self.config.ssh_min_pool_conn,
-                                         max_size=
-                                         self.config.ssh_max_pool_conn)
-        try:
-            total_attempts = attempts
-            with self.sshpool.item() as ssh:
-                while attempts > 0:
-                    attempts -= 1
-                    try:
-                        return self._ssh_execute(ssh, command,
-                                                 check_exit_code=check_exit)
-                    except Exception as e:
-                        LOG.error(e)
-                        greenthread.sleep(randint(20, 500) / 100.0)
-                msg = (_("SSH Command failed after '%(total_attempts)r' "
-                         "attempts : '%(command)s'") %
-                       {'total_attempts': total_attempts, 'command': command})
-                LOG.error(msg)
-                raise exception.CinderException(message=msg)
-        except Exception:
-            with excutils.save_and_reraise_exception():
-                LOG.error(_("Error running ssh command: %s") % command)
-
     def _delete_3par_host(self, hostname):
         self.client.deleteHost(hostname)
 
@@ -568,41 +475,24 @@ exit
     def _set_qos_rule(self, qos, vvs_name):
         max_io = self._get_qos_value(qos, 'maxIOPS')
         max_bw = self._get_qos_value(qos, 'maxBWS')
-        cmd = ['setqos']
-        if max_io is not None:
-            cmd.extend(['-io', '%s' % max_io])
-        if max_bw is not None:
-            cmd.extend(['-bw', '%sM' % max_bw])
-        cmd.append('vvset:' + vvs_name)
-        self._cli_run(cmd)
+        self.client.setQOSRule(vvs_name, max_io, max_bw)
 
     def _add_volume_to_volume_set(self, volume, volume_name,
                                   cpg, vvs_name, qos):
         if vvs_name is not None:
             # Admin has set a volume set name to add the volume to
-            out = self._cli_run(['createvvset', '-add', vvs_name, volume_name])
-            if out and len(out) == 1:
-                if 'does not exist' in out[0]:
-                    msg = _('VV Set %s does not exist.') % vvs_name
-                    LOG.error(msg)
-                    raise exception.InvalidInput(reason=msg)
+            try:
+                self.client.addVolumeToVolumeSet(vvs_name, volume_name)
+            except hpexceptions.HTTPNotFound:
+                msg = _('VV Set %s does not exist.') % vvs_name
+                LOG.error(msg)
+                raise exception.InvalidInput(reason=msg)
         else:
             vvs_name = self._get_3par_vvs_name(volume['id'])
             domain = self.get_domain(cpg)
-            if domain is not None:
-                self._cli_run(['createvvset', '-domain', domain, vvs_name])
-            else:
-                self._cli_run(['createvvset', vvs_name])
+            self.client.createVolumeSet(vvs_name, domain)
             self._set_qos_rule(qos, vvs_name)
-            self._cli_run(['createvvset', '-add', vvs_name, volume_name])
-
-    def _remove_volume_set(self, vvs_name):
-        # Must first clear the QoS rules before removing the volume set
-        self._cli_run(['setqos', '-clear', 'vvset:%s' % (vvs_name)])
-        self._cli_run(['removevvset', '-f', vvs_name])
-
-    def _remove_volume_from_volume_set(self, volume_name, vvs_name):
-        self._cli_run(['removevvset', '-f', vvs_name, volume_name])
+            self.client.addVolumeToVolumeSet(vvs_name, volume_name)
 
     def get_cpg(self, volume, allowSnap=False):
         volume_name = self._get_3par_vol_name(volume['id'])
@@ -768,16 +658,9 @@ exit
     def _copy_volume(self, src_name, dest_name, cpg=None, snap_cpg=None,
                      tpvv=True):
         # Virtual volume sets are not supported with the -online option
-        cmd = ['createvvcopy', '-p', src_name, '-online']
-        if snap_cpg:
-            cmd.extend(['-snp_cpg', snap_cpg])
-        if tpvv:
-            cmd.append('-tpvv')
-        if cpg:
-            cmd.append(cpg)
-        cmd.append(dest_name)
-        LOG.debug('Creating clone of a volume with %s' % cmd)
-        self._cli_run(cmd)
+        LOG.debug('Creating clone of a volume %s' % src_name)
+        self.client.copyVolume(src_name, dest_name, cpg,
+                               snap_cpg, tpvv)
 
     def get_next_word(self, s, search_string):
         """Return the next word.
@@ -815,26 +698,6 @@ exit
             LOG.error(str(ex))
             raise exception.CinderException(ex)
 
-    def _get_vvset_from_3par(self, volume_name):
-        """Get Virtual Volume Set from 3PAR.
-
-        The only way to do this currently is to try and delete the volume
-        to get the error message.
-
-        NOTE(walter-boring): don't call this unless you know the volume is
-        already in a vvset!
-        """
-        cmd = ['removevv', '-f', volume_name]
-        LOG.debug("Issuing remove command to find vvset name %s" % cmd)
-        out = self._cli_run(cmd)
-        vvset_name = None
-        if out and len(out) > 1:
-            if out[1].startswith("Attempt to delete "):
-                words = out[1].split(" ")
-                vvset_name = words[len(words) - 1]
-
-        return vvset_name
-
     def delete_volume(self, volume):
         try:
             volume_name = self._get_3par_vol_name(volume['id'])
@@ -847,19 +710,19 @@ exit
                 if ex.get_code() == 34:
                     # This is a special case which means the
                     # volume is part of a volume set.
-                    vvset_name = self._get_vvset_from_3par(volume_name)
+                    vvset_name = self.client.findVolumeSet(volume_name)
                     LOG.debug("Returned vvset_name = %s" % vvset_name)
                     if vvset_name is not None and \
                        vvset_name.startswith('vvs-'):
                         # We have a single volume per volume set, so
                         # remove the volume set.
-                        self._remove_volume_set(
+                        self.client.deleteVolumeSet(
                             self._get_3par_vvs_name(volume['id']))
                     elif vvset_name is not None:
                         # We have a pre-defined volume set just remove the
                         # volume and leave the volume set.
-                        self._remove_volume_from_volume_set(volume_name,
-                                                            vvset_name)
+                        self.client.removeVolumeFromVolumeSet(vvset_name,
+                                                              volume_name)
                     self.client.deleteVolume(volume_name)
                 else:
                     LOG.error(str(ex))
@@ -998,8 +861,7 @@ exit
             volume_name = self._get_3par_vol_name(volume['id'])
             if value is None:
                 value = ''
-            cmd = ['setvv', '-setkv', key + '=' + value, volume_name]
-            self._cli_run(cmd)
+            self.client.setVolumeMetaData(volume_name, key, value)
         except Exception as ex:
             msg = _('Failure in update_volume_key_value_pair:%s') % str(ex)
             LOG.error(msg)
@@ -1013,8 +875,7 @@ exit
                    self._get_3par_vol_name(volume['id']), str(key)))
         try:
             volume_name = self._get_3par_vol_name(volume['id'])
-            cmd = ['setvv', '-clrkey', key, volume_name]
-            self._cli_run(cmd)
+            self.client.removeVolumeMetaData(volume_name, key)
         except Exception as ex:
             msg = _('Failure in clear_volume_key_value_pair:%s') % str(ex)
             LOG.error(msg)
index 683f75d5e4d20f304b0bcd0deb2ced1bba909c0e..4e09d5369b69f882bc7091b8d7db15d0233eb915 100644 (file)
@@ -54,10 +54,11 @@ class HP3PARFCDriver(cinder.volume.driver.FibreChannelDriver):
         1.2.2 - Added try/finally around client login/logout.
         1.2.3 - Added ability to add WWNs to host.
         1.2.4 - Added metadata during attach/detach bug #1258033.
+        1.3.0 - Removed all SSH code.  We rely on the hp3parclient now.
 
     """
 
-    VERSION = "1.2.4"
+    VERSION = "1.3.0"
 
     def __init__(self, *args, **kwargs):
         super(HP3PARFCDriver, self).__init__(*args, **kwargs)
@@ -232,19 +233,22 @@ class HP3PARFCDriver(cinder.volume.driver.FibreChannelDriver):
         the same wwn but with a different hostname, return the hostname
         used by 3PAR.
         """
-        if domain is not None:
-            command = ['createhost', '-persona', persona_id, '-domain', domain,
-                       hostname]
-        else:
-            command = ['createhost', '-persona', persona_id, hostname]
+        # first search for an existing host
+        host_found = None
         for wwn in wwns:
-            command.append(wwn)
-
-        out = self.common._cli_run(command)
-        if out and len(out) > 1:
-            return self.common.parse_create_host_error(hostname, out)
+            host_found = self.common.client.findHost(wwn=wwn)
+            if host_found is not None:
+                break
 
-        return hostname
+        if host_found is not None:
+            self.common.hosts_naming_dict[hostname] = host_found
+            return host_found
+        else:
+            persona_id = int(persona_id)
+            self.common.client.createHost(hostname, FCWwns=wwns,
+                                          optional={'domain': domain,
+                                                    'persona': persona_id})
+            return hostname
 
     def _modify_3par_fibrechan_host(self, hostname, wwn):
         mod_request = {'pathOperation': self.common.client.HOST_EDIT_ADD,
index b78b6601f2c13b9754b1355e58e3d237b383bf6e..b5c331d3128cb3d24dc18c6bca236c2bf22853f1 100644 (file)
@@ -58,10 +58,11 @@ class HP3PARISCSIDriver(cinder.volume.driver.ISCSIDriver):
         1.2.5 - Added metadata during attach/detach bug #1258033
         1.2.6 - Use least-used iscsi n:s:p for iscsi volume attach bug #1269515
                 This update now requires 3.1.2 MU3 firmware
+        1.3.0 - Removed all SSH code.  We rely on the hp3parclient now.
 
     """
 
-    VERSION = "1.2.6"
+    VERSION = "1.3.0"
 
     def __init__(self, *args, **kwargs):
         super(HP3PARISCSIDriver, self).__init__(*args, **kwargs)
@@ -302,16 +303,21 @@ class HP3PARISCSIDriver(cinder.volume.driver.ISCSIDriver):
         the same iqn but with a different hostname, return the hostname
         used by 3PAR.
         """
-        if domain is not None:
-            cmd = ['createhost', '-iscsi', '-persona', persona_id, '-domain',
-                   domain, hostname, iscsi_iqn]
+        # first search for an existing host
+        host_found = self.common.client.findHost(iqn=iscsi_iqn)
+        if host_found is not None:
+            self.common.hosts_naming_dict[hostname] = host_found
+            return host_found
         else:
-            cmd = ['createhost', '-iscsi', '-persona', persona_id, hostname,
-                   iscsi_iqn]
-        out = self.common._cli_run(cmd)
-        if out and len(out) > 1:
-            return self.common.parse_create_host_error(hostname, out)
-        return hostname
+            if isinstance(iscsi_iqn, str) or isinstance(iscsi_iqn, unicode):
+                iqn = [iscsi_iqn]
+            else:
+                iqn = iscsi_iqn
+            persona_id = int(persona_id)
+            self.common.client.createHost(hostname, iscsiNames=iqn,
+                                          optional={'domain': domain,
+                                                    'persona': persona_id})
+            return hostname
 
     def _modify_3par_iscsi_host(self, hostname, iscsi_iqn):
         mod_request = {'pathOperation': self.common.client.HOST_EDIT_ADD,