autoserv revision c229956e546e1398cce5ca80203363b303b8fbe7
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_logging_config 13from autotest_lib.server import server_job, utils, autoserv_parser, autotest 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_sigterm(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_sigterm) 33 34 if parser.options.machines: 35 machines = parser.options.machines.replace(',', ' ').strip().split() 36 else: 37 machines = [] 38 machines_file = parser.options.machines_file 39 label = parser.options.label 40 group_name = parser.options.group_name 41 user = parser.options.user 42 client = parser.options.client 43 server = parser.options.server 44 install_before = parser.options.install_before 45 install_after = parser.options.install_after 46 verify = parser.options.verify 47 repair = parser.options.repair 48 cleanup = parser.options.cleanup 49 no_tee = parser.options.no_tee 50 parse_job = parser.options.parse_job 51 host_protection = parser.options.host_protection 52 ssh_user = parser.options.ssh_user 53 ssh_port = parser.options.ssh_port 54 ssh_pass = parser.options.ssh_pass 55 collect_crashinfo = parser.options.collect_crashinfo 56 57 # can't be both a client and a server side test 58 if client and server: 59 print "Can not specify a test as both server and client!" 60 sys.exit(1) 61 62 if len(parser.args) < 1 and not (verify or repair or cleanup 63 or collect_crashinfo): 64 print parser.parser.print_help() 65 sys.exit(1) 66 67 # We have a control file unless it's just a verify/repair/cleanup job 68 if len(parser.args) > 0: 69 control = parser.args[0] 70 else: 71 control = None 72 73 if machines_file: 74 machines = [] 75 for m in open(machines_file, 'r').readlines(): 76 # remove comments, spaces 77 m = re.sub('#.*', '', m).strip() 78 if m: 79 machines.append(m) 80 print "Read list of machines from file: %s" % machines_file 81 print ','.join(machines) 82 83 if machines: 84 for machine in machines: 85 if not machine or re.search('\s', machine): 86 print "Invalid machine %s" % str(machine) 87 sys.exit(1) 88 machines = list(set(machines)) 89 machines.sort() 90 91 if group_name and len(machines) < 2: 92 print ("-G %r may only be supplied with more than one machine." 93 % group_name) 94 sys.exit(1) 95 96 job = server_job.server_job(control, parser.args[1:], results, label, 97 user, machines, client, parse_job, 98 ssh_user, ssh_port, ssh_pass, 99 group_name=group_name) 100 job.logging.start_logging() 101 102 # perform checks 103 job.precheck() 104 105 # run the job 106 exit_code = 0 107 try: 108 try: 109 if repair: 110 job.repair(host_protection) 111 elif verify: 112 job.verify() 113 else: 114 job.run(cleanup, install_before, install_after, 115 only_collect_crashinfo=collect_crashinfo) 116 finally: 117 while job.hosts: 118 host = job.hosts.pop() 119 host.close() 120 except: 121 exit_code = 1 122 traceback.print_exc() 123 124 if pid_file_manager: 125 pid_file_manager.num_tests_failed = job.num_tests_failed 126 pid_file_manager.close_file(exit_code) 127 job.cleanup_parser() 128 129 sys.exit(exit_code) 130 131 132def main(): 133 # grab the parser 134 parser = autoserv_parser.autoserv_parser 135 parser.parse_args() 136 137 if len(sys.argv) == 1: 138 parser.parser.print_help() 139 sys.exit(1) 140 141 if parser.options.no_logging: 142 results = None 143 else: 144 results = parser.options.results 145 if not results: 146 results = 'results.' + time.strftime('%Y-%m-%d-%H.%M.%S') 147 results = os.path.abspath(results) 148 resultdir_exists = os.path.exists(os.path.join(results, 'control.srv')) 149 if not parser.options.collect_crashinfo and resultdir_exists: 150 error = "Error: results directory already exists: %s\n" % results 151 sys.stderr.write(error) 152 sys.exit(1) 153 154 # Now that we certified that there's no leftover results dir from 155 # previous jobs, lets create the result dir since the logging system 156 # needs to create the log file in there. 157 if not os.path.isdir(results): 158 os.makedirs(results) 159 160 logging_manager.configure_logging( 161 server_logging_config.ServerLoggingConfig(), results_dir=results, 162 use_console=not parser.options.no_tee, 163 verbose=parser.options.verbose, 164 no_console_prefix=parser.options.no_console_prefix) 165 if results: 166 logging.info("Results placed in %s" % results) 167 168 if parser.options.write_pidfile: 169 if parser.options.collect_crashinfo: 170 pidfile_label = 'collect_crashinfo' 171 else: 172 pidfile_label = 'autoserv' 173 pid_file_manager = pidfile.PidFileManager(pidfile_label, results) 174 pid_file_manager.open_file() 175 else: 176 pid_file_manager = None 177 178 autotest.BaseAutotest.set_install_in_tmpdir( 179 parser.options.install_in_tmpdir) 180 181 exit_code = 0 182 try: 183 try: 184 run_autoserv(pid_file_manager, results, parser) 185 except SystemExit, e: 186 exit_code = e.code 187 except: 188 traceback.print_exc() 189 # If we don't know what happened, we'll classify it as 190 # an 'abort' and return 1. 191 exit_code = 1 192 finally: 193 if pid_file_manager: 194 pid_file_manager.close_file(exit_code) 195 sys.exit(exit_code) 196 197 198if __name__ == '__main__': 199 main() 200