autoserv.py revision 6437ff5bb28a0cc97582766826f866a39affae2a
1#!/usr/bin/python -u 2# 3# Copyright 2007 Google Inc. Released under the GPL v2 4 5""" 6Run an control file through the server side engine 7""" 8 9__author__ = """\ 10mbligh@google.com (Martin J. Bligh) 11""" 12 13import sys, os, re, traceback, signal 14 15import common 16from autotest_lib.server import server_job, utils 17 18# send stdin to /dev/null 19dev_null = os.open(os.devnull, os.O_RDONLY) 20os.dup2(dev_null, sys.stdin.fileno()) 21os.close(dev_null) 22 23 24class PidFileManager(object): 25 pid_file = None 26 27 def open_pid_file(self, results_dir): 28 pid_file_path = os.path.join(results_dir, '.autoserv_execute') 29 assert not os.path.exists(pid_file_path) 30 self.pid_file = open(pid_file_path, 'w') 31 self.pid_file.write(str(os.getpid()) + '\n') 32 self.pid_file.flush() 33 34 35 def close_pid_file(self, exit_code, signal_code=0): 36 if not self.pid_file: 37 return 38 real_exit_code = (exit_code << 8) | (signal_code & 0xFF) 39 self.pid_file.write(str(real_exit_code) + '\n') 40 self.pid_file.close() 41 42 43pid_file_manager = PidFileManager() 44 45 46# Create separate process group 47os.setpgrp() 48 49# Implement SIGTERM handler 50def handle_sigint(signum, frame): 51 pid_file_manager.close_pid_file(1, signal.SIGTERM) 52 os.killpg(os.getpgrp(), signal.SIGKILL) 53 54# Set signal handler 55signal.signal(signal.SIGTERM, handle_sigint) 56 57 58usage = """\ 59usage: autoserv 60 [-h, --help] # This help message 61 [-m machine,[machine,...]] # list of machines to pass to control file 62 [-M machines_file] # list of machines (from a file) 63 [-c] # control file is a client side control 64 [-r resultsdir] # specify results directory (default '.') 65 [-i] # reinstall machines before running the job 66 [-I] # reinstall machines after running the job 67 [-b] # reboot all specified machines after the job 68 [-l label] # label for the job (arbitrary string) 69 [-u user] # username for the job (email address) 70 [-v] # verify the machines only 71 [-R] # repair the machines 72 [-n] # no teeing the status to stdout/stderr 73 [-p] # write pidfile (.autoserv_execute) 74 [-P jobname] # parse the results of the job 75 <control file> # name of the control file to run 76 [args ...] # args to pass through to the control file 77""" 78 79args = sys.argv[1:] 80parser = utils.AutoservOptionParser(args) 81 82# Get a useful value for running 'USER' 83realuser = os.environ.get('USER') 84if not realuser: 85 realuser = 'anonymous' 86 87machines = parser.parse_opts_param('-m', None, split = ',') 88machines_file = parser.parse_opts_param('-M', None) 89results = parser.parse_opts_param('-r', os.path.abspath('.')) 90results = os.path.abspath(results) 91label = parser.parse_opts_param('-l', '') 92user = parser.parse_opts_param('-u', realuser) 93client = parser.parse_opts('-c') 94reboot = parser.parse_opts('-b') 95install_before = parser.parse_opts('-i') 96install_after = parser.parse_opts('-I') 97verify = parser.parse_opts('-v') 98repair = parser.parse_opts('-R') 99no_tee = parser.parse_opts('-n') 100help = parser.parse_opts('-h') or parser.parse_opts('--help') 101write_pidfile = parser.parse_opts('-p') 102parse_job = parser.parse_opts_param('-P', '') 103 104if help is True: 105 print usage 106 sys.exit(0) 107 108if len(parser.args) < 1 and not verify and not repair: 109 print usage 110 sys.exit(-1) 111 112if machines_file: 113 machines = [] 114 for m in open(machines_file, 'r').readlines(): 115 m = re.sub('#.*', '', m).strip() # remove comments, spaces 116 if m: 117 machines.append(m) 118 print "Read list of machines from file: %s" % machines_file 119 print ','.join(machines) 120 121if machines: 122 for machine in machines: 123 if not machine or re.search('\s', machine): 124 print "Invalid machine %s" % str(machine) 125 sys.exit(1) 126 machines = list(set(machines)) 127 machines.sort() 128 129# We have a control file unless it's just a verify/repair job 130if len(parser.args) > 0: 131 control = parser.args[0] 132else: 133 control = None 134 135job = server_job.server_job(control, parser.args[1:], results, label, 136 user, machines, client, parse_job) 137debug_dir = os.path.join(results, 'debug') 138if no_tee: 139 job.stdout.redirect(os.path.join(debug_dir, 'autoserv.stdout')) 140 job.stderr.redirect(os.path.join(debug_dir, 'autoserv.stderr')) 141else: 142 job.stdout.tee_redirect(os.path.join(debug_dir, 'autoserv.stdout')) 143 job.stderr.tee_redirect(os.path.join(debug_dir, 'autoserv.stderr')) 144 145if write_pidfile: 146 pid_file_manager.open_pid_file(results) 147 148# run the job 149exit_code = 0 150try: 151 if repair: 152 job.repair() 153 elif verify: 154 job.verify() 155 else: 156 try: 157 job.run(reboot, install_before, install_after) 158 finally: 159 job._cleanup() 160except: 161 job.aborted = True 162 traceback.print_exc() 163 164if getattr(job, 'aborted', False): 165 exit_code = 1 166pid_file_manager.close_pid_file(exit_code) 167 168sys.exit(exit_code) 169