Skip to content

Commit 114c78b

Browse files
NambrokWescoeur
andcommitted
feat(Linstor): rewrite linstorhostcall logic
Try to use host_OpaqueRef to access primary then try on the master host if it doesn't work, then find the primary with linstor API or if no primary, any other host. Signed-off-by: Damien Thenot <[email protected]> Co-authored-by: Ronan Abhamon <[email protected]>
1 parent b7b7e43 commit 114c78b

File tree

2 files changed

+66
-38
lines changed

2 files changed

+66
-38
lines changed

drivers/linstorvhdutil.py

Lines changed: 48 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -31,18 +31,21 @@
3131

3232

3333
def call_remote_method(session, host_ref, method, device_path, args):
34+
host_rec = session.xenapi.host.get_record(host_ref)
35+
host_uuid = host_rec['uuid']
36+
3437
try:
3538
response = session.xenapi.host.call_plugin(
3639
host_ref, MANAGER_PLUGIN, method, args
3740
)
3841
except Exception as e:
39-
util.SMlog('call-plugin ({} with {}) exception: {}'.format(
40-
method, args, e
42+
util.SMlog('call-plugin on {} ({} with {}) exception: {}'.format(
43+
host_uuid, method, args, e
4144
))
4245
raise util.SMException(str(e))
4346

44-
util.SMlog('call-plugin ({} with {}) returned: {}'.format(
45-
method, args, response
47+
util.SMlog('call-plugin on {} ({} with {}) returned: {}'.format(
48+
host_uuid, method, args, response
4649
))
4750

4851
return response
@@ -85,33 +88,6 @@ def wrapper(*args, **kwargs):
8588
self._linstor.get_volume_name(vdi_uuid)
8689
)
8790

88-
# A. Try a call using directly the DRBD device to avoid
89-
# remote request.
90-
91-
# Try to read locally if the device is not in use or if the device
92-
# is up to date and not diskless.
93-
(node_names, in_use_by) = \
94-
self._linstor.find_up_to_date_diskful_nodes(vdi_uuid)
95-
96-
local_e = None
97-
try:
98-
if not in_use_by or socket.gethostname() in node_names:
99-
return self._call_local_method(local_method, device_path, *args[2:], **kwargs)
100-
except ErofsLinstorCallException as e:
101-
local_e = e.cmd_err
102-
except Exception as e:
103-
local_e = e
104-
105-
util.SMlog(
106-
'unable to execute `{}` locally, retry using a readable host... (cause: {})'.format(
107-
remote_method, local_e if local_e else 'local diskless + in use or not up to date'
108-
)
109-
)
110-
111-
if in_use_by:
112-
node_names = {in_use_by}
113-
114-
# B. Execute the plugin on master or slave.
11591
remote_args = {
11692
'devicePath': device_path,
11793
'groupName': self._linstor.group_name
@@ -120,14 +96,48 @@ def wrapper(*args, **kwargs):
12096
remote_args = {str(key): str(value) for key, value in remote_args.items()}
12197

12298
try:
123-
def remote_call():
124-
host_ref = self._get_readonly_host(vdi_uuid, device_path, node_names)
125-
return call_remote_method(self._session, host_ref, remote_method, device_path, remote_args)
126-
response = util.retry(remote_call, 5, 2)
127-
except Exception as remote_e:
128-
self._raise_openers_exception(device_path, local_e or remote_e)
99+
host_ref_attached = util.get_hosts_attached_on(self._session, [vdi_uuid])[0]
100+
if host_ref_attached:
101+
response = call_remote_method(
102+
self._session, host_ref_attached, remote_method, device_path, remote_args
103+
)
104+
return response_parser(self, vdi_uuid, response)
105+
except Exception as e:
106+
util.SMlog(
107+
'Failed to call method on attached host. Trying local access... (cause: {})'.format(e),
108+
priority=util.LOG_DEBUG
109+
)
110+
111+
try:
112+
master_ref = self._session.xenapi.pool.get_all_records().values()[0]['master']
113+
response = call_remote_method(self._session, master_ref, remote_method, device_path, remote_args)
114+
return response_parser(self, vdi_uuid, response)
115+
except Exception as e:
116+
util.SMlog(
117+
'Failed to call method on master host. Finding primary node... (cause: {})'.format(e),
118+
priority=util.LOG_DEBUG
119+
)
120+
121+
nodes, primary_hostname = self._linstor.find_up_to_date_diskful_nodes(vdi_uuid)
122+
if primary_hostname:
123+
try:
124+
host_ref = self._get_readonly_host(vdi_uuid, device_path, {primary_hostname})
125+
response = call_remote_method(self._session, host_ref, remote_method, device_path, remote_args)
126+
return response_parser(self, vdi_uuid, response)
127+
except Exception as remote_e:
128+
self._raise_openers_exception(device_path, remote_e)
129+
else:
130+
util.SMlog(
131+
'Couldn\'t get primary for {}. Trying with another node...'.format(vdi_uuid),
132+
priority=util.LOG_DEBUG
133+
)
134+
try:
135+
host = self._get_readonly_host(vdi_uuid, device_path, nodes)
136+
response = call_remote_method(self._session, host, remote_method, device_path, remote_args)
137+
return response_parser(self, vdi_uuid, response)
138+
except Exception as remote_e:
139+
self._raise_openers_exception(device_path, remote_e)
129140

130-
return response_parser(self, vdi_uuid, response)
131141
return wrapper
132142
return decorated
133143

drivers/linstorvolumemanager.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1439,6 +1439,24 @@ def find_up_to_date_diskful_nodes(self, volume_uuid):
14391439

14401440
return (node_names, in_use_by)
14411441

1442+
def get_primary(self, volume_uuid):
1443+
"""
1444+
Find the node that opened a volume, i.e. the primary.
1445+
:rtype: str
1446+
"""
1447+
volume_name = self.get_volume_name(volume_uuid)
1448+
1449+
resource_states = filter(
1450+
lambda resource_state: resource_state.name == volume_name,
1451+
self._get_resource_cache().resource_states
1452+
)
1453+
1454+
for resource_state in resource_states:
1455+
if resource_state.in_use:
1456+
return resource_state.node_name
1457+
1458+
return None
1459+
14421460
def invalidate_resource_cache(self):
14431461
"""
14441462
If resources are impacted by external commands like vhdutil,

0 commit comments

Comments
 (0)