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