blob: a3a9683ff7a7d21d23003525dd99553a06e29d20 [file] [log] [blame]
mbligh6203ace2007-10-04 21:54:24 +00001#!/usr/bin/python -u
mblighdcd57a82007-07-11 23:06:47 +00002#
3# Copyright 2007 Google Inc. Released under the GPL v2
4
mblighc8949b82007-07-23 16:33:58 +00005"""
mblighf1c52842007-10-16 15:21:38 +00006Run an control file through the server side engine
mblighdcd57a82007-07-11 23:06:47 +00007"""
8
mblighf1c52842007-10-16 15:21:38 +00009__author__ = """\
10mbligh@google.com (Martin J. Bligh)
mblighc8949b82007-07-23 16:33:58 +000011"""
mblighdcd57a82007-07-11 23:06:47 +000012
mblighf5427bb2008-04-09 15:55:57 +000013import sys, os, re, traceback, signal
mbligh0c3548d2008-02-01 18:08:53 +000014
mblighf5427bb2008-04-09 15:55:57 +000015import common
16from autotest_lib.server import server_job, utils
mblighf7243e12008-03-05 16:01:21 +000017
mblighc251a1f2008-03-26 17:14:15 +000018# 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
mblighbb421852008-03-11 22:36:16 +000024class 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
mblighf7243e12008-03-05 16:01:21 +000046# Create separate process group
47os.setpgrp()
48
mblighbb421852008-03-11 22:36:16 +000049# Implement SIGTERM handler
mblighf7243e12008-03-05 16:01:21 +000050def handle_sigint(signum, frame):
mblighbb421852008-03-11 22:36:16 +000051 pid_file_manager.close_pid_file(1, signal.SIGTERM)
mbligh38c2d032008-03-07 00:26:57 +000052 os.killpg(os.getpgrp(), signal.SIGKILL)
mblighbb421852008-03-11 22:36:16 +000053
mblighf7243e12008-03-05 16:01:21 +000054# Set signal handler
55signal.signal(signal.SIGTERM, handle_sigint)
56
mblighdcd57a82007-07-11 23:06:47 +000057
mblighf1c52842007-10-16 15:21:38 +000058usage = """\
59usage: autoserv
mbligh9e618782008-03-13 15:35:09 +000060 [-h, --help] # This help message
mblighf36243d2007-10-30 15:36:16 +000061 [-m machine,[machine,...]] # list of machines to pass to control file
mbligh842c6592007-11-05 18:27:23 +000062 [-M machines_file] # list of machines (from a file)
mblighf1c52842007-10-16 15:21:38 +000063 [-c] # control file is a client side control
64 [-r resultsdir] # specify results directory (default '.')
mblighf36243d2007-10-30 15:36:16 +000065 [-i] # reinstall machines before running the job
66 [-I] # reinstall machines after running the job
67 [-b] # reboot all specified machines after the job
mbligh18420c22007-10-16 22:27:14 +000068 [-l label] # label for the job (arbitrary string)
mblighf1c52842007-10-16 15:21:38 +000069 [-u user] # username for the job (email address)
mbligh1d42d4e2007-11-05 22:42:00 +000070 [-v] # verify the machines only
71 [-R] # repair the machines
mblighe5cd0fd2008-01-26 23:07:31 +000072 [-n] # no teeing the status to stdout/stderr
mblighbb421852008-03-11 22:36:16 +000073 [-p] # write pidfile (.autoserv_execute)
mbligh6437ff52008-04-17 15:24:38 +000074 [-P jobname] # parse the results of the job
mblighf1c52842007-10-16 15:21:38 +000075 <control file> # name of the control file to run
76 [args ...] # args to pass through to the control file
mbligh29aa9702007-08-09 22:41:43 +000077"""
78
mbligh9d1c7302007-10-07 18:53:13 +000079args = sys.argv[1:]
mbligh40f122a2007-11-03 23:08:46 +000080parser = utils.AutoservOptionParser(args)
mbligh9d1c7302007-10-07 18:53:13 +000081
mbligh74fc0462007-11-05 20:24:17 +000082# Get a useful value for running 'USER'
83realuser = os.environ.get('USER')
84if not realuser:
85 realuser = 'anonymous'
86
mbligh40f122a2007-11-03 23:08:46 +000087machines = parser.parse_opts_param('-m', None, split = ',')
mbligh842c6592007-11-05 18:27:23 +000088machines_file = parser.parse_opts_param('-M', None)
mbligh40f122a2007-11-03 23:08:46 +000089results = parser.parse_opts_param('-r', os.path.abspath('.'))
mbligh1d42d4e2007-11-05 22:42:00 +000090results = os.path.abspath(results)
mbligh40f122a2007-11-03 23:08:46 +000091label = parser.parse_opts_param('-l', '')
mbligh74fc0462007-11-05 20:24:17 +000092user = parser.parse_opts_param('-u', realuser)
mbligh40f122a2007-11-03 23:08:46 +000093client = parser.parse_opts('-c')
94reboot = parser.parse_opts('-b')
95install_before = parser.parse_opts('-i')
96install_after = parser.parse_opts('-I')
mbligh1d42d4e2007-11-05 22:42:00 +000097verify = parser.parse_opts('-v')
98repair = parser.parse_opts('-R')
mblighe5cd0fd2008-01-26 23:07:31 +000099no_tee = parser.parse_opts('-n')
mbligh9e618782008-03-13 15:35:09 +0000100help = parser.parse_opts('-h') or parser.parse_opts('--help')
mblighbb421852008-03-11 22:36:16 +0000101write_pidfile = parser.parse_opts('-p')
mbligh6437ff52008-04-17 15:24:38 +0000102parse_job = parser.parse_opts_param('-P', '')
mblighc99add62007-09-27 17:02:58 +0000103
mbligh9e618782008-03-13 15:35:09 +0000104if help is True:
mbligh6437ff52008-04-17 15:24:38 +0000105 print usage
106 sys.exit(0)
mblighc99add62007-09-27 17:02:58 +0000107
mbligh1d42d4e2007-11-05 22:42:00 +0000108if len(parser.args) < 1 and not verify and not repair:
mbligh4ef86232007-10-23 00:09:53 +0000109 print usage
110 sys.exit(-1)
mblighc99add62007-09-27 17:02:58 +0000111
mbligh842c6592007-11-05 18:27:23 +0000112if 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
mblighdbf37612007-11-24 19:38:11 +0000121if 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)
mbligh535a4542008-02-11 16:26:36 +0000126 machines = list(set(machines))
127 machines.sort()
mblighdbf37612007-11-24 19:38:11 +0000128
mblighe25fd5b2008-01-22 17:23:37 +0000129# 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
mbligh1d42d4e2007-11-05 22:42:00 +0000134
mblighe25fd5b2008-01-22 17:23:37 +0000135job = server_job.server_job(control, parser.args[1:], results, label,
mbligh6437ff52008-04-17 15:24:38 +0000136 user, machines, client, parse_job)
mblighe5cd0fd2008-01-26 23:07:31 +0000137debug_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'))
mblighfaf0cd42007-11-19 16:00:24 +0000144
mblighbb421852008-03-11 22:36:16 +0000145if write_pidfile:
146 pid_file_manager.open_pid_file(results)
mblighe25fd5b2008-01-22 17:23:37 +0000147
mblighbb421852008-03-11 22:36:16 +0000148# run the job
149exit_code = 0
mblighfaf0cd42007-11-19 16:00:24 +0000150try:
mblighbb421852008-03-11 22:36:16 +0000151 if repair:
152 job.repair()
153 elif verify:
154 job.verify()
155 else:
mbligh6437ff52008-04-17 15:24:38 +0000156 try:
157 job.run(reboot, install_before, install_after)
158 finally:
mblighfe0af112008-04-17 15:27:47 +0000159 job.cleanup_parser()
mblighfaf0cd42007-11-19 16:00:24 +0000160except:
mbligh394ff512008-02-21 16:53:11 +0000161 job.aborted = True
mblighfaf0cd42007-11-19 16:00:24 +0000162 traceback.print_exc()
163
mblighfaf0cd42007-11-19 16:00:24 +0000164if getattr(job, 'aborted', False):
mblighbb421852008-03-11 22:36:16 +0000165 exit_code = 1
166pid_file_manager.close_pid_file(exit_code)
167
168sys.exit(exit_code)