[autotest] add a --ssh_options option to autoserv
This CL follows the template of
https://chromium-review.googlesource.com/167415
BUG=chromium:285378
TEST=Unit tests pass. Manually verified that specifying
--ssh_options="-F /dev/null -i /dev/null" caused those flags to be
threaded into ssh commands.
Change-Id: Ie0496862d05d42192d55501fc0ed1c3a6274fe79
Reviewed-on: https://chromium-review.googlesource.com/168099
Reviewed-by: Aviv Keshet <[email protected]>
Tested-by: Aviv Keshet <[email protected]>
Commit-Queue: Aviv Keshet <[email protected]>
diff --git a/server/autoserv b/server/autoserv
index 95d6c3d..b3b3bb4 100755
--- a/server/autoserv
+++ b/server/autoserv
@@ -105,6 +105,7 @@
verify_job_repo_url = parser.options.verify_job_repo_url
skip_crash_collection = parser.options.skip_crash_collection
ssh_verbosity = int(parser.options.ssh_verbosity)
+ ssh_options = parser.options.ssh_options
# can't be both a client and a server side test
if client and server:
@@ -158,7 +159,8 @@
job = server_job.server_job(control, parser.args[1:], results, label,
user, machines, client, parse_job,
ssh_user, ssh_port, ssh_pass,
- ssh_verbosity_flag, test_retry, **kwargs)
+ ssh_verbosity_flag, ssh_options,
+ test_retry, **kwargs)
job.logging.start_logging()
job.init_parser()
diff --git a/server/autoserv_parser.py b/server/autoserv_parser.py
index f4a1af0..682a78b 100644
--- a/server/autoserv_parser.py
+++ b/server/autoserv_parser.py
@@ -161,6 +161,10 @@
type="choice", choices=["0", "1", "2", "3"],
help=("Verbosity level for ssh, between 0 "
"and 3 inclusive. [default: 0]"))
+ self.parser.add_option("--ssh_options", action="store",
+ dest="ssh_options", default=None,
+ help=("A string giving command line flags "
+ "that will be included in ssh commands"))
def parse_args(self):
diff --git a/server/autoserv_utils.py b/server/autoserv_utils.py
index 752de22..69ac3f7 100644
--- a/server/autoserv_utils.py
+++ b/server/autoserv_utils.py
@@ -14,7 +14,8 @@
queue_entry=None, verbose=True,
write_pidfile=True, fast_mode=False,
ssh_verbosity=0,
- no_console_prefix=False):
+ no_console_prefix=False,
+ ssh_options=None,):
"""
Construct an autoserv command from a job or host queue entry.
@@ -39,6 +40,8 @@
verbosity level of ssh. Default: 0.
@param no_console_prefix: If true, supress timestamps and other prefix info
in autoserv console logs.
+ @param ssh_options: A string giving extra arguments to be tacked on to
+ ssh commands.
@returns The autoserv command line as a list of executable + parameters.
"""
command = [os.path.join(autoserv_directory, 'autoserv')]
@@ -55,6 +58,9 @@
if ssh_verbosity:
command += ['--ssh_verbosity', str(ssh_verbosity)]
+ if ssh_options:
+ command += ['--ssh_options', ssh_options]
+
if no_console_prefix:
command += ['--no_console_prefix']
diff --git a/server/hosts/factory.py b/server/hosts/factory.py
index bcc22d0..6c81618 100644
--- a/server/hosts/factory.py
+++ b/server/hosts/factory.py
@@ -1,7 +1,7 @@
"""Provides a factory method to create a host object."""
-from autotest_lib.client.common_lib import utils, error, global_config
+from autotest_lib.client.common_lib import error, global_config
from autotest_lib.server import autotest, utils as server_utils
from autotest_lib.server.hosts import site_factory, site_host, ssh_host, serial
from autotest_lib.server.hosts import logfile_monitor
@@ -102,6 +102,8 @@
hostname, args['user'], args['password'], args['port'] = \
server_utils.parse_machine(hostname, ssh_user, ssh_pass, ssh_port)
args['ssh_verbosity_flag'] = ssh_verbosity_flag
+ args['ssh_options'] = ssh_options
+
# create a custom host class for this machine and return an instance of it
host_class = type("%s_host" % hostname, tuple(classes), {})
diff --git a/server/hosts/site_host.py b/server/hosts/site_host.py
index 063d341..3c09b1f 100644
--- a/server/hosts/site_host.py
+++ b/server/hosts/site_host.py
@@ -208,6 +208,7 @@
def _initialize(self, hostname, servo_args=None, ssh_verbosity_flag='',
+ ssh_options='',
*args, **dargs):
"""Initialize superclasses, and |self.servo|.
@@ -229,6 +230,7 @@
self.env['LIBC_FATAL_STDERR_'] = '1'
self._rpc_proxy_map = {}
self._ssh_verbosity_flag = ssh_verbosity_flag
+ self._ssh_options = ssh_options
self.servo = _get_lab_servo(hostname)
if not self.servo and servo_args is not None:
self.servo = servo.Servo(**servo_args)
@@ -1003,12 +1005,14 @@
@param connect_timeout Ignored.
@param alive_interval Ignored.
"""
- base_command = ('/usr/bin/ssh -a -x %s %s -o StrictHostKeyChecking=no'
+ base_command = ('/usr/bin/ssh -a -x %s %s %s'
+ ' -o StrictHostKeyChecking=no'
' -o UserKnownHostsFile=/dev/null -o BatchMode=yes'
' -o ConnectTimeout=30 -o ServerAliveInterval=180'
' -o ServerAliveCountMax=3 -o ConnectionAttempts=4'
' -o Protocol=2 -l %s -p %d')
- return base_command % (self._ssh_verbosity_flag, opts, user, port)
+ return base_command % (self._ssh_verbosity_flag, self._ssh_options,
+ opts, user, port)
def _create_ssh_tunnel(self, port, local_port):
diff --git a/server/server_job.py b/server/server_job.py
index 225820a..f113b23 100644
--- a/server/server_job.py
+++ b/server/server_job.py
@@ -141,10 +141,12 @@
_STATUS_VERSION = 1
+ # TODO crbug.com/285395 eliminate ssh_verbosity_flag
def __init__(self, control, args, resultdir, label, user, machines,
client=False, parse_job='',
ssh_user='root', ssh_port=22, ssh_pass='',
- ssh_verbosity_flag='', test_retry=0, group_name='',
+ ssh_verbosity_flag='', ssh_options='',
+ test_retry=0, group_name='',
tag='', disable_sysinfo=False,
control_filename=SERVER_CONTROL_FILENAME):
"""
@@ -163,6 +165,8 @@
@param ssh_pass: The SSH passphrase, if needed.
@param ssh_verbosity_flag: The SSH verbosity flag, '-v', '-vv',
'-vvv', or an empty string if not needed.
+ @param ssh_options: A string giving additional options that will be
+ included in ssh commands.
@param test_retry: The number of times to retry a test if the test did
not complete successfully.
@param group_name: If supplied, this will be written out as
@@ -199,6 +203,7 @@
self._ssh_port = ssh_port
self._ssh_pass = ssh_pass
self._ssh_verbosity_flag = ssh_verbosity_flag
+ self._ssh_options = ssh_options
self.tag = tag
self.last_boot_tag = None
self.hosts = set()
@@ -346,6 +351,23 @@
self.__insert_test(test)
self._using_parser = False
+ # TODO crbug.com/285395 add a kwargs parameter.
+ def _make_namespace(self):
+ """Create a namespace dictionary to be passed along to control file.
+
+ Creates a namespace argument populated with standard values:
+ machines, job, ssh_user, ssh_port, ssh_pass, ssh_verbosity_flag,
+ and ssh_options.
+ """
+ namespace = {'machines' : self.machines,
+ 'job' : self,
+ 'ssh_user' : self._ssh_user,
+ 'ssh_port' : self._ssh_port,
+ 'ssh_pass' : self._ssh_pass,
+ 'ssh_verbosity_flag' : self._ssh_verbosity_flag,
+ 'ssh_options' : self._ssh_options}
+ return namespace
+
def verify(self):
"""Verify machines are all ssh-able."""
@@ -354,11 +376,7 @@
if self.resultdir:
os.chdir(self.resultdir)
try:
- namespace = {'machines' : self.machines, 'job' : self,
- 'ssh_user' : self._ssh_user,
- 'ssh_port' : self._ssh_port,
- 'ssh_pass' : self._ssh_pass,
- 'ssh_verbosity_flag' : self._ssh_verbosity_flag}
+ namespace = self._make_namespace()
self._execute_code(VERIFY_CONTROL_FILE, namespace, protect=False)
except Exception, e:
msg = ('Verify failed\n' + str(e) + '\n' + traceback.format_exc())
@@ -374,11 +392,7 @@
os.chdir(self.resultdir)
try:
- namespace = {'machines' : self.machines, 'job' : self,
- 'ssh_user' : self._ssh_user,
- 'ssh_port' : self._ssh_port,
- 'ssh_pass' : self._ssh_pass,
- 'ssh_verbosity_flag' : self._ssh_verbosity_flag}
+ namespace = self._make_namespace()
self._execute_code(RESET_CONTROL_FILE, namespace, protect=False)
except Exception as e:
msg = ('Reset failed\n' + str(e) + '\n' +
@@ -392,11 +406,9 @@
raise error.AutoservError('No machines specified to repair')
if self.resultdir:
os.chdir(self.resultdir)
- namespace = {'machines': self.machines, 'job': self,
- 'ssh_user': self._ssh_user, 'ssh_port': self._ssh_port,
- 'ssh_pass': self._ssh_pass,
- 'ssh_verbosity_flag' : self._ssh_verbosity_flag,
- 'protection_level': host_protection}
+
+ namespace = self._make_namespace()
+ namespace.update({'protection_level' : host_protection})
self._execute_code(REPAIR_CONTROL_FILE, namespace, protect=False)
@@ -548,13 +560,8 @@
control_file_dir = self.resultdir
self.aborted = False
- namespace['machines'] = machines
- namespace['args'] = self.args
- namespace['job'] = self
- namespace['ssh_user'] = self._ssh_user
- namespace['ssh_port'] = self._ssh_port
- namespace['ssh_pass'] = self._ssh_pass
- namespace['ssh_verbosity_flag'] = self._ssh_verbosity_flag
+ namespace.update(self._make_namespace())
+ namespace.update({'args' : self.args})
test_start_time = int(time.time())
if self.resultdir:
@@ -1067,6 +1074,7 @@
namespace['hosts'].factory.ssh_pass = self._ssh_pass
namespace['hosts'].factory.ssh_verbosity_flag = (
self._ssh_verbosity_flag)
+ namespace['hosts'].factory.ssh_options = self._ssh_options
def _execute_code(self, code_file, namespace, protect=True):