You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
143 lines
4.5 KiB
143 lines
4.5 KiB
# Copyright (c) 2014 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.
|
|
|
|
import contextlib
|
|
import getpass
|
|
import subprocess
|
|
import os
|
|
|
|
import common
|
|
from autotest_lib.server.hosts import ssh_host
|
|
from autotest_lib.client.common_lib import error
|
|
from autotest_lib.client.common_lib import global_config
|
|
from autotest_lib.client.common_lib import utils
|
|
from autotest_lib.server.cros.dynamic_suite import frontend_wrappers
|
|
|
|
|
|
@contextlib.contextmanager
|
|
def chdir(dirname=None):
|
|
"""A context manager to help change directories.
|
|
|
|
Will chdir into the provided dirname for the lifetime of the context and
|
|
return to cwd thereafter.
|
|
|
|
@param dirname: The dirname to chdir into.
|
|
"""
|
|
curdir = os.getcwd()
|
|
try:
|
|
if dirname is not None:
|
|
os.chdir(dirname)
|
|
yield
|
|
finally:
|
|
os.chdir(curdir)
|
|
|
|
|
|
def local_runner(cmd, stream_output=False):
|
|
"""
|
|
Runs a command on the local system as the current user.
|
|
|
|
@param cmd: The command to run.
|
|
@param stream_output: If True, streams the stdout of the process.
|
|
|
|
@returns: The output of cmd, will be stdout and stderr.
|
|
@raises CalledProcessError: If there was a non-0 return code.
|
|
"""
|
|
print 'Running command: %s' % cmd
|
|
proc = subprocess.Popen(
|
|
cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
|
if stream_output:
|
|
output = ''
|
|
for newline in iter(proc.stdout.readline, ''):
|
|
output += newline
|
|
print newline.rstrip(os.linesep)
|
|
else:
|
|
output = proc.communicate()[0]
|
|
|
|
return_code = proc.wait()
|
|
if return_code !=0:
|
|
print "ERROR: '%s' failed with error:\n%s" % (cmd, output)
|
|
raise subprocess.CalledProcessError(return_code, cmd, output[:1024])
|
|
return output
|
|
|
|
|
|
_host_objects = {}
|
|
|
|
def host_object_runner(host, **kwargs):
|
|
"""
|
|
Returns a function that returns the output of running a command via a host
|
|
object.
|
|
|
|
@param host: The host to run a command on.
|
|
@returns: A function that can invoke a command remotely.
|
|
"""
|
|
try:
|
|
host_object = _host_objects[host]
|
|
except KeyError:
|
|
username = global_config.global_config.get_config_value(
|
|
'CROS', 'infrastructure_user')
|
|
host_object = ssh_host.SSHHost(host, user=username)
|
|
_host_objects[host] = host_object
|
|
|
|
def runner(cmd):
|
|
"""
|
|
Runs a command via a host object on the enclosed host. Translates
|
|
host.run errors to the subprocess equivalent to expose a common API.
|
|
|
|
@param cmd: The command to run.
|
|
@returns: The output of cmd.
|
|
@raises CalledProcessError: If there was a non-0 return code.
|
|
"""
|
|
try:
|
|
return host_object.run(cmd).stdout
|
|
except error.AutotestHostRunError as e:
|
|
exit_status = e.result_obj.exit_status
|
|
command = e.result_obj.command
|
|
raise subprocess.CalledProcessError(exit_status, command)
|
|
return runner
|
|
|
|
|
|
def googlesh_runner(host, **kwargs):
|
|
"""
|
|
Returns a function that return the output of running a command via shelling
|
|
out to `googlesh`.
|
|
|
|
@param host: The host to run a command on
|
|
@returns: A function that can invoke a command remotely.
|
|
"""
|
|
def runner(cmd):
|
|
"""
|
|
Runs a command via googlesh on the enclosed host.
|
|
|
|
@param cmd: The command to run.
|
|
@returns: The output of cmd.
|
|
@raises CalledProcessError: If there was a non-0 return code.
|
|
"""
|
|
out = subprocess.check_output(['googlesh', '-s', '-uchromeos-test',
|
|
'-m%s' % host, '%s' % cmd],
|
|
stderr=subprocess.STDOUT)
|
|
return out
|
|
return runner
|
|
|
|
|
|
def execute_command(host, cmd, **kwargs):
|
|
"""
|
|
Executes a command on the host `host`. This an optimization that if
|
|
we're already chromeos-test, we can just ssh to the machine in question.
|
|
Or if we're local, we don't have to ssh at all.
|
|
|
|
@param host: The hostname to execute the command on.
|
|
@param cmd: The command to run. Special shell syntax (such as pipes)
|
|
is allowed.
|
|
@param kwargs: Key word arguments for the runner functions.
|
|
@returns: The output of the command.
|
|
"""
|
|
if utils.is_localhost(host):
|
|
runner = local_runner
|
|
elif getpass.getuser() == 'chromeos-test':
|
|
runner = host_object_runner(host)
|
|
else:
|
|
runner = googlesh_runner(host)
|
|
|
|
return runner(cmd, **kwargs)
|