blob: df5186668ab7797b0ea4d01e4b5c284e51f2c532 [file] [log] [blame]
Aviv Keshet69ce4e52013-01-17 12:51:48 -08001import 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>
13<br>
14"""
15
16_FOOTER = """
17</body>
18</html>
19"""
20
21class StatusServerRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
22 def _send_headers(self):
23 self.send_response(200, 'OK')
24 self.send_header('Content-Type', 'text/html')
25 self.end_headers()
26
27
28 def _parse_arguments(self):
29 path_parts = self.path.split('?', 1)
30 if len(path_parts) == 1:
31 return {}
32
33 encoded_args = path_parts[1]
34 return cgi.parse_qs(encoded_args)
35
36
37 def _write_line(self, line=''):
38 self.wfile.write(line + '<br>\n')
39
40
41 def _write_field(self, field, value):
42 self._write_line('%s=%s' % (field, value))
43
44
45 def _write_all_fields(self):
46 self._write_line('Config values:')
47 for field in scheduler_config.SchedulerConfig.FIELDS:
48 self._write_field(field, getattr(scheduler_config.config, field))
49 self._write_line()
50
51
showard324bf812009-01-20 23:23:38 +000052 def _write_drone(self, drone):
showard1b7142d2010-01-15 00:21:37 +000053 if drone.allowed_users:
54 allowed_users = ', '.join(drone.allowed_users)
55 else:
56 allowed_users = 'all'
57 line = ('%s: %s/%s processes, users: %s'
58 % (drone.hostname, drone.active_processes, drone.max_processes,
59 allowed_users))
showard324bf812009-01-20 23:23:38 +000060 if not drone.enabled:
showardc5afc462009-01-13 00:09:39 +000061 line += ' (disabled)'
62 self._write_line(line)
63
64
65 def _write_drone_list(self):
66 self._write_line('Drones:')
showard324bf812009-01-20 23:23:38 +000067 for drone in self.server._drone_manager.get_drones():
68 self._write_drone(drone)
showardc5afc462009-01-13 00:09:39 +000069 self._write_line()
70
71
showardd1ee1dd2009-01-07 21:33:08 +000072 def _execute_actions(self, arguments):
73 if 'reparse_config' in arguments:
74 scheduler_config.config.read_config()
showard324bf812009-01-20 23:23:38 +000075 self.server._drone_manager.refresh_drone_configs()
showardc5afc462009-01-13 00:09:39 +000076 self._write_line('Reparsed config!')
Eric Lia82dc352011-02-23 13:15:52 -080077 elif 'restart_scheduler' in arguments:
78 self.server._shutdown_scheduler = True
79 self._write_line('Posted the shutdown request')
showardd1ee1dd2009-01-07 21:33:08 +000080 self._write_line()
81
82
83 def do_GET(self):
84 self._send_headers()
85 self.wfile.write(_HEADER)
86
87 arguments = self._parse_arguments()
88 self._execute_actions(arguments)
89 self._write_all_fields()
showardc5afc462009-01-13 00:09:39 +000090 self._write_drone_list()
showardd1ee1dd2009-01-07 21:33:08 +000091
92 self.wfile.write(_FOOTER)
93
94
showard55b4b542009-01-08 23:30:30 +000095class StatusServer(BaseHTTPServer.HTTPServer):
jamesrenc44ae992010-02-19 00:12:54 +000096 def __init__(self):
showard55b4b542009-01-08 23:30:30 +000097 address = ('', _PORT)
98 # HTTPServer is an old-style class :(
99 BaseHTTPServer.HTTPServer.__init__(self, address,
100 StatusServerRequestHandler)
101 self._shutting_down = False
jamesrenc44ae992010-02-19 00:12:54 +0000102 self._drone_manager = drone_manager.instance()
Eric Lia82dc352011-02-23 13:15:52 -0800103 self._shutdown_scheduler = False
showardd1ee1dd2009-01-07 21:33:08 +0000104
showard4fd61be2009-01-13 00:09:52 +0000105 # ensure the listening socket is not inherited by child processes
106 old_flags = fcntl.fcntl(self.fileno(), fcntl.F_GETFD)
107 fcntl.fcntl(self.fileno(), fcntl.F_SETFD, old_flags | fcntl.FD_CLOEXEC)
108
showardd1ee1dd2009-01-07 21:33:08 +0000109
showard55b4b542009-01-08 23:30:30 +0000110 def shutdown(self):
111 if self._shutting_down:
112 return
showardf098ebd2009-06-10 00:13:33 +0000113 logging.info('Shutting down server...')
showard55b4b542009-01-08 23:30:30 +0000114 self._shutting_down = True
115 # make one last request to awaken the server thread and make it exit
116 urllib.urlopen('http://localhost:%s' % _PORT)
117
118
119 def _serve_until_shutdown(self):
showardf098ebd2009-06-10 00:13:33 +0000120 logging.info('Status server running on %s', self.server_address)
showard55b4b542009-01-08 23:30:30 +0000121 while not self._shutting_down:
122 self.handle_request()
showardd1ee1dd2009-01-07 21:33:08 +0000123
124
125 def start(self):
showard55b4b542009-01-08 23:30:30 +0000126 self._thread = threading.Thread(target=self._serve_until_shutdown,
127 name='status_server')
showardd1ee1dd2009-01-07 21:33:08 +0000128 self._thread.start()