]> review.fuel-infra Code Review - openstack-build/cinder-build.git/commitdiff
3PAR Only remove FC Zone on last volume detach
authorWalter A. Boring IV <walter.boring@hp.com>
Fri, 27 Jun 2014 23:00:01 +0000 (16:00 -0700)
committerWalter A. Boring IV <walter.boring@hp.com>
Mon, 30 Jun 2014 20:49:45 +0000 (13:49 -0700)
This patch checks to make sure that we don't
include the initiator_target_map in the return
of terminate_connection if there are volumes
still attached for a particular host.  The
FibreChannel ZoneManager doesn't remove zones
if there isn't an initiator_target_map in the
return of terminate_connection.

Change-Id: I98db5adb6da38454933a6e4b78085193f1d37680
Partial-Bug: #1308318

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

index cb554c6a44c15e9abfce64fa777f98ed34ab3d79..45d81e8f1772f1214260db356ac7f9c6b8ba3aa7 100644 (file)
@@ -1318,10 +1318,13 @@ class TestHP3PARFCDriver(HP3PARBaseDriver, test.TestCase):
         # setup_mock_client drive with default configuration
         # and return the mock HTTP 3PAR client
         mock_client = self.setup_driver()
-        mock_client.getHostVLUNs.return_value = [
-            {'active': True,
-             'volumeName': self.VOLUME_3PAR_NAME,
-             'lun': None, 'type': 0}]
+
+        effects = [
+            [{'active': True, 'volumeName': self.VOLUME_3PAR_NAME,
+              'lun': None, 'type': 0}],
+            hpexceptions.HTTPNotFound]
+
+        mock_client.getHostVLUNs.side_effect = effects
 
         expected = [
             mock.call.login(HP3PAR_USER_NAME, HP3PAR_USER_PASS),
@@ -1331,13 +1334,19 @@ class TestHP3PARFCDriver(HP3PARBaseDriver, test.TestCase):
                 None,
                 self.FAKE_HOST),
             mock.call.deleteHost(self.FAKE_HOST),
+            mock.call.getHostVLUNs(self.FAKE_HOST),
             mock.call.getPorts(),
             mock.call.logout()]
 
-        self.driver.terminate_connection(self.volume, self.connector)
+        conn_info = self.driver.terminate_connection(self.volume,
+                                                     self.connector)
         mock_client.assert_has_calls(expected)
+        self.assertIn('data', conn_info)
+        self.assertIn('initiator_target_map', conn_info['data'])
         mock_client.reset_mock()
 
+        mock_client.getHostVLUNs.side_effect = effects
+
         # mock some deleteHost exceptions that are handled
         delete_with_vlun = hpexceptions.HTTPConflict(
             error={'message': "has exported VLUN"})
@@ -1346,11 +1355,14 @@ class TestHP3PARFCDriver(HP3PARBaseDriver, test.TestCase):
         mock_client.deleteHost = mock.Mock(
             side_effect=[delete_with_vlun, delete_with_hostset])
 
-        self.driver.terminate_connection(self.volume, self.connector)
+        conn_info = self.driver.terminate_connection(self.volume,
+                                                     self.connector)
         mock_client.assert_has_calls(expected)
         mock_client.reset_mock()
+        mock_client.getHostVLUNs.side_effect = effects
 
-        self.driver.terminate_connection(self.volume, self.connector)
+        conn_info = self.driver.terminate_connection(self.volume,
+                                                     self.connector)
         mock_client.assert_has_calls(expected)
 
     def test_terminate_connection_more_vols(self):
@@ -1373,11 +1385,13 @@ class TestHP3PARFCDriver(HP3PARBaseDriver, test.TestCase):
                 self.VOLUME_3PAR_NAME,
                 None,
                 self.FAKE_HOST),
-            mock.call.getPorts(),
+            mock.call.getHostVLUNs(self.FAKE_HOST),
             mock.call.logout()]
 
-        self.driver.terminate_connection(self.volume, self.connector)
+        conn_info = self.driver.terminate_connection(self.volume,
+                                                     self.connector)
         mock_client.assert_has_calls(expect_less)
+        self.assertNotIn('initiator_target_map', conn_info['data'])
 
     def test_get_volume_stats(self):
         # setup_mock_client drive with default configuration
index 413a17db611b61899803debc7d127c3a4ddd0757..45db9047b8611e2ed054f839dc5e55a31a3219f6 100644 (file)
@@ -62,10 +62,11 @@ class HP3PARFCDriver(cinder.volume.driver.FibreChannelDriver):
         2.0.2 - Add back-end assisted volume migrate
         2.0.3 - Added initiator-target map for FC Zone Manager
         2.0.4 - Added support for managing/unmanaging of volumes
+        2.0.5 - Only remove FC Zone on last volume detach
 
     """
 
-    VERSION = "2.0.4"
+    VERSION = "2.0.5"
 
     def __init__(self, *args, **kwargs):
         super(HP3PARFCDriver, self).__init__(*args, **kwargs)
@@ -229,12 +230,20 @@ class HP3PARFCDriver(cinder.volume.driver.FibreChannelDriver):
             self.common.terminate_connection(volume, hostname,
                                              wwn=connector['wwpns'])
 
-            target_wwns, init_targ_map = self._build_initiator_target_map(
-                connector)
-
             info = {'driver_volume_type': 'fibre_channel',
-                    'data': {'target_wwn': target_wwns,
-                             'initiator_target_map': init_targ_map}}
+                    'data': {}}
+
+            try:
+                self.common.client.getHostVLUNs(hostname)
+            except hpexceptions.HTTPNotFound:
+                # No more exports for this host.
+                LOG.info(_("Need to remove FC Zone, building initiator "
+                         "target map"))
+                target_wwns, init_targ_map = self._build_initiator_target_map(
+                    connector)
+
+                info['data'] = {'target_wwn': target_wwns,
+                                'initiator_target_map': init_targ_map}
             return info
 
         finally: