showard | f098ebd | 2009-06-10 00:13:33 +0000 | [diff] [blame] | 1 | import os, BaseHTTPServer, cgi, threading, urllib, fcntl, logging |
showard | d1ee1dd | 2009-01-07 21:33:08 +0000 | [diff] [blame] | 2 | import common |
jamesren | c44ae99 | 2010-02-19 00:12:54 +0000 | [diff] [blame] | 3 | from autotest_lib.scheduler import drone_manager, scheduler_config |
showard | d1ee1dd | 2009-01-07 21:33:08 +0000 | [diff] [blame] | 4 | |
| 5 | _PORT = 13467 |
| 6 | |
| 7 | _HEADER = """ |
| 8 | <html> |
| 9 | <head><title>Scheduler status</title></head> |
| 10 | <body> |
| 11 | Actions:<br> |
| 12 | <a href="?reparse_config=1">Reparse global config values</a><br> |
Eric Li | a82dc35 | 2011-02-23 13:15:52 -0800 | [diff] [blame^] | 13 | <a href="?restart_scheduler=1">Restart the scheduler</a><br> |
showard | d1ee1dd | 2009-01-07 21:33:08 +0000 | [diff] [blame] | 14 | <br> |
| 15 | """ |
| 16 | |
| 17 | _FOOTER = """ |
| 18 | </body> |
| 19 | </html> |
| 20 | """ |
| 21 | |
| 22 | class 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 | |
showard | 324bf81 | 2009-01-20 23:23:38 +0000 | [diff] [blame] | 53 | def _write_drone(self, drone): |
showard | 1b7142d | 2010-01-15 00:21:37 +0000 | [diff] [blame] | 54 | 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)) |
showard | 324bf81 | 2009-01-20 23:23:38 +0000 | [diff] [blame] | 61 | if not drone.enabled: |
showard | c5afc46 | 2009-01-13 00:09:39 +0000 | [diff] [blame] | 62 | line += ' (disabled)' |
| 63 | self._write_line(line) |
| 64 | |
| 65 | |
| 66 | def _write_drone_list(self): |
| 67 | self._write_line('Drones:') |
showard | 324bf81 | 2009-01-20 23:23:38 +0000 | [diff] [blame] | 68 | for drone in self.server._drone_manager.get_drones(): |
| 69 | self._write_drone(drone) |
showard | c5afc46 | 2009-01-13 00:09:39 +0000 | [diff] [blame] | 70 | self._write_line() |
| 71 | |
| 72 | |
showard | d1ee1dd | 2009-01-07 21:33:08 +0000 | [diff] [blame] | 73 | def _execute_actions(self, arguments): |
| 74 | if 'reparse_config' in arguments: |
| 75 | scheduler_config.config.read_config() |
showard | 324bf81 | 2009-01-20 23:23:38 +0000 | [diff] [blame] | 76 | self.server._drone_manager.refresh_drone_configs() |
showard | c5afc46 | 2009-01-13 00:09:39 +0000 | [diff] [blame] | 77 | self._write_line('Reparsed config!') |
Eric Li | a82dc35 | 2011-02-23 13:15:52 -0800 | [diff] [blame^] | 78 | elif 'restart_scheduler' in arguments: |
| 79 | self.server._shutdown_scheduler = True |
| 80 | self._write_line('Posted the shutdown request') |
showard | d1ee1dd | 2009-01-07 21:33:08 +0000 | [diff] [blame] | 81 | 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() |
showard | c5afc46 | 2009-01-13 00:09:39 +0000 | [diff] [blame] | 91 | self._write_drone_list() |
showard | d1ee1dd | 2009-01-07 21:33:08 +0000 | [diff] [blame] | 92 | |
| 93 | self.wfile.write(_FOOTER) |
| 94 | |
| 95 | |
showard | 55b4b54 | 2009-01-08 23:30:30 +0000 | [diff] [blame] | 96 | class StatusServer(BaseHTTPServer.HTTPServer): |
jamesren | c44ae99 | 2010-02-19 00:12:54 +0000 | [diff] [blame] | 97 | def __init__(self): |
showard | 55b4b54 | 2009-01-08 23:30:30 +0000 | [diff] [blame] | 98 | address = ('', _PORT) |
| 99 | # HTTPServer is an old-style class :( |
| 100 | BaseHTTPServer.HTTPServer.__init__(self, address, |
| 101 | StatusServerRequestHandler) |
| 102 | self._shutting_down = False |
jamesren | c44ae99 | 2010-02-19 00:12:54 +0000 | [diff] [blame] | 103 | self._drone_manager = drone_manager.instance() |
Eric Li | a82dc35 | 2011-02-23 13:15:52 -0800 | [diff] [blame^] | 104 | self._shutdown_scheduler = False |
showard | d1ee1dd | 2009-01-07 21:33:08 +0000 | [diff] [blame] | 105 | |
showard | 4fd61be | 2009-01-13 00:09:52 +0000 | [diff] [blame] | 106 | # 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 | |
showard | d1ee1dd | 2009-01-07 21:33:08 +0000 | [diff] [blame] | 110 | |
showard | 55b4b54 | 2009-01-08 23:30:30 +0000 | [diff] [blame] | 111 | def shutdown(self): |
| 112 | if self._shutting_down: |
| 113 | return |
showard | f098ebd | 2009-06-10 00:13:33 +0000 | [diff] [blame] | 114 | logging.info('Shutting down server...') |
showard | 55b4b54 | 2009-01-08 23:30:30 +0000 | [diff] [blame] | 115 | 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): |
showard | f098ebd | 2009-06-10 00:13:33 +0000 | [diff] [blame] | 121 | logging.info('Status server running on %s', self.server_address) |
showard | 55b4b54 | 2009-01-08 23:30:30 +0000 | [diff] [blame] | 122 | while not self._shutting_down: |
| 123 | self.handle_request() |
showard | d1ee1dd | 2009-01-07 21:33:08 +0000 | [diff] [blame] | 124 | |
| 125 | |
| 126 | def start(self): |
showard | 55b4b54 | 2009-01-08 23:30:30 +0000 | [diff] [blame] | 127 | self._thread = threading.Thread(target=self._serve_until_shutdown, |
| 128 | name='status_server') |
showard | d1ee1dd | 2009-01-07 21:33:08 +0000 | [diff] [blame] | 129 | self._thread.start() |