]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
Fix hooks for dealing with member actions
authorSalvatore Orlando <salv.orlando@gmail.com>
Fri, 31 Jul 2015 22:17:11 +0000 (15:17 -0700)
committerKevin Benton <blak111@gmail.com>
Mon, 31 Aug 2015 17:17:15 +0000 (10:17 -0700)
This patch ensures that operations like add_router_interface
are correctly dispatched to the plugin.
It does so by introducing fairly ugly hacks in the
resource_identifier, and attribute_population pecan hooks.

This is however the best possible solution wiht the current
infrastructure which basically relies on hooks for request
dispatching.

Change-Id: I34880d1ce796cfd6f81d16fc1b9fd8387b5db056

neutron/newapi/controllers/root.py
neutron/newapi/hooks/attribute_population.py
neutron/newapi/hooks/resource_identifier.py

index 3426d9c38db3990d813342f671031f39ba7cc1aa..1e2fb553d88bd1175a2971aac17cb9044fbd15f6 100644 (file)
@@ -131,6 +131,11 @@ class ItemController(object):
 
     @when(index, method='PUT')
     def put(self, *args, **kwargs):
+        if request.member_action:
+            member_action_method = getattr(request.plugin,
+                                           request.member_action)
+            return member_action_method(request.context, self.item,
+                                        request.prepared_data)
         # TODO(kevinbenton): bulk?
         updater = getattr(request.plugin, 'update_%s' % request.resource_type)
         return updater(request.context, self.item, request.prepared_data)
index 938e40b4a164d839df529126072f126717617bd5..cb95cbce783921f5e134bf6d91dc09d6899f106e 100644 (file)
@@ -32,12 +32,20 @@ class AttributePopulationHook(hooks.PecanHook):
         resource = state.request.resource_type
         if not resource:
             return
-        state.request.prepared_data = v2base.Controller.prepare_request_body(
-            state.request.context, state.request.json, is_create, resource,
-            _attributes_for_resource(resource))
+        if state.request.member_action:
+            # Neutron currently does not describe request bodies for member
+            # actions in meh. prepare_request_body should not be called for
+            # member actions, and the body should be passed as it is. The
+            # plugin will do the validation (yuck).
+            state.request.prepared_data = state.request.json
+        else:
+            state.request.prepared_data = (
+                v2base.Controller.prepare_request_body(
+                    state.request.context, state.request.json, is_create,
+                    resource, _attributes_for_resource(resource)))
         state.request.resources = _extract_resources_from_state(state)
         # make the original object available:
-        if not is_create:
+        if not is_create and not state.request.member_action:
             obj_id = _pull_id_from_request(state.request)
             attrs = _attributes_for_resource(resource)
             field_list = [name for (name, value) in attrs.items()
index 91000f4f0dda80b701524e76eba86d1b14eb0e80..889e20a17ad86f87e72bc2905f5a1d1b49f3dd4a 100644 (file)
@@ -30,19 +30,54 @@ class ResourceIdentifierHook(hooks.PecanHook):
     def before(self, state):
         # TODO(kevinbenton): find a better way to look this up. maybe something
         # in the pecan internals somewhere?
+        # TODO(salv-orlando): try and leverage _lookup to this aim. Also remove
+        # the "special" code path for "actions"
         state.request.resource_type = None
         try:
-            url_type = state.request.path.split('/')[2].rsplit('.', 1)[0]
+            # TODO(blogan): remove this dirty hack and do a better solution
+            # needs to work with /v2.0, /v2.0/ports, and /v2.0/ports.json
+            uri = state.request.path
+            if not uri.endswith('.json'):
+                uri += '.json'
+            # Remove the format suffix if any
+            uri = uri.rsplit('.', 1)[0].split('/')[2:]
+            if not uri:
+                # there's nothing to process in the URI
+                return
         except IndexError:
             return
-        if url_type == 'extensions':
+        resource_type = uri[0]
+        if resource_type == 'extensions':
             return
         for plural, single in attributes.PLURALS.items():
-            if plural == url_type:
+            if plural == resource_type:
                 state.request.resource_type = single
                 state.request.plugin = self._plugin_for_resource(single)
+                state.request.member_action = self._parse_action(
+                    single, plural, uri[1:])
                 return
-        abort(404, detail='Resource: %s' % url_type)
+        abort(404, detail='Resource: %s' % resource_type)
+
+    def _parse_action(self, resource, collection, remainder):
+        # NOTE(salv-orlando): This check is revolting and makes me
+        # puke, but avoids silly failures when dealing with API actions
+        # such as "add_router_interface".
+        if len(remainder) > 1:
+            action = remainder[1]
+        else:
+            return
+        ext_mgr = extensions.PluginAwareExtensionManager.get_instance()
+        resource_exts = ext_mgr.get_resources()
+        for ext in resource_exts:
+            if (ext.collection == collection and
+                action in ext.member_actions):
+                return action
+        # Action or resource extension not found
+        if action:
+            abort(404, detail="Action %(action)s for resource "
+                              "%(resource)s undefined" %
+                              {'action': action,
+                               'resource': resource})
 
     def _plugin_for_resource(self, resource):
         # NOTE(kevinbenton): memoizing the responses to this had no useful