mirror of
https://github.com/xcat2/confluent.git
synced 2025-01-18 05:33:17 +00:00
First part of hooking noderange into configuration
Make expansion of groups and rejection of unrecognized elements work. Additionally, implement dynamic groups. A group may have a 'noderange' attribute. In this case it is considered to have 'dynamic' members. This only has meaning in noderange expansion, not in deriving configuration data. This does not yet add the search by attribute value capabilities and still doesn't do the pagination or + operators.
This commit is contained in:
parent
7a346ed0d3
commit
0515acd054
@ -796,7 +796,7 @@ class ConfigManager(object):
|
||||
if not autocreate and group not in self._cfgstore['nodegroups']:
|
||||
raise ValueError("{0} group does not exist".format(group))
|
||||
for attr in attribmap[group].iterkeys():
|
||||
if (attr != 'nodes' and
|
||||
if (attr not in ('nodes', 'noderange') and
|
||||
(attr not in allattributes.node or
|
||||
('type' in allattributes.node[attr] and
|
||||
not isinstance(attribmap[group][attr],
|
||||
@ -819,6 +819,8 @@ class ConfigManager(object):
|
||||
for attr in attribmap[group].iterkeys():
|
||||
if attr == 'nodes':
|
||||
newdict = set(attribmap[group][attr])
|
||||
elif attr == 'noderange':
|
||||
newdict = attribmap[group][attr]
|
||||
elif (isinstance(attribmap[group][attr], str) or
|
||||
isinstance(attribmap[group][attr], unicode)):
|
||||
newdict = {'value': attribmap[group][attr]}
|
||||
@ -832,7 +834,7 @@ class ConfigManager(object):
|
||||
self._sync_nodes_to_group(group=group,
|
||||
nodes=attribmap[group]['nodes'],
|
||||
changeset=changeset)
|
||||
else: # update inheritence
|
||||
elif attr != 'noderange': # update inheritence
|
||||
for node in cfgobj['nodes']:
|
||||
nodecfg = self._cfgstore['nodes'][node]
|
||||
self._do_inheritance(nodecfg, attr, node, changeset,
|
||||
|
@ -1,6 +1,7 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2014 IBM Corporation
|
||||
# Copyright 2015 Lenovo
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
@ -21,7 +22,6 @@
|
||||
|
||||
import itertools
|
||||
import pyparsing as pp
|
||||
import re
|
||||
|
||||
# construct custom grammar with pyparsing
|
||||
_nodeword = pp.Word(pp.alphanums + '/=-:.*+')
|
||||
@ -33,16 +33,17 @@ _parser = pp.nestedExpr(content=_grammar)
|
||||
|
||||
_numextractor = pp.OneOrMore(pp.Word(pp.alphas + '-') | pp.Word(pp.nums))
|
||||
|
||||
#TODO: pagination operators <pp.nums and >pp.nums for begin and end respective
|
||||
|
||||
# TODO: pagination operators <pp.nums and >pp.nums for begin and end respective
|
||||
class NodeRange(object):
|
||||
"""Iterate over a noderange
|
||||
|
||||
:param noderange: string representing a noderange to evaluate
|
||||
:param verify: whether or not to perform lookups in the config
|
||||
:param config: Config manager object to use to vet elements
|
||||
"""
|
||||
|
||||
def __init__(self, noderange, verify=True):
|
||||
self.verify = verify
|
||||
def __init__(self, noderange, config=None):
|
||||
self.cfm = config
|
||||
elements = _parser.parseString("(" + noderange + ")").asList()[0]
|
||||
self._noderange = self._evaluate(elements)
|
||||
|
||||
@ -71,21 +72,21 @@ class NodeRange(object):
|
||||
return current_range
|
||||
|
||||
def failorreturn(self, atom):
|
||||
if self.verify:
|
||||
if self.cfm is not None:
|
||||
raise Exception(atom + " not valid")
|
||||
return set([atom])
|
||||
|
||||
def expandrange(self, range, delimiter):
|
||||
pieces = range.split(delimiter)
|
||||
def expandrange(self, seqrange, delimiter):
|
||||
pieces = seqrange.split(delimiter)
|
||||
if len(pieces) % 2 != 0:
|
||||
return self.failorreturn(range)
|
||||
return self.failorreturn(seqrange)
|
||||
halflen = len(pieces) / 2
|
||||
left = delimiter.join(pieces[:halflen])
|
||||
right = delimiter.join(pieces[halflen:])
|
||||
leftbits = _numextractor.parseString(left).asList()
|
||||
rightbits = _numextractor.parseString(right).asList()
|
||||
if len(leftbits) != len(rightbits):
|
||||
return self.failorreturn(range)
|
||||
return self.failorreturn(seqrange)
|
||||
finalfmt = ''
|
||||
iterators = []
|
||||
for idx in xrange(len(leftbits)):
|
||||
@ -93,7 +94,7 @@ class NodeRange(object):
|
||||
finalfmt += leftbits[idx]
|
||||
elif leftbits[idx][0] in pp.alphas:
|
||||
# if string portion unequal, not going to work
|
||||
return self.failorreturn(range)
|
||||
return self.failorreturn(seqrange)
|
||||
else:
|
||||
curseq = []
|
||||
finalfmt += '{%d}' % len(iterators)
|
||||
@ -109,7 +110,7 @@ class NodeRange(object):
|
||||
minnum = leftnum
|
||||
maxnum = rightnum + 1
|
||||
else: # differently padded, but same number...
|
||||
return self.failorreturn(range)
|
||||
return self.failorreturn(seqrange)
|
||||
numformat = '{0:0%d}' % width
|
||||
for num in xrange(minnum, maxnum):
|
||||
curseq.append(numformat.format(num))
|
||||
@ -123,19 +124,23 @@ class NodeRange(object):
|
||||
for idx in xrange(len(element)):
|
||||
if element[idx][0] == '[':
|
||||
nodes = set([])
|
||||
for numeric in NodeRange(element[idx][1:-1], False).nodes:
|
||||
for numeric in NodeRange(element[idx][1:-1]).nodes:
|
||||
nodes |= self._expandstring(
|
||||
[prefix + numeric] + element[idx + 1:])
|
||||
[prefix + numeric] + element[idx + 1:])
|
||||
return nodes
|
||||
else:
|
||||
prefix += element[idx]
|
||||
element = prefix
|
||||
nodes = set([])
|
||||
if self.verify:
|
||||
#this is where we would check for exactly this
|
||||
raise Exception("TODO: link with actual config")
|
||||
#this is where we would check for a literal groupname
|
||||
#ok, now time to understand the various things
|
||||
if self.cfm is not None:
|
||||
# this is where we would check for exactly this
|
||||
if self.cfm.is_node(element):
|
||||
return set([element])
|
||||
if self.cfm.is_nodegroup(element):
|
||||
grpcfg = self.cfm.get_nodegroup_attributes(element)
|
||||
nodes = grpcfg['nodes']
|
||||
if 'noderange' in grpcfg and grpcfg['noderange']:
|
||||
nodes |= NodeRange(grpcfg['noderange'], self.cfm).nodes
|
||||
return nodes
|
||||
if '-' in element and ':' not in element:
|
||||
return self.expandrange(element, '-')
|
||||
elif ':' in element: # : range for less ambiguity
|
||||
@ -146,5 +151,6 @@ class NodeRange(object):
|
||||
raise Exception('TODO: regex noderange')
|
||||
elif '+' in element:
|
||||
raise Exception('TODO: plus range')
|
||||
if not self.verify:
|
||||
if self.cfm is None:
|
||||
return set([element])
|
||||
raise Exception(element + ' not a recognized node, group, or alias')
|
||||
|
Loading…
x
Reference in New Issue
Block a user