| #!/usr/bin/python -u |
| # Copyright 2007-2008 Martin J. Bligh <mbligh@google.com>, Google Inc. |
| # Released under the GPL v2 |
| |
| """ |
| Run an control file through the server side engine |
| """ |
| |
| import sys, os, re, traceback, signal, time, logging, logging.config |
| |
| import common |
| from autotest_lib.server import server_job, utils, autoserv_parser, autotest |
| from autotest_lib.client.common_lib import pidfile |
| |
| def run_autoserv(pid_file_manager, results, parser): |
| # send stdin to /dev/null |
| dev_null = os.open(os.devnull, os.O_RDONLY) |
| os.dup2(dev_null, sys.stdin.fileno()) |
| os.close(dev_null) |
| |
| # Create separate process group |
| os.setpgrp() |
| |
| # Implement SIGTERM handler |
| def handle_sigint(signum, frame): |
| if pid_file_manager: |
| pid_file_manager.close_file(1, signal.SIGTERM) |
| os.killpg(os.getpgrp(), signal.SIGKILL) |
| |
| # Set signal handler |
| signal.signal(signal.SIGTERM, handle_sigint) |
| |
| # Get a useful value for running 'USER' |
| realuser = os.environ.get('USER') |
| if not realuser: |
| realuser = 'anonymous' |
| |
| if parser.options.machines: |
| machines = parser.options.machines.replace(',', ' ').strip().split() |
| else: |
| machines = [] |
| machines_file = parser.options.machines_file |
| label = parser.options.label |
| user = parser.options.user |
| client = parser.options.client |
| server = parser.options.server |
| install_before = parser.options.install_before |
| install_after = parser.options.install_after |
| verify = parser.options.verify |
| repair = parser.options.repair |
| cleanup = parser.options.cleanup |
| no_tee = parser.options.no_tee |
| parse_job = parser.options.parse_job |
| host_protection = parser.options.host_protection |
| ssh_user = parser.options.ssh_user |
| ssh_port = parser.options.ssh_port |
| ssh_pass = parser.options.ssh_pass |
| collect_crashinfo = parser.options.collect_crashinfo |
| |
| # can't be both a client and a server side test |
| if client and server: |
| print "Can not specify a test as both server and client!" |
| sys.exit(1) |
| |
| if len(parser.args) < 1 and not (verify or repair or cleanup |
| or collect_crashinfo): |
| print parser.parser.print_help() |
| sys.exit(1) |
| |
| # We have a control file unless it's just a verify/repair/cleanup job |
| if len(parser.args) > 0: |
| control = parser.args[0] |
| else: |
| control = None |
| |
| if machines_file: |
| machines = [] |
| for m in open(machines_file, 'r').readlines(): |
| # remove comments, spaces |
| m = re.sub('#.*', '', m).strip() |
| if m: |
| machines.append(m) |
| print "Read list of machines from file: %s" % machines_file |
| print ','.join(machines) |
| |
| if machines: |
| for machine in machines: |
| if not machine or re.search('\s', machine): |
| print "Invalid machine %s" % str(machine) |
| sys.exit(1) |
| machines = list(set(machines)) |
| machines.sort() |
| |
| job = server_job.server_job(control, parser.args[1:], results, label, |
| user, machines, client, parse_job, |
| ssh_user, ssh_port, ssh_pass) |
| if results: |
| debug_dir = os.path.join(results, 'debug') |
| stdout = os.path.join(debug_dir, 'autoserv.stdout') |
| stderr = os.path.join(debug_dir, 'autoserv.stderr') |
| if no_tee: |
| job.stdout.redirect(stdout) |
| job.stderr.redirect(stderr) |
| else: |
| job.stdout.tee_redirect(stdout) |
| job.stderr.tee_redirect(stderr) |
| |
| # perform checks |
| job.precheck() |
| |
| # run the job |
| exit_code = 0 |
| try: |
| if repair: |
| job.repair(host_protection) |
| elif verify: |
| job.verify() |
| else: |
| try: |
| job.run(cleanup, install_before, install_after, |
| only_collect_crashinfo=collect_crashinfo) |
| finally: |
| while job.hosts: |
| host = job.hosts.pop() |
| host.close() |
| except: |
| exit_code = 1 |
| traceback.print_exc() |
| |
| if pid_file_manager: |
| pid_file_manager.num_tests_failed = job.num_tests_failed |
| pid_file_manager.close_file(exit_code) |
| job.cleanup_parser() |
| |
| sys.exit(exit_code) |
| |
| |
| def main(): |
| # grab the parser |
| parser = autoserv_parser.autoserv_parser |
| parser.parse_args() |
| |
| if len(sys.argv) == 1: |
| parser.parser.print_help() |
| sys.exit(1) |
| |
| results = parser.options.results |
| if not parser.options.no_logging: |
| if not results: |
| results = 'results.' + time.strftime('%Y-%m-%d-%H.%M.%S') |
| results = os.path.abspath(results) |
| resultdir_exists = os.path.exists(os.path.join(results, 'control.srv')) |
| if not parser.options.collect_crashinfo and resultdir_exists: |
| error = "Error: results directory already exists: %s\n" % results |
| sys.stderr.write(error) |
| sys.exit(1) |
| |
| # Now that we certified that there's no leftover results dir from |
| # previous jobs, lets create the result dir since the logging system |
| # needs to create the log file in there. |
| if not os.path.isdir(results): |
| os.makedirs(results) |
| os.environ['AUTOSERV_RESULTS'] = results |
| serverdir = os.path.dirname(__file__) |
| logging.config.fileConfig('%s/debug_server.ini' % serverdir) |
| logging.info("Results placed in %s" % results) |
| else: |
| # If we supply -N, no results dir will be generated, so |
| # we'll configure the logging system on code. |
| stamp = '[%(asctime)s - %(levelname)-8s] %(message)s' |
| root_logger = logging.getLogger() |
| formatter = logging.Formatter(stamp, datefmt='%H:%M:%S') |
| # Let's verify if we already have handlers for the root logger |
| # at this point. |
| if len(root_logger.handlers) == 0: |
| autoserv_handler = logging.StreamHandler(sys.stdout,) |
| autoserv_handler.setFormatter(formatter) |
| root_logger.addHandler(autoserv_handler) |
| else: |
| # If we already have any handlers up at this point, let's |
| # just configure this one we already have. |
| root_logger.handlers[0].setFormatter(formatter) |
| |
| # When the -N flag is being used, we are assuming DEBUG level for the |
| # execution. We could read the level from the configuration file, |
| # but I am not sure if this is the right way to go, since we are doing |
| # all the configuration on code (lmr). |
| root_logger.setLevel(logging.DEBUG) |
| |
| |
| if parser.options.write_pidfile: |
| pid_file_manager = pidfile.PidFileManager("autoserv", results) |
| pid_file_manager.open_file() |
| else: |
| pid_file_manager = None |
| |
| autotest.BaseAutotest.set_install_in_tmpdir( |
| parser.options.install_in_tmpdir) |
| |
| exit_code = 0 |
| try: |
| try: |
| run_autoserv(pid_file_manager, results, parser) |
| except SystemExit, e: |
| exit_code = e.code |
| except: |
| traceback.print_exc() |
| # If we don't know what happened, we'll classify it as |
| # an 'abort' and return 1. |
| exit_code = 1 |
| finally: |
| if pid_file_manager: |
| pid_file_manager.close_file(exit_code) |
| sys.exit(exit_code) |
| |
| |
| if __name__ == '__main__': |
| main() |