diff --git a/confluent/config/configmanager.py b/confluent/config/configmanager.py index 2a780637..e1b3ff6e 100644 --- a/confluent/config/configmanager.py +++ b/confluent/config/configmanager.py @@ -404,6 +404,13 @@ class ConfigManager(object): return False return True + def is_nodegroup(self, nodegroup): + if 'groups' not in self._cfgstore: + return False + if nodegroup not in self._cfgstore['groups']: + return False + return True + def get_groups(self): if 'groups' not in self._cfgstore: return [] @@ -414,6 +421,9 @@ class ConfigManager(object): return [] return self._cfgstore['nodes'].iterkeys() + def get_nodegroup_attributes(self, nodegroup, attributes=[]): + return self._cfgstore['groups'][nodegroup] + def get_node_attributes(self, nodelist, attributes=[]): if 'nodes' not in self._cfgstore: return None @@ -470,7 +480,6 @@ 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: @@ -479,6 +488,7 @@ class ConfigManager(object): nodecfg[attrib] = \ copy.deepcopy(self._cfgstore['groups'][group][attrib]) nodecfg[attrib]['inheritedfrom'] = group + self._refresh_nodecfg(nodecfg, attrib) return if srcgroup is not None and group == srcgroup: # break out @@ -555,6 +565,20 @@ class ConfigManager(object): for node in cfgobj['nodes']: nodecfg = self._cfgstore['nodes'][node] self._do_inheritance(nodecfg, attr, group) + self._bg_sync_to_file() + + def _refresh_nodecfg(self, cfgobj, attrname): + exprmgr = None + if 'expression' in cfgobj[attrname]: # evaluate now + if exprmgr is None: + exprmgr = _ExpressionFormat(cfgobj, node) + cfgobj[attrname] = _decode_attribute(attrname, cfgobj, + formatter=exprmgr) + if ('_expressionkeys' in cfgobj and + attrname in cfgobj['_expressionkeys']): + if exprmgr is None: + exprmgr = _ExpressionFormat(cfgobj, node) + self._recalculate_expressions(cfgobj, formatter=exprmgr) def del_nodes(self, nodes): if 'nodes' not in self._cfgstore: diff --git a/confluent/messages.py b/confluent/messages.py index 7952f8ae..7d502786 100644 --- a/confluent/messages.py +++ b/confluent/messages.py @@ -150,6 +150,9 @@ class InputAttributes(ConfluentMessage): nestedmode = False if not inputdata: raise exc.InvalidArgumentException + if nodes is None: + self.attribs = inputdata + return for node in nodes: if node in inputdata: nestedmode = True @@ -283,7 +286,7 @@ class ListAttributes(ConfluentMessage): if node is None: self.kvpairs = kv else: - self .kvpairs = {node: kv} + self.kvpairs = {node: kv} class CryptedAttributes(Attributes): diff --git a/confluent/pluginapi.py b/confluent/pluginapi.py index 493503b6..92e2385b 100644 --- a/confluent/pluginapi.py +++ b/confluent/pluginapi.py @@ -91,6 +91,13 @@ noderesources = { }, } +nodegroupresources = { + 'attributes': { + 'all': PluginRoute({'handler': 'attributes'}), + 'current': PluginRoute({'handler': 'attributes'}), + }, +} + def stripnode(iterablersp, node): for i in iterablersp: @@ -131,6 +138,14 @@ def delete_node_collection(collectionpath, configmanager): raise Exception("Not implemented") +def enumerate_nodegroup_collection(collectionpath, configmanager): + nodegroup = collectionpath[1] + if not configmanager.is_nodegroup(nodegroup): + raise exc.NotFoundException("Invalid element requested") + del collectionpath[0:2] + collection = nested_lookup(nodegroupresources, collectionpath) + return iterate_resources(collection) + def enumerate_node_collection(collectionpath, configmanager): if collectionpath == ['node']: # it is just '/node/', need a list of nodes return iterate_collections(configmanager.get_nodes()) @@ -192,8 +207,21 @@ def handle_path(path, operation, configmanager, inputdata=None): if iscollection: if operation == "delete": return delete_nodegroup_collection(pathcomponents, configmanager) + elif operation == "retrieve": + return enumerate_nodegroup_collection(pathcomponents, configmanager) else: raise Exception("TODO") + try: + plugroute = nested_lookup(nodegroupresources, pathcomponents[2:]).routeinfo + except KeyError: + raise exc.NotFoundException("Invalid element requested") + inputdata = msg.get_input_message( + pathcomponents[2:], operation, inputdata) + if 'handler' in plugroute: # fixed handler definition + return pluginmap[plugroute['handler']].__dict__[operation]( + nodes=None, element=pathcomponents, + configmanager=configmanager, + inputdata=inputdata) elif pathcomponents[0] in ('node', 'system', 'vm'): #single node request of some sort try: diff --git a/plugins/configuration/attributes.py b/plugins/configuration/attributes.py index 1cf81b9a..46749bb2 100644 --- a/plugins/configuration/attributes.py +++ b/plugins/configuration/attributes.py @@ -3,6 +3,66 @@ import confluent.messages as msg import confluent.config.attributes as allattributes def retrieve(nodes, element, configmanager, inputdata): + if nodes is not None: + return retrieve_nodes(nodes, element, configmanager, inputdata) + elif element[0] == 'nodegroup': + return retrieve_nodegroup(element[1], element[3], configmanager, inputdata) + + +def retrieve_nodegroup(nodegroup, element, configmanager, inputdata): + grpcfg = configmanager.get_nodegroup_attributes(nodegroup) + if element == 'all': + nodes = [] + if 'nodes' in grpcfg: + nodes = list(grpcfg['nodes']) + yield msg.ListAttributes(kv={'nodes': nodes}, + desc="The nodes belonging to this group") + for attribute in sorted(allattributes.node.iterkeys()): + if attribute == 'groups': + continue + if attribute in grpcfg: + val = grpcfg[attribute]['value'] + else: + val = None + if attribute.startswith('secret.'): + yield msg.CryptedAttributes( + kv={attribute: None}, + desc=allattributes.node[attribute]['description']) + elif isinstance(val, list): + raise Exception("TODO") + else: + yield msg.Attributes( + kv={attribute: val}, + desc=allattributes.node[attribute]['description']) + if element == 'current': + for attribute in sorted(grpcfg.iterkeys()): + currattr = grpcfg[attribute] + desc="" + if attribute == 'nodes': + desc = 'The nodes belonging to this group' + else: + desc = allattributes.node[attribute]['description'] + if 'value' in currattr: + yield msg.Attributes( + kv={attribute: currattr['value']}, + desc=desc) + elif 'cryptvalue' in currattr: + yield msg.CryptedAttributes( + kv={attribute: currattr}, + desc=desc) + elif isinstance(currattr, set): + yield msg.ListAttributes( + kv={attribute: list(currattr)}, + desc=desc) + elif isinstance(currattr, list): + yield msg.ListAttributes( + kv={attribute: currattr}, + desc=desc) + else: + raise Exception("BUGGY ATTRIBUTE FOR NODE") + + +def retrieve_nodes(nodes, element, configmanager, inputdata): attributes = configmanager.get_node_attributes(nodes) if element[-1] == 'all': for node in nodes: @@ -42,11 +102,24 @@ def retrieve(nodes, element, configmanager, inputdata): {attribute: currattr}, allattributes.node[attribute]['description']) else: - print repr(currattr) raise Exception("BUGGY ATTRIBUTE FOR NODE") def update(nodes, element, configmanager, inputdata): + if nodes is not None: + return update_nodes(nodes, element, configmanager, inputdata) + elif element[0] == 'nodegroup': + return update_nodegroup(element[1], element[3], configmanager, inputdata) + raise Exception("This line should never be reached") + +def update_nodegroup(group, element, configmanager, inputdata): + try: + configmanager.set_group_attributes({group: inputdata.attribs}) + except ValueError: + raise exc.InvalidArgumentException() + return retrieve_nodegroup(group, element, configmanager, inputdata) + +def update_nodes(nodes, element, configmanager, inputdata): updatedict = {} for node in nodes: updatenode = inputdata.get_attributes(node)