mirror of
https://github.com/xcat2/confluent.git
synced 2025-01-17 21:23:18 +00:00
Allow noderange pagination of all nodes
When a noderange starts with '<' or '>', use the set of all nodes as basis for pagination. Additionally, provide better feedback to client on noderange parsing issues. Also implement natural sort in various places after doing it for the pagination.
This commit is contained in:
parent
ca4c1673a5
commit
1c6430bf3f
@ -262,7 +262,12 @@ def enumerate_nodegroup_collection(collectionpath, configmanager):
|
||||
|
||||
def enumerate_node_collection(collectionpath, configmanager):
|
||||
if collectionpath == ['nodes']: # it is just '/node/', need to list nodes
|
||||
return iterate_collections(configmanager.list_nodes())
|
||||
allnodes = list(configmanager.list_nodes())
|
||||
try:
|
||||
allnodes.sort(key=noderange.humanify_nodename)
|
||||
except TypeError:
|
||||
allnodes.sort()
|
||||
return iterate_collections(allnodes)
|
||||
nodeorrange = collectionpath[1]
|
||||
if collectionpath[0] == 'nodes' and not configmanager.is_node(nodeorrange):
|
||||
raise exc.NotFoundException("Invalid element requested")
|
||||
@ -368,8 +373,8 @@ def handle_node_request(configmanager, inputdata, operation,
|
||||
if isnoderange:
|
||||
try:
|
||||
nodes = noderange.NodeRange(nodeorrange, configmanager).nodes
|
||||
except Exception:
|
||||
raise exc.NotFoundException("Invalid Noderange")
|
||||
except Exception as e:
|
||||
raise exc.NotFoundException("Invalid Noderange: " + str(e))
|
||||
else:
|
||||
nodes = (nodeorrange,)
|
||||
except IndexError: # doesn't actually have a long enough path
|
||||
@ -381,9 +386,19 @@ def handle_node_request(configmanager, inputdata, operation,
|
||||
if operation == "create":
|
||||
inputdata = msg.InputAttributes(pathcomponents, inputdata)
|
||||
create_node(inputdata.attribs, configmanager)
|
||||
return iterate_collections(configmanager.list_nodes())
|
||||
allnodes = list(configmanager.list_nodes())
|
||||
try:
|
||||
allnodes.sort(key=noderange.humanify_nodename)
|
||||
except TypeError:
|
||||
allnodes.sort()
|
||||
return iterate_collections(allnodes)
|
||||
if isnoderange and len(pathcomponents) == 3 and pathcomponents[2] == 'nodes':
|
||||
# this means that it's a list of relevant nodes
|
||||
nodes = list(nodes)
|
||||
try:
|
||||
nodes.sort(key=noderange.humanify_nodename)
|
||||
except TypeError:
|
||||
nodes.sort()
|
||||
return iterate_collections(nodes)
|
||||
if len(pathcomponents) == 2:
|
||||
iscollection = True
|
||||
|
@ -393,9 +393,9 @@ def resourcehandler_backend(env, start_response):
|
||||
pagecontent += datum
|
||||
start_response('200 OK', headers)
|
||||
yield pagecontent
|
||||
except exc.NotFoundException:
|
||||
except exc.NotFoundException as ne:
|
||||
start_response('404 Not found', headers)
|
||||
yield "404 - Request path not recognized"
|
||||
yield "404 - Request path not recognized - " + str(ne)
|
||||
except exc.InvalidArgumentException as e:
|
||||
start_response('400 Bad Request - ' + str(e), headers)
|
||||
yield '400 - Bad Request - ' + str(e)
|
||||
|
@ -22,19 +22,30 @@
|
||||
|
||||
import itertools
|
||||
import pyparsing as pp
|
||||
import re
|
||||
|
||||
# construct custom grammar with pyparsing
|
||||
_nodeword = pp.Word(pp.alphanums + '~^$/=-:.*+!')
|
||||
_nodebracket = pp.QuotedString(quoteChar='[', endQuoteChar=']',
|
||||
unquoteResults=False)
|
||||
_nodeatom = pp.Group(pp.OneOrMore(_nodeword | _nodebracket))
|
||||
_paginationstart = pp.Word('<', pp.nums)
|
||||
_paginationend = pp.Word('>', pp.nums)
|
||||
_paginationstart = pp.Group(pp.Word('<', pp.nums))
|
||||
_paginationend = pp.Group(pp.Word('>', pp.nums))
|
||||
_grammar = _nodeatom | ',-' | ',' | '@' | _paginationstart | _paginationend
|
||||
_parser = pp.nestedExpr(content=_grammar)
|
||||
|
||||
_numextractor = pp.OneOrMore(pp.Word(pp.alphas + '-') | pp.Word(pp.nums))
|
||||
|
||||
numregex = re.compile('([0-9]+)')
|
||||
def humanify_nodename(nodename):
|
||||
"""Analyzes nodename in a human way to enable natural sort
|
||||
|
||||
:param nodename: The node name to analyze
|
||||
:returns: A structure that can be consumed by 'sorted'
|
||||
"""
|
||||
return [int(text) if text.isdigit() else text.lower()
|
||||
for text in re.split(numregex, nodename)]
|
||||
|
||||
|
||||
# TODO: pagination operators <pp.nums and >pp.nums for begin and end respective
|
||||
class NodeRange(object):
|
||||
@ -48,15 +59,27 @@ class NodeRange(object):
|
||||
self.beginpage = None
|
||||
self.endpage = None
|
||||
self.cfm = config
|
||||
elements = _parser.parseString("(" + noderange + ")").asList()[0]
|
||||
self._noderange = self._evaluate(elements)
|
||||
try:
|
||||
elements = _parser.parseString("(" + noderange + ")").asList()[0]
|
||||
except pp.ParseException as pe:
|
||||
raise Exception("Invalid syntax")
|
||||
if noderange[0] in ('<', '>'):
|
||||
# pagination across all nodes
|
||||
self._evaluate(elements)
|
||||
self._noderange = set(self.cfm.list_nodes())
|
||||
else:
|
||||
self._noderange = self._evaluate(elements)
|
||||
|
||||
@property
|
||||
def nodes(self):
|
||||
if self.beginpage is None and self.endpage is None:
|
||||
return self._noderange
|
||||
sortedlist = list(self._noderange)
|
||||
sortedlist.sort()
|
||||
try:
|
||||
sortedlist.sort(key=humanify_nodename)
|
||||
except TypeError:
|
||||
# The natural sort attempt failed, fallback to ascii sort
|
||||
sortedlist.sort()
|
||||
if self.beginpage is not None:
|
||||
sortedlist = sortedlist[self.beginpage:]
|
||||
if self.endpage is not None:
|
||||
@ -135,8 +158,6 @@ class NodeRange(object):
|
||||
def expand_entity(self, entname):
|
||||
if self.cfm is None or self.cfm.is_node(entname):
|
||||
return set([entname])
|
||||
if self.cfm.is_node(entname):
|
||||
return set([entname])
|
||||
if self.cfm.is_nodegroup(entname):
|
||||
grpcfg = self.cfm.get_nodegroup_attributes(entname)
|
||||
nodes = grpcfg['nodes']
|
||||
@ -144,6 +165,7 @@ class NodeRange(object):
|
||||
nodes |= NodeRange(
|
||||
grpcfg['noderange']['value'], self.cfm).nodes
|
||||
return nodes
|
||||
raise Exception('Unknown node ' + entname)
|
||||
|
||||
def _expandstring(self, element, filternodes=None):
|
||||
prefix = ''
|
||||
|
@ -214,9 +214,9 @@ def process_request(connection, request, cfm, authdata, authname, skipauth):
|
||||
configmanager.ConfigManager.shutdown()
|
||||
else:
|
||||
hdlr = pluginapi.handle_path(path, operation, cfm, params)
|
||||
except exc.NotFoundException:
|
||||
except exc.NotFoundException as e:
|
||||
tlvdata.send(connection, {"errorcode": 404,
|
||||
"error": "Target not found"})
|
||||
"error": "Target not found - " + str(e)})
|
||||
tlvdata.send(connection, {"_requestdone": 1})
|
||||
except exc.InvalidArgumentException as e:
|
||||
tlvdata.send(connection, {"errorcode": 400,
|
||||
|
Loading…
x
Reference in New Issue
Block a user