Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

driver/sshdriver: read from tools #1558

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
40 changes: 26 additions & 14 deletions labgrid/driver/sshdriver.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,15 @@ class SSHDriver(CommandMixin, Driver, CommandProtocol, FileTransferProtocol):
def __attrs_post_init__(self):
super().__attrs_post_init__()
self._keepalive = None
self._ssh = self._get_tool("ssh")
self._scp = self._get_tool("scp")
self._sshfs = self._get_tool("sshfs")
self._rsync = self._get_tool("rsync")

def _get_tool(self, name):
if self.target.env:
return self.target.env.config.get_tool(name)
return name

def _get_username(self):
"""Get the username from this class or from NetworkService"""
Expand Down Expand Up @@ -105,7 +114,7 @@ def _start_own_master_once(self, timeout):
self.tmpdir, f'control-{self.networkservice.address}'
)

args = ["ssh", "-f", *self.ssh_prefix, "-x", "-o", f"ConnectTimeout={timeout}",
args = [self._ssh, "-f", *self.ssh_prefix, "-x", "-o", f"ConnectTimeout={timeout}",
"-o", "ControlPersist=300", "-o",
"UserKnownHostsFile=/dev/null", "-o", "StrictHostKeyChecking=no",
"-o", "ServerAliveInterval=15", "-MN", "-S", control.replace('%', '%%'), "-p",
Expand Down Expand Up @@ -203,7 +212,7 @@ def _run(self, cmd, codec="utf-8", decodeerrors="strict", timeout=None):
if not self._check_keepalive():
raise ExecutionError("Keepalive no longer running")

complete_cmd = ["ssh", "-x", *self.ssh_prefix,
complete_cmd = [self._ssh, "-x", *self.ssh_prefix,
"-p", str(self.networkservice.port), "-l", self._get_username(),
self.networkservice.address
] + cmd.split(" ")
Expand Down Expand Up @@ -238,7 +247,7 @@ def interact(self, cmd=None):
if not self._check_keepalive():
raise ExecutionError("Keepalive no longer running")

complete_cmd = ["ssh", "-x", *self.ssh_prefix,
complete_cmd = [self._ssh, "-x", *self.ssh_prefix,
"-t",
self.networkservice.address
]
Expand All @@ -252,7 +261,7 @@ def interact(self, cmd=None):

@contextlib.contextmanager
def _forward(self, forward):
cmd = ["ssh", *self.ssh_prefix,
cmd = [self._ssh, *self.ssh_prefix,
"-O", "forward", forward,
self.networkservice.address
]
Expand All @@ -261,7 +270,7 @@ def _forward(self, forward):
try:
yield
finally:
cmd = ["ssh", *self.ssh_prefix,
cmd = [self._ssh, *self.ssh_prefix,
"-O", "cancel", forward,
self.networkservice.address
]
Expand Down Expand Up @@ -361,7 +370,8 @@ def scp(self, *, src, dst):
if dst.startswith(':'):
dst = '_' + dst

complete_cmd = ["scp",
complete_cmd = [self._scp,
"-S", self._ssh,
"-F", "none",
"-o", f"ControlPath={self.control.replace('%', '%%')}",
src, dst,
Expand Down Expand Up @@ -391,12 +401,12 @@ def rsync(self, *, src, dst, extra=[]):
if dst.startswith(':'):
dst = '_' + dst

ssh_cmd = ["ssh",
ssh_cmd = [self._ssh,
"-F", "none",
"-o", f"ControlPath={self.control.replace('%', '%%')}",
]

complete_cmd = ["rsync",
complete_cmd = [self._rsync,
"-v",
f"--rsh={' '.join(ssh_cmd)}",
"-rlpt", # --recursive --links --perms --times
Expand All @@ -417,7 +427,7 @@ def sshfs(self, *, path, mountpoint):
if not self._check_keepalive():
raise ExecutionError("Keepalive no longer running")

complete_cmd = ["sshfs",
complete_cmd = [self._sshfs,
"-F", "none",
"-f",
"-o", f"ControlPath={self.control.replace('%', '%%')}",
Expand Down Expand Up @@ -445,7 +455,7 @@ def get_status(self):

@cached_property
def _ssh_version(self):
version = subprocess.run(["ssh", "-V"], capture_output=True, text=True)
version = subprocess.run([self._ssh, "-V"], capture_output=True, text=True)
version = re.match(r"^OpenSSH_(\d+)\.(\d+)", version.stderr)
return tuple(int(x) for x in version.groups())

Expand All @@ -472,7 +482,8 @@ def _scp_supports_explicit_scp_mode(self):
@step(args=['filename', 'remotepath'])
def put(self, filename, remotepath=''):
transfer_cmd = [
"scp",
self._scp,
"-S", self._ssh,
*self.ssh_prefix,
"-P", str(self.networkservice.port),
"-r",
Expand Down Expand Up @@ -502,7 +513,8 @@ def put(self, filename, remotepath=''):
@step(args=['filename', 'destination'])
def get(self, filename, destination="."):
transfer_cmd = [
"scp",
self._scp,
"-S", self._ssh,
*self.ssh_prefix,
"-P", str(self.networkservice.port),
"-r",
Expand Down Expand Up @@ -530,7 +542,7 @@ def get(self, filename, destination="."):

def _cleanup_own_master(self):
"""Exit the controlmaster and delete the tmpdir"""
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
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
res = subprocess.call(
complete_cmd,
stdin=subprocess.DEVNULL,
Expand All @@ -547,7 +559,7 @@ def _cleanup_own_master(self):

def _start_keepalive(self):
"""Starts a keepalive connection via the own or external master."""
args = ["ssh", *self.ssh_prefix, self.networkservice.address, "cat"]
args = [self._ssh, *self.ssh_prefix, self.networkservice.address, "cat"]

assert self._keepalive is None
self._keepalive = subprocess.Popen(
Expand Down
16 changes: 16 additions & 0 deletions man/labgrid-device-config.5
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,14 @@ See: <https://www.intel.com/content/www/us/en/docs/programmable/683039/22\-3/hp
Path to the rk\-usb\-loader binary, used by the RKUSBDriver.
See: <https://git.pengutronix.de/cgit/barebox/tree/scripts/rk\-usb\-loader.c>
.TP
.B \fBrsync\fP
Path to the rsync binary, used by the SSHDriver.
See: <https://github.com/rsyncproject/rsync>
.TP
.B \fBscp\fP
Path to the scp binary, used by the SSHDriver.
See: <https://github.com/openssh/openssh\-portable>
.TP
.B \fBsd\-mux\-ctrl\fP
Path to the sd\-mux\-ctrl binary, used by the USBSDWireDriver.
See: <https://git.tizen.org/cgit/tools/testlab/sd\-mux/>
Expand All @@ -140,6 +148,14 @@ See: <https://git.tizen.org/cgit/tools/testlab/sd\-mux/>
Path to the sispmctl binary, used by the SiSPMPowerDriver.
See: <https://sispmctl.sourceforge.net/>
.TP
.B \fBssh\fP
Path to the ssh binary, used by the SSHDriver.
See: <https://github.com/openssh/openssh\-portable>
.TP
.B \fBsshfs\fP
Path to the sshfs binary, used by the SSHDriver.
See: <https://github.com/libfuse/sshfs>
.TP
.B \fBuhubctl\fP
Path to the uhubctl binary, used by the USBPowerDriver.
See: <https://github.com/mvp/uhubctl>
Expand Down
16 changes: 16 additions & 0 deletions man/labgrid-device-config.rst
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,14 @@ TOOLS KEYS
Path to the rk-usb-loader binary, used by the RKUSBDriver.
See: https://git.pengutronix.de/cgit/barebox/tree/scripts/rk-usb-loader.c

``rsync``
Path to the rsync binary, used by the SSHDriver.
See: https://github.com/rsyncproject/rsync

``scp``
Path to the scp binary, used by the SSHDriver.
See: https://github.com/openssh/openssh-portable

``sd-mux-ctrl``
Path to the sd-mux-ctrl binary, used by the USBSDWireDriver.
See: https://git.tizen.org/cgit/tools/testlab/sd-mux/
Expand All @@ -139,6 +147,14 @@ TOOLS KEYS
Path to the sispmctl binary, used by the SiSPMPowerDriver.
See: https://sispmctl.sourceforge.net/

``ssh``
Path to the ssh binary, used by the SSHDriver.
See: https://github.com/openssh/openssh-portable

``sshfs``
Path to the sshfs binary, used by the SSHDriver.
See: https://github.com/libfuse/sshfs

``uhubctl``
Path to the uhubctl binary, used by the USBPowerDriver.
See: https://github.com/mvp/uhubctl
Expand Down
22 changes: 22 additions & 0 deletions tests/test_sshdriver.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import pytest
import socket

from labgrid import Environment
from labgrid.driver import SSHDriver, ExecutionError
from labgrid.exceptions import NoResourceFoundError
from labgrid.resource import NetworkService
Expand Down Expand Up @@ -58,6 +59,27 @@ def test_run_check_raise(target, ssh_driver_mocked_and_activated, mocker):
assert res == (['error'], [], 1)
target.deactivate(s)

def test_default_tools(target):
NetworkService(target, "service", "1.2.3.4", "root")
s = SSHDriver(target, "ssh")
assert [s._ssh, s._scp, s._sshfs, s._rsync] == ["ssh", "scp", "sshfs", "rsync"]

def test_custom_tools(target, tmpdir):
p = tmpdir.join("config.yaml")
p.write(
"""
tools:
ssh: "/path/to/ssh"
scp: "/path/to/scp"
sshfs: "/path/to/sshfs"
rsync: "/path/to/rsync"
"""
)
target.env = Environment(str(p))
NetworkService(target, "service", "1.2.3.4", "root")
s = SSHDriver(target, "ssh")
assert [s._ssh, s._scp, s._sshfs, s._rsync] == [f"/path/to/{t}" for t in ("ssh", "scp", "sshfs", "rsync")]

@pytest.fixture(scope='function')
def ssh_localhost(target, pytestconfig):
name = pytestconfig.getoption("--ssh-username")
Expand Down