| Index: infra/bots/flavor/ssh_flavor.py
|
| diff --git a/infra/bots/flavor/ssh_flavor.py b/infra/bots/flavor/ssh_flavor.py
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..07c383f60338baffeb65d4f4c3ec13fcbf597fe1
|
| --- /dev/null
|
| +++ b/infra/bots/flavor/ssh_flavor.py
|
| @@ -0,0 +1,123 @@
|
| +#!/usr/bin/env python
|
| +#
|
| +# Copyright 2016 Google Inc.
|
| +#
|
| +# Use of this source code is governed by a BSD-style license that can be
|
| +# found in the LICENSE file.
|
| +
|
| +
|
| +import default_flavor
|
| +import os
|
| +import posixpath
|
| +import subprocess
|
| +import ssh_devices
|
| +
|
| +
|
| +"""Utils for running tests remotely over SSH."""
|
| +
|
| +
|
| +class SSHFlavorUtils(default_flavor.DefaultFlavorUtils):
|
| + def __init__(self, *args, **kwargs):
|
| + super(SSHFlavorUtils, self).__init__(*args, **kwargs)
|
| + slave_info = ssh_devices.SLAVE_INFO.get(self._bot_info.slave_name,
|
| + ssh_devices.SLAVE_INFO['default'])
|
| + self._host = slave_info.ssh_host
|
| + self._port = slave_info.ssh_port
|
| + self._user = slave_info.ssh_user
|
| +
|
| + @property
|
| + def host(self):
|
| + return self._host
|
| +
|
| + @property
|
| + def port(self):
|
| + return self._port
|
| +
|
| + @property
|
| + def user(self):
|
| + return self._user
|
| +
|
| + def ssh(self, cmd, **kwargs):
|
| + """Run the given SSH command."""
|
| + ssh_cmd = ['ssh']
|
| + if self.port:
|
| + ssh_cmd.extend(['-p', self.port])
|
| + dest = self.host
|
| + if self.user:
|
| + dest = self.user + '@' + dest
|
| + ssh_cmd.append(dest)
|
| + ssh_cmd.extend(cmd)
|
| + return self._bot_info.run(ssh_cmd, **kwargs)
|
| +
|
| + def step(self, *args, **kwargs):
|
| + """Run the given step over SSH."""
|
| + self.ssh(*args, **kwargs)
|
| +
|
| + def device_path_join(self, *args):
|
| + """Like os.path.join(), but for paths on a remote machine."""
|
| + return posixpath.join(*args)
|
| +
|
| + def device_path_exists(self, path): # pragma: no cover
|
| + """Like os.path.exists(), but for paths on a remote device."""
|
| + try:
|
| + self.ssh(['test', '-e', path])
|
| + return True
|
| + except subprocess.CalledProcessError:
|
| + return False
|
| +
|
| + def _remove_device_dir(self, path):
|
| + """Remove the directory on the device."""
|
| + self.ssh(['rm', '-rf', path])
|
| +
|
| + def _create_device_dir(self, path):
|
| + """Create the directory on the device."""
|
| + self.ssh(['mkdir', '-p', path])
|
| +
|
| + def create_clean_device_dir(self, path):
|
| + """Like shutil.rmtree() + os.makedirs(), but on a remote device."""
|
| + self._remove_device_dir(path)
|
| + self._create_device_dir(path)
|
| +
|
| + def _make_scp_cmd(self, remote_path, recurse=True):
|
| + """Prepare an SCP command.
|
| +
|
| + Returns a partial SCP command and an adjusted remote path.
|
| + """
|
| + cmd = ['scp']
|
| + if recurse:
|
| + cmd.append('-r')
|
| + if self.port:
|
| + cmd.extend(['-P', self.port])
|
| + adj_remote_path = self.host + ':' + remote_path
|
| + if self.user:
|
| + adj_remote_path = self.user + '@' + adj_remote_path
|
| + return cmd, adj_remote_path
|
| +
|
| + def copy_directory_contents_to_device(self, host_dir, device_dir):
|
| + """Like shutil.copytree(), but for copying to a remote device."""
|
| + _, remote_path = self._make_scp_cmd(device_dir)
|
| + cmd = [os.path.join(self._bot_info.skia_dir, 'tools',
|
| + 'scp_dir_contents.sh'),
|
| + host_dir, remote_path]
|
| + self._bot_info.run(cmd)
|
| +
|
| + def copy_directory_contents_to_host(self, device_dir, host_dir):
|
| + """Like shutil.copytree(), but for copying from a remote device."""
|
| + _, remote_path = self._make_scp_cmd(device_dir)
|
| + cmd = [os.path.join(self._bot_info.skia_dir, 'tools',
|
| + 'scp_dir_contents.sh'),
|
| + remote_path, host_dir]
|
| + self._bot_info.run(cmd)
|
| +
|
| + def copy_file_to_device(self, host_path, device_path):
|
| + """Like shutil.copyfile, but for copying to a connected device."""
|
| + cmd, remote_path = self._make_scp_cmd(device_path, recurse=False)
|
| + cmd.extend([host_path, remote_path])
|
| + self._bot_info.run(cmd)
|
| +
|
| + def read_file_on_device(self, path):
|
| + return self.ssh(['cat', path]).rstrip()
|
| +
|
| + def remove_file_on_device(self, path):
|
| + """Delete the given file."""
|
| + return self.ssh(['rm', '-f', path])
|
|
|