diff options
| author | Cole Robinson <crobinso@redhat.com> | 2012-01-23 11:29:24 -0500 |
|---|---|---|
| committer | Cole Robinson <crobinso@redhat.com> | 2012-01-24 13:30:23 -0500 |
| commit | fefb88877c6d6f00626df747eb0172484c16f0ec (patch) | |
| tree | ce132ed4c2f86517d8caccd907e4f01968ae124d | |
| parent | 3ad3292efd7fcba7b58bc9c8b1cb84e8b00a10fa (diff) | |
| download | nova-fefb88877c6d6f00626df747eb0172484c16f0ec.tar.gz nova-fefb88877c6d6f00626df747eb0172484c16f0ec.tar.xz nova-fefb88877c6d6f00626df747eb0172484c16f0ec.zip | |
extensions: Allow registering actions for create + delete
This allows an extension to add new actions for create and delete
operations to an existing collection.
Currently when extending an existing collection (API namespace), an
extension can register brand new 'actions', and extend any preexisting API
functionality, but unfortunately create and delete are special cases that
don't fall under the 'actions' classification, meaning the infrastructure
can't handle them unless extending an existing impl.
Stubbing out the create/delete methods in the original resource with
the equiv of a NotImplementedError doesn't work, since 'extend'ing
requires the original implementation to exit correctly.
Whitelist 'create' and 'delete' and handle them appropriately.
v2:
Add myself to Authors
Update wsgi.action docs
Add a test case
v3:
Actually update Authors
Change-Id: I550ae93c5e200f18644042ac81656bc76dbe8955
| -rw-r--r-- | Authors | 1 | ||||
| -rw-r--r-- | nova/api/openstack/wsgi.py | 15 | ||||
| -rw-r--r-- | nova/tests/api/openstack/test_wsgi.py | 29 |
3 files changed, 41 insertions, 4 deletions
@@ -30,6 +30,7 @@ Chris Behrens <cbehrens@codestud.com> Christian Berendt <berendt@b1-systems.de> Christopher MacGown <chris@pistoncloud.com> Chuck Short <zulcss@ubuntu.com> +Cole Robinson <crobinso@redhat.com> Cor Cornelisse <cor@hyves.nl> Cory Wright <corywright@gmail.com> Dan Prince <dan.prince@rackspace.com> diff --git a/nova/api/openstack/wsgi.py b/nova/api/openstack/wsgi.py index bcb64c98a..8a7a077b8 100644 --- a/nova/api/openstack/wsgi.py +++ b/nova/api/openstack/wsgi.py @@ -884,15 +884,19 @@ class Resource(wsgi.Application): else: meth = getattr(self.controller, action) except AttributeError as ex: - if action != 'action' or not self.wsgi_actions: + if (not self.wsgi_actions or + action not in ['action', 'create', 'delete']): # Propagate the error raise else: return meth, self.wsgi_extensions.get(action, []) - # OK, it's an action; figure out which action... - mtype = _MEDIA_TYPE_MAP.get(content_type) - action_name = self.action_peek[mtype](body) + if action == 'action': + # OK, it's an action; figure out which action... + mtype = _MEDIA_TYPE_MAP.get(content_type) + action_name = self.action_peek[mtype](body) + else: + action_name = action # Look up the action method return (self.wsgi_actions[action_name], @@ -908,6 +912,9 @@ def action(name): """Mark a function as an action. The given name will be taken as the action key in the body. + + This is also overloaded to allow extensions to provide + non-extending definitions of create and delete operations. """ def decorator(func): diff --git a/nova/tests/api/openstack/test_wsgi.py b/nova/tests/api/openstack/test_wsgi.py index 90d048443..3dfcb2388 100644 --- a/nova/tests/api/openstack/test_wsgi.py +++ b/nova/tests/api/openstack/test_wsgi.py @@ -516,6 +516,35 @@ class ResourceTest(test.TestCase): self.assertEqual(method, controller._action_foo) self.assertEqual(extensions, [extended._action_foo]) + def test_get_method_action_whitelist_extensions(self): + class Controller(wsgi.Controller): + def index(self, req, pants=None): + return pants + + class ControllerExtended(wsgi.Controller): + @wsgi.action('create') + def _create(self, req, body): + pass + + @wsgi.action('delete') + def _delete(self, req, id): + pass + + controller = Controller() + extended = ControllerExtended() + resource = wsgi.Resource(controller) + resource.register_actions(extended) + + method, extensions = resource.get_method(None, 'create', + 'application/json', + '{"create": true}') + self.assertEqual(method, extended._create) + self.assertEqual(extensions, []) + + method, extensions = resource.get_method(None, 'delete', None, None) + self.assertEqual(method, extended._delete) + self.assertEqual(extensions, []) + def test_pre_process_extensions_regular(self): class Controller(object): def index(self, req, pants=None): |
