Example #1
0
    def run_async(self,
                  command,
                  stdout_tee=None,
                  stderr_tee=None,
                  args=(),
                  connect_timeout=30,
                  options='',
                  verbose=True,
                  stderr_level=utils.DEFAULT_STDERR_LEVEL,
                  cmd_outside_subshell=''):
        """
        Run a command on the remote host. Returns an AsyncJob object to
        interact with the remote process.

        Sorry, but you can't use stdin--that's how we do job control.

        This is mostly copied from SSHHost.run and SSHHost._run
        """
        if verbose:
            logging.debug("Running (async ssh) '%s'" % command)

        # Start a master SSH connection if necessary.
        self.start_master_ssh()

        env = " ".join("=".join(pair) for pair in self.env.iteritems())

        ssh_cmd = self.ssh_command(connect_timeout, options)
        if not env.strip():
            env = ""
        else:
            env = "export %s;" % env
        for arg in args:
            command += ' "%s"' % utils.sh_escape(arg)
        full_cmd = '{ssh_cmd} "{env} {cmd} {killer_bits}"'.format(
            ssh_cmd=ssh_cmd,
            env=env,
            cmd=utils.sh_escape("%s (%s)" % (cmd_outside_subshell, command)),
            killer_bits=utils.sh_escape("& read; kill -9 $!"))

        job = utils.AsyncJob(full_cmd,
                             stdout_tee=stdout_tee,
                             stderr_tee=stderr_tee,
                             verbose=verbose,
                             stderr_level=stderr_level,
                             stdin=subprocess.PIPE)

        def kill_func():
            #this triggers the remote kill
            os.write(job.sp.stdin.fileno(), "lulz\n")
            utils.nuke_subprocess(job.sp)

        job.kill_func = kill_func

        return job
Example #2
0
def scp_remote_escape(filename):
    """
    Escape special characters from a filename so that it can be passed
    to scp (within double quotes) as a remote file.

    Bis-quoting has to be used with scp for remote files, "bis-quoting"
    as in quoting x 2
    scp does not support a newline in the filename

    Args:
            filename: the filename string to escape.

    Returns:
            The escaped filename string. The required englobing double
            quotes are NOT added and so should be added at some point by
            the caller.
    """
    escape_chars = r' !"$&' "'" r'()*,:;<=>?[\]^`{|}'

    new_name = []
    for char in filename:
        if char in escape_chars:
            new_name.append("\\%s" % (char, ))
        else:
            new_name.append(char)

    return utils.sh_escape("".join(new_name))
Example #3
0
def scp_remote_escape(filename):
    """
    Escape special characters from a filename so that it can be passed
    to scp (within double quotes) as a remote file.

    Bis-quoting has to be used with scp for remote files, "bis-quoting"
    as in quoting x 2
    scp does not support a newline in the filename

    Args:
            filename: the filename string to escape.

    Returns:
            The escaped filename string. The required englobing double
            quotes are NOT added and so should be added at some point by
            the caller.
    """
    escape_chars= r' !"$&' "'" r'()*,:;<=>?[\]^`{|}'

    new_name= []
    for char in filename:
        if char in escape_chars:
            new_name.append("\\%s" % (char,))
        else:
            new_name.append(char)

    return utils.sh_escape("".join(new_name))
    def run_once(self, host):
        """Run U2FTest"""
        self.host = host
        self.last_len = 0
        self.output = ''

        if not self.host.path_exists(self.U2FTEST_PATH):
            raise error.TestNAError('Device does not have U2FTest support')

        # Login and start u2fd
        self.setup_u2fd()
        device = self.get_u2f_device()

        # Run U2FTest with the U2F device
        u2ftest_cmd = utils.sh_escape('%s %s' % (self.U2FTEST_PATH, device))
        full_ssh_command = '%s "%s"' % (self.host.ssh_command(options='-tt'),
                                        u2ftest_cmd)
        self.stdout = StringIO.StringIO()
        # Start running U2FTest in the background.
        self.u2ftest_job = utils.BgJob(full_ssh_command,
                                       nickname='u2ftest',
                                       stdout_tee=self.stdout,
                                       stderr_tee=utils.TEE_TO_LOGS,
                                       stdin=subprocess.PIPE)
        if self.u2ftest_job == None:
            raise error.TestFail('could not start u2ftest')

        try:
            # This will timeout if the process doesn't complete in 10 seconds.
            utils.wait_for_value(self.check_u2ftest_and_press_power_button,
                                 expected_value=True)
        finally:
            self.close_u2ftest()
Example #5
0
    def run_async(self, command, stdout_tee=None, stderr_tee=None, args=(),
                  connect_timeout=30, options='', verbose=True,
                  stderr_level=utils.DEFAULT_STDERR_LEVEL,
                  cmd_outside_subshell=''):
        """
        Run a command on the remote host. Returns an AsyncJob object to
        interact with the remote process.

        Sorry, but you can't use stdin--that's how we do job control.

        This is mostly copied from SSHHost.run and SSHHost._run
        """
        if verbose:
            logging.debug("Running (async ssh) '%s'" % command)

        # Start a master SSH connection if necessary.
        self.start_master_ssh()

        env = " ".join("=".join(pair) for pair in self.env.iteritems())

        ssh_cmd = self.ssh_command(connect_timeout, options)
        if not env.strip():
            env = ""
        else:
            env = "export %s;" % env
        for arg in args:
            command += ' "%s"' % utils.sh_escape(arg)
        full_cmd = '{ssh_cmd} "{env} {cmd} {killer_bits}"'.format(
            ssh_cmd = ssh_cmd, env = env,
            cmd = utils.sh_escape("%s (%s)" % (cmd_outside_subshell, command)),
            killer_bits = utils.sh_escape("& read; kill -9 $!"))

        job = utils.AsyncJob(full_cmd, stdout_tee=stdout_tee,
                              stderr_tee=stderr_tee, verbose=verbose,
                              stderr_level=stderr_level,
                              stdin=subprocess.PIPE)

        def kill_func():
            #this triggers the remote kill
            os.write(job.sp.stdin.fileno(), "lulz\n")
            utils.nuke_subprocess(job.sp)

        job.kill_func = kill_func

        return job
 def format(self, record):
     s = super(VarLogMessageFormatter, self).format(record)
     # On Brillo the logger binary is not available. Disable after error.
     if self._should_respew:
         try:
             os.system('logger -t "autotest" "%s"' % utils.sh_escape(s))
         except OSError:
             self._should_respew = False
     return s
 def _test_in_shell(self, text):
     escaped_text = utils.sh_escape(text)
     proc = subprocess.Popen('echo "%s"' % escaped_text, shell=True,
                             stdin=open(os.devnull, 'r'),
                             stdout=subprocess.PIPE,
                             stderr=open(os.devnull, 'w'))
     stdout, _ = proc.communicate()
     self.assertEqual(proc.returncode, 0)
     self.assertEqual(stdout[:-1], text)
    def path_exists(self, path):
        """Determine if path exists on the remote machine.

        @param path: path to check

        @return: bool(path exists)"""
        result = self.run('test -e "%s"' % utils.sh_escape(path),
                          ignore_status=True)
        return result.exit_status == 0
 def _test_in_shell(self, text):
     escaped_text = utils.sh_escape(text)
     proc = subprocess.Popen('echo "%s"' % escaped_text,
                             shell=True,
                             stdin=open(os.devnull, 'r'),
                             stdout=subprocess.PIPE,
                             stderr=open(os.devnull, 'w'))
     stdout, _ = proc.communicate()
     self.assertEqual(proc.returncode, 0)
     self.assertEqual(stdout[:-1], text)
Example #10
0
def unarchive(host, source_material):
    """Uncompress and untar an archive on a host.

    If the "source_material" is compresses (according to the file
    extension) it will be uncompressed. Supported compression formats
    are gzip and bzip2. Afterwards, if the source_material is a tar
    archive, it will be untarred.

    Args:
            host: the host object on which the archive is located
            source_material: the path of the archive on the host

    Returns:
            The file or directory name of the unarchived source material.
            If the material is a tar archive, it will be extracted in the
            directory where it is and the path returned will be the first
            entry in the archive, assuming it is the topmost directory.
            If the material is not an archive, nothing will be done so this
            function is "harmless" when it is "useless".
    """
    # uncompress
    if (source_material.endswith(".gz") or source_material.endswith(".gzip")):
        host.run('gunzip "%s"' % (utils.sh_escape(source_material)))
        source_material = ".".join(source_material.split(".")[:-1])
    elif source_material.endswith("bz2"):
        host.run('bunzip2 "%s"' % (utils.sh_escape(source_material)))
        source_material = ".".join(source_material.split(".")[:-1])

    # untar
    if source_material.endswith(".tar"):
        retval = host.run('tar -C "%s" -xvf "%s"' % (
            utils.sh_escape(os.path.dirname(source_material)),
            utils.sh_escape(source_material),
        ))
        source_material = os.path.join(os.path.dirname(source_material),
                                       retval.stdout.split()[0])

    return source_material
Example #11
0
def unarchive(host, source_material):
    """Uncompress and untar an archive on a host.

    If the "source_material" is compresses (according to the file
    extension) it will be uncompressed. Supported compression formats
    are gzip and bzip2. Afterwards, if the source_material is a tar
    archive, it will be untarred.

    Args:
            host: the host object on which the archive is located
            source_material: the path of the archive on the host

    Returns:
            The file or directory name of the unarchived source material.
            If the material is a tar archive, it will be extracted in the
            directory where it is and the path returned will be the first
            entry in the archive, assuming it is the topmost directory.
            If the material is not an archive, nothing will be done so this
            function is "harmless" when it is "useless".
    """
    # uncompress
    if (source_material.endswith(".gz") or
            source_material.endswith(".gzip")):
        host.run('gunzip "%s"' % (utils.sh_escape(source_material)))
        source_material= ".".join(source_material.split(".")[:-1])
    elif source_material.endswith("bz2"):
        host.run('bunzip2 "%s"' % (utils.sh_escape(source_material)))
        source_material= ".".join(source_material.split(".")[:-1])

    # untar
    if source_material.endswith(".tar"):
        retval= host.run('tar -C "%s" -xvf "%s"' % (
                utils.sh_escape(os.path.dirname(source_material)),
                utils.sh_escape(source_material),))
        source_material= os.path.join(os.path.dirname(source_material),
                retval.stdout.split()[0])

    return source_material
Example #12
0
    def _ensure_deps(self, dut, test_name):
        """
        Ensure the dependencies are locally available on DUT.

        @param dut: The autotest host object representing DUT.
        @param test_name: Name of the telemetry test.
        """
        # Get DEPs using host's telemetry.
        # Example output, fetch_benchmark_deps.py --output-deps=deps octane:
        # {'octane': ['tools/perf/page_sets/data/octane_002.wprgo']}
        perf_path = os.path.join(self._telemetry_path, 'tools', 'perf')
        deps_path = os.path.join(perf_path, 'fetch_benchmark_deps_result.json')
        fetch_path = os.path.join(perf_path, 'fetch_benchmark_deps.py')
        format_fetch = ('python %s --output-deps=%s %s')
        command_fetch = format_fetch % (fetch_path, deps_path, test_name)
        command_get = 'cat %s' % deps_path

        if self._devserver:
            devserver_hostname = self._devserver.url().split(
                    'http://')[1].split(':')[0]
            command_fetch = 'ssh %s %s' % (devserver_hostname, command_fetch)
            command_get = 'ssh %s %s' % (devserver_hostname, command_get)

        logging.info('Getting DEPs: %s', command_fetch)
        _, _, exit_code = self._run_cmd(command_fetch)
        if exit_code != 0:
            raise error.TestFail('Error occurred while fetching DEPs.')
        stdout, _, exit_code = self._run_cmd(command_get)
        if exit_code != 0:
            raise error.TestFail('Error occurred while getting DEPs.')

        # Download DEPs to DUT.
        # send_file() relies on rsync over ssh. Couldn't be better.
        deps = json.loads(stdout)
        for dep in deps[test_name]:
            src = os.path.join(self._telemetry_path, dep)
            dst = os.path.join(DUT_CHROME_ROOT, dep)
            if self._devserver:
                logging.info('Copying: %s -> %s', src, dst)
                rsync_cmd = utils.sh_escape('rsync %s %s %s:%s' %
                                            (self._host.rsync_options(), src,
                                            self._host.hostname, dst))
                utils.run('ssh %s "%s"' % (devserver_hostname, rsync_cmd))
            else:
                if not os.path.isfile(src):
                    raise error.TestFail('Error occurred while saving DEPs.')
                logging.info('Copying: %s -> %s', src, dst)
                dut.send_file(src, dst)
    def run(self,
            command,
            timeout=3600,
            ignore_status=False,
            stdout_tee=utils.TEE_TO_LOGS,
            stderr_tee=utils.TEE_TO_LOGS,
            connect_timeout=30,
            stdin=None,
            verbose=True,
            args=(),
            ignore_timeout=False):
        """
        Run a command on the remote host.
        @see common_lib.hosts.host.run()

        @param connect_timeout: connection timeout (in seconds)
        @param options: string with additional ssh command options
        @param verbose: log the commands
        @param ignore_timeout: bool True command timeouts should be
                               ignored.  Will return None on command timeout.

        @raises AutoservRunError: if the command failed
        @raises AutoservSSHTimeout: ssh connection has timed out
        """

        stdout = utils.get_stream_tee_file(stdout_tee,
                                           utils.DEFAULT_STDOUT_LEVEL,
                                           prefix=utils.STDOUT_PREFIX)
        stderr = utils.get_stream_tee_file(
            stderr_tee,
            utils.get_stderr_level(ignore_status),
            prefix=utils.STDERR_PREFIX)

        for arg in args:
            command += ' "%s"' % utils.sh_escape(arg)

        if verbose:
            logging.debug("Running (ssh-paramiko) '%s'", command)

        # start up the command
        start_time = time.time()
        try:
            channel = self._open_channel(timeout)
            channel.exec_command(command)
        except (socket.error, paramiko.SSHException, EOFError), e:
            # This has to match the string from paramiko *exactly*.
            if str(e) != 'Channel closed.':
                raise error.AutoservSSHTimeout("ssh failed: %s" % e)
    def _ensure_deps(self, dut, test_name):
        """
        Ensure the dependencies are locally available on DUT.

        @param dut: The autotest host object representing DUT.
        @param test_name: Name of the telemetry test.
        """
        # Get DEPs using host's telemetry.
        format_string = ('python %s/tools/perf/fetch_benchmark_deps.py %s')
        command = format_string % (self._telemetry_path, test_name)
        stdout = StringIO.StringIO()
        stderr = StringIO.StringIO()

        if self._devserver:
            devserver_hostname = self._devserver.url().split(
                'http://')[1].split(':')[0]
            command = 'ssh %s %s' % (devserver_hostname, command)

        logging.info('Getting DEPs: %s', command)
        try:
            result = utils.run(command, stdout_tee=stdout, stderr_tee=stderr)
        except error.CmdError as e:
            logging.debug('Error occurred getting DEPs: %s\n %s\n',
                          stdout.getvalue(), stderr.getvalue())
            raise error.TestFail('Error occurred while getting DEPs.')

        # Download DEPs to DUT.
        # send_file() relies on rsync over ssh. Couldn't be better.
        stdout_str = stdout.getvalue()
        stdout.close()
        stderr.close()
        for dep in stdout_str.split():
            src = os.path.join(self._telemetry_path, dep)
            dst = os.path.join(DUT_CHROME_ROOT, dep)
            if self._devserver:
                logging.info('Copying: %s -> %s', src, dst)
                rsync_cmd = utils.sh_escape('rsync %s %s %s:%s' %
                                            (self._host.rsync_options(), src,
                                             self._host.hostname, dst))
                utils.run('ssh %s "%s"' % (devserver_hostname, rsync_cmd))
            else:
                if not os.path.isfile(src):
                    raise error.TestFail('Error occurred while saving DEPs.')
                logging.info('Copying: %s -> %s', src, dst)
                dut.send_file(src, dst)
    def _ssh_call(self, url):
        """Helper function to make a 'SSH call'.

        @param url: The URL to be called.

        @return The output string of the call.
        @throws CommunicationError when the SSH command failed.
        """
        cmd = 'ssh %s \'curl "%s"\'' % (self._hostname, utils.sh_escape(url))
        logging.debug('Gs Cache call: %s', _truncate_long_message(cmd))
        try:
            result = utils.run(cmd, timeout=_SSH_CALL_TIMEOUT_SECONDS)
        except error.CmdError as err:
            if err.result_obj.exit_status == _CURL_RC_CANNOT_CONNECT_TO_HOST:
                raise NoGsCacheServerError(
                    'Cannot connect to Gs Cache at %s via SSH.' % self._netloc)

            raise CommunicationError('Error occurred: rc=%d, cmd=%s' %
                                     (err.result_obj.exit_status, err.command))

        return result.stdout
    def _get_staged_file_info(self, staged_url):
        """
        Gets the staged files info that includes SHA256 and size.

        @param staged_url: the staged file url.

        @returns file info (SHA256 and size).

        """
        split_url = staged_url.rpartition('/static/')
        file_info_url = os.path.join(split_url[0], 'api/fileinfo',
                                     split_url[2])
        logging.info('file info url: %s', file_info_url)
        devserver_hostname = urlparse.urlparse(file_info_url).hostname
        cmd = 'ssh %s \'curl "%s"\'' % (devserver_hostname,
                                        utils.sh_escape(file_info_url))
        try:
            result = utils.run(cmd).stdout
            return json.loads(result)
        except error.CmdError as e:
            logging.error('Failed to read file info: %s', e)
            raise error.TestFail('Could not reach fileinfo API on devserver.')
Example #17
0
    def run(self, command, timeout=3600, ignore_status=False,
            stdout_tee=utils.TEE_TO_LOGS, stderr_tee=utils.TEE_TO_LOGS,
            connect_timeout=30, stdin=None, verbose=True, args=()):
        """
        Run a command on the remote host.
        @see common_lib.hosts.host.run()

        @param connect_timeout: connection timeout (in seconds)
        @param options: string with additional ssh command options
        @param verbose: log the commands

        @raises AutoservRunError: if the command failed
        @raises AutoservSSHTimeout: ssh connection has timed out
        """

        stdout = utils.get_stream_tee_file(
                stdout_tee, utils.DEFAULT_STDOUT_LEVEL,
                prefix=utils.STDOUT_PREFIX)
        stderr = utils.get_stream_tee_file(
                stderr_tee, utils.get_stderr_level(ignore_status),
                prefix=utils.STDERR_PREFIX)

        for arg in args:
            command += ' "%s"' % utils.sh_escape(arg)

        if verbose:
            logging.debug("Running (ssh-paramiko) '%s'" % command)

        # start up the command
        start_time = time.time()
        try:
            channel = self._open_channel(timeout)
            channel.exec_command(command)
        except (socket.error, paramiko.SSHException, EOFError), e:
            # This has to match the string from paramiko *exactly*.
            if str(e) != 'Channel closed.':
                raise error.AutoservSSHTimeout("ssh failed: %s" % e)
Example #18
0
 def path_exists(self, path):
     """ Determine if path exists on the remote machine. """
     result = self.run('ls "%s" > /dev/null' % utils.sh_escape(path),
                       ignore_status=True)
     return result.exit_status == 0
Example #19
0
TELEMETRY_TIMEOUT_MINS = 120

DUT_CHROME_ROOT = '/usr/local/telemetry/src'
DUT_COMMON_SSH_OPTIONS = [
    '-o StrictHostKeyChecking=no', '-o UserKnownHostsFile=/dev/null',
    '-o BatchMode=yes', '-o ConnectTimeout=30', '-o ServerAliveInterval=900',
    '-o ServerAliveCountMax=3', '-o ConnectionAttempts=4', '-o Protocol=2'
]
DUT_SSH_OPTIONS = ' '.join(DUT_COMMON_SSH_OPTIONS + ['-x', '-a', '-l root'])
DUT_SCP_OPTIONS = ' '.join(DUT_COMMON_SSH_OPTIONS)
DUT_RSYNC_OPTIONS = ' '.join([
    '--rsh="/usr/bin/ssh %s"' % DUT_SSH_OPTIONS, '-L', '--timeout=1800', '-az',
    '--no-o', '--no-g'
])
# Prevent double quotes from being unfolded.
DUT_RSYNC_OPTIONS = utils.sh_escape(DUT_RSYNC_OPTIONS)

# Result Statuses
SUCCESS_STATUS = 'SUCCESS'
WARNING_STATUS = 'WARNING'
FAILED_STATUS = 'FAILED'

# A list of benchmarks with that the telemetry test harness can run on dut.
ON_DUT_WHITE_LIST = [
    'dromaeo.domcoreattr', 'dromaeo.domcoremodify', 'dromaeo.domcorequery',
    'dromaeo.domcoretraverse', 'image_decoding.image_decoding_measurement',
    'jetstream', 'kraken', 'memory.top_7_stress', 'octane',
    'page_cycler.typical_25', 'page_cycler_v2.typical_25', 'robohornet_pro',
    'smoothness.top_25_smooth', 'smoothness.tough_animation_cases',
    'smoothness.tough_canvas_cases', 'smoothness.tough_filters_cases',
    'smoothness.tough_pinch_zoom_cases', 'smoothness.tough_scrolling_cases',
Example #20
0
 def path_exists(self, path):
     """ Determine if path exists on the remote machine. """
     result = self.run('ls "%s" > /dev/null' % utils.sh_escape(path),
                       ignore_status=True)
     return result.exit_status == 0