autoserv.py revision 75cdfee87bfaa3cf3f9860832b228a6d32aaed2f
1#!/usr/bin/python -u 2# Copyright 2007-2008 Martin J. Bligh <mbligh@google.com>, Google Inc. 3# Released under the GPL v2 4 5""" 6Run an control file through the server side engine 7""" 8 9import sys, os, re, traceback, signal, time, logging 10 11import common 12from autotest_lib.server import server_job, utils, autoserv_parser, autotest 13from autotest_lib.server import server_logging_config 14from autotest_lib.client.common_lib import pidfile, logging_manager 15 16def run_autoserv(pid_file_manager, results, parser): 17 # send stdin to /dev/null 18 dev_null = os.open(os.devnull, os.O_RDONLY) 19 os.dup2(dev_null, sys.stdin.fileno()) 20 os.close(dev_null) 21 22 # Create separate process group 23 os.setpgrp() 24 25 # Implement SIGTERM handler 26 def handle_sigint(signum, frame): 27 if pid_file_manager: 28 pid_file_manager.close_file(1, signal.SIGTERM) 29 os.killpg(os.getpgrp(), signal.SIGKILL) 30 31 # Set signal handler 32 signal.signal(signal.SIGTERM, handle_sigint) 33 34 # Get a useful value for running 'USER' 35 realuser = os.environ.get('USER') 36 if not realuser: 37 realuser = 'anonymous' 38 39 if parser.options.machines: 40 machines = parser.options.machines.replace(',', ' ').strip().split() 41 else: 42 machines = [] 43 machines_file = parser.options.machines_file 44 label = parser.options.label 45 group_name = parser.options.group_name 46 user = parser.options.user 47 client = parser.options.client 48 server = parser.options.server 49 install_before = parser.options.install_before 50 install_after = parser.options.install_after 51 verify = parser.options.verify 52 repair = parser.options.repair 53 cleanup = parser.options.cleanup 54 no_tee = parser.options.no_tee 55 parse_job = parser.options.parse_job 56 host_protection = parser.options.host_protection 57 ssh_user = parser.options.ssh_user 58 ssh_port = parser.options.ssh_port 59 ssh_pass = parser.options.ssh_pass 60 collect_crashinfo = parser.options.collect_crashinfo 61 62 # can't be both a client and a server side test 63 if client and server: 64 print "Can not specify a test as both server and client!" 65 sys.exit(1) 66 67 if len(parser.args) < 1 and not (verify or repair or cleanup 68 or collect_crashinfo): 69 print parser.parser.print_help() 70 sys.exit(1) 71 72 # We have a control file unless it's just a verify/repair/cleanup job 73 if len(parser.args) > 0: 74 control = parser.args[0] 75 else: 76 control = None 77 78 if machines_file: 79 machines = [] 80 for m in open(machines_file, 'r').readlines(): 81 # remove comments, spaces 82 m = re.sub('#.*', '', m).strip() 83 if m: 84 machines.append(m) 85 print "Read list of machines from file: %s" % machines_file 86 print ','.join(machines) 87 88 if machines: 89 for machine in machines: 90 if not machine or re.search('\s', machine): 91 print "Invalid machine %s" % str(machine) 92 sys.exit(1) 93 machines = list(set(machines)) 94 machines.sort() 95 96 if group_name and len(machines) < 2: 97 print ("-G %r may only be supplied with more than one machine." 98 % group_name) 99 sys.exit(1) 100 101 job = server_job.server_job(control, parser.args[1:], results, label, 102 user, machines, client, parse_job, 103 ssh_user, ssh_port, ssh_pass, 104 group_name=group_name) 105 job.logging.start_logging() 106 107 # perform checks 108 job.precheck() 109 110 # run the job 111 exit_code = 0 112 try: 113 try: 114 if repair: 115 job.repair(host_protection) 116 elif verify: 117 job.verify() 118 else: 119 job.run(cleanup, install_before, install_after, 120 only_collect_crashinfo=collect_crashinfo) 121 finally: 122 while job.hosts: 123 host = job.hosts.pop() 124 host.close() 125 except: 126 exit_code = 1 127 traceback.print_exc() 128 129 if pid_file_manager: 130 pid_file_manager.num_tests_failed = job.num_tests_failed 131 pid_file_manager.close_file(exit_code) 132 job.cleanup_parser() 133 134 sys.exit(exit_code) 135 136 137def main(): 138 # grab the parser 139 parser = autoserv_parser.autoserv_parser 140 parser.parse_args() 141 142 if len(sys.argv) == 1: 143 parser.parser.print_help() 144 sys.exit(1) 145 146 if parser.options.no_logging: 147 results = None 148 else: 149 results = parser.options.results 150 if not results: 151 results = 'results.' + time.strftime('%Y-%m-%d-%H.%M.%S') 152 results = os.path.abspath(results) 153 resultdir_exists = os.path.exists(os.path.join(results, 'control.srv')) 154 if not parser.options.collect_crashinfo and resultdir_exists: 155 error = "Error: results directory already exists: %s\n" % results 156 sys.stderr.write(error) 157 sys.exit(1) 158 159 # Now that we certified that there's no leftover results dir from 160 # previous jobs, lets create the result dir since the logging system 161 # needs to create the log file in there. 162 if not os.path.isdir(results): 163 os.makedirs(results) 164 165 logging_manager.configure_logging( 166 server_logging_config.ServerLoggingConfig(), results_dir=results, 167 use_console=not parser.options.no_tee) 168 if results: 169 logging.info("Results placed in %s" % results) 170 171 if parser.options.write_pidfile: 172 if parser.options.collect_crashinfo: 173 pidfile_label = 'collect_crashinfo' 174 else: 175 pidfile_label = 'autoserv' 176 pid_file_manager = pidfile.PidFileManager(pidfile_label, results) 177 pid_file_manager.open_file() 178 else: 179 pid_file_manager = None 180 181 autotest.BaseAutotest.set_install_in_tmpdir( 182 parser.options.install_in_tmpdir) 183 184 exit_code = 0 185 try: 186 try: 187 run_autoserv(pid_file_manager, results, parser) 188 except SystemExit, e: 189 exit_code = e.code 190 except: 191 traceback.print_exc() 192 # If we don't know what happened, we'll classify it as 193 # an 'abort' and return 1. 194 exit_code = 1 195 finally: 196 if pid_file_manager: 197 pid_file_manager.close_file(exit_code) 198 sys.exit(exit_code) 199 200 201if __name__ == '__main__': 202 main() 203