blob: c52867127912b63bfcb5214e3b0f0087c4274bf7 [file] [log] [blame]
showardf098ebd2009-06-10 00:13:33 +00001import os, BaseHTTPServer, cgi, threading, urllib, fcntl, logging
showardd1ee1dd2009-01-07 21:33:08 +00002import common
jamesrenc44ae992010-02-19 00:12:54 +00003from autotest_lib.scheduler import drone_manager, scheduler_config
showardd1ee1dd2009-01-07 21:33:08 +00004
5_PORT = 13467
6
7_HEADER = """
8<html>
9<head><title>Scheduler status</title></head>
10<body>
11Actions:<br>
12<a href="?reparse_config=1">Reparse global config values</a><br>
Eric Lia82dc352011-02-23 13:15:52 -080013<a href="?restart_scheduler=1">Restart the scheduler</a><br>
showardd1ee1dd2009-01-07 21:33:08 +000014<br>
15"""
16
17_FOOTER = """
18</body>
19</html>
20"""
21
22class StatusServerRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
23 def _send_headers(self):
24 self.send_response(200, 'OK')
25 self.send_header('Content-Type', 'text/html')
26 self.end_headers()
27
28
29 def _parse_arguments(self):
30 path_parts = self.path.split('?', 1)
31 if len(path_parts) == 1:
32 return {}
33
34 encoded_args = path_parts[1]
35 return cgi.parse_qs(encoded_args)
36
37
38 def _write_line(self, line=''):
39 self.wfile.write(line + '<br>\n')
40
41
42 def _write_field(self, field, value):
43 self._write_line('%s=%s' % (field, value))
44
45
46 def _write_all_fields(self):
47 self._write_line('Config values:')
48 for field in scheduler_config.SchedulerConfig.FIELDS:
49 self._write_field(field, getattr(scheduler_config.config, field))
50 self._write_line()
51
52
showard324bf812009-01-20 23:23:38 +000053 def _write_drone(self, drone):
showard1b7142d2010-01-15 00:21:37 +000054 if drone.allowed_users:
55 allowed_users = ', '.join(drone.allowed_users)
56 else:
57 allowed_users = 'all'
58 line = ('%s: %s/%s processes, users: %s'
59 % (drone.hostname, drone.active_processes, drone.max_processes,
60 allowed_users))
showard324bf812009-01-20 23:23:38 +000061 if not drone.enabled:
showardc5afc462009-01-13 00:09:39 +000062 line += ' (disabled)'
63 self._write_line(line)
64
65
66 def _write_drone_list(self):
67 self._write_line('Drones:')
showard324bf812009-01-20 23:23:38 +000068 for drone in self.server._drone_manager.get_drones():
69 self._write_drone(drone)
showardc5afc462009-01-13 00:09:39 +000070 self._write_line()
71
72
showardd1ee1dd2009-01-07 21:33:08 +000073 def _execute_actions(self, arguments):
74 if 'reparse_config' in arguments:
75 scheduler_config.config.read_config()
showard324bf812009-01-20 23:23:38 +000076 self.server._drone_manager.refresh_drone_configs()
showardc5afc462009-01-13 00:09:39 +000077 self._write_line('Reparsed config!')
Eric Lia82dc352011-02-23 13:15:52 -080078 elif 'restart_scheduler' in arguments:
79 self.server._shutdown_scheduler = True
80 self._write_line('Posted the shutdown request')
showardd1ee1dd2009-01-07 21:33:08 +000081 self._write_line()
82
83
84 def do_GET(self):
85 self._send_headers()
86 self.wfile.write(_HEADER)
87
88 arguments = self._parse_arguments()
89 self._execute_actions(arguments)
90 self._write_all_fields()
showardc5afc462009-01-13 00:09:39 +000091 self._write_drone_list()
showardd1ee1dd2009-01-07 21:33:08 +000092
93 self.wfile.write(_FOOTER)
94
95
showard55b4b542009-01-08 23:30:30 +000096class StatusServer(BaseHTTPServer.HTTPServer):
jamesrenc44ae992010-02-19 00:12:54 +000097 def __init__(self):
showard55b4b542009-01-08 23:30:30 +000098 address = ('', _PORT)
99 # HTTPServer is an old-style class :(
100 BaseHTTPServer.HTTPServer.__init__(self, address,
101 StatusServerRequestHandler)
102 self._shutting_down = False
jamesrenc44ae992010-02-19 00:12:54 +0000103 self._drone_manager = drone_manager.instance()
Eric Lia82dc352011-02-23 13:15:52 -0800104 self._shutdown_scheduler = False
showardd1ee1dd2009-01-07 21:33:08 +0000105
showard4fd61be2009-01-13 00:09:52 +0000106 # ensure the listening socket is not inherited by child processes
107 old_flags = fcntl.fcntl(self.fileno(), fcntl.F_GETFD)
108 fcntl.fcntl(self.fileno(), fcntl.F_SETFD, old_flags | fcntl.FD_CLOEXEC)
109
showardd1ee1dd2009-01-07 21:33:08 +0000110
showard55b4b542009-01-08 23:30:30 +0000111 def shutdown(self):
112 if self._shutting_down:
113 return
showardf098ebd2009-06-10 00:13:33 +0000114 logging.info('Shutting down server...')
showard55b4b542009-01-08 23:30:30 +0000115 self._shutting_down = True
116 # make one last request to awaken the server thread and make it exit
117 urllib.urlopen('http://localhost:%s' % _PORT)
118
119
120 def _serve_until_shutdown(self):
showardf098ebd2009-06-10 00:13:33 +0000121 logging.info('Status server running on %s', self.server_address)
showard55b4b542009-01-08 23:30:30 +0000122 while not self._shutting_down:
123 self.handle_request()
showardd1ee1dd2009-01-07 21:33:08 +0000124
125
126 def start(self):
showard55b4b542009-01-08 23:30:30 +0000127 self._thread = threading.Thread(target=self._serve_until_shutdown,
128 name='status_server')
showardd1ee1dd2009-01-07 21:33:08 +0000129 self._thread.start()