diff --git a/confluent/config/attributes.py b/confluent/config/attributes.py index 72abc999..37c27c43 100644 --- a/confluent/config/attributes.py +++ b/confluent/config/attributes.py @@ -54,7 +54,7 @@ node = { 'groups': { 'type': (list, tuple), 'default': 'all', - 'description': ('List of static groups for which this node is' + 'description': ('List of static groups for which this node is ' 'considered a member'), }, #'type': { @@ -128,8 +128,8 @@ node = { # 'serial console configuration') # }, 'console.method': { - 'description': ('Indicate the method used to access the console of' - 'The managed node.') + 'description': ('Indicate the method used to access the console of ' + 'the managed node.') }, # 'virtualization.host': { # 'description': ('Hypervisor where this node does/should reside'), diff --git a/confluent/config/configmanager.py b/confluent/config/configmanager.py index c09c7f6c..f7fe8756 100644 --- a/confluent/config/configmanager.py +++ b/confluent/config/configmanager.py @@ -54,6 +54,7 @@ from Crypto.Hash import SHA256 import array import ast import collections +import confluent.config.attributes as attributes import confluent.util import copy import cPickle @@ -236,9 +237,9 @@ class _ExpressionFormat(string.Formatter): ast.BitOr: operator.or_, } - def __init__(self, nodeobj): + def __init__(self, nodeobj, nodename): self._nodeobj = nodeobj - self._numbers = re.findall(self.nummatch, nodeobj['name']['value']) + self._nodename = nodename def get_field(self, field_name, args, kwargs): parsed = ast.parse(field_name) @@ -246,10 +247,6 @@ class _ExpressionFormat(string.Formatter): def _handle_ast_node(self, node): if isinstance(node, ast.Num): - if '_expressionkeys' not in self._nodeobj: - self._nodeobj['_expressionkeys'] = set(['name']) - else: - self._nodeobj['_expressionkeys'].add('name') return node.n elif isinstance(node, ast.Attribute): #ok, we have something with a dot @@ -266,10 +263,12 @@ class _ExpressionFormat(string.Formatter): elif isinstance(node, ast.Name): var = node.id if var == 'nodename': - return self._nodeobj['name']['value'] + return self._nodename mg = re.match(self.posmatch, var) if mg: idx = int(mg.group(1)) + if self._numbers == None: + self._numbers = re.findall(self.nummatch, self._nodename) return int(self._numbers[idx - 1]) else: if var in self._nodeobj: @@ -471,6 +470,7 @@ class ConfigManager(object): # if the attribute is not set, this will search for a candidate # if it is set, but inheritedfrom, search for a replacement, just # in case + print repr(nodecfg['groups']) for group in nodecfg['groups']: if attrib in self._cfgstore['groups'][group]: if srcgroup is not None and group != srcgroup: @@ -498,8 +498,7 @@ class ConfigManager(object): elif group not in self._cfgstore['grouplist']: self._cfgstore['grouplist'].append(group) if group not in self._cfgstore['groups']: - self._cfgstore['groups'][group] = {'name': {'value': group}, - 'nodes': set([node]) } + self._cfgstore['groups'][group] = {'nodes': set([node])} elif 'nodes' not in self._cfgstore['groups'][group]: self._cfgstore['groups'][group]['nodes'] = set([node]) elif node not in self._cfgstore['groups'][group]['nodes']: @@ -519,8 +518,7 @@ class ConfigManager(object): self._node_removed_from_group(node, group) for node in nodes: if node not in self._cfgstore['nodes']: - self._cfgstore['nodes'][node] = {'name': {'value': node}, - 'groups': [group] } + self._cfgstore['nodes'][node] = {'groups': [group]} elif 'groups' not in self._cfgstore['nodes'][node]: self._cfgstore['nodes'][node]['groups'] = [group] elif group not in self._cfgstore['nodes'][node]['groups']: @@ -534,7 +532,7 @@ class ConfigManager(object): self._cfgstore['groups'] = {} for group in attribmap.iterkeys(): if group not in self._cfgstore['groups']: - self._cfgstore['groups'][group] = {'name': {'value': group}, 'nodes': set([])} + self._cfgstore['groups'][group] = {'nodes': set([])} cfgobj = self._cfgstore['groups'][group] for attr in attribmap[group].iterkeys(): newdict = {} @@ -571,11 +569,14 @@ class ConfigManager(object): # flows to peers, all should have the same result for node in attribmap.iterkeys(): if node not in self._cfgstore['nodes']: - self._cfgstore['nodes'][node] = {'name': {'value': node}} + self._cfgstore['nodes'][node] = {} cfgobj = self._cfgstore['nodes'][node] - exprmgr = _ExpressionFormat(cfgobj) recalcexpressions = False for attrname in attribmap[node].iterkeys(): + if (attrname not in attributes.node or + ('type' in attributes.node[attrname] and + type(attribmap[node][attrname]) not in attributes.node[attrname])): + raise ValueError newdict = {} if (isinstance(attribmap[node][attrname], str)): newdict = {'value': attribmap[node][attrname] } @@ -592,10 +593,13 @@ class ConfigManager(object): attrname in cfgobj['_expressionkeys']): recalcexpressions = True if 'expression' in cfgobj[attrname]: # evaluate now + if exprmgr is None: + exprmgr = _ExpressionFormat(cfgobj, node) cfgobj[attrname] = _decode_attribute(attrname, cfgobj, formatter=exprmgr) if recalcexpressions: - exprmgr = _ExpressionFormat(cfgobj) + if exprmgr is None: + exprmgr = _ExpressionFormat(cfgobj, node) self._recalculate_expressions(cfgobj, formatter=exprmgr) self._bg_sync_to_file() #TODO: wait for synchronization to suceed/fail??) diff --git a/confluent/messages.py b/confluent/messages.py index 7160fb08..44cb5969 100644 --- a/confluent/messages.py +++ b/confluent/messages.py @@ -35,10 +35,6 @@ class ConfluentMessage(object): val = self.kvpairs[key] value = self.defaultvalue type = self.defaulttype - try: - desc = self.desc - except: - desc = '' if 'value' in val: value = val['value'] if value is None: @@ -52,17 +48,17 @@ class ConfluentMessage(object): for v in val: snippet += ('' - ).format(type, key, v, desc) + ).format(type, key, v, self.desc) snippet += ( '' '').format(type, key, desc) + 'value="{1}">').format(type, key, self.desc) return snippet snippet += (key + ":" + '' - ).format(type, key, value, desc) + ).format(type, key, value, self.desc) return snippet @@ -264,7 +260,7 @@ class PowerState(ConfluentChoiceMessage): class Attributes(ConfluentMessage): - def __init__(self, node=None, kv=None, desc=None): + def __init__(self, node=None, kv=None, desc=''): self.desc = desc nkv = {} for key in kv.iterkeys(): @@ -278,7 +274,8 @@ class Attributes(ConfluentMessage): class ListAttributes(ConfluentMessage): - def __init__(self, node, kv): + def __init__(self, node, kv, desc=''): + self.desc = desc self .kvpairs = { node: kv } @@ -287,15 +284,17 @@ class ListAttributes(ConfluentMessage): class CryptedAttributes(Attributes): defaulttype = 'password' - def __init__(self, node=None, kv=None, desc=None): + def __init__(self, node=None, kv=None, desc=''): # for now, just keep the dictionary keys and discard crypt value self.desc = desc nkv = {} for key in kv.iterkeys(): - if kv[key]['cryptvalue'] != '': - nkv[key] = {'isset': True} - else: - nkv[key] = {'isset': False} + nkv[key] = {'isset': False} + try: + if kv[key] is not None and kv[key]['cryptvalue'] != '': + nkv[key] = {'isset': True} + except KeyError: + pass if node is None: self.kvpairs = nkv else: diff --git a/plugins/configuration/attributes.py b/plugins/configuration/attributes.py index 59503a5b..1cf81b9a 100644 --- a/plugins/configuration/attributes.py +++ b/plugins/configuration/attributes.py @@ -1,3 +1,4 @@ +import confluent.exceptions as exc import confluent.messages as msg import confluent.config.attributes as allattributes @@ -11,29 +12,35 @@ def retrieve(nodes, element, configmanager, inputdata): elif attribute == 'groups': # no setting, provide a blank val = [] else: # no setting, provide a blank - val = {'value': '', 'cryptvalue': ''} + val = {'value': None} if attribute.startswith('secret.'): yield msg.CryptedAttributes(node, - {attribute: val}) + {attribute: val}, + allattributes.node[attribute]['description']) elif isinstance(val, list): yield msg.ListAttributes(node, - {attribute: val}) + {attribute: val}, + allattributes.node[attribute]['description']) else: yield msg.Attributes(node, - {attribute: val['value']}) + {attribute: val['value']}, + allattributes.node[attribute]['description']) elif element[-1] == 'current': for node in attributes.iterkeys(): for attribute in sorted(attributes[node].iterkeys()): currattr = attributes[node][attribute] if 'value' in currattr: yield msg.Attributes(node, - {attribute: currattr['value']}) + {attribute: currattr['value']}, + allattributes.node[attribute]['description']) elif 'cryptvalue' in currattr: yield msg.CryptedAttributes(node, - {attribute: currattr}) + {attribute: currattr}, + allattributes.node[attribute]['description']) elif isinstance(currattr, list): yield msg.ListAttributes(node, - {attribute: currattr}) + {attribute: currattr}, + allattributes.node[attribute]['description']) else: print repr(currattr) raise Exception("BUGGY ATTRIBUTE FOR NODE") @@ -45,5 +52,8 @@ def update(nodes, element, configmanager, inputdata): updatenode = inputdata.get_attributes(node) if updatenode: updatedict[node] = updatenode - configmanager.set_node_attributes(updatedict) + try: + configmanager.set_node_attributes(updatedict) + except ValueError: + raise exc.InvalidArgumentException() return retrieve(nodes, element, configmanager, inputdata)