blob: ead9e31948d6a70d9a077e73c4efb51ae132b35b [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
mbligh7cd30fd2008-10-21 16:25:19 +000013import sys, os, re, traceback, signal, time
mbligh0c3548d2008-02-01 18:08:53 +000014
mblighf5427bb2008-04-09 15:55:57 +000015import common
mblighcce191f2008-09-19 20:31:03 +000016from autotest_lib.server import server_job, utils, autoserv_parser
mbligh0b8c32d2008-10-29 16:46:04 +000017from autotest_lib.client.common_lib import debug
18
19
20debug.configure(module='server')
mbligh29aa9702007-08-09 22:41:43 +000021
mbligh9d1c7302007-10-07 18:53:13 +000022
mbligh92c0fc22008-11-20 16:52:23 +000023
24# send stdin to /dev/null
25dev_null = os.open(os.devnull, sys.stdin.fileno())
26os.dup2(dev_null, sys.stdin.fileno())
27os.close(dev_null)
28
29
mbligha46678d2008-05-01 20:00:01 +000030class PidFileManager(object):
jadmanski0afbb632008-06-06 21:10:57 +000031 pid_file = None
showard21baa452008-10-21 00:08:39 +000032 num_tests_failed = 0
mbligh74fc0462007-11-05 20:24:17 +000033
jadmanski0afbb632008-06-06 21:10:57 +000034 def open_pid_file(self, results_dir):
35 pid_file_path = os.path.join(results_dir, '.autoserv_execute')
36 assert not os.path.exists(pid_file_path)
37 self.pid_file = open(pid_file_path, 'w')
38 self.pid_file.write(str(os.getpid()) + '\n')
39 self.pid_file.flush()
mblighc99add62007-09-27 17:02:58 +000040
mblighc99add62007-09-27 17:02:58 +000041
jadmanski0afbb632008-06-06 21:10:57 +000042 def close_pid_file(self, exit_code, signal_code=0):
43 if not self.pid_file:
44 return
45 real_exit_code = (exit_code << 8) | (signal_code & 0xFF)
46 self.pid_file.write(str(real_exit_code) + '\n')
showard21baa452008-10-21 00:08:39 +000047 self.pid_file.write(str(self.num_tests_failed) + '\n')
jadmanski0afbb632008-06-06 21:10:57 +000048 self.pid_file.close()
49 self.pid_file = None
mblighc99add62007-09-27 17:02:58 +000050
mbligh842c6592007-11-05 18:27:23 +000051
mbligha46678d2008-05-01 20:00:01 +000052def run_autoserv(pid_file_manager, results, parser):
jadmanski0afbb632008-06-06 21:10:57 +000053 # send stdin to /dev/null
54 dev_null = os.open(os.devnull, os.O_RDONLY)
55 os.dup2(dev_null, sys.stdin.fileno())
56 os.close(dev_null)
mblighdbf37612007-11-24 19:38:11 +000057
jadmanski0afbb632008-06-06 21:10:57 +000058 # Create separate process group
59 os.setpgrp()
mbligh1d42d4e2007-11-05 22:42:00 +000060
jadmanski0afbb632008-06-06 21:10:57 +000061 # Implement SIGTERM handler
62 def handle_sigint(signum, frame):
63 pid_file_manager.close_pid_file(1, signal.SIGTERM)
64 os.killpg(os.getpgrp(), signal.SIGKILL)
mblighfaf0cd42007-11-19 16:00:24 +000065
jadmanski0afbb632008-06-06 21:10:57 +000066 # Set signal handler
67 signal.signal(signal.SIGTERM, handle_sigint)
mblighe25fd5b2008-01-22 17:23:37 +000068
jadmanski0afbb632008-06-06 21:10:57 +000069 # Get a useful value for running 'USER'
70 realuser = os.environ.get('USER')
71 if not realuser:
72 realuser = 'anonymous'
mbligha46678d2008-05-01 20:00:01 +000073
mblighcce191f2008-09-19 20:31:03 +000074 if parser.options.machines:
75 machines = parser.options.machines.replace(',', ' ').strip().split()
76 else:
77 machines = []
jadmanski0afbb632008-06-06 21:10:57 +000078 machines_file = parser.options.machines_file
mblighb2bea302008-07-24 20:25:57 +000079 label = parser.options.label
80 user = parser.options.user
81 client = parser.options.client
82 server = parser.options.server
jadmanski0afbb632008-06-06 21:10:57 +000083 install_before = parser.options.install_before
mblighb2bea302008-07-24 20:25:57 +000084 install_after = parser.options.install_after
85 verify = parser.options.verify
86 repair = parser.options.repair
showard45ae8192008-11-05 19:32:53 +000087 cleanup = parser.options.cleanup
mblighb2bea302008-07-24 20:25:57 +000088 no_tee = parser.options.no_tee
jadmanski0afbb632008-06-06 21:10:57 +000089 parse_job = parser.options.parse_job
jadmanskifbc1f0a2008-07-09 14:12:54 +000090 host_protection = parser.options.host_protection
jadmanski0afbb632008-06-06 21:10:57 +000091 ssh_user = parser.options.ssh_user
92 ssh_port = parser.options.ssh_port
93 ssh_pass = parser.options.ssh_pass
mbligha46678d2008-05-01 20:00:01 +000094
mblighb2bea302008-07-24 20:25:57 +000095 # can't be both a client and a server side test
96 if client and server:
97 print "Can not specify a test as both server and client!"
98 sys.exit(1)
99
showard45ae8192008-11-05 19:32:53 +0000100 if len(parser.args) < 1 and not (verify or repair or cleanup):
jadmanski0afbb632008-06-06 21:10:57 +0000101 print parser.parser.print_help()
102 sys.exit(1)
mbligha46678d2008-05-01 20:00:01 +0000103
showard45ae8192008-11-05 19:32:53 +0000104 # We have a control file unless it's just a verify/repair/cleanup job
jadmanski0afbb632008-06-06 21:10:57 +0000105 if len(parser.args) > 0:
106 control = parser.args[0]
107 else:
108 control = None
mbligha46678d2008-05-01 20:00:01 +0000109
jadmanski0afbb632008-06-06 21:10:57 +0000110 if machines_file:
111 machines = []
112 for m in open(machines_file, 'r').readlines():
113 # remove comments, spaces
114 m = re.sub('#.*', '', m).strip()
115 if m:
116 machines.append(m)
117 print "Read list of machines from file: %s" % machines_file
118 print ','.join(machines)
mbligha46678d2008-05-01 20:00:01 +0000119
jadmanski0afbb632008-06-06 21:10:57 +0000120 if machines:
121 for machine in machines:
122 if not machine or re.search('\s', machine):
123 print "Invalid machine %s" % str(machine)
124 sys.exit(1)
125 machines = list(set(machines))
126 machines.sort()
mbligha46678d2008-05-01 20:00:01 +0000127
jadmanski0afbb632008-06-06 21:10:57 +0000128 job = server_job.server_job(control, parser.args[1:], results, label,
129 user, machines, client, parse_job,
130 ssh_user, ssh_port, ssh_pass)
mbligh80e1eba2008-11-19 00:26:18 +0000131 if results:
132 debug_dir = os.path.join(results, 'debug')
133 stdout = os.path.join(debug_dir, 'autoserv.stdout')
134 stderr = os.path.join(debug_dir, 'autoserv.stderr')
135 if no_tee:
136 job.stdout.redirect(stdout)
137 job.stderr.redirect(stderr)
138 else:
139 job.stdout.tee_redirect(stdout)
140 job.stderr.tee_redirect(stderr)
mbligha46678d2008-05-01 20:00:01 +0000141
mbligh161fe6f2008-06-19 16:26:04 +0000142 # perform checks
143 job.precheck()
144
jadmanski0afbb632008-06-06 21:10:57 +0000145 # run the job
146 exit_code = 0
147 try:
148 if repair:
jadmanskifbc1f0a2008-07-09 14:12:54 +0000149 job.repair(host_protection)
jadmanski0afbb632008-06-06 21:10:57 +0000150 elif verify:
151 job.verify()
152 else:
153 try:
showard45ae8192008-11-05 19:32:53 +0000154 job.run(cleanup, install_before, install_after)
jadmanski0afbb632008-06-06 21:10:57 +0000155 finally:
156 job.cleanup_parser()
jadmanski53aaf382008-11-17 16:22:31 +0000157 while job.hosts:
158 host = job.hosts.pop()
159 host.close()
jadmanski0afbb632008-06-06 21:10:57 +0000160 except:
jadmanski27b37ea2008-10-29 23:54:31 +0000161 exit_code = 1
jadmanski0afbb632008-06-06 21:10:57 +0000162 traceback.print_exc()
mbligha46678d2008-05-01 20:00:01 +0000163
showard21baa452008-10-21 00:08:39 +0000164 pid_file_manager.num_tests_failed = job.num_tests_failed
165
jadmanski27b37ea2008-10-29 23:54:31 +0000166 sys.exit(exit_code)
mbligha46678d2008-05-01 20:00:01 +0000167
168
169def main():
jadmanski0afbb632008-06-06 21:10:57 +0000170 pid_file_manager = PidFileManager()
mbligha46678d2008-05-01 20:00:01 +0000171
jadmanski0afbb632008-06-06 21:10:57 +0000172 # grab the parser
173 parser = autoserv_parser.autoserv_parser
mbligha46678d2008-05-01 20:00:01 +0000174
jadmanski0afbb632008-06-06 21:10:57 +0000175 if len(sys.argv) == 1:
176 parser.parser.print_help()
177 sys.exit(1)
mbligha6f13082008-06-05 23:53:46 +0000178
mbligh49acee52008-11-05 00:16:09 +0000179 if os.path.exists(os.path.join(results, 'control.srv')):
180 error = "Error: results directory already exists: %s\n" % results
181 sys.stderr.write(error)
182 sys.exit(1)
183 print "Results placed in %s" % results
184
mbligh80e1eba2008-11-19 00:26:18 +0000185 results = parser.options.results
186 if not parser.options.no_logging:
187 if not results:
188 results = 'results.' + time.strftime('%Y-%m-%d-%H.%M.%S')
189 results = os.path.abspath(results)
190 if os.path.exists(os.path.join(results, 'control.srv')):
191 error = "Error: results directory already exists: %s\n" % results
192 sys.stderr.write(error)
193 sys.exit(1)
194 print "Results placed in %s" % results
mbligh10717632008-11-19 00:21:57 +0000195
mbligh80e1eba2008-11-19 00:26:18 +0000196 if parser.options.write_pidfile:
jadmanski0afbb632008-06-06 21:10:57 +0000197 pid_file_manager.open_pid_file(results)
mbligha46678d2008-05-01 20:00:01 +0000198
jadmanski0afbb632008-06-06 21:10:57 +0000199 exit_code = 0
200 try:
201 try:
mbligh10717632008-11-19 00:21:57 +0000202 run_autoserv(pid_file_manager, results, parser)
jadmanski0afbb632008-06-06 21:10:57 +0000203 except SystemExit, e:
204 exit_code = e.code
205 except:
206 traceback.print_exc()
207 # If we don't know what happened, we'll classify it as
208 # an 'abort' and return 1.
209 exit_code = 1
210 finally:
211 pid_file_manager.close_pid_file(exit_code)
212 sys.exit(exit_code)
mblighfaf0cd42007-11-19 16:00:24 +0000213
mblighbb421852008-03-11 22:36:16 +0000214
mbligha46678d2008-05-01 20:00:01 +0000215if __name__ == '__main__':
jadmanski0afbb632008-06-06 21:10:57 +0000216 main()