2 # Copyright 2007-2008 Martin J. Bligh <mbligh@google.com>, Google Inc.
3 # Released under the GPL v2
6 Run an control file through the server side engine
9 import sys
, os
, re
, traceback
, signal
, time
, logging
, getpass
13 from autotest_lib
.client
.common_lib
.global_config
import global_config
14 require_atfork
= global_config
.get_config_value(
15 'AUTOSERV', 'require_atfork_module', type=bool, default
=True)
19 atfork
.monkeypatch_os_fork_functions()
20 import atfork
.stdlib_fixer
21 # Fix the Python standard library for threading+fork safety with its
22 # internal locks. http://code.google.com/p/python-atfork/
24 warnings
.filterwarnings('ignore', 'logging module already imported')
25 atfork
.stdlib_fixer
.fix_logging_module()
26 except ImportError, e
:
27 from autotest_lib
.client
.common_lib
import global_config
28 if global_config
.global_config
.get_config_value(
29 'AUTOSERV', 'require_atfork_module', type=bool, default
=False):
30 print >>sys
.stderr
, 'Please run utils/build_externals.py'
34 from autotest_lib
.server
import server_logging_config
35 from autotest_lib
.server
import server_job
, utils
, autoserv_parser
, autotest
36 from autotest_lib
.client
.common_lib
import pidfile
, logging_manager
38 def run_autoserv(pid_file_manager
, results
, parser
):
39 # send stdin to /dev/null
40 dev_null
= os
.open(os
.devnull
, os
.O_RDONLY
)
41 os
.dup2(dev_null
, sys
.stdin
.fileno())
44 # Create separate process group
47 # Implement SIGTERM handler
48 def handle_sigterm(signum
, frame
):
50 pid_file_manager
.close_file(1, signal
.SIGTERM
)
51 os
.killpg(os
.getpgrp(), signal
.SIGKILL
)
54 signal
.signal(signal
.SIGTERM
, handle_sigterm
)
56 # Ignore SIGTTOU's generated by output from forked children.
57 signal
.signal(signal
.SIGTTOU
, signal
.SIG_IGN
)
59 # Server side tests that call shell scripts often depend on $USER being set
60 # but depending on how you launch your autotest scheduler it may not be set.
61 os
.environ
['USER'] = getpass
.getuser()
63 if parser
.options
.machines
:
64 machines
= parser
.options
.machines
.replace(',', ' ').strip().split()
67 machines_file
= parser
.options
.machines_file
68 label
= parser
.options
.label
69 group_name
= parser
.options
.group_name
70 user
= parser
.options
.user
71 client
= parser
.options
.client
72 server
= parser
.options
.server
73 install_before
= parser
.options
.install_before
74 install_after
= parser
.options
.install_after
75 verify
= parser
.options
.verify
76 repair
= parser
.options
.repair
77 cleanup
= parser
.options
.cleanup
78 no_tee
= parser
.options
.no_tee
79 parse_job
= parser
.options
.parse_job
80 execution_tag
= parser
.options
.execution_tag
82 execution_tag
= parse_job
83 host_protection
= parser
.options
.host_protection
84 ssh_user
= parser
.options
.ssh_user
85 ssh_port
= parser
.options
.ssh_port
86 ssh_pass
= parser
.options
.ssh_pass
87 collect_crashinfo
= parser
.options
.collect_crashinfo
88 control_filename
= parser
.options
.control_filename
90 # can't be both a client and a server side test
92 parser
.parser
.error("Can not specify a test as both server and client!")
94 if len(parser
.args
) < 1 and not (verify
or repair
or cleanup
95 or collect_crashinfo
):
96 parser
.parser
.error("Missing argument: control file")
98 # We have a control file unless it's just a verify/repair/cleanup job
99 if len(parser
.args
) > 0:
100 control
= parser
.args
[0]
106 for m
in open(machines_file
, 'r').readlines():
107 # remove comments, spaces
108 m
= re
.sub('#.*', '', m
).strip()
111 print "Read list of machines from file: %s" % machines_file
112 print ','.join(machines
)
115 for machine
in machines
:
116 if not machine
or re
.search('\s', machine
):
117 parser
.parser
.error("Invalid machine: %s" % str(machine
))
118 machines
= list(set(machines
))
121 if group_name
and len(machines
) < 2:
122 parser
.parser
.error("-G %r may only be supplied with more than one machine."
125 kwargs
= {'group_name': group_name
, 'tag': execution_tag
}
127 kwargs
['control_filename'] = control_filename
128 job
= server_job
.server_job(control
, parser
.args
[1:], results
, label
,
129 user
, machines
, client
, parse_job
,
130 ssh_user
, ssh_port
, ssh_pass
, **kwargs
)
131 job
.logging
.start_logging()
142 job
.repair(host_protection
)
146 job
.run(cleanup
, install_before
, install_after
,
147 only_collect_crashinfo
=collect_crashinfo
)
150 host
= job
.hosts
.pop()
154 traceback
.print_exc()
157 pid_file_manager
.num_tests_failed
= job
.num_tests_failed
158 pid_file_manager
.close_file(exit_code
)
166 parser
= autoserv_parser
.autoserv_parser
169 if len(sys
.argv
) == 1:
170 parser
.parser
.print_help()
173 if parser
.options
.no_logging
:
176 results
= parser
.options
.results
178 results
= 'results.' + time
.strftime('%Y-%m-%d-%H.%M.%S')
179 results
= os
.path
.abspath(results
)
180 resultdir_exists
= False
181 for filename
in ('control.srv', 'status.log', '.autoserv_execute'):
182 if os
.path
.exists(os
.path
.join(results
, filename
)):
183 resultdir_exists
= True
184 if not parser
.options
.use_existing_results
and resultdir_exists
:
185 error
= "Error: results directory already exists: %s\n" % results
186 sys
.stderr
.write(error
)
189 # Now that we certified that there's no leftover results dir from
190 # previous jobs, lets create the result dir since the logging system
191 # needs to create the log file in there.
192 if not os
.path
.isdir(results
):
195 logging_manager
.configure_logging(
196 server_logging_config
.ServerLoggingConfig(), results_dir
=results
,
197 use_console
=not parser
.options
.no_tee
,
198 verbose
=parser
.options
.verbose
,
199 no_console_prefix
=parser
.options
.no_console_prefix
)
201 logging
.info("Results placed in %s" % results
)
203 # wait until now to perform this check, so it get properly logged
204 if parser
.options
.use_existing_results
and not resultdir_exists
:
205 logging
.error("No existing results directory found: %s", results
)
209 if parser
.options
.write_pidfile
:
210 pid_file_manager
= pidfile
.PidFileManager(parser
.options
.pidfile_label
,
212 pid_file_manager
.open_file()
214 pid_file_manager
= None
216 autotest
.BaseAutotest
.set_install_in_tmpdir(
217 parser
.options
.install_in_tmpdir
)
222 run_autoserv(pid_file_manager
, results
, parser
)
223 except SystemExit, e
:
226 traceback
.print_exc()
227 # If we don't know what happened, we'll classify it as
228 # an 'abort' and return 1.
232 pid_file_manager
.close_file(exit_code
)
236 if __name__
== '__main__':