autoserv.py revision a5cb40631a50dcf9235d124613e281f0ffc4d959
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 10 11import common 12from autotest_lib.server import server_job, utils, autoserv_parser, autotest 13from autotest_lib.client.common_lib import debug, pidfile 14 15 16debug.configure(module='server') 17 18 19def run_autoserv(pid_file_manager, results, parser): 20 # send stdin to /dev/null 21 dev_null = os.open(os.devnull, os.O_RDONLY) 22 os.dup2(dev_null, sys.stdin.fileno()) 23 os.close(dev_null) 24 25 # Create separate process group 26 os.setpgrp() 27 28 # Implement SIGTERM handler 29 def handle_sigint(signum, frame): 30 if pid_file_manager: 31 pid_file_manager.close_file(1, signal.SIGTERM) 32 os.killpg(os.getpgrp(), signal.SIGKILL) 33 34 # Set signal handler 35 signal.signal(signal.SIGTERM, handle_sigint) 36 37 # Get a useful value for running 'USER' 38 realuser = os.environ.get('USER') 39 if not realuser: 40 realuser = 'anonymous' 41 42 if parser.options.machines: 43 machines = parser.options.machines.replace(',', ' ').strip().split() 44 else: 45 machines = [] 46 machines_file = parser.options.machines_file 47 label = parser.options.label 48 user = parser.options.user 49 client = parser.options.client 50 server = parser.options.server 51 install_before = parser.options.install_before 52 install_after = parser.options.install_after 53 verify = parser.options.verify 54 repair = parser.options.repair 55 cleanup = parser.options.cleanup 56 no_tee = parser.options.no_tee 57 parse_job = parser.options.parse_job 58 host_protection = parser.options.host_protection 59 ssh_user = parser.options.ssh_user 60 ssh_port = parser.options.ssh_port 61 ssh_pass = parser.options.ssh_pass 62 63 # can't be both a client and a server side test 64 if client and server: 65 print "Can not specify a test as both server and client!" 66 sys.exit(1) 67 68 if len(parser.args) < 1 and not (verify or repair or cleanup): 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 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 if results: 100 debug_dir = os.path.join(results, 'debug') 101 stdout = os.path.join(debug_dir, 'autoserv.stdout') 102 stderr = os.path.join(debug_dir, 'autoserv.stderr') 103 if no_tee: 104 job.stdout.redirect(stdout) 105 job.stderr.redirect(stderr) 106 else: 107 job.stdout.tee_redirect(stdout) 108 job.stderr.tee_redirect(stderr) 109 110 # perform checks 111 job.precheck() 112 113 # run the job 114 exit_code = 0 115 try: 116 if repair: 117 job.repair(host_protection) 118 elif verify: 119 job.verify() 120 else: 121 try: 122 job.run(cleanup, install_before, install_after) 123 finally: 124 while job.hosts: 125 host = job.hosts.pop() 126 host.close() 127 except: 128 exit_code = 1 129 traceback.print_exc() 130 131 if pid_file_manager: 132 pid_file_manager.num_tests_failed = job.num_tests_failed 133 pid_file_manager.close_file(exit_code) 134 job.cleanup_parser() 135 136 sys.exit(exit_code) 137 138 139def main(): 140 # grab the parser 141 parser = autoserv_parser.autoserv_parser 142 parser.parse_args() 143 144 if len(sys.argv) == 1: 145 parser.parser.print_help() 146 sys.exit(1) 147 148 results = parser.options.results 149 if not parser.options.no_logging: 150 if not results: 151 results = 'results.' + time.strftime('%Y-%m-%d-%H.%M.%S') 152 results = os.path.abspath(results) 153 if os.path.exists(os.path.join(results, 'control.srv')): 154 error = "Error: results directory already exists: %s\n" % results 155 sys.stderr.write(error) 156 sys.exit(1) 157 print "Results placed in %s" % results 158 159 if parser.options.write_pidfile: 160 pid_file_manager = pidfile.PidFileManager("autoserv", results) 161 pid_file_manager.open_file() 162 else: 163 pid_file_manager = None 164 165 autotest.BaseAutotest.set_install_in_tmpdir( 166 parser.options.install_in_tmpdir) 167 168 exit_code = 0 169 try: 170 try: 171 run_autoserv(pid_file_manager, results, parser) 172 except SystemExit, e: 173 exit_code = e.code 174 except: 175 traceback.print_exc() 176 # If we don't know what happened, we'll classify it as 177 # an 'abort' and return 1. 178 exit_code = 1 179 finally: 180 if pid_file_manager: 181 pid_file_manager.close_file(exit_code) 182 sys.exit(exit_code) 183 184 185if __name__ == '__main__': 186 main() 187