Skip to content

Commit 9978d7f

Browse files
YthogthaNambrok
authored andcommitted
fix(blktap2): retry host key tag removal on XAPI HTTP failure (#149)
- Add a decorator to retry a method when a XAPI call fails with HTTPStatus.INTERNAL_SERVER_ERROR. - Decorate blktap2:_get_pool_config(): this method gets data, therefore it can be retried. - Decorate blktap2:_check_tag(). - Retry plugin call of cancel_coalesce_master in blktap2:_check_journal_coalesce_chain(). - Remove superfluous calls to XAPI in blktap2:activate(). Signed-off-by: Arnaud Garcia-Fernandez <arnaud.garcia-fernandez@vates.tech>
1 parent 441d074 commit 9978d7f

2 files changed

Lines changed: 40 additions & 23 deletions

File tree

drivers/blktap2.py

Lines changed: 17 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@
3030
from lock import Lock
3131
import util
3232
import xmlrpc.client
33-
import http.client
3433
import errno
3534
import signal
3635
import subprocess
@@ -1556,6 +1555,13 @@ def call_pluginhandler(cls, session, host_ref, sr_uuid, vdi_uuid, action,
15561555
util.logException("BLKTAP2:call_pluginhandler %s" % e)
15571556
return False
15581557

1558+
@util.xapi_safe_call
1559+
def _call_xapi_plugin(self, *args):
1560+
"""
1561+
wrapper to retry xenapi.host.call_plugin on XAPI HTTP failure.
1562+
"""
1563+
return self._session.xenapi.host.call_plugin(*args)
1564+
15591565
def _add_tag(self, vdi_uuid, writable):
15601566
util.SMlog("Adding tag to: %s" % vdi_uuid)
15611567
attach_mode = "RO"
@@ -1601,6 +1607,7 @@ def _add_tag(self, vdi_uuid, writable):
16011607
util.SMlog("Activate lock succeeded")
16021608
return True
16031609

1610+
@util.xapi_safe_call
16041611
def _check_tag(self, vdi_uuid):
16051612
vdi_ref = self._session.xenapi.VDI.get_by_uuid(vdi_uuid)
16061613
sm_config = self._session.xenapi.VDI.get_sm_config(vdi_ref)
@@ -1609,6 +1616,7 @@ def _check_tag(self, vdi_uuid):
16091616
return False
16101617
return True
16111618

1619+
@util.xapi_safe_call
16121620
def _remove_tag(self, vdi_uuid):
16131621
vdi_ref = self._session.xenapi.VDI.get_by_uuid(vdi_uuid)
16141622
host_ref = self._session.xenapi.host.get_by_uuid(util.get_this_host())
@@ -1620,8 +1628,9 @@ def _remove_tag(self, vdi_uuid):
16201628
else:
16211629
util.SMlog("_remove_tag: host key %s not found, ignore" % host_key)
16221630

1631+
@util.xapi_safe_call
16231632
def _get_pool_config(self, pool_name):
1624-
pool_info = dict()
1633+
pool_info = {}
16251634
vdi_ref = self.target.vdi.sr.srcmd.params.get('vdi_ref')
16261635
if not vdi_ref:
16271636
# attach_from_config context: HA disks don't need to be in any
@@ -1706,9 +1715,7 @@ def activate(self, sr_uuid, vdi_uuid, writable, caching_params):
17061715
options = {"rdonly": not writable}
17071716
options.update(caching_params)
17081717

1709-
sr_ref = self.target.vdi.sr.srcmd.params.get('sr_ref')
1710-
sr_other_config = self._session.xenapi.SR.get_other_config(sr_ref)
1711-
for i in range(self.ATTACH_DETACH_RETRY_SECS):
1718+
for _ in range(self.ATTACH_DETACH_RETRY_SECS):
17121719
try:
17131720
if self._activate_locked(sr_uuid, vdi_uuid, options):
17141721
return
@@ -1795,8 +1802,8 @@ def _check_journal_coalesce_chain(self, sr_uuid: str, vdi_uuid: str) -> bool:
17951802
host_ref = self._get_sr_master_host_ref()
17961803
for vdi in vdi_to_cancel:
17971804
args = {"sr_uuid": sr_uuid, "vdi_uuid": vdi}
1798-
util.SMlog("Calling cancel_coalesce_master with args: {}".format(args))
1799-
self._session.xenapi.host.call_plugin(\
1805+
util.SMlog(f"Calling cancel_coalesce_master with args: {args}")
1806+
self._call_xapi_plugin(
18001807
host_ref, PLUGIN_ON_SLAVE, "cancel_coalesce_master", args)
18011808

18021809
return True
@@ -1871,22 +1878,9 @@ def _activate_locked(self, sr_uuid, vdi_uuid, options):
18711878
util.SMlog("Exception in activate/attach")
18721879
if self.tap_wanted():
18731880
util.fistpoint.activate_custom_fn(
1874-
"blktap_activate_error_handling",
1875-
lambda: time.sleep(30))
1876-
while True:
1877-
try:
1878-
self._remove_tag(vdi_uuid)
1879-
break
1880-
except xmlrpc.client.ProtocolError as e:
1881-
# If there's a connection error, keep trying forever.
1882-
if e.errcode == http.HTTPStatus.INTERNAL_SERVER_ERROR.value:
1883-
continue
1884-
else:
1885-
util.SMlog('failed to remove tag: %s' % e)
1886-
break
1887-
except Exception as e:
1888-
util.SMlog('failed to remove tag: %s' % e)
1889-
break
1881+
"blktap_activate_error_handling",
1882+
lambda: time.sleep(30))
1883+
self._remove_tag(vdi_uuid)
18901884
raise
18911885
finally:
18921886
vdi_ref = self._session.xenapi.VDI.get_by_uuid(vdi_uuid)

drivers/util.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
import xs_errors
4040
import XenAPI # pylint: disable=import-error
4141
import xmlrpc.client
42+
import http.client
4243
import base64
4344
import syslog
4445
import resource
@@ -783,6 +784,28 @@ def get_localAPI_session():
783784
return session
784785

785786

787+
def xapi_safe_call(function):
788+
"""
789+
Decorator to catch classic XAPI connection problems and retry forever.
790+
The method should be only called for XAPI calls.
791+
eg: blktap2.py#VDI:_remove_tag()
792+
"""
793+
def wrapper(*args, **kwargs):
794+
call_str = f"{function.__name__}(args={args}, kwargs={kwargs})"
795+
while True:
796+
try:
797+
return function(*args, **kwargs)
798+
except xmlrpc.client.ProtocolError as e:
799+
# If there's a connection error, keep trying forever.
800+
if e.errcode == http.HTTPStatus.INTERNAL_SERVER_ERROR.value:
801+
continue
802+
raise
803+
except Exception as e:
804+
SMlog(f"Failed XAPI call `{call_str}`: `{e}`")
805+
raise
806+
return wrapper
807+
808+
786809
def get_this_host():
787810
uuid = None
788811
f = open("/etc/xensource-inventory", 'r')

0 commit comments

Comments
 (0)