Because beaker uses the 'push' method for running tests, there has always
been a catch-22 on how to start autotest after provisioning the box.
Currently, beaker uses a daemon called 'beah' to do all the initial
bootstrapping. In order to move away from beah we needed another
alternate approach.
Bill P. suggested to use an env variable. So that is what I did.
When autotest runs from the /etc/init.d on bootup it will look for
'AUTOTEST_HARNESS'. If that is set, call 'autotest bootstrap'. The
env will tell autotest to use the harness beaker, download an initial
control and pass that to the 'run' command. autotest will proceed as normal.
This is kind of an ugly hack but I could not think of another solution to deal
with bootstrapping after provisioning.
Signed-off-by: Don Zickus <dzickus(a)redhat.com>
---
client/autotest_local.py | 2 +-
client/cmdparser.py | 78 ++++++++++++++++++++++++++++++++++++++++------
client/shared/error.py | 4 ++
3 files changed, 73 insertions(+), 11 deletions(-)
diff --git a/client/autotest_local.py b/client/autotest_local.py
index ab5dbd6..0ebe42c 100644
--- a/client/autotest_local.py
+++ b/client/autotest_local.py
@@ -44,7 +44,7 @@ class AutotestLocalApp:
def parse_cmdline(self):
self.options, args = self.opt_parser.parse_args()
- self.args = self.cmd_parser.parse_args(args)
+ self.args = self.cmd_parser.parse_args(args, self.options)
# Check for a control file if not in prebuild mode.
if len(args) != 1 and self.options.client_test_setup is None:
diff --git a/client/cmdparser.py b/client/cmdparser.py
index 5683835..90e3703 100644
--- a/client/cmdparser.py
+++ b/client/cmdparser.py
@@ -8,7 +8,8 @@ import os, re, sys, logging
from autotest.client import os_dep, utils
from autotest.client.shared import logging_config, logging_manager
from autotest.client.shared.settings import settings
-from autotest.client.shared import packages
+from autotest.client.shared import packages, error
+from autotest.client import harness
LOCALDIRTEST = "tests"
GLOBALDIRTEST = settings.get_value('COMMON', 'test_dir',
default="")
@@ -26,7 +27,7 @@ FETCHDIRTEST = os.path.join(output_dir, 'site_tests')
if not os.path.isdir(FETCHDIRTEST):
os.makedirs(FETCHDIRTEST)
-DEBUG = False
+DEBUG = True
class CmdParserLoggingConfig(logging_config.LoggingConfig):
"""
@@ -35,16 +36,17 @@ class CmdParserLoggingConfig(logging_config.LoggingConfig):
"""
def configure_logging(self, results_dir=None, verbose=False):
super(CmdParserLoggingConfig, self).configure_logging(use_console=True,
- verbose=False)
-
-logging_manager.configure_logging(CmdParserLoggingConfig())
+ verbose=verbose)
class CommandParser(object):
"""
A client-side command wrapper for the autotest client.
"""
- COMMAND_LIST = ['help', 'list', 'run', 'fetch']
+ COMMAND_LIST = ['help', 'list', 'run', 'fetch',
'bootstrap']
+
+ def __init__(self):
+ self.internal_fetch = False
@classmethod
def _print_control_list(cls, pipe, path):
@@ -87,7 +89,7 @@ class CommandParser(object):
pipe.write(' %-50s %s\n' % (text, desc))
- def fetch(self, args):
+ def fetch(self, args, options):
"""
fetch a remote control file or packages
@@ -114,6 +116,9 @@ class CommandParser(object):
pkgmgr.install_pkg(name, 'test', pkg_dir, install_dir,
repo_url=url)
+ if self.internal_fetch:
+ return test_name
+
raise SystemExit(0)
@@ -125,6 +130,8 @@ class CommandParser(object):
@param args is not used here.
"""
logging.info("Commands:")
+ logging.info("bootstrap [-H <harness>] Use harness to fetch control
file")
+ logging.info("\tcan also export AUTOTEST_HARNESS=<harness> to avoid -H
option")
logging.info("fetch <url> [<file>]\tFetch a remote file/package
and install it")
logging.info("\tgit://...:[<branch>] [<file/directory>]")
logging.info("\thttp://... [<file>]")
@@ -182,12 +189,14 @@ class CommandParser(object):
raise SystemExit(0)
- def parse_args(self, args):
+ def parse_args(self, args, options):
"""
Process a client side command.
@param args: Command line args.
"""
+ logging_manager.configure_logging(CmdParserLoggingConfig(),
verbose=options.verbose)
+
if len(args) and args[0] in self.COMMAND_LIST:
cmd = args.pop(0)
else:
@@ -199,7 +208,7 @@ class CommandParser(object):
cmd = 'list_tests'
try:
try:
- args = getattr(self, cmd)(args)
+ args = getattr(self, cmd)(args, options)
except TypeError:
args = getattr(self, cmd)()
except SystemExit, return_code:
@@ -215,7 +224,7 @@ class CommandParser(object):
return args
- def run(self, args):
+ def run(self, args, options):
"""
Wrap args with a path and send it back to autotest.
"""
@@ -241,3 +250,52 @@ class CommandParser(object):
logging.error("Can not find test %s", test)
raise SystemExit(1)
+
+ def bootstrap(self, args, options):
+ """
+ Bootstrap autotest by fetching the control file first and pass it back
+
+ Currently this relies on a harness to retrieve the file
+ """
+ def harness_env():
+ if 'AUTOTEST_HARNESS' in os.environ:
+ return os.environ['AUTOTEST_HARNESS']
+ return None
+
+ class stub_job(object):
+ def config_set(self, name, value):
+ return
+
+ if not options.harness and not harness_env():
+ self.help()
+
+ if options.harness:
+ harness_name = options.harness
+ elif harness_env():
+ harness_name = harness_env()
+ options.harness = harness_name
+
+ if options.harness_args:
+ harness_args = options.harness_args
+ else:
+ harness_args = None
+
+ myjob=stub_job()
+
+ # let harness initialize itself
+ try:
+ myharness = harness.select(harness_name, myjob, harness_args)
+ if not getattr(myharness, 'bootstrap'):
+ raise error.HarnessError("Does not support bootstrapping\n")
+ except Exception, error_detail:
+ if DEBUG:
+ raise
+ sys.stderr.write("Harness %s failed to initialize -> %s\n" %
(harness_name, error_detail))
+ self.help()
+ sys.exit(1)
+
+ # get remote control file and stick it in FETCHDIRTEST
+ control = myharness.bootstrap(FETCHDIRTEST)
+ args.append(control)
+
+ return args
diff --git a/client/shared/error.py b/client/shared/error.py
index cf7793a..a0b1667 100644
--- a/client/shared/error.py
+++ b/client/shared/error.py
@@ -307,6 +307,10 @@ class DataSyncError(NetCommunicationError):
pass
+class HarnessError(JobError):
+ """Indicates problem with the harness."""
+ pass
+
class InstallError(JobError):
"""Indicates an installation error which Terminates and fails the
job."""
pass
--
1.7.1