| # 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 |