summaryrefslogtreecommitdiffstats
path: root/nova/api
diff options
context:
space:
mode:
authorDan Prince <dan.prince@rackspace.com>2011-03-14 16:58:03 -0400
committerDan Prince <dan.prince@rackspace.com>2011-03-14 16:58:03 -0400
commit229c5bc3324d5df39ca959d71a540a806bc5ad3e (patch)
tree715d2a03aa51b114b354cf688597c2c592a2f6b6 /nova/api
parent2bfa7b29c7882da559041cea771b9243555828fa (diff)
Implement action extensions.
Diffstat (limited to 'nova/api')
-rw-r--r--nova/api/openstack/__init__.py1
-rw-r--r--nova/api/openstack/extensions.py106
2 files changed, 106 insertions, 1 deletions
diff --git a/nova/api/openstack/__init__.py b/nova/api/openstack/__init__.py
index 9b7b76a91..8a458eea1 100644
--- a/nova/api/openstack/__init__.py
+++ b/nova/api/openstack/__init__.py
@@ -124,7 +124,6 @@ class APIRouter(wsgi.Router):
if ext_mgr is None:
ext_mgr = extensions.ExtensionManager(FLAGS.osapi_extensions_path)
for resource in ext_mgr.get_resources():
- print resource
resource.add_routes(mapper)
super(APIRouter, self).__init__(mapper)
diff --git a/nova/api/openstack/extensions.py b/nova/api/openstack/extensions.py
index 13789863b..e41de3120 100644
--- a/nova/api/openstack/extensions.py
+++ b/nova/api/openstack/extensions.py
@@ -18,11 +18,101 @@
import imp
import os
import sys
+import routes
+import webob.dec
+import webob.exc
+
+from nova import flags
+from nova import log as logging
+from nova import wsgi
+
+
+LOG = logging.getLogger('extensions')
+
+
+FLAGS = flags.FLAGS
+
+
+class ExtensionActionController(wsgi.Controller):
+
+ def __init__(self, application, action_name, handler):
+
+ self.application = application
+ self.action_name = action_name
+ self.handler = handler
+
+ def action(self, req, id):
+
+ input_dict = self._deserialize(req.body, req.get_content_type())
+ if self.action_name in input_dict:
+ return self.handler(input_dict, req, id)
+ # no action handler found (bump to downstream application)
+ res = self.application
+ return res
+
+
+class ExtensionMiddleware(wsgi.Middleware):
+ """
+ Extensions middleware that intercepts configured routes for extensions.
+ """
+ @classmethod
+ def factory(cls, global_config, **local_config):
+ """ paste factory """
+ def _factory(app):
+ return cls(app, **local_config)
+ return _factory
+
+ def __init__(self, application, ext_mgr=None):
+ mapper = routes.Mapper()
+
+ if ext_mgr is None:
+ ext_mgr = ExtensionManager(FLAGS.osapi_extensions_path)
+
+ # create custom mapper connections for extended actions
+ for action in ext_mgr.get_actions():
+ controller = ExtensionActionController(application, action.name,
+ action.handler)
+ mapper.connect("/%s/{id}/action.:(format)" % action.collection,
+ action='action',
+ controller=controller,
+ conditions=dict(method=['POST']))
+ mapper.connect("/%s/{id}/action" % action.collection,
+ action='action',
+ controller=controller,
+ conditions=dict(method=['POST']))
+
+ self._router = routes.middleware.RoutesMiddleware(self._dispatch,
+ mapper)
+
+ super(ExtensionMiddleware, self).__init__(application)
+
+ @webob.dec.wsgify(RequestClass=wsgi.Request)
+ def __call__(self, req):
+ """
+ Route the incoming request with router.
+ """
+ req.environ['extended.app'] = self.application
+ return self._router
+
+ @staticmethod
+ @webob.dec.wsgify(RequestClass=wsgi.Request)
+ def _dispatch(req):
+ """
+ Called by self._router after matching the incoming request to a route
+ and putting the information into req.environ. Either returns the
+ routed WSGI app's response or defers to the extended application.
+ """
+ match = req.environ['wsgiorg.routing_args'][1]
+ if not match:
+ return req.environ['extended.app']
+ app = match['controller']
+ return app
class ExtensionManager(object):
def __init__(self, path):
+ LOG.audit(_('Initializing extension manager.'))
self.path = path
self.extensions = []
@@ -37,6 +127,12 @@ class ExtensionManager(object):
resources.append(ext.get_resources())
return resources
+ def get_actions(self):
+ actions = []
+ for ext in self.extensions:
+ actions.extend(ext.get_actions())
+ return actions
+
def _load_extensions(self):
"""
Load extensions from the configured path. The extension name is
@@ -48,6 +144,7 @@ class ExtensionManager(object):
return
for f in os.listdir(self.path):
+ LOG.audit(_('Loading extension file: %s'), f)
mod_name, file_ext = os.path.splitext(os.path.split(f)[-1])
ext_path = os.path.join(self.path, f)
if file_ext.lower() == '.py':
@@ -56,6 +153,15 @@ class ExtensionManager(object):
self.extensions.append(getattr(mod, ext_name)())
+class ExtensionAction(object):
+
+ def __init__(self, member, collection, name, handler):
+ self.member = member
+ self.collection = collection
+ self.name = name
+ self.handler = handler
+
+
class ExtensionResource(object):
"""
Example ExtensionResource object. All ExtensionResource objects should