autotestd_monitor revision e8e73c6c1160fbd238172820ed5cb87da278e7ba
1#!/usr/bin/python
2
3import common
4import sys, os, signal, time, subprocess, fcntl
5
6logdir = sys.argv[1]
7stdout_start = int(sys.argv[2])  # number of bytes we can skip on stdout
8stderr_start = int(sys.argv[3])  # nubmer of bytes we can skip on stderr
9
10devnull = open(os.devnull, 'w')
11
12# launch some tail processes to pump the std* streams
13def launch_tail(filename, outstream, start):
14    path = os.path.join(logdir, filename)
15    argv = ['tail', '--retry', '--follow=name', '--bytes=+%d' % start, path]
16    # stdout=sys.stdout fails on pre-2.5 python (bug in subprocess module)
17    if outstream != subprocess.PIPE and outstream.fileno() == 1:
18        return subprocess.Popen(argv, stderr=devnull)
19    else:
20        return subprocess.Popen(argv, stdout=outstream, stderr=devnull)
21stdout_pump = launch_tail('stdout', sys.stdout, stdout_start)
22stderr_pump = launch_tail('stderr', sys.stderr, stderr_start)
23
24# wait for logdir/started to exist to be sure autotestd is started
25start_time = time.time()
26started_file_path = os.path.join(logdir, 'started')
27while not os.path.exists(started_file_path):
28    time.sleep(1)
29    if time.time() - start_time >= 30:
30        raise Exception("autotestd failed to start in %s" % logdir)
31os.remove(started_file_path)
32
33# watch the exit code file for an exit
34exit_code_file = open(os.path.join(logdir, 'exit_code'))
35fcntl.flock(exit_code_file, fcntl.LOCK_EX)
36try:
37    exit_code = exit_code_file.read()
38    if len(exit_code) != 4:
39        exit_code = -signal.SIGKILL   # autotestd was nuked
40    else:
41        exit_code = int(exit_code)
42finally:
43    fcntl.flock(exit_code_file, fcntl.LOCK_UN)
44    exit_code_file.close()
45
46time.sleep(2) # tail runs in 1s polling loop, so give them a chance to finish
47os.kill(stdout_pump.pid, signal.SIGTERM)
48os.kill(stderr_pump.pid, signal.SIGTERM)
49
50# exit (with the same code as autotestd)
51sys.exit(exit_code)
52