]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
Introduce base interface for core resource extensions
authorIhar Hrachyshka <ihrachys@redhat.com>
Thu, 6 Aug 2015 14:59:53 +0000 (16:59 +0200)
committerIhar Hrachyshka <ihrachys@redhat.com>
Fri, 7 Aug 2015 19:36:15 +0000 (21:36 +0200)
The interface can be found in neutron.core_extensions.base.

Adopted the interface in qos core resource extension.

Alos moved qos_extension under neutron.core_extensions.qos. Partially,
this is to avoid confusion around the fact that the module does not
really contain a neutron API extension but core resource extension.

Change-Id: I6f6976aa49694f7ef17afa4e93bc769cd0069f65
Partially-Implements: blueprint quantum-qos-api

doc/source/devref/quality_of_service.rst
neutron/core_extensions/__init__.py [new file with mode: 0644]
neutron/core_extensions/base.py [new file with mode: 0644]
neutron/core_extensions/qos.py [moved from neutron/services/qos/qos_extension.py with 91% similarity]
neutron/plugins/ml2/extensions/qos.py
neutron/tests/api/test_qos.py
neutron/tests/unit/core_extensions/__init__.py [new file with mode: 0644]
neutron/tests/unit/core_extensions/test_qos.py [moved from neutron/tests/unit/services/qos/test_qos_extension.py with 67% similarity]

index 023eb42f6ea53bbc48a530ce50177352959789ab..5895122f799b4d65889493e58b85ba97b68352da 100644 (file)
@@ -35,19 +35,22 @@ Service side design
   MQ-based reference notification driver which updates agents via messaging
   bus, using `RPC callbacks <rpc_callbacks.html>`_.
 
-* neutron.services.qos.qos_extension:
-  Contains a class that can be used by external code to extend core
-  (network/port) resources with QoS details (at the moment, it's just
-  qos_policy_id). This class is designed in a way that should allow its
-  integration into different plugins. Alternatively, we may want to have a core
-  resource extension manager that would utilize it, among other extensions, and
-  that could be easily integrated into plugins.
+* neutron.core_extensions.base:
+  Contains an interface class to implement core resource (port/network)
+  extensions. Core resource extensions are then easily integrated into
+  interested plugins. We may need to  have a core resource extension manager
+  that would utilize those extensions, to avoid plugin modifications for every
+  new core resource extension.
+
+* neutron.core_extensions.qos:
+  Contains QoS core resource extension that conforms to the interface described
+  above.
 
 * neutron.plugins.ml2.extensions.qos:
   Contains ml2 extension driver that handles core resource updates by reusing
-  the qos_extension module mentioned above. In the future, we would like to see
-  a plugin-agnostic core resource extension manager that could be integrated
-  into other plugins with ease.
+  the core_extensions.qos module mentioned above. In the future, we would like
+  to see a plugin-agnostic core resource extension manager that could be
+  integrated into other plugins with ease.
 
 
 Supported QoS rule types
diff --git a/neutron/core_extensions/__init__.py b/neutron/core_extensions/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/neutron/core_extensions/base.py b/neutron/core_extensions/base.py
new file mode 100644 (file)
index 0000000..67cbf87
--- /dev/null
@@ -0,0 +1,48 @@
+# Copyright (c) 2015 Red Hat Inc.
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+import abc
+
+import six
+
+
+NETWORK = 'network'
+PORT = 'port'
+
+
+CORE_RESOURCES = [NETWORK, PORT]
+
+
+@six.add_metaclass(abc.ABCMeta)
+class CoreResourceExtension(object):
+
+    @abc.abstractmethod
+    def process_fields(self, context, resource_type,
+                       requested_resource, actual_resource):
+        """Process extension fields.
+
+        :param context: neutron api request context
+        :param resource_type: core resource type (one of CORE_RESOURCES)
+        :param requested_resource: resource dict that contains extension fields
+        :param actual_resource: actual resource dict known to plugin
+        """
+
+    @abc.abstractmethod
+    def extract_fields(self, resource_type, resource):
+        """Extract extension fields.
+
+        :param resource_type: core resource type (one of CORE_RESOURCES)
+        :param resource: resource dict that contains extension fields
+        """
similarity index 91%
rename from neutron/services/qos/qos_extension.py
rename to neutron/core_extensions/qos.py
index 77ae4220e06e5a062a8090b51aada0cc5766f129..76f5164e5caf06c50f46bc96baf14a1ec2c20d8b 100644 (file)
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+from neutron.core_extensions import base
 from neutron.db import api as db_api
 from neutron import manager
 from neutron.objects.qos import policy as policy_object
 from neutron.plugins.common import constants as plugin_constants
 from neutron.services.qos import qos_consts
 
-NETWORK = 'network'
-PORT = 'port'
 
-
-# TODO(QoS): Add interface to define how this should look like
-class QosResourceExtensionHandler(object):
+class QosCoreResourceExtension(base.CoreResourceExtension):
 
     @property
     def plugin_loaded(self):
@@ -70,15 +67,15 @@ class QosResourceExtensionHandler(object):
         with db_api.autonested_transaction(context.session):
             return getattr(self, method_name)(context=context, **kwargs)
 
-    def process_resource(self, context, resource_type, requested_resource,
-                         actual_resource):
+    def process_fields(self, context, resource_type,
+                       requested_resource, actual_resource):
         if (qos_consts.QOS_POLICY_ID in requested_resource and
             self.plugin_loaded):
             self._exec('_update_%s_policy' % resource_type, context,
                        {resource_type: actual_resource,
                         "%s_changes" % resource_type: requested_resource})
 
-    def extract_resource_fields(self, resource_type, resource):
+    def extract_fields(self, resource_type, resource):
         if not self.plugin_loaded:
             return {}
 
index a11b232c7abc6d74d287286827c654e078b14441..4de7cf653a7b805c2895f7a18f7f17d288d34987 100644 (file)
@@ -15,8 +15,9 @@
 
 from oslo_log import log as logging
 
+from neutron.core_extensions import base as base_core
+from neutron.core_extensions import qos as qos_core
 from neutron.plugins.ml2 import driver_api as api
-from neutron.services.qos import qos_extension
 
 LOG = logging.getLogger(__name__)
 
@@ -24,27 +25,26 @@ LOG = logging.getLogger(__name__)
 class QosExtensionDriver(api.ExtensionDriver):
 
     def initialize(self):
-        self.qos_ext_handler = qos_extension.QosResourceExtensionHandler()
+        self.core_ext_handler = qos_core.QosCoreResourceExtension()
         LOG.debug("QosExtensionDriver initialization complete")
 
     def process_create_network(self, context, data, result):
-        self.qos_ext_handler.process_resource(
-            context, qos_extension.NETWORK, data, result)
+        self.core_ext_handler.process_fields(
+            context, base_core.NETWORK, data, result)
 
     process_update_network = process_create_network
 
     def process_create_port(self, context, data, result):
-        self.qos_ext_handler.process_resource(
-            context, qos_extension.PORT, data, result)
+        self.core_ext_handler.process_fields(
+            context, base_core.PORT, data, result)
 
     process_update_port = process_create_port
 
     def extend_network_dict(self, session, db_data, result):
         result.update(
-            self.qos_ext_handler.extract_resource_fields(qos_extension.NETWORK,
-                                                         db_data))
+            self.core_ext_handler.extract_fields(
+                base_core.NETWORK, db_data))
 
     def extend_port_dict(self, session, db_data, result):
         result.update(
-            self.qos_ext_handler.extract_resource_fields(qos_extension.PORT,
-                                                         db_data))
+            self.core_ext_handler.extract_fields(base_core.PORT, db_data))
index 453b85387ff7f242a66491957464aa0d26a9a939..8c81d14699ee159d20138af1f843ebc7f9c56214 100644 (file)
@@ -140,7 +140,7 @@ class QosTestJSON(base.BaseAdminNetworkTest):
                                         description='test policy',
                                         shared=False)
         #TODO(QoS): This currently raises an exception on the server side. See
-        #           services/qos/qos_extension.py for comments on this subject.
+        #           core_extensions/qos.py for comments on this subject.
         network = self.create_network('test network',
                                       qos_policy_id=policy['id'])
 
@@ -193,7 +193,7 @@ class QosTestJSON(base.BaseAdminNetworkTest):
                                         shared=False)
         network = self.create_shared_network('test network')
         #TODO(QoS): This currently raises an exception on the server side. See
-        #           services/qos/qos_extension.py for comments on this subject.
+        #           core_extensions/qos.py for comments on this subject.
         port = self.create_port(network, qos_policy_id=policy['id'])
 
         retrieved_port = self.admin_client.show_port(port['id'])
diff --git a/neutron/tests/unit/core_extensions/__init__.py b/neutron/tests/unit/core_extensions/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
similarity index 67%
rename from neutron/tests/unit/services/qos/test_qos_extension.py
rename to neutron/tests/unit/core_extensions/test_qos.py
index 4252167ea7d96da92ec31dcd076a5259066a715d..dddfc692f60e5b8f8daf97f3613893ee1f6920c2 100644 (file)
 import mock
 
 from neutron import context
+from neutron.core_extensions import base as base_core
+from neutron.core_extensions import qos as qos_core
 from neutron.plugins.common import constants as plugin_constants
 from neutron.services.qos import qos_consts
-from neutron.services.qos import qos_extension
 from neutron.tests import base
 
 
@@ -27,18 +28,18 @@ def _get_test_dbdata(qos_policy_id):
                                                'network_id': 'fake_net_id'}}
 
 
-class QosResourceExtensionHandlerTestCase(base.BaseTestCase):
+class QosCoreResourceExtensionTestCase(base.BaseTestCase):
 
     def setUp(self):
-        super(QosResourceExtensionHandlerTestCase, self).setUp()
-        self.ext_handler = qos_extension.QosResourceExtensionHandler()
+        super(QosCoreResourceExtensionTestCase, self).setUp()
+        self.core_extension = qos_core.QosCoreResourceExtension()
         policy_p = mock.patch('neutron.objects.qos.policy.QosPolicy')
         self.policy_m = policy_p.start()
         self.context = context.get_admin_context()
 
-    def test_process_resource_no_qos_policy_id(self):
-        self.ext_handler.process_resource(
-            self.context, qos_extension.PORT, {}, None)
+    def test_process_fields_no_qos_policy_id(self):
+        self.core_extension.process_fields(
+            self.context, base_core.PORT, {}, None)
         self.assertFalse(self.policy_m.called)
 
     def _mock_plugin_loaded(self, plugin_loaded):
@@ -48,28 +49,28 @@ class QosResourceExtensionHandlerTestCase(base.BaseTestCase):
         return mock.patch('neutron.manager.NeutronManager.get_service_plugins',
                           return_value=plugins)
 
-    def test_process_resource_no_qos_plugin_loaded(self):
+    def test_process_fields_no_qos_plugin_loaded(self):
         with self._mock_plugin_loaded(False):
-            self.ext_handler.process_resource(
-                self.context, qos_extension.PORT,
+            self.core_extension.process_fields(
+                self.context, base_core.PORT,
                 {qos_consts.QOS_POLICY_ID: None}, None)
             self.assertFalse(self.policy_m.called)
 
-    def test_process_resource_port_new_policy(self):
+    def test_process_fields_port_new_policy(self):
         with self._mock_plugin_loaded(True):
             qos_policy_id = mock.Mock()
             actual_port = {'id': mock.Mock(),
                            qos_consts.QOS_POLICY_ID: qos_policy_id}
             qos_policy = mock.MagicMock()
             self.policy_m.get_by_id = mock.Mock(return_value=qos_policy)
-            self.ext_handler.process_resource(
-                self.context, qos_extension.PORT,
+            self.core_extension.process_fields(
+                self.context, base_core.PORT,
                 {qos_consts.QOS_POLICY_ID: qos_policy_id},
                 actual_port)
 
             qos_policy.attach_port.assert_called_once_with(actual_port['id'])
 
-    def test_process_resource_port_updated_policy(self):
+    def test_process_fields_port_updated_policy(self):
         with self._mock_plugin_loaded(True):
             qos_policy_id = mock.Mock()
             port_id = mock.Mock()
@@ -80,29 +81,29 @@ class QosResourceExtensionHandlerTestCase(base.BaseTestCase):
                 return_value=old_qos_policy)
             new_qos_policy = mock.MagicMock()
             self.policy_m.get_by_id = mock.Mock(return_value=new_qos_policy)
-            self.ext_handler.process_resource(
-                self.context, qos_extension.PORT,
+            self.core_extension.process_fields(
+                self.context, base_core.PORT,
                 {qos_consts.QOS_POLICY_ID: qos_policy_id},
                 actual_port)
 
             old_qos_policy.detach_port.assert_called_once_with(port_id)
             new_qos_policy.attach_port.assert_called_once_with(port_id)
 
-    def test_process_resource_network_new_policy(self):
+    def test_process_fields_network_new_policy(self):
         with self._mock_plugin_loaded(True):
             qos_policy_id = mock.Mock()
             actual_network = {'id': mock.Mock(),
                               qos_consts.QOS_POLICY_ID: qos_policy_id}
             qos_policy = mock.MagicMock()
             self.policy_m.get_by_id = mock.Mock(return_value=qos_policy)
-            self.ext_handler.process_resource(
-                self.context, qos_extension.NETWORK,
+            self.core_extension.process_fields(
+                self.context, base_core.NETWORK,
                 {qos_consts.QOS_POLICY_ID: qos_policy_id}, actual_network)
 
             qos_policy.attach_network.assert_called_once_with(
                 actual_network['id'])
 
-    def test_process_resource_network_updated_policy(self):
+    def test_process_fields_network_updated_policy(self):
         with self._mock_plugin_loaded(True):
             qos_policy_id = mock.Mock()
             network_id = mock.Mock()
@@ -113,42 +114,42 @@ class QosResourceExtensionHandlerTestCase(base.BaseTestCase):
                 return_value=old_qos_policy)
             new_qos_policy = mock.MagicMock()
             self.policy_m.get_by_id = mock.Mock(return_value=new_qos_policy)
-            self.ext_handler.process_resource(
-                self.context, qos_extension.NETWORK,
+            self.core_extension.process_fields(
+                self.context, base_core.NETWORK,
                 {qos_consts.QOS_POLICY_ID: qos_policy_id}, actual_network)
 
             old_qos_policy.detach_network.assert_called_once_with(network_id)
             new_qos_policy.attach_network.assert_called_once_with(network_id)
 
-    def test_extract_resource_fields_plugin_not_loaded(self):
+    def test_extract_fields_plugin_not_loaded(self):
         with self._mock_plugin_loaded(False):
-            fields = self.ext_handler.extract_resource_fields(None, None)
+            fields = self.core_extension.extract_fields(None, None)
             self.assertEqual({}, fields)
 
-    def _test_extract_resource_fields_for_port(self, qos_policy_id):
+    def _test_extract_fields_for_port(self, qos_policy_id):
         with self._mock_plugin_loaded(True):
-            fields = self.ext_handler.extract_resource_fields(
-                qos_extension.PORT, _get_test_dbdata(qos_policy_id))
+            fields = self.core_extension.extract_fields(
+                base_core.PORT, _get_test_dbdata(qos_policy_id))
             self.assertEqual({qos_consts.QOS_POLICY_ID: qos_policy_id}, fields)
 
-    def test_extract_resource_fields_no_port_policy(self):
-        self._test_extract_resource_fields_for_port(None)
+    def test_extract_fields_no_port_policy(self):
+        self._test_extract_fields_for_port(None)
 
-    def test_extract_resource_fields_port_policy_exists(self):
+    def test_extract_fields_port_policy_exists(self):
         qos_policy_id = mock.Mock()
-        self._test_extract_resource_fields_for_port(qos_policy_id)
+        self._test_extract_fields_for_port(qos_policy_id)
 
-    def _test_extract_resource_fields_for_network(self, qos_policy_id):
+    def _test_extract_fields_for_network(self, qos_policy_id):
         with self._mock_plugin_loaded(True):
-            fields = self.ext_handler.extract_resource_fields(
-                qos_extension.NETWORK, _get_test_dbdata(qos_policy_id))
+            fields = self.core_extension.extract_fields(
+                base_core.NETWORK, _get_test_dbdata(qos_policy_id))
             self.assertEqual({qos_consts.QOS_POLICY_ID: qos_policy_id}, fields)
 
-    def test_extract_resource_fields_no_network_policy(self):
-        self._test_extract_resource_fields_for_network(None)
+    def test_extract_fields_no_network_policy(self):
+        self._test_extract_fields_for_network(None)
 
-    def test_extract_resource_fields_network_policy_exists(self):
+    def test_extract_fields_network_policy_exists(self):
         qos_policy_id = mock.Mock()
         qos_policy = mock.Mock()
         qos_policy.id = qos_policy_id
-        self._test_extract_resource_fields_for_network(qos_policy_id)
+        self._test_extract_fields_for_network(qos_policy_id)