Skip to content

Commit 43f278c

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 9596d3b commit 43f278c

File tree

2 files changed

+66
-38
lines changed

2 files changed

+66
-38
lines changed

Diff for: drivers/linstorvhdutil.py

+48-38
Original file line numberDiff line numberDiff line change
@@ -33,18 +33,21 @@
3333

3434

3535
def call_remote_method(session, host_ref, method, device_path, args):
36+
host_rec = session.xenapi.host.get_record(host_ref)
37+
host_uuid = host_rec['uuid']
38+
3639
try:
3740
response = session.xenapi.host.call_plugin(
3841
host_ref, MANAGER_PLUGIN, method, args
3942
)
4043
except Exception as e:
41-
util.SMlog('call-plugin ({} with {}) exception: {}'.format(
42-
method, args, e
44+
util.SMlog('call-plugin on {} ({} with {}) exception: {}'.format(
45+
host_uuid, method, args, e
4346
))
4447
raise util.SMException(str(e))
4548

46-
util.SMlog('call-plugin ({} with {}) returned: {}'.format(
47-
method, args, response
49+
util.SMlog('call-plugin on {} ({} with {}) returned: {}'.format(
50+
host_uuid, method, args, response
4851
))
4952

5053
return response
@@ -86,33 +89,6 @@ def wrapper(*args, **kwargs):
8689
self._linstor.get_volume_name(vdi_uuid)
8790
)
8891

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

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

131-
return response_parser(self, vdi_uuid, response)
132142
return wrapper
133143
return decorated
134144

Diff for: drivers/linstorvolumemanager.py

+18
Original file line numberDiff line numberDiff line change
@@ -1431,6 +1431,24 @@ def find_up_to_date_diskful_nodes(self, volume_uuid):
14311431

14321432
return (node_names, in_use_by)
14331433

1434+
def get_primary(self, volume_uuid):
1435+
"""
1436+
Find the node that opened a volume, i.e. the primary.
1437+
:rtype: str
1438+
"""
1439+
volume_name = self.get_volume_name(volume_uuid)
1440+
1441+
resource_states = filter(
1442+
lambda resource_state: resource_state.name == volume_name,
1443+
self._get_resource_cache().resource_states
1444+
)
1445+
1446+
for resource_state in resource_states:
1447+
if resource_state.in_use:
1448+
return resource_state.node_name
1449+
1450+
return None
1451+
14341452
def invalidate_resource_cache(self):
14351453
"""
14361454
If resources are impacted by external commands like vhdutil,

0 commit comments

Comments
 (0)