autoserv revision a6f1308334f91fc5b9463cebe34a08d3be733f7c
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
17from autotest_lib.server import autoserv_parser
18
19
20class PidFileManager(object):
21	pid_file = None
22
23	def open_pid_file(self, results_dir):
24		pid_file_path = os.path.join(results_dir, '.autoserv_execute')
25		assert not os.path.exists(pid_file_path)
26		self.pid_file = open(pid_file_path, 'w')
27		self.pid_file.write(str(os.getpid()) + '\n')
28		self.pid_file.flush()
29
30
31	def close_pid_file(self, exit_code, signal_code=0):
32		if not self.pid_file:
33			return
34		real_exit_code = (exit_code << 8) | (signal_code & 0xFF)
35		self.pid_file.write(str(real_exit_code) + '\n')
36		self.pid_file.close()
37		self.pid_file = None
38
39
40def run_autoserv(pid_file_manager, results, parser):
41	# send stdin to /dev/null
42	dev_null = os.open(os.devnull, os.O_RDONLY)
43	os.dup2(dev_null, sys.stdin.fileno())
44	os.close(dev_null)
45
46	# Create separate process group
47	os.setpgrp()
48
49	# Implement SIGTERM handler
50	def 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
55	signal.signal(signal.SIGTERM, handle_sigint)
56
57	# Get a useful value for running 'USER'
58	realuser = os.environ.get('USER')
59	if not realuser:
60		realuser = 'anonymous'
61
62	machines = parser.options.machines.split(',')
63	machines_file = parser.options.machines_file
64	label    = parser.options.label
65	user     = parser.options.user
66	client   = parser.options.client
67	reboot   = parser.options.reboot
68	install_before = parser.options.install_before
69	install_after  = parser.options.install_after
70	verify   = parser.options.verify
71	repair   = parser.options.repair
72	no_tee   = parser.options.no_tee
73	parse_job = parser.options.parse_job
74	ssh_user = parser.options.ssh_user
75	ssh_port = parser.options.ssh_port
76	ssh_pass = parser.options.ssh_pass
77
78	if len(parser.args) < 1 and not verify and not repair:
79		print parser.parser.print_help()
80		sys.exit(1)
81
82	# We have a control file unless it's just a verify/repair job
83	if len(parser.args) > 0:
84		control = parser.args[0]
85	else:
86		control = None
87
88	if machines_file:
89		machines = []
90		for m in open(machines_file, 'r').readlines():
91			# remove comments, spaces
92			m = re.sub('#.*', '', m).strip()
93			if m:
94				machines.append(m)
95		print "Read list of machines from file: %s" % machines_file
96		print ','.join(machines)
97
98	if machines:
99		for machine in machines:
100			if not machine or re.search('\s', machine):
101				print "Invalid machine %s" % str(machine)
102				sys.exit(1)
103		machines = list(set(machines))
104		machines.sort()
105
106	job = server_job.server_job(control, parser.args[1:], results, label,
107				    user, machines, client, parse_job,
108				    ssh_user, ssh_port, ssh_pass)
109	debug_dir = os.path.join(results, 'debug')
110	stdout = os.path.join(debug_dir, 'autoserv.stdout')
111	stderr = os.path.join(debug_dir, 'autoserv.stderr')
112	if no_tee:
113		job.stdout.redirect(stdout)
114		job.stderr.redirect(stderr)
115	else:
116		job.stdout.tee_redirect(stdout)
117		job.stderr.tee_redirect(stderr)
118
119	# run the job
120	exit_code = 0
121	try:
122		if repair:
123			job.repair()
124		elif verify:
125			job.verify()
126		else:
127			try:
128				job.run(reboot, install_before, install_after)
129			finally:
130				job.cleanup_parser()
131	except:
132		job.aborted = True
133		traceback.print_exc()
134
135	if getattr(job, 'aborted', False):
136		sys.exit(1)
137
138
139def main():
140	pid_file_manager = PidFileManager()
141
142	# grab the parser
143	parser = autoserv_parser.autoserv_parser
144
145	if len(sys.argv) == 1:
146		parser.parser.print_help()
147		sys.exit(1)
148
149	results  = parser.options.results
150	results  = os.path.abspath(results)
151	write_pidfile = parser.options.write_pidfile
152	if write_pidfile:
153		pid_file_manager.open_pid_file(results)
154
155	exit_code = 0
156	try:
157		try:
158			run_autoserv(pid_file_manager, results, parser)
159		except SystemExit, e:
160			exit_code = e.code
161		except:
162			traceback.print_exc()
163			# If we don't know what happened, we'll classify it as
164			# an 'abort' and return 1.
165			exit_code = 1
166	finally:
167		pid_file_manager.close_pid_file(exit_code)
168	sys.exit(exit_code)
169
170
171if __name__ == '__main__':
172	main()
173