diff --git a/confluent/httpapi.py b/confluent/httpapi.py index 4d64a093..cdfd8364 100644 --- a/confluent/httpapi.py +++ b/confluent/httpapi.py @@ -257,6 +257,9 @@ def _assemble_html(responses, resource, querydict): yield '' yield '' yield '%s
' % (resource, resource) + print 'got a %s' % resource + if resource in ('/', './'): + pass if resource[-1] == '/': yield '../
' else: diff --git a/confluent/messages.py b/confluent/messages.py index 0bce04dc..a93407ff 100644 --- a/confluent/messages.py +++ b/confluent/messages.py @@ -76,9 +76,9 @@ class ChildCollection(LinkRelation): self.href = collname def get_input_message(path, operation, inputdata, nodes=None): - if 'power/state' in path and operation != 'retrieve': + if path[0] == 'power' and path[1] == 'state' and operation != 'retrieve': return InputPowerMessage(path, nodes, inputdata) - elif path.startswith('attributes/') and operation != 'retrieve': + elif path[0] == 'attributes' and operation != 'retrieve': return InputAttributes(path, nodes, inputdata) elif inputdata: raise exc.InvalidArgumentException() diff --git a/confluent/pluginapi.py b/confluent/pluginapi.py index 288424be..b653218f 100644 --- a/confluent/pluginapi.py +++ b/confluent/pluginapi.py @@ -25,6 +25,8 @@ import sys pluginmap = {} +def nested_lookup(nestdict, key): + return reduce(dict.__getitem__, key, nestdict) def load_plugins(): # To know our plugins directory, we get the parent path of 'bin' @@ -62,7 +64,40 @@ nodecollections = { rootcollections = { 'node/': nodecollections } -# _ elements are for internal use (e.g. special console scheme) + +class PluginRoute(object): + def __init__(self, routedict): + self.routeinfo = routedict +# _ prefix indicates internal use (e.g. special console scheme) and should not +# be enumerated in any collection +noderesources = { + '_console': { + 'session': PluginRoute({ + 'pluginattrs': ['console.method' ,'hardwaremanagement.method'], + }), + }, + 'console': { + #this is a dummy value, http or socket must handle special + 'session': PluginRoute({}), + }, + 'power': { + 'state': PluginRoute({ + 'pluginattrs': ['hardwaremanagement.method'], + 'default': 'ipmi', + }), + }, + 'boot': { + 'device': PluginRoute({ + 'pluginattrs': ['hardwaremanagement.method'], + 'default': 'ipmi', + }), + }, + 'attributes': { + 'all': PluginRoute({ 'handler': 'attributes' }), + 'current': PluginRoute({ 'handler': 'attributes' }), + }, +} + nodeelements = { '_console/session': { 'pluginattrs': ['console.method' ,'hardwaremanagement.method'], @@ -97,21 +132,21 @@ def iterate_collections(iterable): coll = coll + '/' yield msg.ChildCollection(coll) -def enumerate_collection(collection, configmanager): - if collection.startswith("/"): - collection = collection[1:] - if collection == 'node/': +def iterate_resources(fancydict): + for resource in fancydict.iterkeys(): + if resource.startswith("_"): + continue + if not isinstance(fancydict[resource], PluginRoute): # a resource + resource += '/' + yield msg.ChildCollection(resource) + +def enumerate_node_collection(collectionpath, configmanager): + print repr(collectionpath) + if collectionpath == [ 'node' ]: #it is simple '/node/', need a list of nodes return iterate_collections(configmanager.get_nodes()) - elif collection.startswith('node/'): - nodecoll = collection.replace('node/','') - print nodecoll - if '/' not in nodecoll[:-1]: # it is supposed to be a node - node = nodecoll[:-1] - if not configmanager.is_node(node): - raise exc.NotFoundException("Invalid node requested") - return iterate_collections(nodecollections.iterkeys()) - else: - raise exc.NotFoundException("Invalid path") + del collectionpath[0:2] + collection = nested_lookup(noderesources, collectionpath) + return iterate_resources(collection) def enumerate_collections(collections): @@ -125,23 +160,36 @@ def handle_path(path, operation, configmanager, inputdata=None): An exception is made for console/session, which should return a class with connect(), read(), write(bytes), and close() ''' - if path == '/': + iscollection = False + pathcomponents = path.split('/') + del pathcomponents[0] # discard the value from leading / + print repr(pathcomponents) + if pathcomponents[-1] == '': + iscollection = True + del pathcomponents[-1] + if not pathcomponents: #root collection list return enumerate_collections(rootcollections) - elif path[-1] == '/': - return enumerate_collection(path, configmanager) - elif (path.startswith("/node/") or path.startswith("/system/") or - # single node requests - path.startswith("/vm/")): - nodeidx = path.find("/",1) + 1 - node = path[nodeidx:] - node, _, element = node.partition("/") - if element not in nodeelements: + elif pathcomponents[0] in ('node', 'system', 'vm'): + #single node request of some sort + try: + node = pathcomponents[1] + except IndexError: # doesn't actually have a long enough path + return iterate_collections(configmanager.get_nodes()) + if iscollection: + print "oh hi there..." + print repr(pathcomponents[2:]) + return enumerate_node_collection(pathcomponents, configmanager) + print repr(pathcomponents) + del pathcomponents[0:2] + print repr(pathcomponents) + try: + plugroute = nested_lookup(noderesources, pathcomponents).routeinfo + except KeyError: raise exc.NotFoundException("Invalid element requested") - inputdata = msg.get_input_message(element, operation, inputdata, (node,)) - plugroute = nodeelements[element] + inputdata = msg.get_input_message(pathcomponents, operation, inputdata, (node,)) if 'handler' in plugroute: #fixed handler definition passvalue = pluginmap[plugroute['handler']].__dict__[operation]( - nodes=(node,), element=element, + nodes=(node,), element=pathcomponents, configmanager=configmanager, inputdata=inputdata) elif 'pluginattrs' in plugroute: @@ -150,12 +198,12 @@ def handle_path(path, operation, configmanager, inputdata=None): for attrname in plugroute['pluginattrs']: if attrname in nodeattr[node]: passvalue = pluginmap[nodeattr[node][attrname]['value']].__dict__[operation]( - nodes=(node,), element=element, + nodes=(node,), element=pathcomponents, configmanager=configmanager, inputdata=inputdata) if 'default' in plugroute: passvalue = pluginmap[plugroute['default']].__dict__[operation]( - nodes=(node,), element=element, configmanager=configmanager, + nodes=(node,), element=pathcomponents, configmanager=configmanager, inputdata=inputdata) if isinstance(passvalue, console.Console): return passvalue diff --git a/plugins/configuration/attributes.py b/plugins/configuration/attributes.py index 05ba5eb3..78fd93db 100644 --- a/plugins/configuration/attributes.py +++ b/plugins/configuration/attributes.py @@ -3,7 +3,7 @@ import confluent.config.attributes as allattributes def retrieve(nodes, element, configmanager, inputdata): attributes = configmanager.get_node_attributes(nodes) - if element.endswith('/all'): + if element[-1] == 'all': for node in nodes: for attribute in sorted(allattributes.node.iterkeys()): if attribute in attributes[node]: #have a setting for it @@ -16,7 +16,7 @@ def retrieve(nodes, element, configmanager, inputdata): else: yield msg.Attributes(node, {attribute: val['value']}) - elif element.endswith('/current'): + elif element[-1] == 'current': for node in attributes.iterkeys(): for attribute in sorted(attributes[node].iterkeys()): currattr = attributes[node][attribute] diff --git a/plugins/hardwaremanagement/ipmi.py b/plugins/hardwaremanagement/ipmi.py index 98473e37..48dc523e 100644 --- a/plugins/hardwaremanagement/ipmi.py +++ b/plugins/hardwaremanagement/ipmi.py @@ -251,7 +251,7 @@ class IpmiHandler(object): def handle_request(self): while not self.loggedin: wait_on_ipmi() - if self.element == 'power/state': + if self.element == [ 'power', 'state' ]: if 'read' == self.op: power = self.call_ipmicmd(self.ipmicmd.get_power) return msg.PowerState(node=self.node, @@ -266,7 +266,7 @@ class IpmiHandler(object): def create(nodes, element, configmanager, inputdata): - if element == '_console/session': + if element == [ '_console', 'session' ]: if len(nodes) > 1: raise Exception("_console/session does not support multiple nodes") return IpmiConsole(nodes[0], configmanager)