import BaseHTTPServer, cgi, threading, urllib, fcntl, logging import common from autotest_lib.scheduler import drone_manager, scheduler_config _PORT = 13467 _HEADER = """ Scheduler status Actions:
Reparse global config values

""" _FOOTER = """ """ class StatusServerRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): def _send_headers(self): self.send_response(200, 'OK') self.send_header('Content-Type', 'text/html') self.end_headers() def _parse_arguments(self): path_parts = self.path.split('?', 1) if len(path_parts) == 1: return {} encoded_args = path_parts[1] return cgi.parse_qs(encoded_args) def _write_line(self, line=''): self.wfile.write(line + '
\n') def _write_field(self, field, value): self._write_line('%s=%s' % (field, value)) def _write_all_fields(self): self._write_line('Config values:') for field, datatype in scheduler_config.SchedulerConfig.FIELDS: self._write_field(field, getattr(scheduler_config.config, field)) self._write_line() def _write_drone(self, drone): if drone.allowed_users: allowed_users = ', '.join(drone.allowed_users) else: allowed_users = 'all' line = ('%s: %s/%s processes, users: %s' % (drone.hostname, drone.active_processes, drone.max_processes, allowed_users)) if not drone.enabled: line += ' (disabled)' self._write_line(line) def _write_drone_list(self): self._write_line('Drones:') for drone in self.server._drone_manager.get_drones(): self._write_drone(drone) self._write_line() def _execute_actions(self, arguments): if 'reparse_config' in arguments: scheduler_config.config.read_config() self.server._drone_manager.refresh_drone_configs() self._write_line('Reparsed config!') elif 'restart_scheduler' in arguments: self.server._shutdown_scheduler = True self._write_line('Posted the shutdown request') self._write_line() def do_GET(self): self._send_headers() self.wfile.write(_HEADER) arguments = self._parse_arguments() self._execute_actions(arguments) self._write_all_fields() self._write_drone_list() self.wfile.write(_FOOTER) class StatusServer(BaseHTTPServer.HTTPServer): def __init__(self): address = ('', _PORT) # HTTPServer is an old-style class :( BaseHTTPServer.HTTPServer.__init__(self, address, StatusServerRequestHandler) self._shutting_down = False self._drone_manager = drone_manager.instance() self._shutdown_scheduler = False # ensure the listening socket is not inherited by child processes old_flags = fcntl.fcntl(self.fileno(), fcntl.F_GETFD) fcntl.fcntl(self.fileno(), fcntl.F_SETFD, old_flags | fcntl.FD_CLOEXEC) def shutdown(self): if self._shutting_down: return logging.info('Shutting down server...') self._shutting_down = True # make one last request to awaken the server thread and make it exit urllib.urlopen('http://localhost:%s' % _PORT) def _serve_until_shutdown(self): logging.info('Status server running on %s', self.server_address) while not self._shutting_down: self.handle_request() def start(self): self._thread = threading.Thread(target=self._serve_until_shutdown, name='status_server') self._thread.start()