Merge "Add retry in VNX driver when DB lock error happened"
This commit is contained in:
commit
200f2b02fb
@ -39,6 +39,9 @@ MSG_INTERFACE_NON_EXISTENT = '13691781134'
|
||||
MSG_JOIN_DOMAIN = '13157007726'
|
||||
MSG_UNJOIN_DOMAIN = '13157007723'
|
||||
|
||||
# Necessary to retry when VNX database is locked for provisioning operation
|
||||
MSG_CODE_RETRY = '13421840537'
|
||||
|
||||
IP_ALLOCATIONS = 2
|
||||
|
||||
CONTENT_TYPE_URLENCODE = {'Content-Type': 'application/x-www-form-urlencoded'}
|
||||
|
@ -98,7 +98,7 @@ class StorageObject(object):
|
||||
'info': response})
|
||||
|
||||
def _response_validation(self, response, error_code):
|
||||
"""Translate different status to ok/error status."""
|
||||
"""Validates whether a response includes a certain error code."""
|
||||
msg_codes = self._get_problem_message_codes(response['problems'])
|
||||
|
||||
for code in msg_codes:
|
||||
@ -146,6 +146,7 @@ class StorageObject(object):
|
||||
)
|
||||
)
|
||||
|
||||
@utils.retry(exception.EMCVnxLockRequiredException)
|
||||
def _send_request(self, req):
|
||||
req_xml = constants.XML_HEADER + ET.tostring(req).decode('utf-8')
|
||||
|
||||
@ -155,6 +156,11 @@ class StorageObject(object):
|
||||
|
||||
self._translate_response(response)
|
||||
|
||||
if (response['maxSeverity'] != constants.STATUS_OK and
|
||||
self._response_validation(response,
|
||||
constants.MSG_CODE_RETRY)):
|
||||
raise exception.EMCVnxLockRequiredException
|
||||
|
||||
return response
|
||||
|
||||
@utils.retry(exception.EMCVnxLockRequiredException)
|
||||
|
@ -247,6 +247,21 @@ class StorageObjectTestData(object):
|
||||
'</Fault> '
|
||||
)
|
||||
|
||||
@response
|
||||
def resp_need_retry(self):
|
||||
return ('<TaskResponse taskId="915525">'
|
||||
'<Status maxSeverity = "error">'
|
||||
'<Problem messageCode = "13421840537" component = "fake"'
|
||||
' message = "unable to acquire lock(s), try later"'
|
||||
' severity = "error" >'
|
||||
'<Description> fake desp. </Description>'
|
||||
'<Action>fake action </Action>'
|
||||
'</Problem></Status></TaskResponse>')
|
||||
|
||||
@start_task
|
||||
def req_fake_start_task(self):
|
||||
return '<StartFake name="foo"></StartFake>'
|
||||
|
||||
|
||||
class FileSystemTestData(StorageObjectTestData):
|
||||
def __init__(self):
|
||||
|
@ -16,6 +16,7 @@
|
||||
import copy
|
||||
|
||||
import ddt
|
||||
from lxml import builder
|
||||
import mock
|
||||
from oslo_concurrency import processutils
|
||||
|
||||
@ -24,6 +25,7 @@ from manila import exception
|
||||
from manila.share.drivers.emc.plugins.vnx import connector
|
||||
from manila.share.drivers.emc.plugins.vnx import constants
|
||||
from manila.share.drivers.emc.plugins.vnx import object_manager as manager
|
||||
from manila.share.drivers.emc.plugins.vnx import xml_api_parser as parser
|
||||
from manila import test
|
||||
from manila.tests.share.drivers.emc.plugins.vnx import fakes
|
||||
from manila.tests.share.drivers.emc.plugins.vnx import utils
|
||||
@ -71,17 +73,17 @@ class StorageObjectManagerTestCase(test.TestCase):
|
||||
fake_type)
|
||||
|
||||
|
||||
class StorageObjectTestCase(test.TestCase):
|
||||
class StorageObjectTestCaseBase(test.TestCase):
|
||||
@mock.patch.object(connector, "XMLAPIConnector", mock.Mock())
|
||||
@mock.patch.object(connector, "SSHConnector", mock.Mock())
|
||||
def setUp(self):
|
||||
super(StorageObjectTestCase, self).setUp()
|
||||
super(StorageObjectTestCaseBase, self).setUp()
|
||||
|
||||
emd_share_driver = fakes.FakeEMCShareDriver()
|
||||
|
||||
self.manager = manager.StorageObjectManager(
|
||||
emd_share_driver.configuration)
|
||||
|
||||
self.base = fakes.StorageObjectTestData()
|
||||
self.pool = fakes.PoolTestData()
|
||||
self.vdm = fakes.VDMTestData()
|
||||
self.mover = fakes.MoverTestData()
|
||||
@ -94,7 +96,32 @@ class StorageObjectTestCase(test.TestCase):
|
||||
self.dns = fakes.DNSDomainTestData()
|
||||
|
||||
|
||||
class FileSystemTestCase(StorageObjectTestCase):
|
||||
class StorageObjectTestCase(StorageObjectTestCaseBase):
|
||||
|
||||
def test_xml_api_retry(self):
|
||||
hook = utils.RequestSideEffect()
|
||||
hook.append(self.base.resp_need_retry())
|
||||
hook.append(self.base.resp_task_succeed())
|
||||
elt_maker = builder.ElementMaker(nsmap={None: constants.XML_NAMESPACE})
|
||||
xml_parser = parser.XMLAPIParser()
|
||||
storage_object = manager.StorageObject(self.manager.connectors,
|
||||
elt_maker, xml_parser,
|
||||
self.manager)
|
||||
storage_object.conn['XML'].request = utils.EMCMock(side_effect=hook)
|
||||
fake_req = storage_object._build_task_package(
|
||||
elt_maker.StartFake(name='foo')
|
||||
)
|
||||
resp = storage_object._send_request(fake_req)
|
||||
self.assertEqual('ok', resp['maxSeverity'])
|
||||
|
||||
expected_calls = [
|
||||
mock.call(self.base.req_fake_start_task()),
|
||||
mock.call(self.base.req_fake_start_task())
|
||||
]
|
||||
storage_object.conn['XML'].request.assert_has_calls(expected_calls)
|
||||
|
||||
|
||||
class FileSystemTestCase(StorageObjectTestCaseBase):
|
||||
def setUp(self):
|
||||
super(self.__class__, self).setUp()
|
||||
self.hook = utils.RequestSideEffect()
|
||||
@ -507,7 +534,7 @@ class FileSystemTestCase(StorageObjectTestCase):
|
||||
context.conn['SSH'].run_ssh.assert_has_calls(ssh_calls)
|
||||
|
||||
|
||||
class MountPointTestCase(StorageObjectTestCase):
|
||||
class MountPointTestCase(StorageObjectTestCaseBase):
|
||||
def setUp(self):
|
||||
super(self.__class__, self).setUp()
|
||||
self.hook = utils.RequestSideEffect()
|
||||
@ -824,7 +851,7 @@ class MountPointTestCase(StorageObjectTestCase):
|
||||
context.conn['XML'].request.assert_has_calls(expected_calls)
|
||||
|
||||
|
||||
class VDMTestCase(StorageObjectTestCase):
|
||||
class VDMTestCase(StorageObjectTestCaseBase):
|
||||
def setUp(self):
|
||||
super(self.__class__, self).setUp()
|
||||
self.hook = utils.RequestSideEffect()
|
||||
@ -1088,7 +1115,7 @@ class VDMTestCase(StorageObjectTestCase):
|
||||
context.conn['SSH'].run_ssh.assert_has_calls(ssh_calls)
|
||||
|
||||
|
||||
class StoragePoolTestCase(StorageObjectTestCase):
|
||||
class StoragePoolTestCase(StorageObjectTestCaseBase):
|
||||
def setUp(self):
|
||||
super(self.__class__, self).setUp()
|
||||
self.hook = utils.RequestSideEffect()
|
||||
@ -1155,7 +1182,7 @@ class StoragePoolTestCase(StorageObjectTestCase):
|
||||
context.conn['XML'].request.assert_has_calls(expected_calls)
|
||||
|
||||
|
||||
class MoverTestCase(StorageObjectTestCase):
|
||||
class MoverTestCase(StorageObjectTestCaseBase):
|
||||
def setUp(self):
|
||||
super(self.__class__, self).setUp()
|
||||
self.hook = utils.RequestSideEffect()
|
||||
@ -1332,7 +1359,7 @@ class MoverTestCase(StorageObjectTestCase):
|
||||
context.conn['SSH'].run_ssh.assert_has_calls(ssh_calls)
|
||||
|
||||
|
||||
class SnapshotTestCase(StorageObjectTestCase):
|
||||
class SnapshotTestCase(StorageObjectTestCaseBase):
|
||||
def setUp(self):
|
||||
super(self.__class__, self).setUp()
|
||||
self.hook = utils.RequestSideEffect()
|
||||
@ -1522,7 +1549,7 @@ class SnapshotTestCase(StorageObjectTestCase):
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class MoverInterfaceTestCase(StorageObjectTestCase):
|
||||
class MoverInterfaceTestCase(StorageObjectTestCaseBase):
|
||||
def setUp(self):
|
||||
super(self.__class__, self).setUp()
|
||||
self.hook = utils.RequestSideEffect()
|
||||
@ -1815,7 +1842,7 @@ class MoverInterfaceTestCase(StorageObjectTestCase):
|
||||
context.conn['XML'].request.assert_has_calls(expected_calls)
|
||||
|
||||
|
||||
class DNSDomainTestCase(StorageObjectTestCase):
|
||||
class DNSDomainTestCase(StorageObjectTestCaseBase):
|
||||
def setUp(self):
|
||||
super(self.__class__, self).setUp()
|
||||
self.hook = utils.RequestSideEffect()
|
||||
@ -1925,7 +1952,7 @@ class DNSDomainTestCase(StorageObjectTestCase):
|
||||
self.assertTrue(sleep_mock.called)
|
||||
|
||||
|
||||
class CIFSServerTestCase(StorageObjectTestCase):
|
||||
class CIFSServerTestCase(StorageObjectTestCaseBase):
|
||||
def setUp(self):
|
||||
super(self.__class__, self).setUp()
|
||||
self.hook = utils.RequestSideEffect()
|
||||
@ -2363,7 +2390,7 @@ class CIFSServerTestCase(StorageObjectTestCase):
|
||||
context.conn['XML'].request.assert_has_calls(expected_calls)
|
||||
|
||||
|
||||
class CIFSShareTestCase(StorageObjectTestCase):
|
||||
class CIFSShareTestCase(StorageObjectTestCaseBase):
|
||||
def setUp(self):
|
||||
super(self.__class__, self).setUp()
|
||||
self.hook = utils.RequestSideEffect()
|
||||
@ -2712,7 +2739,7 @@ class CIFSShareTestCase(StorageObjectTestCase):
|
||||
context.conn['SSH'].run_ssh.assert_has_calls(ssh_calls)
|
||||
|
||||
|
||||
class NFSShareTestCase(StorageObjectTestCase):
|
||||
class NFSShareTestCase(StorageObjectTestCaseBase):
|
||||
def setUp(self):
|
||||
super(self.__class__, self).setUp()
|
||||
self.ssh_hook = utils.SSHSideEffect()
|
||||
|
Loading…
Reference in New Issue
Block a user