2
0
mirror of https://github.com/xcat2/confluent.git synced 2025-06-16 03:10:37 +00:00

Have configmanager protect against unrecognized data.

When doing a set, check the keynames and value types as
appropriate.  raise ValueError in the configmanager case
since it could be code or human mistake.  attributes plugin
then catches this error and propogates it up as an InvalidArgumentException
if it is just trying to pass in data from user.
This commit is contained in:
Jarrod Johnson
2014-02-13 12:58:03 -05:00
parent 8ede431b60
commit c77eb5be3b
4 changed files with 53 additions and 40 deletions

View File

@ -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'),

View File

@ -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??)

View File

@ -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 += ('<input type="{0}" name="{1}" value="{2}" '
' "title="{3}">'
).format(type, key, v, desc)
).format(type, key, v, self.desc)
snippet += (
'<input type="{0}" name="{1}" value="" title="{2}">'
'<input type="checkbox" name="restexplorerhonorkey" '
'value="{1}">').format(type, key, desc)
'value="{1}">').format(type, key, self.desc)
return snippet
snippet += (key + ":" +
'<input type="{0}" name="{1}" value="{2}" '
'title="{3}"><input type="checkbox" '
'name="restexplorerhonorkey" value="{1}">'
).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:

View File

@ -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)