@@ -75,23 +75,14 @@ class NoPathLinstorCallException(LinstorCallException):
7575 pass
7676
7777def log_successful_call (target_host , device_path , vdi_uuid , remote_method , response ):
78- util .SMlog (
79- 'Successful access on {} for device {} ({}): `{}` => {}' .format (target_host , device_path , vdi_uuid , remote_method , str (response )),
80- priority = util .LOG_DEBUG
81- )
78+ util .SMlog ('Successful access on {} for device {} ({}): `{}` => {}' .format (
79+ target_host , device_path , vdi_uuid , remote_method , str (response )
80+ ), priority = util .LOG_DEBUG )
8281
8382def log_failed_call (target_host , next_target , device_path , vdi_uuid , remote_method , e ):
84- util .SMlog (
85- 'Failed to call method on {} for device {} ({}): {}. Trying accessing on {}... (cause: {})' .format (
86- target_host ,
87- device_path ,
88- vdi_uuid ,
89- remote_method ,
90- next_target ,
91- e
92- ),
93- priority = util .LOG_DEBUG
94- )
83+ util .SMlog ('Failed to call method on {} for device {} ({}): {}. Trying accessing on {}... (cause: {})' .format (
84+ target_host , device_path , vdi_uuid , remote_method , next_target , e
85+ ), priority = util .LOG_DEBUG )
9586
9687def linstorhostcall (local_method , remote_method ):
9788 def decorated (response_parser ):
@@ -110,52 +101,44 @@ def wrapper(*args, **kwargs):
110101 remote_args .update (** kwargs )
111102 remote_args = {str (key ): str (value ) for key , value in remote_args .items ()}
112103
104+ def call_method (host_label , host_ref ):
105+ response = call_remote_method (self ._session , host_ref , remote_method , remote_args )
106+ log_successful_call (host_label , device_path , vdi_uuid , remote_method , response )
107+ return response_parser (self , vdi_uuid , response )
108+
109+ # 1. Try on attached host.
113110 try :
114111 host_ref_attached = next (iter (util .get_hosts_attached_on (self ._session , [vdi_uuid ])), None )
115112 if host_ref_attached :
116- response = call_remote_method (
117- self ._session , host_ref_attached , remote_method , device_path , remote_args
118- )
119- log_successful_call ('attached node' , device_path , vdi_uuid , remote_method , response )
120- return response_parser (self , vdi_uuid , response )
113+ return call_method ('attached host' , host_ref_attached )
121114 except Exception as e :
122- log_failed_call ('attached node ' , 'master' , device_path , vdi_uuid , remote_method , e )
115+ log_failed_call ('attached host ' , 'master' , device_path , vdi_uuid , remote_method , e )
123116
117+ # 2. Try on master host.
124118 try :
125- master_ref = util .get_master_ref (self ._session )
126- response = call_remote_method (self ._session , master_ref , remote_method , device_path , remote_args )
127- log_successful_call ('master' , device_path , vdi_uuid , remote_method , response )
128- return response_parser (self , vdi_uuid , response )
119+ return call_method ('master' , util .get_master_ref (self ._session ))
129120 except Exception as e :
130121 log_failed_call ('master' , 'primary' , device_path , vdi_uuid , remote_method , e )
131122
123+ # 3. Try on a primary.
124+ hosts = self ._get_hosts (remote_method , device_path )
132125
133126 nodes , primary_hostname = self ._linstor .find_up_to_date_diskful_nodes (vdi_uuid )
134127 if primary_hostname :
135128 try :
136- host_ref = self ._get_readonly_host (vdi_uuid , device_path , {primary_hostname })
137- response = call_remote_method (self ._session , host_ref , remote_method , device_path , remote_args )
138- log_successful_call ('primary' , device_path , vdi_uuid , remote_method , response )
139- return response_parser (self , vdi_uuid , response )
129+ return call_method ('primary' , self ._find_host_ref_from_hostname (hosts , primary_hostname ))
140130 except Exception as remote_e :
141131 self ._raise_openers_exception (device_path , remote_e )
142- else :
143- log_failed_call (
144- 'primary' ,
145- 'another node' ,
146- device_path ,
147- vdi_uuid ,
148- remote_method ,
149- 'no primary'
150- )
151132
152- try :
153- host = self ._get_readonly_host (vdi_uuid , device_path , nodes )
154- response = call_remote_method (self ._session , host , remote_method , device_path , remote_args )
155- log_successful_call ('another node' , device_path , vdi_uuid , remote_method , response )
156- return response_parser (self , vdi_uuid , response )
157- except Exception as remote_e :
158- self ._raise_openers_exception (device_path , remote_e )
133+ log_failed_call ('primary' , 'another node' , device_path , vdi_uuid , remote_method , 'no primary' )
134+
135+ # 4. Try on any host with local data.
136+ try :
137+ return call_method ('another node' , next (filter (None ,
138+ (self ._find_host_ref_from_hostname (hosts , hostname ) for hostname in nodes )
139+ ), None ))
140+ except Exception as remote_e :
141+ self ._raise_openers_exception (device_path , remote_e )
159142
160143 return wrapper
161144 return decorated
@@ -463,35 +446,22 @@ def _extract_uuid(self, device_path):
463446 device_path .rstrip ('\n ' )
464447 )
465448
466- def _get_readonly_host (self , vdi_uuid , device_path , node_names ):
467- """
468- When vhd-util is called to fetch VDI info we must find a
469- diskful DRBD disk to read the data. It's the goal of this function.
470- Why? Because when a VHD is open in RO mode, the LVM layer is used
471- directly to bypass DRBD verifications (we can have only one process
472- that reads/writes to disk with DRBD devices).
473- """
474-
475- if not node_names :
449+ def _get_hosts (self , remote_method , device_path ):
450+ try :
451+ return self ._session .xenapi .host .get_all_records ()
452+ except Exception as e :
476453 raise xs_errors .XenError (
477454 'VDIUnavailable' ,
478- opterr = 'Unable to find diskful node: {} (path={})'
479- .format (vdi_uuid , device_path )
455+ opterr = 'Unable to get host list to run vhdutil command `{}` (path={}): {} '
456+ .format (remote_method , device_path , e )
480457 )
481458
482- hosts = self ._session .xenapi .host .get_all_records ()
483- for host_ref , host_record in hosts .items ():
484- if host_record ['hostname' ] in node_names :
485- return host_ref
486-
487- raise xs_errors .XenError (
488- 'VDIUnavailable' ,
489- opterr = 'Unable to find a valid host from VDI: {} (path={})'
490- .format (vdi_uuid , device_path )
491- )
492-
493459 # --------------------------------------------------------------------------
494460
461+ @staticmethod
462+ def _find_host_ref_from_hostname (hosts , hostname ):
463+ return next ((ref for ref , rec in hosts .items () if rec ['hostname' ] == hostname ), None )
464+
495465 def _raise_openers_exception (self , device_path , e ):
496466 if isinstance (e , util .CommandException ):
497467 e_str = 'cmd: `{}`, code: `{}`, reason: `{}`' .format (e .cmd , e .code , e .reason )
@@ -560,14 +530,7 @@ def _call_method(self, local_method, remote_method, device_path, use_parent, *ar
560530
561531 # B. Execute the command on another host.
562532 # B.1. Get host list.
563- try :
564- hosts = self ._session .xenapi .host .get_all_records ()
565- except Exception as e :
566- raise xs_errors .XenError (
567- 'VDIUnavailable' ,
568- opterr = 'Unable to get host list to run vhd-util command `{}` (path={}): {}'
569- .format (remote_method , device_path , e )
570- )
533+ hosts = self ._get_hosts (remote_method , device_path )
571534
572535 # B.2. Prepare remote args.
573536 remote_args = {
@@ -602,9 +565,8 @@ def remote_call():
602565 if not openers :
603566 continue
604567
605- try :
606- host_ref = next (ref for ref , rec in hosts .items () if rec ['hostname' ] == hostname )
607- except StopIteration :
568+ host_ref = self ._find_host_ref_from_hostname (hosts , hostname )
569+ if not host_ref :
608570 continue
609571
610572 no_host_found = False
0 commit comments