]> review.fuel-infra Code Review - openstack-build/cinder-build.git/commitdiff
Decrement remaining retries after failed REST call.
authorRichard Hedlind <richard.hedlind@x-io.com>
Wed, 11 Mar 2015 05:46:48 +0000 (23:46 -0600)
committerRichard Hedlind <richard.hedlind@x-io.com>
Mon, 16 Mar 2015 22:28:45 +0000 (16:28 -0600)
Also, update unit test to properly test the retry path.

Change-Id: I89863a44102bdeebce09de80fa5c5131af67f564
Closes-Bug: #1429283

cinder/tests/test_xio.py
cinder/volume/drivers/xio.py

index ed6af574e9b737248aab38b50a2938c1449339a5..49a75b8eee73e8cdc3b12c7189fc2c31eb12e607 100644 (file)
@@ -78,6 +78,9 @@ FC_CONN2 = {'wwpns': ['init_wwn3', 'init_wwn4'],
 
 ISE_HTTP_IP = 'http://' + ISE_IP1
 
+ISE_HOST_LOCATION = '/storage/hosts/1'
+ISE_HOST_LOCATION_URL = ISE_HTTP_IP + ISE_HOST_LOCATION
+
 ISE_VOLUME1_LOCATION = '/storage/volumes/volume1'
 ISE_VOLUME1_LOCATION_URL = ISE_HTTP_IP + ISE_VOLUME1_LOCATION
 ISE_VOLUME2_LOCATION = '/storage/volumes/volume2'
@@ -121,6 +124,74 @@ ISE_GET_QUERY_RESP =\
      'location': '',
      'content': " ".join(ISE_GET_QUERY_XML.split())}
 
+ISE_GET_QUERY_NO_CAP_XML =\
+    """<array>
+        <globalid>ABC12345</globalid>
+        <controllers>
+            <controller>
+                <ipaddress>%s</ipaddress>
+                <rank value="1"/>
+            </controller>
+            <controller>
+                <ipaddress>%s</ipaddress>
+                <rank value="0"/>
+            </controller>
+        </controllers>
+       </array>""" % (ISE_IP1, ISE_IP2)
+
+ISE_GET_QUERY_NO_CAP_RESP =\
+    {'status': 200,
+     'location': '',
+     'content': " ".join(ISE_GET_QUERY_NO_CAP_XML.split())}
+
+ISE_GET_QUERY_NO_CTRL_XML =\
+    """<array>
+        <globalid>ABC12345</globalid>
+        <capabilities>
+            <capability value="3" string="Storage" type="source"/>
+            <capability value="49003" string="Volume Affinity"/>
+            <capability value="49004" string="Volume Quality of Service IOPS"/>
+            <capability value="49005" string="Thin Provisioning"/>
+            <capability value="49006" string="Clones" type="source"/>
+            <capability value="49007" string="Thin clones" type="source"/>
+            <capability value="49007" string="Thin clones" type="source"/>
+        </capabilities>
+       </array>"""
+
+ISE_GET_QUERY_NO_CTRL_RESP =\
+    {'status': 200,
+     'location': '',
+     'content': " ".join(ISE_GET_QUERY_NO_CTRL_XML.split())}
+
+ISE_GET_QUERY_NO_IP_XML =\
+    """<array>
+        <globalid>ABC12345</globalid>
+        <capabilities>
+            <test value="1"/>
+            <capability value="3" string="Storage" type="source"/>
+            <capability value="49003" string="Volume Affinity"/>
+            <capability value="49004" string="Volume Quality of Service IOPS"/>
+            <capability value="49005" string="Thin Provisioning"/>
+            <capability value="49006" string="Clones" type="source"/>
+            <capability value="49007" string="Thin clones" type="source"/>
+            <capability value="49007" string="Thin clones" type="source"/>
+        </capabilities>
+        <controllers>
+            <test value="2"/>
+            <controller>
+                <rank value="1"/>
+            </controller>
+            <controller>
+                <rank value="0"/>
+            </controller>
+        </controllers>
+       </array>"""
+
+ISE_GET_QUERY_NO_IP_RESP =\
+    {'status': 200,
+     'location': '',
+     'content': " ".join(ISE_GET_QUERY_NO_IP_XML.split())}
+
 ISE_GET_QUERY_NO_GID_XML =\
     """<array>
         <capabilities>
@@ -414,6 +485,7 @@ ISE_GET_HOSTS_NOHOST_RESP =\
 ISE_GET_HOSTS_HOST1_XML =\
     """<hosts self="http://ip/storage/hosts">
         <host self="http://ip/storage/hosts/1">
+            <type>"OPENSTACK"</type>
             <name>%s</name>
             <id>1</id>
             <endpoints self="http://ip/storage/endpoints">
@@ -435,6 +507,31 @@ ISE_GET_HOSTS_HOST1_RESP =\
      'location': '',
      'content': " ".join(ISE_GET_HOSTS_HOST1_XML.split())}
 
+ISE_GET_HOSTS_HOST1_HOST_TYPE_XML =\
+    """<hosts self="http://ip/storage/hosts">
+        <host self="http://ip/storage/hosts/1">
+            <type>"WINDOWS"</type>
+            <name>%s</name>
+            <id>1</id>
+            <endpoints self="http://ip/storage/endpoints">
+                <endpoint self="http://ip/storage/endpoints/ep1">
+                    <globalid>init_wwn1</globalid>
+                </endpoint>
+                <endpoint self="http://ip/storage/endpoints/ep2">
+                    <globalid>init_wwn2</globalid>
+                </endpoint>
+                <endpoint self="http://ip/storage/endpoints/ep1">
+                    <globalid>init_iqn1</globalid>
+                </endpoint>
+            </endpoints>
+        </host>
+       </hosts>""" % HOST1
+
+ISE_GET_HOSTS_HOST1_HOST_TYPE_RESP =\
+    {'status': 200,
+     'location': '',
+     'content': " ".join(ISE_GET_HOSTS_HOST1_HOST_TYPE_XML.split())}
+
 ISE_GET_HOSTS_HOST2_XML =\
     """<hosts self="http://ip/storage/hosts">
         <host self="http://ip/storage/hosts/2">
@@ -588,6 +685,13 @@ ISE_MODIFY_VOLUME_RESP =\
      'location': ISE_VOLUME1_LOCATION_URL,
      'content': " ".join(ISE_MODIFY_VOLUME_XML.split())}
 
+ISE_MODIFY_HOST_XML = """<host/>"""
+
+ISE_MODIFY_HOST_RESP =\
+    {'status': 201,
+     'location': ISE_HOST_LOCATION_URL,
+     'content': " ".join(ISE_MODIFY_HOST_XML.split())}
+
 ISE_BAD_CONNECTION_RESP =\
     {'status': 0,
      'location': '',
@@ -688,6 +792,7 @@ class XIOISEDriverTestCase(object):
     def test_do_setup(self, mock_req):
         self.setup_driver()
         mock_req.side_effect = iter([ISE_GET_QUERY_RESP])
+        self.driver.do_setup(None)
 
     def test_negative_do_setup_no_clone_support(self, mock_req):
         self.setup_driver()
@@ -695,6 +800,23 @@ class XIOISEDriverTestCase(object):
         self.assertRaises(exception.XIODriverException,
                           self.driver.do_setup, None)
 
+    def test_negative_do_setup_no_capabilities(self, mock_req):
+        self.setup_driver()
+        mock_req.side_effect = iter([ISE_GET_QUERY_NO_CAP_RESP])
+        self.assertRaises(exception.XIODriverException,
+                          self.driver.do_setup, None)
+
+    def test_negative_do_setup_no_ctrl(self, mock_req):
+        self.setup_driver()
+        mock_req.side_effect = iter([ISE_GET_QUERY_NO_CTRL_RESP])
+        self.assertRaises(exception.XIODriverException,
+                          self.driver.do_setup, None)
+
+    def test_negative_do_setup_no_ipaddress(self, mock_req):
+        self.setup_driver()
+        mock_req.side_effect = iter([ISE_GET_QUERY_NO_IP_RESP])
+        self.driver.do_setup(None)
+
     def test_negative_do_setup_bad_globalid_none(self, mock_req):
         self.setup_driver()
         mock_req.side_effect = iter([ISE_GET_QUERY_NO_GID_RESP])
@@ -742,7 +864,7 @@ class XIOISEDriverTestCase(object):
             protocol = 'fibre_channel'
         exp_result = {}
         exp_result = {'vendor_name': "X-IO",
-                      'driver_version': "1.1.0",
+                      'driver_version': "1.1.1",
                       'volume_backend_name': backend_name,
                       'reserved_percentage': 0,
                       'total_capacity_gb': 100,
@@ -908,6 +1030,37 @@ class XIOISEDriverTestCase(object):
             self.driver.initialize_connection(VOLUME1, self.connector)
         self.assertDictMatch(exp_result, act_result)
 
+    def test_initialize_connection_positive_host_type(self, mock_req):
+        mock_req.side_effect = iter([ISE_GET_QUERY_RESP,
+                                     ISE_GET_HOSTS_HOST1_HOST_TYPE_RESP,
+                                     ISE_MODIFY_HOST_RESP,
+                                     ISE_CREATE_ALLOC_RESP,
+                                     ISE_GET_ALLOC_WITH_EP_RESP,
+                                     ISE_GET_CONTROLLERS_RESP])
+        self.setup_driver()
+
+        exp_result = {}
+        if self.configuration.ise_protocol == 'iscsi':
+            exp_result = {"driver_volume_type": "iscsi",
+                          "data": {"target_lun": '1',
+                                   "volume_id": '1',
+                                   "access_mode": 'rw',
+                                   "target_discovered": False,
+                                   "target_iqn": ISE_IQN,
+                                   "target_portal": ISE_ISCSI_IP1 + ":3260"}}
+        elif self.configuration.ise_protocol == 'fibre_channel':
+            exp_result = {"driver_volume_type": "fibre_channel",
+                          "data": {"target_lun": '1',
+                                   "volume_id": '1',
+                                   "access_mode": 'rw',
+                                   "target_discovered": True,
+                                   "initiator_target_map": ISE_INIT_TARGET_MAP,
+                                   "target_wwn": ISE_TARGETS}}
+
+        act_result =\
+            self.driver.initialize_connection(VOLUME1, self.connector)
+        self.assertDictMatch(exp_result, act_result)
+
     def test_initialize_connection_positive_chap(self, mock_req):
         mock_req.side_effect = iter([ISE_GET_QUERY_RESP,
                                      ISE_GET_HOSTS_HOST2_RESP,
@@ -942,6 +1095,25 @@ class XIOISEDriverTestCase(object):
             self.driver.initialize_connection(VOLUME2, self.connector)
         self.assertDictMatch(exp_result, act_result)
 
+    def test_initialize_connection_negative_no_host(self, mock_req):
+        mock_req.side_effect = iter([ISE_GET_QUERY_RESP,
+                                     ISE_GET_HOSTS_HOST2_RESP,
+                                     ISE_CREATE_HOST_RESP,
+                                     ISE_GET_HOSTS_HOST2_RESP])
+        self.setup_driver()
+        self.assertRaises(exception.XIODriverException,
+                          self.driver.initialize_connection,
+                          VOLUME2, self.connector)
+
+    def test_initialize_connection_negative_host_type(self, mock_req):
+        mock_req.side_effect = iter([ISE_GET_QUERY_RESP,
+                                     ISE_GET_HOSTS_HOST1_HOST_TYPE_RESP,
+                                     ISE_400_RESP])
+        self.setup_driver()
+        self.assertRaises(exception.XIODriverException,
+                          self.driver.initialize_connection,
+                          VOLUME2, self.connector)
+
     def test_terminate_connection_positive(self, mock_req):
         self.setup_driver()
         if self.configuration.ise_protocol == 'iscsi':
@@ -1052,8 +1224,12 @@ class XIOISEDriverTestCase(object):
 
         mock_req.side_effect = iter([ISE_GET_QUERY_RESP,
                                      ISE_GET_VOL1_STATUS_RESP,
+                                     ISE_400_INVALID_STATE_RESP,
+                                     ISE_400_INVALID_STATE_RESP,
+                                     ISE_400_INVALID_STATE_RESP,
+                                     ISE_400_INVALID_STATE_RESP,
                                      ISE_400_INVALID_STATE_RESP])
-        self.configuration.ise_completion_retries = 1
+        self.configuration.ise_completion_retries = 5
         self.setup_driver()
         self.assertRaises(exception.XIODriverException,
                           self.driver.create_snapshot, SNAPSHOT1)
index 48e3c778cd425e569d2f13e79394e3d9b6954223..a498ee313f368c41da1d3b16a122d5054e2d3e0d 100644 (file)
@@ -64,11 +64,12 @@ def RaiseXIODriverException():
 
 class XIOISEDriver(object):
 
-    VERSION = '1.1.0'
+    VERSION = '1.1.1'
 
     # Version   Changes
     # 1.0.0     Base driver
     # 1.1.0     QoS, affinity, retype and thin support
+    # 1.1.1     Fix retry loop (Bug 1429283)
 
     def __init__(self, *args, **kwargs):
         super(XIOISEDriver, self).__init__()
@@ -349,7 +350,7 @@ class XIOISEDriver(object):
             if remaining == 0:
                 # We are done - let our caller handle response
                 raise loopingcall.LoopingCallDone(response)
-            args['retries'] = remaining
+            loop_args['retries'] = remaining
 
         # Setup retries, interval and call wait function.
         loop_args = {}