|
@@ -5,6 +5,7 @@ from __future__ import print_function, unicode_literals
|
|
|
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
|
|
|
|
|
|
import cgi
|
|
|
+import difflib
|
|
|
import json
|
|
|
import logging
|
|
|
import re
|
|
@@ -111,6 +112,11 @@ class BatcaveHttpRequestHandler(BaseHTTPRequestHandler):
|
|
|
self.__respond_providers(query)
|
|
|
return
|
|
|
|
|
|
+ # /find?name=foo&fuzzy=1
|
|
|
+ if path == 'find':
|
|
|
+ self.__respond_findnode(query)
|
|
|
+ return
|
|
|
+
|
|
|
# /node/<id>.json - node's data
|
|
|
# /node/<id>/field - return specific field from node's data
|
|
|
match = REGEX_URL_NODEINFO.match(path)
|
|
@@ -321,6 +327,56 @@ angesprochen und sollte aus einer Mehrzahl von Gründen nicht
|
|
|
self.__send_headers('text/plain')
|
|
|
self.wfile.write(status)
|
|
|
|
|
|
+ def __respond_findnode(self, query):
|
|
|
+ """Find nodes matching the supplied name."""
|
|
|
+
|
|
|
+ self.__send_headers('application/json',
|
|
|
+ extra={'Content-Disposition': 'inline'})
|
|
|
+
|
|
|
+ name = query.get('name').lower()
|
|
|
+ fuzzy = query.get('fuzzy', '0') == '1'
|
|
|
+
|
|
|
+ names = {}
|
|
|
+ for node in self.server.storage.get_nodes():
|
|
|
+ nodename = node.get('hostname').lower()
|
|
|
+ if nodename not in names:
|
|
|
+ # first time we see this name
|
|
|
+ names[nodename] = [node]
|
|
|
+ else:
|
|
|
+ # we've seen this name before
|
|
|
+ names[nodename].append(node)
|
|
|
+
|
|
|
+ allnames = [x for x in names]
|
|
|
+ resultnames = []
|
|
|
+
|
|
|
+ # check for exact match
|
|
|
+ if name in allnames:
|
|
|
+ # write the exact matches and we're done
|
|
|
+ resultnames = [name]
|
|
|
+
|
|
|
+ else:
|
|
|
+ # are we allowed to fuzzy match?
|
|
|
+ if not fuzzy:
|
|
|
+ # no -> return zero matches
|
|
|
+ self.wfile.write('[]')
|
|
|
+ return
|
|
|
+
|
|
|
+ # let's do fuzzy matching
|
|
|
+ resultnames = difflib.get_close_matches(name, allnames,
|
|
|
+ cutoff=0.75)
|
|
|
+
|
|
|
+ result = []
|
|
|
+ for possibility in resultnames:
|
|
|
+ for x in names[possibility]:
|
|
|
+ x_id = x.get('node_id')
|
|
|
+ result.append({
|
|
|
+ 'id': x_id,
|
|
|
+ 'name': x.get('hostname'),
|
|
|
+ 'status': self.server.storage.get_nodestatus(x_id),
|
|
|
+ })
|
|
|
+
|
|
|
+ self.wfile.write(json.dumps(result))
|
|
|
+
|
|
|
def __respond_nodeidmac2name(self, ids):
|
|
|
"""Return a mapping of the given IDs (or MACs) into their hostname."""
|
|
|
|