@@ -41,6 +41,15 @@ class SSHDriver(CommandMixin, Driver, CommandProtocol, FileTransferProtocol):
4141 def __attrs_post_init__ (self ):
4242 super ().__attrs_post_init__ ()
4343 self ._keepalive = None
44+ self ._ssh = self ._get_tool ("ssh" )
45+ self ._scp = self ._get_tool ("scp" )
46+ self ._sshfs = self ._get_tool ("sshfs" )
47+ self ._rsync = self ._get_tool ("rsync" )
48+
49+ def _get_tool (self , name ):
50+ if self .target .env :
51+ return self .target .env .config .get_tool (name )
52+ return name
4453
4554 def _get_username (self ):
4655 """Get the username from this class or from NetworkService"""
@@ -105,7 +114,7 @@ def _start_own_master_once(self, timeout):
105114 self .tmpdir , f'control-{ self .networkservice .address } '
106115 )
107116
108- args = ["ssh" , "-f" , * self .ssh_prefix , "-x" , "-o" , f"ConnectTimeout={ timeout } " ,
117+ args = [self . _ssh , "-f" , * self .ssh_prefix , "-x" , "-o" , f"ConnectTimeout={ timeout } " ,
109118 "-o" , "ControlPersist=300" , "-o" ,
110119 "UserKnownHostsFile=/dev/null" , "-o" , "StrictHostKeyChecking=no" ,
111120 "-o" , "ServerAliveInterval=15" , "-MN" , "-S" , control .replace ('%' , '%%' ), "-p" ,
@@ -203,7 +212,7 @@ def _run(self, cmd, codec="utf-8", decodeerrors="strict", timeout=None):
203212 if not self ._check_keepalive ():
204213 raise ExecutionError ("Keepalive no longer running" )
205214
206- complete_cmd = ["ssh" , "-x" , * self .ssh_prefix ,
215+ complete_cmd = [self . _ssh , "-x" , * self .ssh_prefix ,
207216 "-p" , str (self .networkservice .port ), "-l" , self ._get_username (),
208217 self .networkservice .address
209218 ] + cmd .split (" " )
@@ -238,7 +247,7 @@ def interact(self, cmd=None):
238247 if not self ._check_keepalive ():
239248 raise ExecutionError ("Keepalive no longer running" )
240249
241- complete_cmd = ["ssh" , "-x" , * self .ssh_prefix ,
250+ complete_cmd = [self . _ssh , "-x" , * self .ssh_prefix ,
242251 "-t" ,
243252 self .networkservice .address
244253 ]
@@ -252,7 +261,7 @@ def interact(self, cmd=None):
252261
253262 @contextlib .contextmanager
254263 def _forward (self , forward ):
255- cmd = ["ssh" , * self .ssh_prefix ,
264+ cmd = [self . _ssh , * self .ssh_prefix ,
256265 "-O" , "forward" , forward ,
257266 self .networkservice .address
258267 ]
@@ -261,7 +270,7 @@ def _forward(self, forward):
261270 try :
262271 yield
263272 finally :
264- cmd = ["ssh" , * self .ssh_prefix ,
273+ cmd = [self . _ssh , * self .ssh_prefix ,
265274 "-O" , "cancel" , forward ,
266275 self .networkservice .address
267276 ]
@@ -361,7 +370,8 @@ def scp(self, *, src, dst):
361370 if dst .startswith (':' ):
362371 dst = '_' + dst
363372
364- complete_cmd = ["scp" ,
373+ complete_cmd = [self ._scp ,
374+ "-S" , self ._ssh ,
365375 "-F" , "none" ,
366376 "-o" , f"ControlPath={ self .control .replace ('%' , '%%' )} " ,
367377 src , dst ,
@@ -391,12 +401,12 @@ def rsync(self, *, src, dst, extra=[]):
391401 if dst .startswith (':' ):
392402 dst = '_' + dst
393403
394- ssh_cmd = ["ssh" ,
404+ ssh_cmd = [self . _ssh ,
395405 "-F" , "none" ,
396406 "-o" , f"ControlPath={ self .control .replace ('%' , '%%' )} " ,
397407 ]
398408
399- complete_cmd = ["rsync" ,
409+ complete_cmd = [self . _rsync ,
400410 "-v" ,
401411 f"--rsh={ ' ' .join (ssh_cmd )} " ,
402412 "-rlpt" , # --recursive --links --perms --times
@@ -417,7 +427,7 @@ def sshfs(self, *, path, mountpoint):
417427 if not self ._check_keepalive ():
418428 raise ExecutionError ("Keepalive no longer running" )
419429
420- complete_cmd = ["sshfs" ,
430+ complete_cmd = [self . _sshfs ,
421431 "-F" , "none" ,
422432 "-f" ,
423433 "-o" , f"ControlPath={ self .control .replace ('%' , '%%' )} " ,
@@ -445,7 +455,7 @@ def get_status(self):
445455
446456 @cached_property
447457 def _ssh_version (self ):
448- version = subprocess .run (["ssh" , "-V" ], capture_output = True , text = True )
458+ version = subprocess .run ([self . _ssh , "-V" ], capture_output = True , text = True )
449459 version = re .match (r"^OpenSSH_(\d+)\.(\d+)" , version .stderr )
450460 return tuple (int (x ) for x in version .groups ())
451461
@@ -472,7 +482,8 @@ def _scp_supports_explicit_scp_mode(self):
472482 @step (args = ['filename' , 'remotepath' ])
473483 def put (self , filename , remotepath = '' ):
474484 transfer_cmd = [
475- "scp" ,
485+ self ._scp ,
486+ "-S" , self ._ssh ,
476487 * self .ssh_prefix ,
477488 "-P" , str (self .networkservice .port ),
478489 "-r" ,
@@ -502,7 +513,8 @@ def put(self, filename, remotepath=''):
502513 @step (args = ['filename' , 'destination' ])
503514 def get (self , filename , destination = "." ):
504515 transfer_cmd = [
505- "scp" ,
516+ self ._scp ,
517+ "-S" , self ._ssh ,
506518 * self .ssh_prefix ,
507519 "-P" , str (self .networkservice .port ),
508520 "-r" ,
@@ -530,7 +542,7 @@ def get(self, filename, destination="."):
530542
531543 def _cleanup_own_master (self ):
532544 """Exit the controlmaster and delete the tmpdir"""
533- complete_cmd = f"ssh -x -o ControlPath={ self .control .replace ('%' , '%%' )} -O exit -p { self .networkservice .port } -l { self ._get_username ()} { self .networkservice .address } " .split (' ' ) # pylint: disable=line-too-long
545+ complete_cmd = f"{ self . _ssh } -x -o ControlPath={ self .control .replace ('%' , '%%' )} -O exit -p { self .networkservice .port } -l { self ._get_username ()} { self .networkservice .address } " .split (' ' ) # pylint: disable=line-too-long
534546 res = subprocess .call (
535547 complete_cmd ,
536548 stdin = subprocess .DEVNULL ,
@@ -547,7 +559,7 @@ def _cleanup_own_master(self):
547559
548560 def _start_keepalive (self ):
549561 """Starts a keepalive connection via the own or external master."""
550- args = ["ssh" , * self .ssh_prefix , self .networkservice .address , "cat" ]
562+ args = [self . _ssh , * self .ssh_prefix , self .networkservice .address , "cat" ]
551563
552564 assert self ._keepalive is None
553565 self ._keepalive = subprocess .Popen (
0 commit comments