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)