def __init__(self, sched, prefix): """ClientRegistry Constructor. Args: sched: A scheduler.Scheduler instance. prefix: The base path where the store will be created/read. """ resource.Resource.__init__(self) # Set things up self.scheduler = sched self.store_path = prefix + "/clients/" # Setup/restore persistent storage for client information if not os.path.isdir(self.store_path): os.makedirs(self.store_path) self.known_clients = DirDBM(self.store_path) # Restore information about jobs done self.jobs_done = {} for client_id in self.known_clients.keys(): num_jobs_done = int(self.known_clients[client_id].split("#")[4]) self.jobs_done[client_id] = num_jobs_done
class ClientRegistry(resource.Resource): """Keeps information about the clients that contacted this server. Besides storing information about our peers (clients), this class also provides a page (resource) from with information about our clients (name, ID, IP, number of jobs completed) can be gathered. Information about client is stored in a DirDBM. For a given client ID, we store it's CLIENT_SENT_HEADERS headers and the # of jobs performed. Information is stored as a string, fields separated by '#'. """ isLeaf = True CLIENT_SENT_HEADERS = ['client-id', 'client-hostname', 'client-version', \ 'client-arver'] HTML_HEADER = """<html> <head> <title>Client Status</title> <link href="./static/style.css" type="text/css" rel="stylesheet" /> <script type="text/javascript" src="./static/sortable.js"></script> </head> <body> <h1>Clients</h1> <table class="sortable" id="clientState"> <thead> <tr> <th>client-hostname</th><th>client-version</th> <th>client-arver</th><th># jobs</th><th>state</th><th>Next job</th> </tr> <thead> <tbody>""" HTML_FOOTER = """</tbody></table> </body> </html> """ def __init__(self, sched, prefix): """ClientRegistry Constructor. Args: sched: A scheduler.Scheduler instance. prefix: The base path where the store will be created/read. """ resource.Resource.__init__(self) # Set things up self.scheduler = sched self.store_path = prefix + "/clients/" # Setup/restore persistent storage for client information if not os.path.isdir(self.store_path): os.makedirs(self.store_path) self.known_clients = DirDBM(self.store_path) # Restore information about jobs done self.jobs_done = {} for client_id in self.known_clients.keys(): num_jobs_done = int(self.known_clients[client_id].split("#")[4]) self.jobs_done[client_id] = num_jobs_done def updateClientStats(self, request, job_done=False): """Updates information about a client and retrieve its id. This method should be called by Task Controllers in order to keep our knowledge about clients fresh and correct. Args: request: The request object passed by the twisted framework. Client identification will be extracted from it. job_done: Was a task/job completed by this client? Pass True if so, or False if this was just a ping or something related. @return client's client_id. """ client_id = request.getHeader('client-id') if client_id is None: raise InvalidClientId() if job_done: self.jobs_done[client_id] = self.jobs_done.get(client_id, 0) + 1 # store client information in persistent storage client_data = [] for hdr in self.CLIENT_SENT_HEADERS: content = request.getHeader(hdr) if not content: content = 'UNKNOWN' client_data.append(content) client_data.append(str(self.jobs_done.get(client_id, 0))) self.known_clients[client_id] = "#".join(client_data) return client_id def render(self, _request): """Render HTML code for the client status page.""" now = time.time() result = [] result.append(self.HTML_HEADER) for client_id in self.known_clients.keys(): # get client status last_seen = self.scheduler.peers.get(client_id) if last_seen: state = 'ALIVE' else: state = 'DEAD' last_seen = now + 1 # Avoid a (None - Float) subtracion bellow # print client data result.append('<tr class="%s" id="%s">' % (state, client_id)) for val in self.known_clients[client_id].split("#")[1:]: result.append('<td>%s</td>' % val) result.append('<td>%s</td>' % state) result.append('<td>%i</td>' % (now - last_seen)) result.append('</tr>') result.append(self.HTML_FOOTER) return "".join(result)