# Copyright 2015 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""This class defines the TestStationHost class."""
import logging
import os
import common
from autotest_lib.client.bin import local_host
from autotest_lib.client.common_lib import error
from autotest_lib.client.common_lib.cros import retry
from autotest_lib.client.cros import constants as cros_constants
from autotest_lib.server.hosts import base_classes
from autotest_lib.server.hosts import moblab_host
from autotest_lib.server.hosts import ssh_host
# TODO(kevcheng): Update the creation method so it's not a research project
# determining the class inheritance model (same for factory.create_host).
def create_teststationhost(hostname, **kwargs):
"""Creates the TestStationHost object.
@param hostname: Hostname of the test station.
@param kwargs: Keyword args to pass to the testbed initialization.
@return: A Test Station Host object.
"""
classes = [TestStationHost]
if hostname == 'localhost':
classes.append(local_host.LocalHost)
else:
classes.append(ssh_host.SSHHost)
host_class = type('new_teststationhost', tuple(classes), {})
return host_class(hostname, **kwargs)
class TestStationHost(base_classes.Host):
"""This class represents a linux box accessible via ssh."""
def check_credentials(self, hostname):
"""Make sure teststation credentials work if we're doing ssh.
@param hostname: Hostname of the machine.
"""
if hostname != 'localhost':
try:
self.run('true')
except error.AutoservRunError:
# Some test stations may not have root access, try user adb.
logging.debug('Switching to user adb.')
self.user = 'adb'
def _initialize(self, hostname='localhost', *args, **dargs):
"""Initialize a Test Station Host.
This will create a Test Station Host. Hostname should always refer
to the host machine connected to the devices under test.
@param hostname: Hostname of the machine, default to localhost.
"""
logging.debug('Initializing Test Station Host running on host: %s.',
hostname)
# Do parent class initializations.
super(TestStationHost, self)._initialize(hostname=hostname, *args,
**dargs)
self.check_credentials(hostname)
# We'll want to do certain things differently if we're on a moblab.
self._is_host_moblab = None
# Keep track of whether the host was closed since multiple AdbHost
# might have an instance of this teststation.
self._is_closed = False
@property
def is_moblab(self):
"""Check if the host running adb command is a Moblab.
@return: True if the host running adb command is a Moblab, False
otherwise.
"""
if self._is_host_moblab is None:
try:
self.run('cat %s | grep -q moblab' % cros_constants.LSB_RELEASE)
self._is_host_moblab = True
except (error.AutoservRunError, error.AutotestHostRunError):
self._is_host_moblab = False
return self._is_host_moblab
def get_tmp_dir(self, parent='/var/tmp'):
"""Return pathname of a temporary directory on the test station.
If parent folder is supplied and the teststation is a moblab. Then
the parent will have the moblab tmp directory prepended to it.
@param parent: The parent dir to create the temporary dir.
@return: Path of the newly created temporary dir.
"""
if self.is_moblab:
parent = (moblab_host.MOBLAB_TMP_DIR if parent == '/tmp'
else os.path.join(moblab_host.MOBLAB_TMP_DIR,
parent.lstrip('/')))
return super(TestStationHost, self).get_tmp_dir(parent=parent)
def run(self, cmd, force_tty=True, *args, **dargs):
"""Run a command on the adb device.
This will run the command on the test station. This method only
exists to modify the command supplied if we're running a fastboot
command on a moblab, otherwise we leave the command untouched.
@param cmd: The command line string.
@param force_tty: Set to True to force pseudo-terminal allocation to
run the command. This allows the command running on remote host
to abort when the ssh command is timed out. Default is True.
@returns A CMDResult object or None if the call timed out and
ignore_timeout is True.
"""
# TODO (sbasi/kevcheng) - Make teststation_host check if running
# on Chrome OS, rather than MobLab when prepending sudo to fastboot.
if cmd.startswith('fastboot ') and self.is_moblab:
cmd = 'sudo -n ' + cmd
if force_tty:
dargs['options'] = dargs.get('options', '') + ' -t '
return super(TestStationHost, self).run(cmd, *args, **dargs)
@retry.retry(error.GenericHostRunError, timeout_min=10)
def download_file(self, src_url, dest_file, unzip=False, unzip_dest=None):
"""Download the given url.
@param src_url: The url to download from.
@param dest_file: Destination for the file to be downloaded to.
@param unzip: If True, unzip the downloaded file.
@param unzip_dest: Location to unzip the downloaded file to. If not
provided, dest_file's directory is used.
@returns: The path of the downloaded file on the teststation.
"""
try:
self.run('wget -q -O "%s" "%s"' % (dest_file, src_url))
readlink_result = self.run('readlink -f "%s"' % dest_file)
full_path = readlink_result.stdout.splitlines()[0]
if unzip:
unzip_dest = unzip_dest or os.path.dirname(full_path)
self.run('unzip "%s" -x -d "%s"' % (dest_file, unzip_dest))
return full_path
except:
# Delete the destination file if download failed.
self.run('rm -f "%s"' % dest_file)
raise