|
@@ -57,6 +57,16 @@ def normalize_ispname(isp):
|
|
|
return isp
|
|
|
|
|
|
|
|
|
+def csvize_values(values):
|
|
|
+ for x in values:
|
|
|
+ if x is None:
|
|
|
+ yield '-/-'
|
|
|
+ elif ' ' in x:
|
|
|
+ yield '"' + x + '"'
|
|
|
+ else:
|
|
|
+ yield str(x)
|
|
|
+
|
|
|
+
|
|
|
class BatcaveHttpRequestHandler(BaseHTTPRequestHandler):
|
|
|
"""Handles a single HTTP request to the BATCAVE."""
|
|
|
|
|
@@ -97,6 +107,11 @@ class BatcaveHttpRequestHandler(BaseHTTPRequestHandler):
|
|
|
self.__respond_nodes(query)
|
|
|
return
|
|
|
|
|
|
+ # /nodes.csv
|
|
|
+ if path == 'nodes.csv':
|
|
|
+ self.__respond_nodes_csv(query)
|
|
|
+ return
|
|
|
+
|
|
|
# /list - list stored nodes
|
|
|
if path == 'list':
|
|
|
self.__respond_list(query)
|
|
@@ -372,6 +387,34 @@ angesprochen und sollte aus einer Mehrzahl von Gründen nicht
|
|
|
extra={'Content-Disposition': 'inline'})
|
|
|
self.wfile.write(json.dumps(result, indent=indent))
|
|
|
|
|
|
+ def __respond_nodes_csv(self, query):
|
|
|
+ self.__send_headers(content_type='text/csv', nocache=True)
|
|
|
+
|
|
|
+ csv_fs = ";"
|
|
|
+
|
|
|
+ fields = query.get('fields', 'ID,Name,Firmware,Autoupdater,Location,Status,Clients').split(',')
|
|
|
+ fieldmapping = {
|
|
|
+ 'ID': 'node_id',
|
|
|
+ 'Name': 'hostname',
|
|
|
+ 'Status': lambda n: self.server.storage.get_nodestatus(node=n),
|
|
|
+ 'Location': lambda n: ' '.join(n.get('location')) if isinstance(n.get('location'), list) else '{latitude} {longitude}'.format(**n.get('location')) if n.get('location') is not None else '',
|
|
|
+ 'Firmware': lambda n: n.get('software', {}).get('firmware'),
|
|
|
+ 'Autoupdater': lambda n: n.get('software', {}).get('autoupdater', 'unknown'),
|
|
|
+ 'Clients': lambda n: str(len(n.get('clients', []))),
|
|
|
+ }
|
|
|
+
|
|
|
+ # write CSV header line
|
|
|
+ self.wfile.write(csv_fs.join(csvize_values(
|
|
|
+ [f for f in fields if f in fieldmapping])))
|
|
|
+ self.wfile.write('\n')
|
|
|
+
|
|
|
+ # output each node
|
|
|
+ for node in self.server.storage.get_nodes():
|
|
|
+ value_gen = [fieldmapping[f] for f in fields if f in fieldmapping]
|
|
|
+ values = [gen(node) if not isinstance(gen, basestring) else node.get(gen) for gen in value_gen]
|
|
|
+ self.wfile.write(csv_fs.join(csvize_values(values)))
|
|
|
+ self.wfile.write('\n')
|
|
|
+
|
|
|
def __respond_node(self, rawid, query):
|
|
|
"""Display node data."""
|
|
|
|