blob: 5be18e709158e6944fdab409e89fd8d61d4c4ad4 [file] [log] [blame]
mblighdcd57a82007-07-11 23:06:47 +00001# Copyright 2007 Google Inc. Released under the GPL v2
2
showardb18134f2009-03-20 20:52:18 +00003import re, os, sys, traceback, subprocess, tempfile, time, pickle, glob, logging
jadmanski043e1132008-11-19 17:10:32 +00004from autotest_lib.server import installable_object, utils
jadmanskiede7e242009-08-10 15:43:33 +00005from autotest_lib.client.common_lib import log, error, autotemp
mbligh09108442008-10-15 16:27:38 +00006from autotest_lib.client.common_lib import global_config, packages
mbligha7007722009-01-13 00:37:11 +00007from autotest_lib.client.common_lib import utils as client_utils
mbligh3c7a1502008-07-24 18:08:47 +00008
mblighdcd57a82007-07-11 23:06:47 +00009AUTOTEST_SVN = 'svn://test.kernel.org/autotest/trunk/client'
10AUTOTEST_HTTP = 'http://test.kernel.org/svn/autotest/trunk/client'
11
12# Timeouts for powering down and up respectively
13HALT_TIME = 300
mbligh07c1eac2007-11-05 18:39:29 +000014BOOT_TIME = 1800
jadmanskiec859142008-05-29 21:33:39 +000015CRASH_RECOVERY_TIME = 9000
mbligh0e4613b2007-10-29 16:55:07 +000016
mblighdcd57a82007-07-11 23:06:47 +000017
mblighd8b39252008-03-20 21:15:03 +000018class BaseAutotest(installable_object.InstallableObject):
jadmanski0afbb632008-06-06 21:10:57 +000019 """
20 This class represents the Autotest program.
mblighdcd57a82007-07-11 23:06:47 +000021
jadmanski0afbb632008-06-06 21:10:57 +000022 Autotest is used to run tests automatically and collect the results.
23 It also supports profilers.
mblighdcd57a82007-07-11 23:06:47 +000024
jadmanski0afbb632008-06-06 21:10:57 +000025 Implementation details:
26 This is a leaf class in an abstract class hierarchy, it must
27 implement the unimplemented methods in parent classes.
28 """
mbligh119c12a2007-11-12 22:13:44 +000029
jadmanski0afbb632008-06-06 21:10:57 +000030 def __init__(self, host = None):
31 self.host = host
32 self.got = False
33 self.installed = False
34 self.serverdir = utils.get_server_dir()
35 super(BaseAutotest, self).__init__()
mblighc8949b82007-07-23 16:33:58 +000036
mblighdc735a22007-08-02 16:54:37 +000037
jadmanskif22fea82008-11-26 20:57:07 +000038 install_in_tmpdir = False
39 @classmethod
40 def set_install_in_tmpdir(cls, flag):
41 """ Sets a flag that controls whether or not Autotest should by
42 default be installed in a "standard" directory (e.g.
43 /home/autotest, /usr/local/autotest) or a temporary directory. """
44 cls.install_in_tmpdir = flag
45
46
47 def _get_install_dir(self, host):
48 """ Determines the location where autotest should be installed on
49 host. If self.install_in_tmpdir is set, it will return a unique
50 temporary directory that autotest can be installed in. """
51 try:
52 autodir = _get_autodir(host)
53 except error.AutotestRunError:
54 autodir = '/usr/local/autotest'
55 if self.install_in_tmpdir:
56 autodir = host.get_tmp_dir(parent=autodir)
57 return autodir
58
59
mbligh1b3b3762008-09-25 02:46:34 +000060 @log.record
mblighb3c0c912008-11-27 00:32:45 +000061 def install(self, host=None, autodir=None):
62 self._install(host=host, autodir=autodir)
jadmanski54f90af2008-10-10 16:20:55 +000063
64
mblighbccad482009-08-24 22:08:31 +000065 def install_no_autoserv(self, host=None, autodir=None):
66 self._install(host=host, autodir=autodir, no_autoserv=True)
67
68
mblighe1cea0a2009-09-03 20:20:16 +000069 def _install(self, host=None, autodir=None, no_autoserv=False):
jadmanski0afbb632008-06-06 21:10:57 +000070 """
71 Install autotest. If get() was not called previously, an
72 attempt will be made to install from the autotest svn
73 repository.
mbligh9a3f5e52008-05-28 21:21:43 +000074
mblighbccad482009-08-24 22:08:31 +000075 @param host A Host instance on which autotest will be installed
76 @param autodir Location on the remote host to install to
77 @param autoserv Disable install modes that depend on the client
78 running with the autoserv harness
mbligh9a3f5e52008-05-28 21:21:43 +000079
mblighbccad482009-08-24 22:08:31 +000080 @exception AutoservError if a tarball was not specified and
81 the target host does not have svn installed in its path
82 """
jadmanski0afbb632008-06-06 21:10:57 +000083 if not host:
84 host = self.host
85 if not self.got:
86 self.get()
87 host.wait_up(timeout=30)
88 host.setup()
showardb18134f2009-03-20 20:52:18 +000089 logging.info("Installing autotest on %s", host.hostname)
mbligh40f122a2007-11-03 23:08:46 +000090
jadmanski54f90af2008-10-10 16:20:55 +000091 # set up the autotest directory on the remote machine
92 if not autodir:
jadmanskif22fea82008-11-26 20:57:07 +000093 autodir = self._get_install_dir(host)
mbligh0562e652008-08-20 20:11:45 +000094 host.set_autodir(autodir)
jadmanski3c236942009-03-04 17:51:26 +000095 host.run('mkdir -p %s' % utils.sh_escape(autodir))
mbligh40f122a2007-11-03 23:08:46 +000096
jadmanski1c3c07b2009-03-03 23:29:36 +000097 # make sure there are no files in $AUTODIR/results
98 results_path = os.path.join(autodir, 'results')
jadmanski3c236942009-03-04 17:51:26 +000099 host.run('rm -rf %s/*' % utils.sh_escape(results_path),
jadmanski1c3c07b2009-03-03 23:29:36 +0000100 ignore_status=True)
101
mblighc5ddfd12008-08-04 17:15:00 +0000102 # Fetch the autotest client from the nearest repository
103 try:
104 c = global_config.global_config
105 repos = c.get_config_value("PACKAGES", 'fetch_location', type=list)
mbligh76d19f72008-10-15 16:24:43 +0000106 pkgmgr = packages.PackageManager(autodir, hostname=host.hostname,
107 repo_urls=repos,
mbligh1e3b0992008-10-14 16:29:54 +0000108 do_locking=False,
109 run_function=host.run,
110 run_function_dargs=dict(timeout=600))
mblighc5ddfd12008-08-04 17:15:00 +0000111 # The packages dir is used to store all the packages that
112 # are fetched on that client. (for the tests,deps etc.
113 # too apart from the client)
114 pkg_dir = os.path.join(autodir, 'packages')
115 # clean up the autodir except for the packages directory
116 host.run('cd %s && ls | grep -v "^packages$"'
117 ' | xargs rm -rf && rm -rf .[^.]*' % autodir)
118 pkgmgr.install_pkg('autotest', 'client', pkg_dir, autodir,
119 preserve_install_dir=True)
120 self.installed = True
121 return
122 except global_config.ConfigError, e:
mbligh6a837772009-09-02 18:15:11 +0000123 logging.info("Could not install autotest using the packaging "
showardb18134f2009-03-20 20:52:18 +0000124 "system: %s", e)
jadmanskib1a51132009-08-07 16:45:50 +0000125 except (error.PackageInstallError, error.AutoservRunError), e:
showardb18134f2009-03-20 20:52:18 +0000126 logging.error("Could not install autotest from %s", repos)
mblighc5ddfd12008-08-04 17:15:00 +0000127
jadmanski0afbb632008-06-06 21:10:57 +0000128 # try to install from file or directory
129 if self.source_material:
130 if os.path.isdir(self.source_material):
jadmanski27b52912009-08-14 17:09:15 +0000131 c = global_config.global_config
132 supports_autoserv_packaging = c.get_config_value(
133 "PACKAGES", "serve_packages_from_autoserv", type=bool)
jadmanski0afbb632008-06-06 21:10:57 +0000134 # Copy autotest recursively
mblighbccad482009-08-24 22:08:31 +0000135 if supports_autoserv_packaging and not no_autoserv:
mbligh875f5352009-09-03 20:20:30 +0000136 dirs_to_exclude = set(["tests", "site_tests", "deps",
137 "profilers"])
jadmanski54f90af2008-10-10 16:20:55 +0000138 light_files = [os.path.join(self.source_material, f)
139 for f in os.listdir(self.source_material)
140 if f not in dirs_to_exclude]
mbligh89e258d2008-10-24 13:58:08 +0000141 host.send_file(light_files, autodir, delete_dest=True)
jadmanski54f90af2008-10-10 16:20:55 +0000142
143 # create empty dirs for all the stuff we excluded
144 commands = []
145 for path in dirs_to_exclude:
146 abs_path = os.path.join(autodir, path)
147 abs_path = utils.sh_escape(abs_path)
148 commands.append("mkdir -p '%s'" % abs_path)
mbligh875f5352009-09-03 20:20:30 +0000149 commands.append("touch '%s'/__init__.py" % abs_path)
jadmanski54f90af2008-10-10 16:20:55 +0000150 host.run(';'.join(commands))
151 else:
mbligh89e258d2008-10-24 13:58:08 +0000152 host.send_file(self.source_material, autodir,
153 delete_dest=True)
jadmanski0afbb632008-06-06 21:10:57 +0000154 else:
155 # Copy autotest via tarball
156 e_msg = 'Installation method not yet implemented!'
157 raise NotImplementedError(e_msg)
showardb18134f2009-03-20 20:52:18 +0000158 logging.info("Installation of autotest completed")
jadmanski0afbb632008-06-06 21:10:57 +0000159 self.installed = True
160 return
mbligh91334902007-09-28 01:47:59 +0000161
jadmanski0afbb632008-06-06 21:10:57 +0000162 # if that fails try to install using svn
163 if utils.run('which svn').exit_status:
mbligh78bf5352008-07-11 20:27:36 +0000164 raise error.AutoservError('svn not found on target machine: %s'
165 % host.name)
jadmanski0afbb632008-06-06 21:10:57 +0000166 try:
mbligh78bf5352008-07-11 20:27:36 +0000167 host.run('svn checkout %s %s' % (AUTOTEST_SVN, autodir))
jadmanski0afbb632008-06-06 21:10:57 +0000168 except error.AutoservRunError, e:
mbligh78bf5352008-07-11 20:27:36 +0000169 host.run('svn checkout %s %s' % (AUTOTEST_HTTP, autodir))
showardb18134f2009-03-20 20:52:18 +0000170 logging.info("Installation of autotest completed")
jadmanski0afbb632008-06-06 21:10:57 +0000171 self.installed = True
mbligh91334902007-09-28 01:47:59 +0000172
173
jadmanski7c7aff32009-03-25 22:43:07 +0000174 def uninstall(self, host=None):
175 """
176 Uninstall (i.e. delete) autotest. Removes the autotest client install
177 from the specified host.
178
179 @params host a Host instance from which the client will be removed
180 """
181 if not self.installed:
182 return
183 if not host:
184 host = self.host
185 autodir = host.get_autodir()
186 if not autodir:
187 return
188
189 # perform the actual uninstall
190 host.run("rm -rf %s" % utils.sh_escape(autodir), ignore_status=True)
191 host.set_autodir(None)
192 self.installed = False
193
194
jadmanski0afbb632008-06-06 21:10:57 +0000195 def get(self, location = None):
196 if not location:
197 location = os.path.join(self.serverdir, '../client')
198 location = os.path.abspath(location)
199 # If there's stuff run on our client directory already, it
200 # can cause problems. Try giving it a quick clean first.
201 cwd = os.getcwd()
202 os.chdir(location)
203 os.system('tools/make_clean')
204 os.chdir(cwd)
205 super(BaseAutotest, self).get(location)
206 self.got = True
mblighdcd57a82007-07-11 23:06:47 +0000207
208
mblighe7d9c602009-07-02 19:02:33 +0000209 def run(self, control_file, results_dir='.', host=None, timeout=None,
210 tag=None, parallel_flag=False, background=False,
211 client_disconnect_timeout=1800, job_tag=''):
jadmanski0afbb632008-06-06 21:10:57 +0000212 """
213 Run an autotest job on the remote machine.
mbligh9a3f5e52008-05-28 21:21:43 +0000214
mblighe7d9c602009-07-02 19:02:33 +0000215 @param control_file: An open file-like-obj of the control file.
216 @param results_dir: A str path where the results should be stored
217 on the local filesystem.
218 @param host: A Host instance on which the control file should
219 be run.
220 @param timeout: Maximum number of seconds to wait for the run or None.
221 @param tag: Tag name for the client side instance of autotest.
222 @param parallel_flag: Flag set when multiple jobs are run at the
223 same time.
224 @param background: Indicates that the client should be launched as
225 a background job; the code calling run will be responsible
226 for monitoring the client and collecting the results.
227 @param client_disconnect_timeout: Seconds to wait for the remote host
228 to come back after a reboot. [default: 30 minutes]
229 @param job_tag: The scheduler's execution tag for this particular job
230 to pass on to the clients. 'job#-owner/hostgroupname'
231
232 @raises AutotestRunError: If there is a problem executing
233 the control file.
jadmanski0afbb632008-06-06 21:10:57 +0000234 """
235 host = self._get_host_and_setup(host)
236 results_dir = os.path.abspath(results_dir)
mblighc1cbc992008-05-27 20:01:45 +0000237
jadmanski0afbb632008-06-06 21:10:57 +0000238 if tag:
239 results_dir = os.path.join(results_dir, tag)
mblighc1cbc992008-05-27 20:01:45 +0000240
mblighb3c0c912008-11-27 00:32:45 +0000241 atrun = _Run(host, results_dir, tag, parallel_flag, background)
jadmanski6dadd832009-02-05 23:39:27 +0000242 self._do_run(control_file, results_dir, host, atrun, timeout,
mblighe7d9c602009-07-02 19:02:33 +0000243 client_disconnect_timeout, job_tag)
mblighd8b39252008-03-20 21:15:03 +0000244
245
jadmanski0afbb632008-06-06 21:10:57 +0000246 def _get_host_and_setup(self, host):
247 if not host:
248 host = self.host
249 if not self.installed:
250 self.install(host)
mbligh91334902007-09-28 01:47:59 +0000251
jadmanski0afbb632008-06-06 21:10:57 +0000252 host.wait_up(timeout=30)
253 return host
mblighd8b39252008-03-20 21:15:03 +0000254
255
jadmanski6dadd832009-02-05 23:39:27 +0000256 def _do_run(self, control_file, results_dir, host, atrun, timeout,
mblighe7d9c602009-07-02 19:02:33 +0000257 client_disconnect_timeout, job_tag):
jadmanski0afbb632008-06-06 21:10:57 +0000258 try:
259 atrun.verify_machine()
260 except:
showardb18134f2009-03-20 20:52:18 +0000261 logging.error("Verify failed on %s. Reinstalling autotest",
262 host.hostname)
jadmanski0afbb632008-06-06 21:10:57 +0000263 self.install(host)
264 atrun.verify_machine()
265 debug = os.path.join(results_dir, 'debug')
266 try:
267 os.makedirs(debug)
mbligh09108442008-10-15 16:27:38 +0000268 except Exception:
jadmanski0afbb632008-06-06 21:10:57 +0000269 pass
mbligh9a3f5e52008-05-28 21:21:43 +0000270
mbligh09108442008-10-15 16:27:38 +0000271 delete_file_list = [atrun.remote_control_file,
272 atrun.remote_control_file + '.state',
273 atrun.manual_control_file,
274 atrun.manual_control_file + '.state']
275 cmd = ';'.join('rm -f ' + control for control in delete_file_list)
276 host.run(cmd, ignore_status=True)
mbligh9a3f5e52008-05-28 21:21:43 +0000277
jadmanski0afbb632008-06-06 21:10:57 +0000278 tmppath = utils.get(control_file)
mblighc5ddfd12008-08-04 17:15:00 +0000279
jadmanskicb0e1612009-02-27 18:03:10 +0000280 # build up the initialization prologue for the control file
281 prologue_lines = []
282 prologue_lines.append("job.default_boot_tag(%r)\n"
283 % host.job.last_boot_tag)
284 prologue_lines.append("job.default_test_cleanup(%r)\n"
285 % host.job.run_test_cleanup)
mblighe7d9c602009-07-02 19:02:33 +0000286 if job_tag:
287 prologue_lines.append("job.default_tag(%r)\n" % job_tag)
jadmanski23afbec2008-09-17 18:12:07 +0000288
mbligh09108442008-10-15 16:27:38 +0000289 # If the packaging system is being used, add the repository list.
mblighc5ddfd12008-08-04 17:15:00 +0000290 try:
mblighc5ddfd12008-08-04 17:15:00 +0000291 c = global_config.global_config
292 repos = c.get_config_value("PACKAGES", 'fetch_location', type=list)
jadmanskiede7e242009-08-10 15:43:33 +0000293 repos.reverse() # high priority packages should be added last
mbligh76d19f72008-10-15 16:24:43 +0000294 pkgmgr = packages.PackageManager('autotest', hostname=host.hostname,
295 repo_urls=repos)
jadmanskib1a51132009-08-07 16:45:50 +0000296 prologue_lines.append('job.add_repository(%s)\n' % repos)
mblighc5ddfd12008-08-04 17:15:00 +0000297 except global_config.ConfigError, e:
298 pass
299
jadmanskie2eef7b2009-03-03 23:55:13 +0000300 # on full-size installs, turn on any profilers the server is using
jadmanski27b52912009-08-14 17:09:15 +0000301 if not atrun.background:
jadmanskie2eef7b2009-03-03 23:55:13 +0000302 running_profilers = host.job.profilers.add_log.iteritems()
303 for profiler, (args, dargs) in running_profilers:
304 call_args = [repr(profiler)]
305 call_args += [repr(arg) for arg in args]
306 call_args += ["%s=%r" % item for item in dargs.iteritems()]
307 prologue_lines.append("job.profilers.add(%s)\n"
308 % ", ".join(call_args))
309 cfile = "".join(prologue_lines)
310
mbligh09108442008-10-15 16:27:38 +0000311 cfile += open(tmppath).read()
312 open(tmppath, "w").write(cfile)
mblighc5ddfd12008-08-04 17:15:00 +0000313
jadmanskic09fc152008-10-15 17:56:59 +0000314 # Create and copy state file to remote_control_file + '.state'
315 sysinfo_state = {"__sysinfo": host.job.sysinfo.serialize()}
316 state_file = self._create_state_file(host.job, sysinfo_state)
317 host.send_file(state_file, atrun.remote_control_file + '.state')
318 os.remove(state_file)
319
mblighc5ddfd12008-08-04 17:15:00 +0000320 # Copy control_file to remote_control_file on the host
jadmanski0afbb632008-06-06 21:10:57 +0000321 host.send_file(tmppath, atrun.remote_control_file)
322 if os.path.abspath(tmppath) != os.path.abspath(control_file):
323 os.remove(tmppath)
mbligh0e4613b2007-10-29 16:55:07 +0000324
jadmanski6bb32d72009-03-19 20:25:24 +0000325 atrun.execute_control(
jadmanski6dadd832009-02-05 23:39:27 +0000326 timeout=timeout,
327 client_disconnect_timeout=client_disconnect_timeout)
jadmanski23afbec2008-09-17 18:12:07 +0000328
329
jadmanskic09fc152008-10-15 17:56:59 +0000330 def _create_state_file(self, job, state_dict):
331 """ Create a state file from a dictionary. Returns the path of the
332 state file. """
333 fd, path = tempfile.mkstemp(dir=job.tmpdir)
334 state_file = os.fdopen(fd, "w")
335 pickle.dump(state_dict, state_file)
336 state_file.close()
337 return path
338
339
jadmanski0afbb632008-06-06 21:10:57 +0000340 def run_timed_test(self, test_name, results_dir='.', host=None,
jadmanskic98c4702009-01-05 15:50:06 +0000341 timeout=None, *args, **dargs):
jadmanski0afbb632008-06-06 21:10:57 +0000342 """
343 Assemble a tiny little control file to just run one test,
344 and run it as an autotest client-side test
345 """
346 if not host:
347 host = self.host
348 if not self.installed:
349 self.install(host)
350 opts = ["%s=%s" % (o[0], repr(o[1])) for o in dargs.items()]
351 cmd = ", ".join([repr(test_name)] + map(repr, args) + opts)
352 control = "job.run_test(%s)\n" % cmd
jadmanskic98c4702009-01-05 15:50:06 +0000353 self.run(control, results_dir, host, timeout=timeout)
mbligh0e4613b2007-10-29 16:55:07 +0000354
355
jadmanskic98c4702009-01-05 15:50:06 +0000356 def run_test(self, test_name, results_dir='.', host=None, *args, **dargs):
jadmanski0afbb632008-06-06 21:10:57 +0000357 self.run_timed_test(test_name, results_dir, host, timeout=None,
jadmanskic98c4702009-01-05 15:50:06 +0000358 *args, **dargs)
mblighd54832b2007-07-25 16:46:56 +0000359
360
mblighdcd57a82007-07-11 23:06:47 +0000361class _Run(object):
jadmanski0afbb632008-06-06 21:10:57 +0000362 """
363 Represents a run of autotest control file. This class maintains
364 all the state necessary as an autotest control file is executed.
mblighdcd57a82007-07-11 23:06:47 +0000365
jadmanski0afbb632008-06-06 21:10:57 +0000366 It is not intended to be used directly, rather control files
367 should be run using the run method in Autotest.
368 """
mblighb3c0c912008-11-27 00:32:45 +0000369 def __init__(self, host, results_dir, tag, parallel_flag, background):
jadmanski0afbb632008-06-06 21:10:57 +0000370 self.host = host
371 self.results_dir = results_dir
372 self.env = host.env
373 self.tag = tag
374 self.parallel_flag = parallel_flag
mblighb3c0c912008-11-27 00:32:45 +0000375 self.background = background
jadmanski0afbb632008-06-06 21:10:57 +0000376 self.autodir = _get_autodir(self.host)
mbligh78bf5352008-07-11 20:27:36 +0000377 control = os.path.join(self.autodir, 'control')
jadmanski0afbb632008-06-06 21:10:57 +0000378 if tag:
mbligh78bf5352008-07-11 20:27:36 +0000379 control += '.' + tag
380 self.manual_control_file = control
381 self.remote_control_file = control + '.autoserv'
mblighdc735a22007-08-02 16:54:37 +0000382
383
jadmanski0afbb632008-06-06 21:10:57 +0000384 def verify_machine(self):
385 binary = os.path.join(self.autodir, 'bin/autotest')
386 try:
387 self.host.run('ls %s > /dev/null 2>&1' % binary)
388 except:
389 raise "Autotest does not appear to be installed"
mblighdc735a22007-08-02 16:54:37 +0000390
jadmanski0afbb632008-06-06 21:10:57 +0000391 if not self.parallel_flag:
392 tmpdir = os.path.join(self.autodir, 'tmp')
393 download = os.path.join(self.autodir, 'tests/download')
394 self.host.run('umount %s' % tmpdir, ignore_status=True)
395 self.host.run('umount %s' % download, ignore_status=True)
mblighdc735a22007-08-02 16:54:37 +0000396
jadmanski6dadd832009-02-05 23:39:27 +0000397
398 def get_base_cmd_args(self, section):
showard234b2962009-07-28 20:02:30 +0000399 args = ['--verbose']
jadmanski0afbb632008-06-06 21:10:57 +0000400 if section > 0:
jadmanski6dadd832009-02-05 23:39:27 +0000401 args.append('-c')
jadmanski0afbb632008-06-06 21:10:57 +0000402 if self.tag:
jadmanski6dadd832009-02-05 23:39:27 +0000403 args.append('-t %s' % self.tag)
jadmanski0afbb632008-06-06 21:10:57 +0000404 if self.host.job.use_external_logging():
jadmanski6dadd832009-02-05 23:39:27 +0000405 args.append('-l')
mblighce955fc2009-08-24 21:59:02 +0000406 if self.host.hostname:
407 args.append('--hostname=%s' % self.host.hostname)
mblighea0405c2009-09-04 22:01:16 +0000408 args.append('--user=%s' % os.environ['LOGNAME'])
mblighce955fc2009-08-24 21:59:02 +0000409
jadmanski6dadd832009-02-05 23:39:27 +0000410 args.append(self.remote_control_file)
411 return args
412
413
414 def get_background_cmd(self, section):
415 cmd = ['nohup', os.path.join(self.autodir, 'bin/autotest_client')]
416 cmd += self.get_base_cmd_args(section)
417 cmd.append('>/dev/null 2>/dev/null &')
418 return ' '.join(cmd)
419
420
421 def get_daemon_cmd(self, section, monitor_dir):
422 cmd = ['nohup', os.path.join(self.autodir, 'bin/autotestd'),
423 monitor_dir, '-H autoserv']
424 cmd += self.get_base_cmd_args(section)
425 cmd.append('>/dev/null 2>/dev/null </dev/null &')
426 return ' '.join(cmd)
427
428
429 def get_monitor_cmd(self, monitor_dir, stdout_read, stderr_read):
430 cmd = [os.path.join(self.autodir, 'bin', 'autotestd_monitor'),
431 monitor_dir, str(stdout_read), str(stderr_read)]
jadmanski0afbb632008-06-06 21:10:57 +0000432 return ' '.join(cmd)
mblighadf2aab2007-11-29 18:16:43 +0000433
mblighd8b39252008-03-20 21:15:03 +0000434
jadmanski0afbb632008-06-06 21:10:57 +0000435 def get_client_log(self, section):
jadmanskie0c7fb62008-12-16 20:51:16 +0000436 """ Find what the "next" client.log.* file should be and open it. """
437 debug_dir = os.path.join(self.results_dir, "debug")
438 client_logs = glob.glob(os.path.join(debug_dir, "client.log.*"))
439 next_log = os.path.join(debug_dir, "client.log.%d" % len(client_logs))
440 return open(next_log, "w", 0)
mblighd8b39252008-03-20 21:15:03 +0000441
442
jadmanskib264ed02009-01-12 23:54:27 +0000443 @staticmethod
444 def is_client_job_finished(last_line):
445 return bool(re.match(r'^END .*\t----\t----\t.*$', last_line))
446
447
448 @staticmethod
449 def is_client_job_rebooting(last_line):
450 return bool(re.match(r'^\t*GOOD\t----\treboot\.start.*$', last_line))
451
452
jadmanskia61edad2009-05-21 22:17:49 +0000453 def log_unexpected_abort(self, stderr_redirector):
454 stderr_redirector.flush_all_buffers()
jadmanskib264ed02009-01-12 23:54:27 +0000455 msg = "Autotest client terminated unexpectedly"
456 self.host.job.record("END ABORT", None, None, msg)
457
458
jadmanski6dadd832009-02-05 23:39:27 +0000459 def _execute_in_background(self, section, timeout):
460 full_cmd = self.get_background_cmd(section)
461 devnull = open(os.devnull, "w")
mblighd8b39252008-03-20 21:15:03 +0000462
jadmanski6dadd832009-02-05 23:39:27 +0000463 old_resultdir = self.host.job.resultdir
jadmanski0afbb632008-06-06 21:10:57 +0000464 try:
jadmanski0afbb632008-06-06 21:10:57 +0000465 self.host.job.resultdir = self.results_dir
466 result = self.host.run(full_cmd, ignore_status=True,
467 timeout=timeout,
jadmanski6dadd832009-02-05 23:39:27 +0000468 stdout_tee=devnull,
469 stderr_tee=devnull)
jadmanski0afbb632008-06-06 21:10:57 +0000470 finally:
jadmanski0afbb632008-06-06 21:10:57 +0000471 self.host.job.resultdir = old_resultdir
jadmanski6dadd832009-02-05 23:39:27 +0000472
473 return result
474
475
476 @staticmethod
477 def _strip_stderr_prologue(stderr):
478 """Strips the 'standard' prologue that get pre-pended to every
479 remote command and returns the text that was actually written to
480 stderr by the remote command."""
481 stderr_lines = stderr.split("\n")[1:]
482 if not stderr_lines:
483 return ""
484 elif stderr_lines[0].startswith("NOTE: autotestd_monitor"):
485 del stderr_lines[0]
486 return "\n".join(stderr_lines)
487
488
489 def _execute_daemon(self, section, timeout, stderr_redirector,
490 client_disconnect_timeout):
491 monitor_dir = self.host.get_tmp_dir()
492 daemon_cmd = self.get_daemon_cmd(section, monitor_dir)
493 client_log = self.get_client_log(section)
494
495 stdout_read = stderr_read = 0
496 old_resultdir = self.host.job.resultdir
497 try:
jadmanski29a4c702009-03-03 23:30:59 +0000498 self.host.job.resultdir = self.results_dir
jadmanski6dadd832009-02-05 23:39:27 +0000499 self.host.run(daemon_cmd, ignore_status=True, timeout=timeout)
jadmanski91d56a92009-04-01 15:20:40 +0000500 disconnect_warnings = []
jadmanski6dadd832009-02-05 23:39:27 +0000501 while True:
502 monitor_cmd = self.get_monitor_cmd(monitor_dir, stdout_read,
503 stderr_read)
504 try:
505 result = self.host.run(monitor_cmd, ignore_status=True,
506 timeout=timeout,
507 stdout_tee=client_log,
508 stderr_tee=stderr_redirector)
509 except error.AutoservRunError, e:
510 result = e.result_obj
511 result.exit_status = None
jadmanski91d56a92009-04-01 15:20:40 +0000512 disconnect_warnings.append(e.description)
513
jadmanski6dadd832009-02-05 23:39:27 +0000514 stderr_redirector.log_warning(
jadmanski91d56a92009-04-01 15:20:40 +0000515 "Autotest client was disconnected: %s" % e.description,
516 "NETWORK")
jadmanski6dadd832009-02-05 23:39:27 +0000517 except error.AutoservSSHTimeout:
518 result = utils.CmdResult(monitor_cmd, "", "", None, 0)
519 stderr_redirector.log_warning(
jadmanski91d56a92009-04-01 15:20:40 +0000520 "Attempt to connect to Autotest client timed out",
521 "NETWORK")
jadmanski6dadd832009-02-05 23:39:27 +0000522
523 stdout_read += len(result.stdout)
524 stderr_read += len(self._strip_stderr_prologue(result.stderr))
525
526 if result.exit_status is not None:
527 return result
528 elif not self.host.wait_up(client_disconnect_timeout):
529 raise error.AutoservSSHTimeout(
530 "client was disconnected, reconnect timed out")
531 finally:
532 self.host.job.resultdir = old_resultdir
533
534
535 def execute_section(self, section, timeout, stderr_redirector,
536 client_disconnect_timeout):
showardb18134f2009-03-20 20:52:18 +0000537 logging.info("Executing %s/bin/autotest %s/control phase %d",
538 self.autodir, self.autodir, section)
jadmanski6dadd832009-02-05 23:39:27 +0000539
540 if self.background:
541 result = self._execute_in_background(section, timeout)
542 else:
543 result = self._execute_daemon(section, timeout, stderr_redirector,
544 client_disconnect_timeout)
545
546 last_line = stderr_redirector.last_line
mbligh2bf2db62007-11-27 00:53:18 +0000547
jadmanskib264ed02009-01-12 23:54:27 +0000548 # check if we failed hard enough to warrant an exception
jadmanski0afbb632008-06-06 21:10:57 +0000549 if result.exit_status == 1:
jadmanskib264ed02009-01-12 23:54:27 +0000550 err = error.AutotestRunError("client job was aborted")
551 elif not self.background and not result.stderr:
552 err = error.AutotestRunError(
jadmanskie4130532009-03-17 18:01:28 +0000553 "execute_section %s failed to return anything\n"
554 "stdout:%s\n" % (section, result.stdout))
jadmanskib264ed02009-01-12 23:54:27 +0000555 else:
556 err = None
mbligh0e4613b2007-10-29 16:55:07 +0000557
jadmanskib264ed02009-01-12 23:54:27 +0000558 # log something if the client failed AND never finished logging
559 if err and not self.is_client_job_finished(last_line):
jadmanskia61edad2009-05-21 22:17:49 +0000560 self.log_unexpected_abort(stderr_redirector)
jadmanskib264ed02009-01-12 23:54:27 +0000561
562 if err:
563 raise err
564 else:
565 return stderr_redirector.last_line
jadmanski4600e342008-10-29 22:54:00 +0000566
567
568 def _wait_for_reboot(self):
showardb18134f2009-03-20 20:52:18 +0000569 logging.info("Client is rebooting")
570 logging.info("Waiting for client to halt")
jadmanski4600e342008-10-29 22:54:00 +0000571 if not self.host.wait_down(HALT_TIME):
572 err = "%s failed to shutdown after %d"
573 err %= (self.host.hostname, HALT_TIME)
574 raise error.AutotestRunError(err)
showardb18134f2009-03-20 20:52:18 +0000575 logging.info("Client down, waiting for restart")
jadmanski4600e342008-10-29 22:54:00 +0000576 if not self.host.wait_up(BOOT_TIME):
577 # since reboot failed
578 # hardreset the machine once if possible
579 # before failing this control file
580 warning = "%s did not come back up, hard resetting"
581 warning %= self.host.hostname
showardb18134f2009-03-20 20:52:18 +0000582 logging.warning(warning)
jadmanski4600e342008-10-29 22:54:00 +0000583 try:
584 self.host.hardreset(wait=False)
mblighd99d3b272008-12-22 14:41:27 +0000585 except (AttributeError, error.AutoservUnsupportedError):
jadmanski4600e342008-10-29 22:54:00 +0000586 warning = "Hard reset unsupported on %s"
587 warning %= self.host.hostname
showardb18134f2009-03-20 20:52:18 +0000588 logging.warning(warning)
jadmanski4600e342008-10-29 22:54:00 +0000589 raise error.AutotestRunError("%s failed to boot after %ds" %
590 (self.host.hostname, BOOT_TIME))
591 self.host.reboot_followup()
mblighdc735a22007-08-02 16:54:37 +0000592
593
jadmanski6bb32d72009-03-19 20:25:24 +0000594 def _process_client_state_file(self):
595 state_file = os.path.basename(self.remote_control_file) + ".state"
596 state_path = os.path.join(self.results_dir, state_file)
597 try:
598 state_dict = pickle.load(open(state_path))
599 except Exception, e:
600 msg = "Ignoring error while loading client job state file: %s" % e
showard372ce3e2009-04-07 18:12:03 +0000601 logging.warning(msg)
jadmanski6bb32d72009-03-19 20:25:24 +0000602 state_dict = {}
603
604 # clear out the state file
605 # TODO: stash the file away somewhere useful instead
606 try:
607 os.remove(state_path)
608 except Exception:
609 pass
610
mblighe9633f52009-07-02 19:01:09 +0000611 logging.debug("Persistent state variables pulled back from %s: %s",
612 self.host.hostname, state_dict)
jadmanski6bb32d72009-03-19 20:25:24 +0000613
614 if "__run_test_cleanup" in state_dict:
615 if state_dict["__run_test_cleanup"]:
616 self.host.job.enable_test_cleanup()
617 else:
618 self.host.job.disable_test_cleanup()
619
620 if "__last_boot_tag" in state_dict:
621 self.host.job.last_boot_tag = state_dict["__last_boot_tag"]
622
623 if "__sysinfo" in state_dict:
624 self.host.job.sysinfo.deserialize(state_dict["__sysinfo"])
625
626
jadmanski6dadd832009-02-05 23:39:27 +0000627 def execute_control(self, timeout=None, client_disconnect_timeout=None):
jadmanski6bb32d72009-03-19 20:25:24 +0000628 if not self.background:
629 collector = log_collector(self.host, self.tag, self.results_dir)
630 hostname = self.host.hostname
631 remote_results = collector.client_results_dir
632 local_results = collector.server_results_dir
633 self.host.job.add_client_log(hostname, remote_results,
634 local_results)
635
jadmanski0afbb632008-06-06 21:10:57 +0000636 section = 0
jadmanski4600e342008-10-29 22:54:00 +0000637 start_time = time.time()
638
jadmanski043e1132008-11-19 17:10:32 +0000639 logger = client_logger(self.host, self.tag, self.results_dir)
jadmanski4600e342008-10-29 22:54:00 +0000640 try:
641 while not timeout or time.time() < start_time + timeout:
642 if timeout:
643 section_timeout = start_time + timeout - time.time()
644 else:
645 section_timeout = None
646 last = self.execute_section(section, section_timeout,
jadmanski6dadd832009-02-05 23:39:27 +0000647 logger, client_disconnect_timeout)
mblighb3c0c912008-11-27 00:32:45 +0000648 if self.background:
649 return
jadmanski4600e342008-10-29 22:54:00 +0000650 section += 1
jadmanskib264ed02009-01-12 23:54:27 +0000651 if self.is_client_job_finished(last):
showardb18134f2009-03-20 20:52:18 +0000652 logging.info("Client complete")
jadmanski4600e342008-10-29 22:54:00 +0000653 return
jadmanskib264ed02009-01-12 23:54:27 +0000654 elif self.is_client_job_rebooting(last):
jadmanski79ab9282008-11-11 17:53:12 +0000655 try:
656 self._wait_for_reboot()
657 except error.AutotestRunError, e:
jadmanski043e1132008-11-19 17:10:32 +0000658 self.host.job.record("ABORT", None, "reboot", str(e))
659 self.host.job.record("END ABORT", None, None, str(e))
jadmanski79ab9282008-11-11 17:53:12 +0000660 raise
jadmanski4600e342008-10-29 22:54:00 +0000661 continue
662
663 # if we reach here, something unexpected happened
jadmanskia61edad2009-05-21 22:17:49 +0000664 self.log_unexpected_abort(logger)
jadmanski4600e342008-10-29 22:54:00 +0000665
666 # give the client machine a chance to recover from a crash
667 self.host.wait_up(CRASH_RECOVERY_TIME)
668 msg = ("Aborting - unexpected final status message from "
669 "client: %s\n") % last
670 raise error.AutotestRunError(msg)
671 finally:
jadmanski043e1132008-11-19 17:10:32 +0000672 logger.close()
jadmanski6bb32d72009-03-19 20:25:24 +0000673 if not self.background:
674 collector.collect_client_job_results()
675 self._process_client_state_file()
676 self.host.job.remove_client_log(hostname, remote_results,
677 local_results)
mblighdcd57a82007-07-11 23:06:47 +0000678
jadmanski0afbb632008-06-06 21:10:57 +0000679 # should only get here if we timed out
680 assert timeout
681 raise error.AutotestTimeoutError()
mbligh0e4613b2007-10-29 16:55:07 +0000682
mblighdcd57a82007-07-11 23:06:47 +0000683
684def _get_autodir(host):
mbligh3c7a1502008-07-24 18:08:47 +0000685 autodir = host.get_autodir()
686 if autodir:
jadmanski8297cf52009-05-21 22:23:02 +0000687 logging.debug('Using existing host autodir: %s', autodir)
mbligh3c7a1502008-07-24 18:08:47 +0000688 return autodir
mblighe2e0bef2009-09-03 20:29:18 +0000689 client_autodir_paths = global_config.global_config.get_config_value(
690 'AUTOSERV', 'client_autodir_paths', type=list,
691 default=['/usr/local/autotest', '/home/autotest'])
692 for path in client_autodir_paths:
jadmanski0afbb632008-06-06 21:10:57 +0000693 try:
mbligh483d1da2009-08-24 22:07:14 +0000694 host.run('test -d %s' % utils.sh_escape(path))
jadmanski8297cf52009-05-21 22:23:02 +0000695 logging.debug('Found autodir at %s', path)
jadmanski0afbb632008-06-06 21:10:57 +0000696 return path
697 except error.AutoservRunError:
mbligh483d1da2009-08-24 22:07:14 +0000698 logging.debug('%s does not exist on %s', path, host.hostname)
jadmanski8297cf52009-05-21 22:23:02 +0000699 raise error.AutotestRunError('Cannot figure out autotest directory')
mblighd8b39252008-03-20 21:15:03 +0000700
701
jadmanski043e1132008-11-19 17:10:32 +0000702class log_collector(object):
703 def __init__(self, host, client_tag, results_dir):
704 self.host = host
705 if not client_tag:
706 client_tag = "default"
707 self.client_results_dir = os.path.join(host.get_autodir(), "results",
708 client_tag)
709 self.server_results_dir = results_dir
710
711
712 def collect_client_job_results(self):
713 """ A method that collects all the current results of a running
714 client job into the results dir. By default does nothing as no
715 client job is running, but when running a client job you can override
716 this with something that will actually do something. """
717
718 # make an effort to wait for the machine to come up
719 try:
720 self.host.wait_up(timeout=30)
721 except error.AutoservError:
722 # don't worry about any errors, we'll try and
723 # get the results anyway
724 pass
725
jadmanski043e1132008-11-19 17:10:32 +0000726 # Copy all dirs in default to results_dir
727 try:
jadmanski043e1132008-11-19 17:10:32 +0000728 self.host.get_file(self.client_results_dir + '/',
mbligh45561782009-05-11 21:14:34 +0000729 self.server_results_dir, preserve_symlinks=True)
jadmanski043e1132008-11-19 17:10:32 +0000730 except Exception:
731 # well, don't stop running just because we couldn't get logs
showardb18134f2009-03-20 20:52:18 +0000732 e_msg = "Unexpected error copying test result logs, continuing ..."
733 logging.error(e_msg)
jadmanski043e1132008-11-19 17:10:32 +0000734 traceback.print_exc(file=sys.stdout)
735
736
jadmanski043e1132008-11-19 17:10:32 +0000737# a file-like object for catching stderr from an autotest client and
738# extracting status logs from it
739class client_logger(object):
740 """Partial file object to write to both stdout and
741 the status log file. We only implement those methods
742 utils.run() actually calls.
743
744 Note that this class is fairly closely coupled with server_job, as it
745 uses special job._ methods to actually carry out the loggging.
746 """
747 status_parser = re.compile(r"^AUTOTEST_STATUS:([^:]*):(.*)$")
748 test_complete_parser = re.compile(r"^AUTOTEST_TEST_COMPLETE:(.*)$")
jadmanskib1a51132009-08-07 16:45:50 +0000749 fetch_package_parser = re.compile(
750 r"^AUTOTEST_FETCH_PACKAGE:([^:]*):([^:]*):(.*)$")
jadmanski043e1132008-11-19 17:10:32 +0000751 extract_indent = re.compile(r"^(\t*).*$")
jadmanskiefe4ebf2009-05-21 22:12:30 +0000752 extract_timestamp = re.compile(r".*\ttimestamp=(\d+)\t.*$")
jadmanski043e1132008-11-19 17:10:32 +0000753
754 def __init__(self, host, tag, server_results_dir):
755 self.host = host
756 self.job = host.job
757 self.log_collector = log_collector(host, tag, server_results_dir)
758 self.leftover = ""
759 self.last_line = ""
jadmanskiefe4ebf2009-05-21 22:12:30 +0000760 self.newest_timestamp = float("-inf")
jadmanski043e1132008-11-19 17:10:32 +0000761 self.logs = {}
jadmanski6dadd832009-02-05 23:39:27 +0000762 self.server_warnings = []
jadmanski043e1132008-11-19 17:10:32 +0000763
764
jadmanskiefe4ebf2009-05-21 22:12:30 +0000765 def _update_timestamp(self, line):
766 match = self.extract_timestamp.search(line)
767 if match:
768 self.newest_timestamp = max(self.newest_timestamp,
769 int(match.group(1)))
770
771
jadmanski043e1132008-11-19 17:10:32 +0000772 def _process_log_dict(self, log_dict):
773 log_list = log_dict.pop("logs", [])
774 for key in sorted(log_dict.iterkeys()):
775 log_list += self._process_log_dict(log_dict.pop(key))
776 return log_list
777
778
779 def _process_logs(self):
780 """Go through the accumulated logs in self.log and print them
781 out to stdout and the status log. Note that this processes
782 logs in an ordering where:
783
784 1) logs to different tags are never interleaved
785 2) logs to x.y come before logs to x.y.z for all z
786 3) logs to x.y come before x.z whenever y < z
787
788 Note that this will in general not be the same as the
789 chronological ordering of the logs. However, if a chronological
790 ordering is desired that one can be reconstructed from the
791 status log by looking at timestamp lines."""
792 log_list = self._process_log_dict(self.logs)
793 for line in log_list:
794 self.job._record_prerendered(line + '\n')
795 if log_list:
796 self.last_line = log_list[-1]
797
798
799 def _process_quoted_line(self, tag, line):
800 """Process a line quoted with an AUTOTEST_STATUS flag. If the
801 tag is blank then we want to push out all the data we've been
802 building up in self.logs, and then the newest line. If the
803 tag is not blank, then push the line into the logs for handling
804 later."""
showardb18134f2009-03-20 20:52:18 +0000805 logging.info(line)
jadmanski043e1132008-11-19 17:10:32 +0000806 if tag == "":
807 self._process_logs()
808 self.job._record_prerendered(line + '\n')
809 self.last_line = line
810 else:
811 tag_parts = [int(x) for x in tag.split(".")]
812 log_dict = self.logs
813 for part in tag_parts:
814 log_dict = log_dict.setdefault(part, {})
815 log_list = log_dict.setdefault("logs", [])
816 log_list.append(line)
817
818
jadmanskif37df842009-02-11 00:03:26 +0000819 def _process_info_line(self, line):
820 """Check if line is an INFO line, and if it is, interpret any control
821 messages (e.g. enabling/disabling warnings) that it may contain."""
822 match = re.search(r"^\t*INFO\t----\t----(.*)\t[^\t]*$", line)
823 if not match:
824 return # not an INFO line
825 for field in match.group(1).split('\t'):
826 if field.startswith("warnings.enable="):
jadmanski16a7ff72009-04-01 18:19:53 +0000827 func = self.job.warning_manager.enable_warnings
jadmanskif37df842009-02-11 00:03:26 +0000828 elif field.startswith("warnings.disable="):
jadmanski16a7ff72009-04-01 18:19:53 +0000829 func = self.job.warning_manager.disable_warnings
jadmanskif37df842009-02-11 00:03:26 +0000830 else:
831 continue
832 warning_type = field.split("=", 1)[1]
jadmanski16a7ff72009-04-01 18:19:53 +0000833 func(warning_type)
jadmanskif37df842009-02-11 00:03:26 +0000834
835
jadmanski043e1132008-11-19 17:10:32 +0000836 def _process_line(self, line):
837 """Write out a line of data to the appropriate stream. Status
838 lines sent by autotest will be prepended with
839 "AUTOTEST_STATUS", and all other lines are ssh error
840 messages."""
841 status_match = self.status_parser.search(line)
842 test_complete_match = self.test_complete_parser.search(line)
jadmanskib1a51132009-08-07 16:45:50 +0000843 fetch_package_match = self.fetch_package_parser.search(line)
jadmanski043e1132008-11-19 17:10:32 +0000844 if status_match:
845 tag, line = status_match.groups()
jadmanskif37df842009-02-11 00:03:26 +0000846 self._process_info_line(line)
jadmanski043e1132008-11-19 17:10:32 +0000847 self._process_quoted_line(tag, line)
848 elif test_complete_match:
jadmanskifcc0d5d2009-02-12 21:52:54 +0000849 self._process_logs()
jadmanski043e1132008-11-19 17:10:32 +0000850 fifo_path, = test_complete_match.groups()
851 self.log_collector.collect_client_job_results()
852 self.host.run("echo A > %s" % fifo_path)
jadmanskib1a51132009-08-07 16:45:50 +0000853 elif fetch_package_match:
854 pkg_name, dest_path, fifo_path = fetch_package_match.groups()
jadmanskiede7e242009-08-10 15:43:33 +0000855 serve_packages = global_config.global_config.get_config_value(
856 "PACKAGES", "serve_packages_from_autoserv", type=bool)
857 if serve_packages and pkg_name.endswith(".tar.bz2"):
858 try:
859 self._send_tarball(pkg_name, dest_path)
860 except Exception:
861 msg = "Package tarball creation failed, continuing anyway"
862 logging.exception(msg)
jadmanskib1a51132009-08-07 16:45:50 +0000863 self.host.run("echo B > %s" % fifo_path)
jadmanski043e1132008-11-19 17:10:32 +0000864 else:
showardb18134f2009-03-20 20:52:18 +0000865 logging.info(line)
jadmanski043e1132008-11-19 17:10:32 +0000866
867
jadmanskiede7e242009-08-10 15:43:33 +0000868 def _send_tarball(self, pkg_name, remote_dest):
869 name, pkg_type = self.job.pkgmgr.parse_tarball_name(pkg_name)
870 src_dirs = []
871 if pkg_type == 'test':
872 src_dirs += [os.path.join(self.job.clientdir, 'site_tests', name),
873 os.path.join(self.job.clientdir, 'tests', name)]
874 elif pkg_type == 'profiler':
875 src_dirs += [os.path.join(self.job.clientdir, 'profilers', name)]
876 elif pkg_type == 'dep':
877 src_dirs += [os.path.join(self.job.clientdir, 'deps', name)]
878 elif pkg_type == 'client':
879 return # you must already have a client to hit this anyway
880 else:
881 return # no other types are supported
882
883 # iterate over src_dirs until we find one that exists, then tar it
884 for src_dir in src_dirs:
885 if os.path.exists(src_dir):
886 try:
887 logging.info('Bundling %s into %s', src_dir, pkg_name)
888 temp_dir = autotemp.tempdir(unique_id='autoserv-packager',
889 dir=self.job.tmpdir)
890 tarball_path = self.job.pkgmgr.tar_package(
mblighbccad482009-08-24 22:08:31 +0000891 pkg_name, src_dir, temp_dir.name, " .")
jadmanskiede7e242009-08-10 15:43:33 +0000892 self.host.send_file(tarball_path, remote_dest)
893 finally:
894 temp_dir.clean()
895 return
896
897
jadmanski043e1132008-11-19 17:10:32 +0000898 def _format_warnings(self, last_line, warnings):
899 # use the indentation of whatever the last log line was
900 indent = self.extract_indent.match(last_line).group(1)
901 # if the last line starts a new group, add an extra indent
902 if last_line.lstrip('\t').startswith("START\t"):
903 indent += '\t'
904 return [self.job._render_record("WARN", None, None, msg,
905 timestamp, indent).rstrip('\n')
906 for timestamp, msg in warnings]
907
908
909 def _process_warnings(self, last_line, log_dict, warnings):
910 if log_dict.keys() in ([], ["logs"]):
911 # there are no sub-jobs, just append the warnings here
912 warnings = self._format_warnings(last_line, warnings)
913 log_list = log_dict.setdefault("logs", [])
914 log_list += warnings
915 for warning in warnings:
916 sys.stdout.write(warning + '\n')
917 else:
918 # there are sub-jobs, so put the warnings in there
919 log_list = log_dict.get("logs", [])
920 if log_list:
921 last_line = log_list[-1]
922 for key in sorted(log_dict.iterkeys()):
923 if key != "logs":
924 self._process_warnings(last_line,
925 log_dict[key],
926 warnings)
927
jadmanskif37df842009-02-11 00:03:26 +0000928
jadmanski91d56a92009-04-01 15:20:40 +0000929 def log_warning(self, msg, warning_type):
jadmanski6dadd832009-02-05 23:39:27 +0000930 """Injects a WARN message into the current status logging stream."""
jadmanski91d56a92009-04-01 15:20:40 +0000931 timestamp = int(time.time())
932 if self.job.warning_manager.is_valid(timestamp, warning_type):
933 self.server_warnings.append((timestamp, msg))
jadmanski6dadd832009-02-05 23:39:27 +0000934
jadmanski043e1132008-11-19 17:10:32 +0000935
936 def write(self, data):
937 # first check for any new console warnings
jadmanski6dadd832009-02-05 23:39:27 +0000938 warnings = self.job._read_warnings() + self.server_warnings
939 warnings.sort() # sort into timestamp order
jadmanski043e1132008-11-19 17:10:32 +0000940 # now process the newest data written out
941 data = self.leftover + data
942 lines = data.split("\n")
943 # process every line but the last one
944 for line in lines[:-1]:
jadmanskiefe4ebf2009-05-21 22:12:30 +0000945 self._update_timestamp(line)
946 # output any warnings between now and the next status line
947 old_warnings = [(timestamp, msg) for timestamp, msg in warnings
948 if timestamp < self.newest_timestamp]
949 self._process_warnings(self.last_line, self.logs, warnings)
950 del warnings[:len(old_warnings)]
jadmanski043e1132008-11-19 17:10:32 +0000951 self._process_line(line)
jadmanskiefe4ebf2009-05-21 22:12:30 +0000952 # save off any warnings not yet logged for later processing
953 self.server_warnings = warnings
jadmanski043e1132008-11-19 17:10:32 +0000954 # save the last line for later processing
955 # since we may not have the whole line yet
956 self.leftover = lines[-1]
957
958
959 def flush(self):
960 sys.stdout.flush()
961
962
jadmanskia61edad2009-05-21 22:17:49 +0000963 def flush_all_buffers(self):
jadmanski043e1132008-11-19 17:10:32 +0000964 if self.leftover:
965 self._process_line(self.leftover)
jadmanskia61edad2009-05-21 22:17:49 +0000966 self.leftover = ""
jadmanskiefe4ebf2009-05-21 22:12:30 +0000967 self._process_warnings(self.last_line, self.logs, self.server_warnings)
jadmanski043e1132008-11-19 17:10:32 +0000968 self._process_logs()
969 self.flush()
970
971
jadmanskia61edad2009-05-21 22:17:49 +0000972 def close(self):
973 self.flush_all_buffers()
974
975
mbligha7007722009-01-13 00:37:11 +0000976SiteAutotest = client_utils.import_site_class(
977 __file__, "autotest_lib.server.site_autotest", "SiteAutotest",
978 BaseAutotest)
mblighd8b39252008-03-20 21:15:03 +0000979
980class Autotest(SiteAutotest):
jadmanski0afbb632008-06-06 21:10:57 +0000981 pass