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 # Server side tests that call shell scripts often depend on $USER being set
57 # but depending on how you launch your autotest scheduler it may not be set.
58 os
.environ
['USER'] = getpass
.getuser()
60 if parser
.options
.machines
:
61 machines
= parser
.options
.machines
.replace(',', ' ').strip().split()
64 machines_file
= parser
.options
.machines_file
65 label
= parser
.options
.label
66 group_name
= parser
.options
.group_name
67 user
= parser
.options
.user
68 client
= parser
.options
.client
69 server
= parser
.options
.server
70 install_before
= parser
.options
.install_before
71 install_after
= parser
.options
.install_after
72 verify
= parser
.options
.verify
73 repair
= parser
.options
.repair
74 cleanup
= parser
.options
.cleanup
75 no_tee
= parser
.options
.no_tee
76 parse_job
= parser
.options
.parse_job
77 execution_tag
= parser
.options
.execution_tag
79 execution_tag
= parse_job
80 host_protection
= parser
.options
.host_protection
81 ssh_user
= parser
.options
.ssh_user
82 ssh_port
= parser
.options
.ssh_port
83 ssh_pass
= parser
.options
.ssh_pass
84 collect_crashinfo
= parser
.options
.collect_crashinfo
85 control_filename
= parser
.options
.control_filename
87 # can't be both a client and a server side test
89 parser
.parser
.error("Can not specify a test as both server and client!")
91 if len(parser
.args
) < 1 and not (verify
or repair
or cleanup
92 or collect_crashinfo
):
93 parser
.parser
.error("Missing argument: control file")
95 # We have a control file unless it's just a verify/repair/cleanup job
96 if len(parser
.args
) > 0:
97 control
= parser
.args
[0]
103 for m
in open(machines_file
, 'r').readlines():
104 # remove comments, spaces
105 m
= re
.sub('#.*', '', m
).strip()
108 print "Read list of machines from file: %s" % machines_file
109 print ','.join(machines
)
112 for machine
in machines
:
113 if not machine
or re
.search('\s', machine
):
114 parser
.parser
.error("Invalid machine: %s" % str(machine
))
115 machines
= list(set(machines
))
118 if group_name
and len(machines
) < 2:
119 parser
.parser
.error("-G %r may only be supplied with more than one machine."
122 kwargs
= {'group_name': group_name
, 'tag': execution_tag
}
124 kwargs
['control_filename'] = control_filename
125 job
= server_job
.server_job(control
, parser
.args
[1:], results
, label
,
126 user
, machines
, client
, parse_job
,
127 ssh_user
, ssh_port
, ssh_pass
, **kwargs
)
128 job
.logging
.start_logging()
139 job
.repair(host_protection
)
143 job
.run(cleanup
, install_before
, install_after
,
144 only_collect_crashinfo
=collect_crashinfo
)
147 host
= job
.hosts
.pop()
151 traceback
.print_exc()
154 pid_file_manager
.num_tests_failed
= job
.num_tests_failed
155 pid_file_manager
.close_file(exit_code
)
163 parser
= autoserv_parser
.autoserv_parser
166 if len(sys
.argv
) == 1:
167 parser
.parser
.print_help()
170 if parser
.options
.no_logging
:
173 results
= parser
.options
.results
175 results
= 'results.' + time
.strftime('%Y-%m-%d-%H.%M.%S')
176 results
= os
.path
.abspath(results
)
177 resultdir_exists
= False
178 for filename
in ('control.srv', 'status.log', '.autoserv_execute'):
179 if os
.path
.exists(os
.path
.join(results
, filename
)):
180 resultdir_exists
= True
181 if not parser
.options
.use_existing_results
and resultdir_exists
:
182 error
= "Error: results directory already exists: %s\n" % results
183 sys
.stderr
.write(error
)
186 # Now that we certified that there's no leftover results dir from
187 # previous jobs, lets create the result dir since the logging system
188 # needs to create the log file in there.
189 if not os
.path
.isdir(results
):
192 logging_manager
.configure_logging(
193 server_logging_config
.ServerLoggingConfig(), results_dir
=results
,
194 use_console
=not parser
.options
.no_tee
,
195 verbose
=parser
.options
.verbose
,
196 no_console_prefix
=parser
.options
.no_console_prefix
)
198 logging
.info("Results placed in %s" % results
)
200 # wait until now to perform this check, so it get properly logged
201 if parser
.options
.use_existing_results
and not resultdir_exists
:
202 logging
.error("No existing results directory found: %s", results
)
206 if parser
.options
.write_pidfile
:
207 pid_file_manager
= pidfile
.PidFileManager(parser
.options
.pidfile_label
,
209 pid_file_manager
.open_file()
211 pid_file_manager
= None
213 autotest
.BaseAutotest
.set_install_in_tmpdir(
214 parser
.options
.install_in_tmpdir
)
219 run_autoserv(pid_file_manager
, results
, parser
)
220 except SystemExit, e
:
223 traceback
.print_exc()
224 # If we don't know what happened, we'll classify it as
225 # an 'abort' and return 1.
229 pid_file_manager
.close_file(exit_code
)
233 if __name__
== '__main__':