]> review.fuel-infra Code Review - openstack-build/cinder-build.git/commitdiff
Fix volume related operation in CloudByte driver
authorAbhishek Shrivastava <abhishek@cloudbyte.com>
Fri, 25 Sep 2015 06:53:38 +0000 (12:23 +0530)
committerAbhishek Shrivastava <abhishek@cloudbyte.com>
Sat, 26 Sep 2015 09:53:41 +0000 (15:23 +0530)
Currently the volume related operation in CloudByte driver does not:

* Update the ISCSI Initiator Group during volume deletion operation,
and
* During retry of any volume operation it does not catches the exact
cause of the failure happened.

So to deal with the following issues two changes has been done in
CloudByte Driver:

* Added a new method "_update_initiator_group"
ISCSI Initiator Group is one of the parameter added to the volumes
at the time of creation in CloudByte Storage. Using this the external
source can access the volumes easily. By default, Initiator Group
value is set to 'ALL', but it should be changed to 'None' before
deletion. Since the following is not happening, thus volume delete
operation fails from OpenStack. In order to avoid this the
"delete_volume" method now uses the "_update_initiator_group" which
update the volume ISCSI Initiatior Groupof the volumes to 'None'
before deletion, and thus volume delete operation will have no issues
while running from OpenStack.

* Added a check to "_retry_volume_operation"
The _retry_volume_operation method was not able to check the exact
cause of the failure happened during volume operation in CloudByte
Storage, which arises if some invalid parameters are provided in
"cinder.conf" against "cloudbyte backend" or if some anomaly happens
at CloudByte Storage during any volume operation from OpenStack. Due
to this, tracking the ERROR becomes a very difficult task to do. Thus
to resolve this issue a "check" has been added to the method which
will raise the exact cause of the error and thus making it easier to
solve.

Change-Id: Ie385df7c18520ea4abb5640fb354bdd18212c5a3
Closes-Bug: #1499297

cinder/tests/unit/test_cloudbyte.py
cinder/volume/drivers/cloudbyte/cloudbyte.py

index e51aecf39405997bce24cb8b056e73f86b13a7a5..4281cae35f98d0c2f18dc8bfbb535d9cd7068e10 100644 (file)
@@ -879,8 +879,8 @@ class CloudByteISCSIDriverTestCase(testtools.TestCase):
         # run the test
         self.driver.delete_volume(volume)
 
-        # assert that 3 api calls were invoked
-        self.assertEqual(3, mock_api_req.call_count)
+        # assert that 7 api calls were invoked
+        self.assertEqual(7, mock_api_req.call_count)
 
         # Test-II
 
@@ -912,8 +912,8 @@ class CloudByteISCSIDriverTestCase(testtools.TestCase):
                           self.driver.delete_volume,
                           volume)
 
-        # assert that 2 api calls were invoked
-        self.assertEqual(2, mock_api_req.call_count)
+        # assert that 6 api calls were invoked
+        self.assertEqual(6, mock_api_req.call_count)
 
         # Test - IV
 
@@ -929,8 +929,8 @@ class CloudByteISCSIDriverTestCase(testtools.TestCase):
                           self.driver.delete_volume,
                           volume)
 
-        # assert that 3 api calls were invoked
-        self.assertEqual(3, mock_api_req.call_count)
+        # assert that 7 api calls were invoked
+        self.assertEqual(7, mock_api_req.call_count)
 
     @mock.patch.object(cloudbyte.CloudByteISCSIDriver,
                        '_api_request_for_cloudbyte')
index 56a8c3c08ed7f4aad368205d33209d8716707ed4..e0de39d180c7d870b8b06a42000b3eadcd937f2c 100644 (file)
@@ -38,9 +38,10 @@ class CloudByteISCSIDriver(san.SanISCSIDriver):
         1.0.0 - Initial driver
         1.1.0 - Add chap support and minor bug fixes
         1.1.1 - Add wait logic for delete volumes
+        1.1.2 - Update ig to None before delete volume
     """
 
-    VERSION = '1.1.1'
+    VERSION = '1.1.2'
     volume_stats = {}
 
     def __init__(self, *args, **kwargs):
@@ -285,6 +286,20 @@ class CloudByteISCSIDriver(san.SanISCSIDriver):
                          "volume [%(cb_volume)s]."),
                      {'operation': operation, 'cb_volume': cb_volume})
             raise loopingcall.LoopingCallDone()
+        elif status == 2:
+            job_result = result_res.get("jobresult")
+            err_msg = job_result.get("errortext")
+            err_code = job_result.get("errorcode")
+            msg = (_(
+                "Error in Operation [%(operation)s] "
+                "for volume [%(cb_volume)s] in CloudByte "
+                "storage: [%(cb_error)s], "
+                "error code: [%(error_code)s]."),
+                {'cb_error': err_msg,
+                 'error_code': err_code,
+                 'cb_volume': cb_volume,
+                 'operation': operation})
+            raise exception.VolumeBackendAPIException(data=msg)
         elif count == max_retries:
             # All attempts exhausted
             LOG.error(_LE("CloudByte operation [%(operation)s] failed"
@@ -449,7 +464,7 @@ class CloudByteISCSIDriver(san.SanISCSIDriver):
 
         return model_update
 
-    def _get_initiator_group_id_from_response(self, data):
+    def _get_initiator_group_id_from_response(self, data, filter):
         """Find iSCSI initiator group id."""
 
         ig_list_res = data.get('listInitiatorsResponse')
@@ -468,7 +483,7 @@ class CloudByteISCSIDriver(san.SanISCSIDriver):
         ig_id = None
 
         for ig in ig_list:
-            if ig.get('initiatorgroup') == 'ALL':
+            if ig.get('initiatorgroup') == filter:
                 ig_id = ig['id']
                 break
 
@@ -710,6 +725,37 @@ class CloudByteISCSIDriver(san.SanISCSIDriver):
 
         return model_update
 
+    def _update_initiator_group(self, volume_id, ig_name):
+
+        # Get account id of this account
+        account_name = self.configuration.cb_account_name
+        account_id = self._get_account_id_from_name(account_name)
+
+        # Fetch the initiator group ID
+        params = {"accountid": account_id}
+
+        iscsi_initiator_data = self._api_request_for_cloudbyte(
+            'listiSCSIInitiator', params)
+
+        # Filter the list of initiator groups with the name
+        ig_id = self._get_initiator_group_id_from_response(
+            iscsi_initiator_data, ig_name)
+
+        params = {"storageid": volume_id}
+
+        iscsi_service_data = self._api_request_for_cloudbyte(
+            'listVolumeiSCSIService', params)
+        iscsi_id = self._get_iscsi_service_id_from_response(
+            volume_id, iscsi_service_data)
+
+        # Update the iscsi service with above fetched iscsi_id
+        self._request_update_iscsi_service(iscsi_id, ig_id, None)
+
+        LOG.debug("CloudByte initiator group updated successfully for volume "
+                  "[%(vol)s] with ig [%(ig)s].",
+                  {'vol': volume_id,
+                   'ig': ig_name})
+
     def create_volume(self, volume):
 
         tsm_name = self.configuration.cb_tsm_name
@@ -771,7 +817,7 @@ class CloudByteISCSIDriver(san.SanISCSIDriver):
         iscsi_initiator_data = self._api_request_for_cloudbyte(
             'listiSCSIInitiator', params)
         ig_id = self._get_initiator_group_id_from_response(
-            iscsi_initiator_data)
+            iscsi_initiator_data, 'ALL')
 
         LOG.debug("Updating iscsi service for CloudByte volume [%s].",
                   cb_volume_name)
@@ -828,6 +874,8 @@ class CloudByteISCSIDriver(san.SanISCSIDriver):
 
             # Delete volume at CloudByte
             if cb_volume_id is not None:
+                # Need to set the initiator group to None before deleting
+                self._update_initiator_group(cb_volume_id, 'None')
 
                 params = {"id": cb_volume_id}
                 del_res = self._api_request_for_cloudbyte('deleteFileSystem',