Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 67 additions & 38 deletions drivers/linstorvhdutil.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,13 @@ def call_remote_method(session, host_ref, method, device_path, args):
host_ref, MANAGER_PLUGIN, method, args
)
except Exception as e:
util.SMlog('call-plugin ({} with {}) exception: {}'.format(
method, args, e
util.SMlog('call-plugin on {} ({} with {}) exception: {}'.format(
host_ref, method, args, e
))
raise util.SMException(str(e))

util.SMlog('call-plugin ({} with {}) returned: {}'.format(
method, args, response
util.SMlog('call-plugin on {} ({} with {}) returned: {}'.format(
host_ref, method, args, response
))

return response
Expand Down Expand Up @@ -74,6 +74,24 @@ class ErofsLinstorCallException(LinstorCallException):
class NoPathLinstorCallException(LinstorCallException):
pass

def log_successful_call(target_host, device_path, vdi_uuid, remote_method, response):
util.SMlog(
'Successful access on {} for device {} ({}): `{}` => {}'.format(target_host, device_path, vdi_uuid, remote_method, str(response)),
priority=util.LOG_DEBUG
)

def log_failed_call(target_host, next_target, device_path, vdi_uuid, remote_method, e):
util.SMlog(
'Failed to call method on {} for device {} ({}): {}. Trying accessing on {}... (cause: {})'.format(
target_host,
device_path,
vdi_uuid,
remote_method,
next_target,
e
),
priority=util.LOG_DEBUG
)

def linstorhostcall(local_method, remote_method):
def decorated(response_parser):
Expand All @@ -85,33 +103,6 @@ def wrapper(*args, **kwargs):
self._linstor.get_volume_name(vdi_uuid)
)

# A. Try a call using directly the DRBD device to avoid
# remote request.

# Try to read locally if the device is not in use or if the device
# is up to date and not diskless.
(node_names, in_use_by) = \
self._linstor.find_up_to_date_diskful_nodes(vdi_uuid)

local_e = None
try:
if not in_use_by or socket.gethostname() in node_names:
return self._call_local_method(local_method, device_path, *args[2:], **kwargs)
except ErofsLinstorCallException as e:
local_e = e.cmd_err
except Exception as e:
local_e = e

util.SMlog(
'unable to execute `{}` locally, retry using a readable host... (cause: {})'.format(
remote_method, local_e if local_e else 'local diskless + in use or not up to date'
)
)

if in_use_by:
node_names = {in_use_by}

# B. Execute the plugin on master or slave.
remote_args = {
'devicePath': device_path,
'groupName': self._linstor.group_name
Expand All @@ -120,14 +111,52 @@ def wrapper(*args, **kwargs):
remote_args = {str(key): str(value) for key, value in remote_args.items()}

try:
def remote_call():
host_ref = self._get_readonly_host(vdi_uuid, device_path, node_names)
return call_remote_method(self._session, host_ref, remote_method, device_path, remote_args)
response = util.retry(remote_call, 5, 2)
except Exception as remote_e:
self._raise_openers_exception(device_path, local_e or remote_e)
host_ref_attached = next(iter(util.get_hosts_attached_on(self._session, [vdi_uuid])))
if host_ref_attached:
response = call_remote_method(
self._session, host_ref_attached, remote_method, device_path, remote_args
)
log_successful_call('attached node', device_path, vdi_uuid, remote_method, response)
return response_parser(self, vdi_uuid, response)
except Exception as e:
log_failed_call('attached node', 'master', device_path, vdi_uuid, remote_method, e)

try:
master_ref = util.get_master_ref(self._session)
response = call_remote_method(self._session, master_ref, remote_method, device_path, remote_args)
log_successful_call('master', device_path, vdi_uuid, remote_method, response)
return response_parser(self, vdi_uuid, response)
except Exception as e:
log_failed_call('master', 'primary', device_path, vdi_uuid, remote_method, e)


nodes, primary_hostname = self._linstor.find_up_to_date_diskful_nodes(vdi_uuid)
if primary_hostname:
try:
host_ref = self._get_readonly_host(vdi_uuid, device_path, {primary_hostname})
response = call_remote_method(self._session, host_ref, remote_method, device_path, remote_args)
log_successful_call('primary', device_path, vdi_uuid, remote_method, response)
return response_parser(self, vdi_uuid, response)
except Exception as remote_e:
self._raise_openers_exception(device_path, remote_e)
else:
log_failed_call(
'primary',
'another node',
device_path,
vdi_uuid,
remote_method,
'no primary'
)

try:
host = self._get_readonly_host(vdi_uuid, device_path, nodes)
response = call_remote_method(self._session, host, remote_method, device_path, remote_args)
log_successful_call('another node', device_path, vdi_uuid, remote_method, response)
return response_parser(self, vdi_uuid, response)
except Exception as remote_e:
self._raise_openers_exception(device_path, remote_e)

return response_parser(self, vdi_uuid, response)
return wrapper
return decorated

Expand Down
4 changes: 2 additions & 2 deletions drivers/linstorvolumemanager.py
Original file line number Diff line number Diff line change
Expand Up @@ -1058,7 +1058,7 @@ def update_volume_uuid(self, volume_uuid, new_volume_uuid, force=False):

# 5. Ok!
volume_properties[self.PROP_NOT_EXISTS] = self.STATE_EXISTS
except Exception as e:
except Exception as err:
try:
# Clear the new volume properties in case of failure.
assert volume_properties.namespace == \
Expand All @@ -1070,7 +1070,7 @@ def update_volume_uuid(self, volume_uuid, new_volume_uuid, force=False):
.format(e)
)
raise LinstorVolumeManagerError(
'Failed to copy volume properties: {}'.format(e)
'Failed to copy volume properties: {}'.format(err)
)

try:
Expand Down