]> review.fuel-infra Code Review - openstack-build/cinder-build.git/commitdiff
Update 3PAR driver session management
authorWalter A. Boring IV <walter.boring@hp.com>
Thu, 30 May 2013 19:05:26 +0000 (12:05 -0700)
committerWalter A. Boring IV <walter.boring@hp.com>
Thu, 30 May 2013 19:05:26 +0000 (12:05 -0700)
The 3PAR REST API server has a limited number of active sessions.
This change to the driver removes the ability of keeping the
REST API session alive for the life of the driver.  Now on every
driver entry point, which is synchronized, we login to the 3PAR
and when the work is complete, we log out of the 3PAR.  This has
the side affect of more overhead to the 3PAR but helps eliminate
failed commands due to maximum sessions reached to the 3PAR.

This patch also changes the locking to be the same lock for all
driver entry points and adds locking around the volume stats.
This patch also migrates all of the client code access to the common
class, which simplifies the drivers.

Change-Id: Ibcec4cf1781262521ccbdf99c4ba4167634a09c4

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 1fa0b3efebd4aafdf1b1a60847599fa3dd897cef..2b90fd143010266a90bd71168851d85e263a3127 100644 (file)
@@ -350,10 +350,10 @@ class HP3PARBaseDriver():
                    'desc': "HOST '%s' was not found" % hostname}
             raise hpexceptions.HTTPNotFound(msg)
         else:
-            self._hosts[hostname] = None
+            del self._hosts[hostname]
 
     def fake_create_3par_vlun(self, volume, hostname):
-        self.driver.client.createVLUN(volume, 19, hostname)
+        self.driver.common.client.createVLUN(volume, 19, hostname)
 
     def fake_get_ports(self):
         return {'FC': self.FAKE_FC_PORTS, 'iSCSI': self.FAKE_ISCSI_PORTS}
@@ -368,7 +368,7 @@ class HP3PARBaseDriver():
         self.flags(lock_path=self.tempdir)
         self.driver.delete_volume(self.volume)
         self.assertRaises(hpexceptions.HTTPNotFound,
-                          self.driver.client.getVolume,
+                          self.driver.common.client.getVolume,
                           self.VOLUME_ID)
 
     def test_create_snapshot(self):
@@ -376,7 +376,7 @@ class HP3PARBaseDriver():
         self.driver.create_snapshot(self.snapshot)
 
         # check to see if the snapshot was created
-        snap_vol = self.driver.client.getVolume(self.SNAPSHOT_3PAR_NAME)
+        snap_vol = self.driver.common.client.getVolume(self.SNAPSHOT_3PAR_NAME)
         self.assertEqual(snap_vol['name'], self.SNAPSHOT_3PAR_NAME)
 
     def test_delete_snapshot(self):
@@ -384,20 +384,20 @@ class HP3PARBaseDriver():
 
         self.driver.create_snapshot(self.snapshot)
         #make sure it exists first
-        vol = self.driver.client.getVolume(self.SNAPSHOT_3PAR_NAME)
+        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.client.getVolume,
+                          self.driver.common.client.getVolume,
                           self.SNAPSHOT_3PAR_NAME)
 
     def test_create_volume_from_snapshot(self):
         self.flags(lock_path=self.tempdir)
         self.driver.create_volume_from_snapshot(self.volume, self.snapshot)
 
-        snap_vol = self.driver.client.getVolume(self.VOLUME_3PAR_NAME)
+        snap_vol = self.driver.common.client.getVolume(self.VOLUME_3PAR_NAME)
         self.assertEqual(snap_vol['name'], self.VOLUME_3PAR_NAME)
 
         volume = self.volume.copy()
@@ -410,12 +410,12 @@ class HP3PARBaseDriver():
         self.flags(lock_path=self.tempdir)
         #setup the connections
         self.driver.initialize_connection(self.volume, self.connector)
-        vlun = self.driver.client.getVLUN(self.VOLUME_3PAR_NAME)
+        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, True)
         # vlun should be gone.
         self.assertRaises(hpexceptions.HTTPNotFound,
-                          self.driver.client.getVLUN,
+                          self.driver.common.client.getVLUN,
                           self.VOLUME_3PAR_NAME)
 
 
@@ -442,7 +442,7 @@ class TestHP3PARFCDriver(HP3PARBaseDriver, test.TestCase):
         configuration.san_password = 'test'
         configuration.hp3par_snapshot_expiration = ""
         configuration.hp3par_snapshot_retention = ""
-        self.stubs.Set(hpfcdriver.HP3PARFCDriver, "_create_client",
+        self.stubs.Set(hpfcdriver.hpcommon.HP3PARCommon, "_create_client",
                        self.fake_create_client)
         self.stubs.Set(hpfcdriver.HP3PARFCDriver,
                        "_create_3par_fibrechan_host",
@@ -515,7 +515,7 @@ class TestHP3PARFCDriver(HP3PARBaseDriver, test.TestCase):
         host = self.fake_get_3par_host(self.FAKE_HOST)
         self.assertEquals(self.FAKE_HOST, host['name'])
         self.assertEquals(HP3PAR_DOMAIN, host['domain'])
-        vlun = self.driver.client.getVLUN(self.VOLUME_3PAR_NAME)
+        vlun = self.driver.common.client.getVLUN(self.VOLUME_3PAR_NAME)
 
         self.assertEquals(self.VOLUME_3PAR_NAME, vlun['volumeName'])
         self.assertEquals(self.FAKE_HOST, vlun['hostname'])
@@ -554,10 +554,10 @@ class TestHP3PARFCDriver(HP3PARBaseDriver, test.TestCase):
         self.assertEquals(stats['free_capacity_gb'], 'infinite')
 
         #modify the CPG to have a limit
-        old_cpg = self.driver.client.getCPG(HP3PAR_CPG)
+        old_cpg = self.driver.common.client.getCPG(HP3PAR_CPG)
         options = {'SDGrowth': {'limitMiB': 8192}}
-        self.driver.client.deleteCPG(HP3PAR_CPG)
-        self.driver.client.createCPG(HP3PAR_CPG, options)
+        self.driver.common.client.deleteCPG(HP3PAR_CPG)
+        self.driver.common.client.createCPG(HP3PAR_CPG, options)
 
         const = 0.0009765625
         stats = self.driver.get_volume_stats(True)
@@ -566,8 +566,8 @@ class TestHP3PARFCDriver(HP3PARBaseDriver, test.TestCase):
         self.assertEquals(stats['total_capacity_gb'], total_capacity_gb)
         free_capacity_gb = int((8192 - old_cpg['UsrUsage']['usedMiB']) * const)
         self.assertEquals(stats['free_capacity_gb'], free_capacity_gb)
-        self.driver.client.deleteCPG(HP3PAR_CPG)
-        self.driver.client.createCPG(HP3PAR_CPG, {})
+        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)
@@ -664,7 +664,7 @@ class TestHP3PARISCSIDriver(HP3PARBaseDriver, test.TestCase):
         configuration.hp3par_snapshot_expiration = ""
         configuration.hp3par_snapshot_retention = ""
 
-        self.stubs.Set(hpdriver.HP3PARISCSIDriver, "_create_client",
+        self.stubs.Set(hpdriver.hpcommon.HP3PARCommon, "_create_client",
                        self.fake_create_client)
         self.stubs.Set(hpdriver.HP3PARISCSIDriver,
                        "_iscsi_discover_target_iqn",
@@ -743,7 +743,7 @@ class TestHP3PARISCSIDriver(HP3PARBaseDriver, test.TestCase):
         host = self.fake_get_3par_host(self.FAKE_HOST)
         self.assertEquals(self.FAKE_HOST, host['name'])
         self.assertEquals(HP3PAR_DOMAIN, host['domain'])
-        vlun = self.driver.client.getVLUN(self.VOLUME_3PAR_NAME)
+        vlun = self.driver.common.client.getVLUN(self.VOLUME_3PAR_NAME)
 
         self.assertEquals(self.VOLUME_3PAR_NAME, vlun['volumeName'])
         self.assertEquals(self.FAKE_HOST, vlun['hostname'])
@@ -782,10 +782,10 @@ class TestHP3PARISCSIDriver(HP3PARBaseDriver, test.TestCase):
         self.assertEquals(stats['free_capacity_gb'], 'infinite')
 
         #modify the CPG to have a limit
-        old_cpg = self.driver.client.getCPG(HP3PAR_CPG)
+        old_cpg = self.driver.common.client.getCPG(HP3PAR_CPG)
         options = {'SDGrowth': {'limitMiB': 8192}}
-        self.driver.client.deleteCPG(HP3PAR_CPG)
-        self.driver.client.createCPG(HP3PAR_CPG, options)
+        self.driver.common.client.deleteCPG(HP3PAR_CPG)
+        self.driver.common.client.createCPG(HP3PAR_CPG, options)
 
         const = 0.0009765625
         stats = self.driver.get_volume_stats(True)
@@ -794,8 +794,8 @@ class TestHP3PARISCSIDriver(HP3PARBaseDriver, test.TestCase):
         self.assertEquals(stats['total_capacity_gb'], total_capacity_gb)
         free_capacity_gb = int((8192 - old_cpg['UsrUsage']['usedMiB']) * const)
         self.assertEquals(stats['free_capacity_gb'], free_capacity_gb)
-        self.driver.client.deleteCPG(HP3PAR_CPG)
-        self.driver.client.createCPG(HP3PAR_CPG, {})
+        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)
index abfb741351995a02187775d33e3be00b48529062..01b19a18e469ec783f263b6a3d1649b9706f90b3 100644 (file)
@@ -46,6 +46,7 @@ import time
 import uuid
 
 from eventlet import greenthread
+from hp3parclient import client
 from hp3parclient import exceptions as hpexceptions
 from oslo.config import cfg
 
@@ -93,7 +94,7 @@ hp3par_opts = [
 ]
 
 
-class HP3PARCommon():
+class HP3PARCommon(object):
 
     stats = {}
 
@@ -113,12 +114,57 @@ class HP3PARCommon():
         self.sshpool = None
         self.config = config
         self.hosts_naming_dict = dict()
+        self.client = None
 
     def check_flags(self, options, required_flags):
         for flag in required_flags:
             if not getattr(options, flag, None):
                 raise exception.InvalidInput(reason=_('%s is not set') % flag)
 
+    def _create_client(self):
+        return client.HP3ParClient(self.config.hp3par_api_url)
+
+    def client_login(self):
+        try:
+            LOG.debug("Connecting to 3PAR")
+            self.client.login(self.config.hp3par_username,
+                              self.config.hp3par_password)
+        except hpexceptions.HTTPUnauthorized as ex:
+            LOG.warning("Failed to connect to 3PAR (%s) because %s" %
+                       (self.config.hp3par_api_url, str(ex)))
+            msg = _("Login to 3PAR array invalid")
+            raise exception.InvalidInput(reason=msg)
+
+    def client_logout(self):
+        self.client.logout()
+        LOG.debug("Disconnect from 3PAR")
+
+    def do_setup(self, context):
+        self.client = self._create_client()
+        if self.config.hp3par_debug:
+            self.client.debug_rest(True)
+
+        self.client_login()
+
+        # make sure the CPG exists
+        try:
+            cpg = self.client.getCPG(self.config.hp3par_cpg)
+        except hpexceptions.HTTPNotFound as ex:
+            err = (_("CPG (%s) doesn't exist on array")
+                   % self.config.hp3par_cpg)
+            LOG.error(err)
+            raise exception.InvalidInput(reason=err)
+
+        if ('domain' not in cpg
+            and cpg['domain'] != self.config.hp3par_domain):
+            err = ("CPG's domain '%s' and config option hp3par_domain '%s'"
+                   " must be the same" %
+                   (cpg['domain'], self.config.hp3par_domain))
+            LOG.error(err)
+            raise exception.InvalidInput(reason=err)
+
+        self.client_logout()
+
     def _get_3par_vol_name(self, volume_id):
         """
         Converts the openstack volume id from
@@ -412,13 +458,13 @@ exit
         LOG.debug("PORTS = %s" % pprint.pformat(ports))
         return ports
 
-    def get_volume_stats(self, refresh, client):
+    def get_volume_stats(self, refresh):
         if refresh:
-            self._update_volume_stats(client)
+            self._update_volume_stats()
 
         return self.stats
 
-    def _update_volume_stats(self, client):
+    def _update_volume_stats(self):
         # const to convert MiB to GB
         const = 0.0009765625
 
@@ -433,7 +479,7 @@ exit
                  'volume_backend_name': None}
 
         try:
-            cpg = client.getCPG(self.config.hp3par_cpg)
+            cpg = self.client.getCPG(self.config.hp3par_cpg)
             if 'limitMiB' not in cpg['SDGrowth']:
                 total_capacity = 'infinite'
                 free_capacity = 'infinite'
@@ -452,19 +498,19 @@ exit
 
         self.stats = stats
 
-    def create_vlun(self, volume, host, client):
+    def create_vlun(self, volume, host):
         """
         In order to export a volume on a 3PAR box, we have to
         create a VLUN.
         """
         volume_name = self._get_3par_vol_name(volume['id'])
         self._create_3par_vlun(volume_name, host['name'])
-        return client.getVLUN(volume_name)
+        return self.client.getVLUN(volume_name)
 
-    def delete_vlun(self, volume, hostname, client):
+    def delete_vlun(self, volume, hostname):
         volume_name = self._get_3par_vol_name(volume['id'])
-        vlun = client.getVLUN(volume_name)
-        client.deleteVLUN(volume_name, vlun['lun'], hostname)
+        vlun = self.client.getVLUN(volume_name)
+        self.client.deleteVLUN(volume_name, vlun['lun'], hostname)
         self._delete_3par_host(hostname)
 
     def _get_volume_type(self, type_id):
@@ -500,7 +546,7 @@ exit
         persona_id = persona_value.split(' ')
         return persona_id[0]
 
-    def create_volume(self, volume, client):
+    def create_volume(self, volume):
         LOG.debug("CREATE VOLUME (%s : %s %s)" %
                   (volume['display_name'], volume['name'],
                    self._get_3par_vol_name(volume['id'])))
@@ -563,7 +609,7 @@ exit
 
             capacity = self._capacity_from_size(volume['size'])
             volume_name = self._get_3par_vol_name(volume['id'])
-            client.createVolume(volume_name, cpg, capacity, extras)
+            self.client.createVolume(volume_name, cpg, capacity, extras)
 
         except hpexceptions.HTTPConflict:
             raise exception.Duplicate(_("Volume (%s) already exists on array")
@@ -605,15 +651,14 @@ exit
         word = re.search(search_string.strip(' ') + ' ([^ ]*)', s)
         return word.groups()[0].strip(' ')
 
-    @utils.synchronized('3parclone', external=True)
-    def create_cloned_volume(self, volume, src_vref, client):
+    def create_cloned_volume(self, volume, src_vref):
 
         try:
             orig_name = self._get_3par_vol_name(volume['source_volid'])
             vol_name = self._get_3par_vol_name(volume['id'])
             # We need to create a new volume first.  Otherwise you
             # can't delete the original
-            new_vol = self.create_volume(volume, client)
+            new_vol = self.create_volume(volume)
 
             # make the 3PAR copy the contents.
             # can't delete the original until the copy is done.
@@ -648,10 +693,10 @@ exit
 
         return None
 
-    def delete_volume(self, volume, client):
+    def delete_volume(self, volume):
         try:
             volume_name = self._get_3par_vol_name(volume['id'])
-            client.deleteVolume(volume_name)
+            self.client.deleteVolume(volume_name)
         except hpexceptions.HTTPNotFound as ex:
             # We'll let this act as if it worked
             # it helps clean up the cinder entries.
@@ -663,7 +708,7 @@ exit
             LOG.error(str(ex))
             raise exception.CinderException(ex.get_description())
 
-    def create_volume_from_snapshot(self, volume, snapshot, client):
+    def create_volume_from_snapshot(self, volume, snapshot):
         """
         Creates a volume from a snapshot.
 
@@ -696,13 +741,13 @@ exit
             optional = {'comment': json.dumps(extra),
                         'readOnly': False}
 
-            client.createSnapshot(vol_name, snap_name, optional)
+            self.client.createSnapshot(vol_name, snap_name, optional)
         except hpexceptions.HTTPForbidden:
             raise exception.NotAuthorized()
         except hpexceptions.HTTPNotFound:
             raise exception.NotFound()
 
-    def create_snapshot(self, snapshot, client):
+    def create_snapshot(self, snapshot):
         LOG.debug("Create Snapshot\n%s" % pprint.pformat(snapshot))
 
         try:
@@ -734,18 +779,18 @@ exit
                 optional['retentionHours'] = (
                     self.config.hp3par_snapshot_retention)
 
-            client.createSnapshot(snap_name, vol_name, optional)
+            self.client.createSnapshot(snap_name, vol_name, optional)
         except hpexceptions.HTTPForbidden:
             raise exception.NotAuthorized()
         except hpexceptions.HTTPNotFound:
             raise exception.NotFound()
 
-    def delete_snapshot(self, snapshot, client):
+    def delete_snapshot(self, snapshot):
         LOG.debug("Delete Snapshot\n%s" % pprint.pformat(snapshot))
 
         try:
             snap_name = self._get_3par_snap_name(snapshot['id'])
-            client.deleteVolume(snap_name)
+            self.client.deleteVolume(snap_name)
         except hpexceptions.HTTPForbidden:
             raise exception.NotAuthorized()
         except hpexceptions.HTTPNotFound as ex:
@@ -765,13 +810,13 @@ exit
                 if (wwn_iqn.upper() in showhost.upper()):
                     return showhost.split(',')[1]
 
-    def terminate_connection(self, volume, hostname, wwn_iqn, client):
+    def terminate_connection(self, volume, hostname, wwn_iqn):
         """ Driver entry point to unattach a volume from an instance."""
         try:
             # does 3par know this host by a different name?
             if hostname in self.hosts_naming_dict:
                 hostname = self.hosts_naming_dict.get(hostname)
-            self.delete_vlun(volume, hostname, client)
+            self.delete_vlun(volume, hostname)
             return
         except hpexceptions.HTTPNotFound as e:
             if 'host does not exist' in e.get_description():
@@ -785,7 +830,7 @@ exit
                 raise
 
         #try again with name retrieved from 3par
-        self.delete_vlun(volume, hostname, client)
+        self.delete_vlun(volume, hostname)
 
     def parse_create_host_error(self, hostname, out):
         search_str = "already used by host "
index 0479e083af92d205cfae577ef9b646d1b0cffbd6..cc55b0a3eec9a2ea6e1c492cc1121c83241c8540 100644 (file)
@@ -30,7 +30,6 @@ Set the following in the cinder.conf file to enable the
 volume_driver=cinder.volume.drivers.san.hp.hp_3par_fc.HP3PARFCDriver
 """
 
-from hp3parclient import client
 from hp3parclient import exceptions as hpexceptions
 from oslo.config import cfg
 
@@ -55,7 +54,6 @@ class HP3PARFCDriver(cinder.volume.driver.FibreChannelDriver):
 
     def __init__(self, *args, **kwargs):
         super(HP3PARFCDriver, self).__init__(*args, **kwargs)
-        self.client = None
         self.common = None
         self.configuration.append_config_values(hpcommon.hp3par_opts)
         self.configuration.append_config_values(san.san_opts)
@@ -70,85 +68,69 @@ class HP3PARFCDriver(cinder.volume.driver.FibreChannelDriver):
                           'san_ip', 'san_login', 'san_password']
         self.common.check_flags(self.configuration, required_flags)
 
-    def _create_client(self):
-        return client.HP3ParClient(self.configuration.hp3par_api_url)
-
+    @utils.synchronized('3par', external=True)
     def get_volume_stats(self, refresh):
-        stats = self.common.get_volume_stats(refresh, self.client)
+        self.common.client_login()
+        stats = self.common.get_volume_stats(refresh)
         stats['storage_protocol'] = 'FC'
         backend_name = self.configuration.safe_get('volume_backend_name')
         stats['volume_backend_name'] = backend_name or self.__class__.__name__
+        self.common.client_logout()
         return stats
 
     def do_setup(self, context):
         self.common = self._init_common()
         self._check_flags()
-        self.client = self._create_client()
-        if self.configuration.hp3par_debug:
-            self.client.debug_rest(True)
-
-        try:
-            LOG.debug("Connecting to 3PAR")
-            self.client.login(self.configuration.hp3par_username,
-                              self.configuration.hp3par_password)
-        except hpexceptions.HTTPUnauthorized as ex:
-            LOG.warning("Failed to connect to 3PAR (%s) because %s" %
-                       (self.configuration.hp3par_api_url, str(ex)))
-            msg = _("Login to 3PAR array invalid")
-            raise exception.InvalidInput(reason=msg)
-
-        # make sure the CPG exists
-        try:
-            cpg = self.client.getCPG(self.configuration.hp3par_cpg)
-        except hpexceptions.HTTPNotFound as ex:
-            err = (_("CPG (%s) doesn't exist on array")
-                   % self.configuration.hp3par_cpg)
-            LOG.error(err)
-            raise exception.InvalidInput(reason=err)
-
-        if ('domain' not in cpg
-            and cpg['domain'] != self.configuration.hp3par_domain):
-            err = "CPG's domain '%s' and config option hp3par_domain '%s' \
-must be the same" % (cpg['domain'], self.configuration.hp3par_domain)
-            LOG.error(err)
-            raise exception.InvalidInput(reason=err)
+        self.common.do_setup(context)
 
     def check_for_setup_error(self):
         """Returns an error if prerequisites aren't met."""
         self._check_flags()
 
-    @utils.synchronized('3par-vol', external=True)
+    @utils.synchronized('3par', external=True)
     def create_volume(self, volume):
-        metadata = self.common.create_volume(volume, self.client)
+        self.common.client_login()
+        metadata = self.common.create_volume(volume)
+        self.common.client_logout()
         return {'metadata': metadata}
 
+    @utils.synchronized('3par', external=True)
     def create_cloned_volume(self, volume, src_vref):
-        new_vol = self.common.create_cloned_volume(volume, src_vref,
-                                                   self.client)
+        self.common.client_login()
+        new_vol = self.common.create_cloned_volume(volume, src_vref)
+        self.common.client_logout()
         return {'metadata': new_vol}
 
-    @utils.synchronized('3par-vol', external=True)
+    @utils.synchronized('3par', external=True)
     def delete_volume(self, volume):
-        self.common.delete_volume(volume, self.client)
+        self.common.client_login()
+        self.common.delete_volume(volume)
+        self.common.client_logout()
 
-    @utils.synchronized('3par-vol', external=True)
+    @utils.synchronized('3par', external=True)
     def create_volume_from_snapshot(self, volume, snapshot):
         """
         Creates a volume from a snapshot.
 
         TODO: support using the size from the user.
         """
-        self.common.create_volume_from_snapshot(volume, snapshot, self.client)
+        self.common.client_login()
+        self.common.create_volume_from_snapshot(volume, snapshot)
+        self.common.client_logout()
 
-    @utils.synchronized('3par-snap', external=True)
+    @utils.synchronized('3par', external=True)
     def create_snapshot(self, snapshot):
-        self.common.create_snapshot(snapshot, self.client)
+        self.common.client_login()
+        self.common.create_snapshot(snapshot)
+        self.common.client_logout()
 
-    @utils.synchronized('3par-snap', external=True)
+    @utils.synchronized('3par', external=True)
     def delete_snapshot(self, snapshot):
-        self.common.delete_snapshot(snapshot, self.client)
+        self.common.client_login()
+        self.common.delete_snapshot(snapshot)
+        self.common.client_logout()
 
-    @utils.synchronized('3par-attach', external=True)
+    @utils.synchronized('3par', external=True)
     def initialize_connection(self, volume, connector):
         """Assigns the volume to a server.
 
@@ -186,27 +168,30 @@ must be the same" % (cpg['domain'], self.configuration.hp3par_domain)
           * Create a VLUN for that HOST with the volume we want to export.
 
         """
+        self.common.client_login()
         # we have to make sure we have a host
         host = self._create_host(volume, connector)
 
         # now that we have a host, create the VLUN
-        vlun = self.common.create_vlun(volume, host, self.client)
+        vlun = self.common.create_vlun(volume, host)
 
         ports = self.common.get_ports()
 
+        self.common.client_logout()
         info = {'driver_volume_type': 'fibre_channel',
                 'data': {'target_lun': vlun['lun'],
                          'target_discovered': True,
                          'target_wwn': ports['FC']}}
         return info
 
-    @utils.synchronized('3par-attach', external=True)
+    @utils.synchronized('3par', external=True)
     def terminate_connection(self, volume, connector, force):
         """Driver entry point to unattach a volume from an instance."""
+        self.common.client_login()
         self.common.terminate_connection(volume,
                                          connector['host'],
-                                         connector['wwpns'],
-                                         self.client)
+                                         connector['wwpns'])
+        self.common.client_logout()
 
     def _create_3par_fibrechan_host(self, hostname, wwn, domain, persona_id):
         """Create a 3PAR host.
@@ -250,14 +235,14 @@ must be the same" % (cpg['domain'], self.configuration.hp3par_domain)
 
         return host
 
-    @utils.synchronized('3par-exp', external=True)
+    @utils.synchronized('3par', external=True)
     def create_export(self, context, volume):
         pass
 
-    @utils.synchronized('3par-exp', external=True)
+    @utils.synchronized('3par', external=True)
     def ensure_export(self, context, volume):
         pass
 
-    @utils.synchronized('3par-exp', external=True)
+    @utils.synchronized('3par', external=True)
     def remove_export(self, context, volume):
         pass
index bf14c8791a32bafceaef1e579ce9243a4a1b0725..4fddb810364c22316f5297098074dba953d8220e 100644 (file)
@@ -30,7 +30,6 @@ Set the following in the cinder.conf file to enable the
 volume_driver=cinder.volume.drivers.san.hp.hp_3par_iscsi.HP3PARISCSIDriver
 """
 
-from hp3parclient import client
 from hp3parclient import exceptions as hpexceptions
 
 from cinder import exception
@@ -53,7 +52,6 @@ class HP3PARISCSIDriver(cinder.volume.driver.ISCSIDriver):
     """
     def __init__(self, *args, **kwargs):
         super(HP3PARISCSIDriver, self).__init__(*args, **kwargs)
-        self.client = None
         self.common = None
         self.configuration.append_config_values(hpcommon.hp3par_opts)
         self.configuration.append_config_values(san.san_opts)
@@ -69,48 +67,20 @@ class HP3PARISCSIDriver(cinder.volume.driver.ISCSIDriver):
                           'san_password']
         self.common.check_flags(self.configuration, required_flags)
 
-    def _create_client(self):
-        return client.HP3ParClient(self.configuration.hp3par_api_url)
-
+    @utils.synchronized('3par', external=True)
     def get_volume_stats(self, refresh):
-        stats = self.common.get_volume_stats(refresh, self.client)
+        self.common.client_login()
+        stats = self.common.get_volume_stats(refresh)
         stats['storage_protocol'] = 'iSCSI'
         backend_name = self.configuration.safe_get('volume_backend_name')
         stats['volume_backend_name'] = backend_name or self.__class__.__name__
+        self.common.client_logout()
         return stats
 
     def do_setup(self, context):
         self.common = self._init_common()
         self._check_flags()
-        self.client = self._create_client()
-        if self.configuration.hp3par_debug:
-            self.client.debug_rest(True)
-
-        try:
-            LOG.debug("Connecting to 3PAR")
-            self.client.login(self.configuration.hp3par_username,
-                              self.configuration.hp3par_password)
-        except hpexceptions.HTTPUnauthorized as ex:
-            LOG.warning("Failed to connect to 3PAR (%s) because %s" %
-                       (self.configuration.hp3par_api_url, str(ex)))
-            msg = _("Login to 3PAR array invalid")
-            raise exception.InvalidInput(reason=msg)
-
-        # make sure the CPG exists
-        try:
-            cpg = self.client.getCPG(self.configuration.hp3par_cpg)
-        except hpexceptions.HTTPNotFound as ex:
-            err = (_("CPG (%s) doesn't exist on array")
-                   % self.configuration.hp3par_cpg)
-            LOG.error(err)
-            raise exception.InvalidInput(reason=err)
-
-        if ('domain' not in cpg and
-            cpg['domain'] != self.configuration.hp3par_domain):
-            err = "CPG's domain '%s' and config option hp3par_domain '%s' \
-must be the same" % (cpg['domain'], self.configuration.hp3par_domain)
-            LOG.error(err)
-            raise exception.InvalidInput(reason=err)
+        self.common.do_setup(context)
 
         # make sure ssh works.
         self._iscsi_discover_target_iqn(self.configuration.iscsi_ip_address)
@@ -119,46 +89,59 @@ must be the same" % (cpg['domain'], self.configuration.hp3par_domain)
         """Returns an error if prerequisites aren't met."""
         self._check_flags()
 
-    @utils.synchronized('3par-vol', external=True)
+    @utils.synchronized('3par', external=True)
     def create_volume(self, volume):
-        metadata = self.common.create_volume(volume, self.client)
+        self.common.client_login()
+        metadata = self.common.create_volume(volume)
+        self.common.client_logout()
 
         return {'provider_location': "%s:%s" %
                 (self.configuration.iscsi_ip_address,
                  self.configuration.iscsi_port),
                 'metadata': metadata}
 
+    @utils.synchronized('3par', external=True)
     def create_cloned_volume(self, volume, src_vref):
         """ Clone an existing volume. """
-        new_vol = self.common.create_cloned_volume(volume, src_vref,
-                                                   self.client)
+        self.common.client_login()
+        new_vol = self.common.create_cloned_volume(volume, src_vref)
+        self.common.client_logout()
+
         return {'provider_location': "%s:%s" %
                 (self.configuration.iscsi_ip_address,
                  self.configuration.iscsi_port),
                 'metadata': new_vol}
 
-    @utils.synchronized('3par-vol', external=True)
+    @utils.synchronized('3par', external=True)
     def delete_volume(self, volume):
-        self.common.delete_volume(volume, self.client)
+        self.common.client_login()
+        self.common.delete_volume(volume)
+        self.common.client_logout()
 
-    @utils.synchronized('3par-vol', external=True)
+    @utils.synchronized('3par', external=True)
     def create_volume_from_snapshot(self, volume, snapshot):
         """
         Creates a volume from a snapshot.
 
         TODO: support using the size from the user.
         """
-        self.common.create_volume_from_snapshot(volume, snapshot, self.client)
+        self.common.client_login()
+        self.common.create_volume_from_snapshot(volume, snapshot)
+        self.common.client_logout()
 
-    @utils.synchronized('3par-snap', external=True)
+    @utils.synchronized('3par', external=True)
     def create_snapshot(self, snapshot):
-        self.common.create_snapshot(snapshot, self.client)
+        self.common.client_login()
+        self.common.create_snapshot(snapshot)
+        self.common.client_logout()
 
-    @utils.synchronized('3par-snap', external=True)
+    @utils.synchronized('3par', external=True)
     def delete_snapshot(self, snapshot):
-        self.common.delete_snapshot(snapshot, self.client)
+        self.common.client_login()
+        self.common.delete_snapshot(snapshot)
+        self.common.client_logout()
 
-    @utils.synchronized('3par-attach', external=True)
+    @utils.synchronized('3par', external=True)
     def initialize_connection(self, volume, connector):
         """Assigns the volume to a server.
 
@@ -184,6 +167,7 @@ must be the same" % (cpg['domain'], self.configuration.hp3par_domain)
           * Create a host on the 3par
           * create vlun on the 3par
         """
+        self.common.client_login()
         # get the target_iqn on the 3par interface.
         target_iqn = self._iscsi_discover_target_iqn(
             self.configuration.iscsi_ip_address)
@@ -192,8 +176,9 @@ must be the same" % (cpg['domain'], self.configuration.hp3par_domain)
         host = self._create_host(volume, connector)
 
         # now that we have a host, create the VLUN
-        vlun = self.common.create_vlun(volume, host, self.client)
+        vlun = self.common.create_vlun(volume, host)
 
+        self.common.client_logout()
         info = {'driver_volume_type': 'iscsi',
                 'data': {'target_portal': "%s:%s" %
                          (self.configuration.iscsi_ip_address,
@@ -205,13 +190,14 @@ must be the same" % (cpg['domain'], self.configuration.hp3par_domain)
                 }
         return info
 
-    @utils.synchronized('3par-attach', external=True)
+    @utils.synchronized('3par', external=True)
     def terminate_connection(self, volume, connector, force):
         """Driver entry point to unattach a volume from an instance."""
+        self.common.client_login()
         self.common.terminate_connection(volume,
                                          connector['host'],
-                                         connector['initiator'],
-                                         self.client)
+                                         connector['initiator'])
+        self.common.client_logout()
 
     def _iscsi_discover_target_iqn(self, remote_ip):
         result = self.common._cli_run('showport -ids', None)
@@ -270,14 +256,14 @@ must be the same" % (cpg['domain'], self.configuration.hp3par_domain)
 
         return host
 
-    @utils.synchronized('3par-exp', external=True)
+    @utils.synchronized('3par', external=True)
     def create_export(self, context, volume):
         pass
 
-    @utils.synchronized('3par-exp', external=True)
+    @utils.synchronized('3par', external=True)
     def ensure_export(self, context, volume):
         pass
 
-    @utils.synchronized('3par-exp', external=True)
+    @utils.synchronized('3par', external=True)
     def remove_export(self, context, volume):
         pass