]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
Add extension callbacks support for networks
authorMike Kolesnik <mkolesni@redhat.com>
Tue, 30 Jun 2015 12:21:30 +0000 (15:21 +0300)
committerMike Kolesnik <mkolesni@redhat.com>
Thu, 2 Jul 2015 08:57:19 +0000 (11:57 +0300)
Add callbacks for extention to the network resource so that interested
extensions can do custom logic when a network is created or updated.

Currently it will be done the same way port notifications are done -
i.e. only in ML2 plugin. We can revisit this in a floow up patch if the
whole notification logic should be moved somewhere else as this merits
further discussion which is out of scope for a mere patch.

This will be utilized in a follow up commit.

Partially-implements: blueprint quantum-qos-api
Change-Id: I38528863e1145caf05fe3b2425511d1c5b5c0f93

neutron/callbacks/resources.py
neutron/plugins/ml2/plugin.py
neutron/tests/unit/plugins/ml2/test_plugin.py

index d796faf49608487a45c4231fcaf23a380dc7e0ff..40f73a653975f2a498c292a404ecd107b85a59fb 100644 (file)
@@ -10,6 +10,7 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+NETWORK = 'network'
 PORT = 'port'
 ROUTER = 'router'
 ROUTER_GATEWAY = 'router_gateway'
@@ -19,6 +20,7 @@ SECURITY_GROUP_RULE = 'security_group_rule'
 SUBNET = 'subnet'
 
 VALID = (
+    NETWORK,
     PORT,
     ROUTER,
     ROUTER_GATEWAY,
index a56039d4548119039d8ad5b4538e902454baea61..aac6dcf907c02b616cd7595843b0d5b6fb9e34a0 100644 (file)
@@ -618,6 +618,8 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
     def create_network(self, context, network):
         result, mech_context = self._create_network_with_retries(context,
                                                                  network)
+        self._notify_registry(
+            resources.NETWORK, events.AFTER_CREATE, context, result)
         try:
             self.mechanism_manager.create_network_postcommit(mech_context)
         except ml2_exc.MechanismDriverError:
@@ -630,6 +632,12 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
 
     def create_network_bulk(self, context, networks):
         objects = self._create_bulk_ml2(attributes.NETWORK, context, networks)
+
+        for obj in objects:
+            self._notify_registry(resources.NETWORK,
+                                  events.AFTER_CREATE,
+                                  context,
+                                  obj)
         return [obj['result'] for obj in objects]
 
     def update_network(self, context, id, network):
@@ -652,6 +660,10 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
                 original_network=original_network)
             self.mechanism_manager.update_network_precommit(mech_context)
 
+        # Notifications must be sent after the above transaction is complete
+        self._notify_registry(
+            resources.NETWORK, events.AFTER_UPDATE, context, updated_network)
+
         # TODO(apech) - handle errors raised by update_network, potentially
         # by re-calling update_network with the previous attributes. For
         # now the error is propogated to the caller, which is expected to
@@ -1496,3 +1508,10 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
             if port:
                 return port.id
         return device
+
+    def _notify_registry(self, resource_type, event_type, context, resource):
+        kwargs = {
+            'context': context,
+            resource_type: resource,
+        }
+        registry.notify(resource_type, event_type, self, **kwargs)
index abb857b3e3a420c44cd791b211691cfcf756467f..a813651d234d750787e16338d947c7105b4f1df3 100644 (file)
@@ -1581,3 +1581,75 @@ class TestMl2PluginCreateUpdateDeletePort(base.BaseTestCase):
             # run the transaction balancing function defined in this test
             plugin.delete_port(self.context, 'fake_id')
             self.assertTrue(self.notify.call_count)
+
+
+class TestMl2PluginCreateUpdateNetwork(base.BaseTestCase):
+    def setUp(self):
+        super(TestMl2PluginCreateUpdateNetwork, self).setUp()
+        self.context = mock.MagicMock()
+        self.notify_p = mock.patch('neutron.callbacks.registry.notify')
+        self.notify = self.notify_p.start()
+
+    def _ensure_transaction_is_closed(self):
+        transaction = self.context.session.begin(subtransactions=True)
+        enter = transaction.__enter__.call_count
+        exit = transaction.__exit__.call_count
+        self.assertEqual(enter, exit)
+
+    def _create_plugin_for_create_update_network(self):
+        plugin = ml2_plugin.Ml2Plugin()
+        plugin.extension_manager = mock.Mock()
+        plugin.type_manager = mock.Mock()
+        plugin.mechanism_manager = mock.Mock()
+        plugin.notifier = mock.Mock()
+        mock.patch('neutron.extensions.providernet.'
+                   '_raise_if_updates_provider_attributes').start()
+
+        self.notify.side_effect = (
+            lambda r, e, t, **kwargs: self._ensure_transaction_is_closed())
+
+        return plugin
+
+    def test_create_network_rpc_outside_transaction(self):
+        with mock.patch.object(ml2_plugin.Ml2Plugin, '__init__') as init,\
+                mock.patch.object(base_plugin.NeutronDbPluginV2,
+                                  'create_network'):
+            init.return_value = None
+
+            plugin = self._create_plugin_for_create_update_network()
+
+            plugin.create_network(self.context, mock.MagicMock())
+
+            kwargs = {'context': self.context, 'network': mock.ANY}
+            self.notify.assert_called_once_with('network', 'after_create',
+                plugin, **kwargs)
+
+    def test_create_network_bulk_rpc_outside_transaction(self):
+        with mock.patch.object(ml2_plugin.Ml2Plugin, '__init__') as init,\
+                mock.patch.object(base_plugin.NeutronDbPluginV2,
+                                  'create_network'):
+            init.return_value = None
+
+            plugin = self._create_plugin_for_create_update_network()
+
+            plugin.create_network_bulk(self.context,
+                                       {'networks':
+                                        [mock.MagicMock(), mock.MagicMock()]})
+
+            self.assertEqual(2, self.notify.call_count)
+
+    def test_update_network_rpc_outside_transaction(self):
+        with mock.patch.object(ml2_plugin.Ml2Plugin, '__init__') as init,\
+                mock.patch.object(base_plugin.NeutronDbPluginV2,
+                                  'update_network'):
+            init.return_value = None
+            plugin = self._create_plugin_for_create_update_network()
+
+            plugin.update_network(self.context, 'fake_id', mock.MagicMock())
+
+            kwargs = {
+                'context': self.context,
+                'network': mock.ANY,
+            }
+            self.notify.assert_called_once_with('network', 'after_update',
+                plugin, **kwargs)