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)