]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
Implement Midonet Juno Network Api calls
authorJoe Mills <joe@midokura.com>
Tue, 1 Jul 2014 09:07:05 +0000 (09:07 +0000)
committerJoe Mills <joe@midokura.com>
Thu, 31 Jul 2014 06:51:10 +0000 (15:51 +0900)
This patch is the first in a series of converting the current midonet plugin
code to the new model described in blueprint midonet-plugin-juno. This patch
focuses specifically on the "network" handlers.

This patch also updates the midonet UT to handle the new objects that need
to be mocked with the new model.

Change-Id: I056d698ce2e312527e756ff56c962cff83a6bc04
Partially-Implements: blueprint midonet-plugin-juno

neutron/plugins/midonet/plugin.py
neutron/tests/unit/midonet/test_midonet_plugin.py

index ac699c37db08ffcb5ac8245bbfe6b2f775132e9f..4bbbf236dfe5c945d43f2dfc623e6b082f506a65 100644 (file)
 # @author: Rossella Sblendido, Midokura Japan KK
 # @author: Duarte Nunes, Midokura Japan KK
 
+import functools
+
 from midonetclient import api
+from midonetclient import exc
+from midonetclient.neutron import client as n_client
 from oslo.config import cfg
 from sqlalchemy.orm import exc as sa_exc
+from webob import exc as w_exc
 
 from neutron.api.v2 import attributes
 from neutron.common import constants
@@ -66,6 +71,21 @@ SG_PORT_GROUP_NAME = "OS_PG_%s"
 SNAT_RULE = 'SNAT'
 
 
+def handle_api_error(fn):
+    """Wrapper for methods that throws custom exceptions."""
+    @functools.wraps(fn)
+    def wrapped(*args, **kwargs):
+        try:
+            return fn(*args, **kwargs)
+        except (w_exc.HTTPException, exc.MidoApiConnectionError) as ex:
+            raise MidonetApiException(msg=ex)
+    return wrapped
+
+
+class MidonetApiException(n_exc.NeutronException):
+    message = _("MidoNet API error: %(msg)s")
+
+
 def _get_nat_ips(type, fip):
     """Get NAT IP address information.
 
@@ -206,6 +226,10 @@ class MidonetPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
         self.provider_router_id = midonet_conf.provider_router_id
         self.provider_router = None
 
+        self.api_cli = n_client.MidonetClient(midonet_conf.midonet_uri,
+                midonet_conf.username,
+                midonet_conf.password,
+                project_id=midonet_conf.project_id)
         self.mido_api = api.MidonetApi(midonet_uri, admin_user,
                                        admin_pass,
                                        project_id=admin_project_id)
@@ -445,72 +469,58 @@ class MidonetPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
 
             LOG.debug(_("MidonetPluginV2.delete_subnet exiting"))
 
+    @handle_api_error
     def create_network(self, context, network):
         """Create Neutron network.
 
         Create a new Neutron network and its corresponding MidoNet bridge.
         """
-        LOG.debug(_('MidonetPluginV2.create_network called: network=%r'),
+        LOG.debug('MidonetPluginV2.create_network called: network=%r',
                   network)
+
         net_data = network['network']
         tenant_id = self._get_tenant_id_for_create(context, net_data)
         net_data['tenant_id'] = tenant_id
         self._ensure_default_security_group(context, tenant_id)
 
-        bridge = self.client.create_bridge(**net_data)
-        net_data['id'] = bridge.get_id()
-
-        session = context.session
-        with session.begin(subtransactions=True):
+        with context.session.begin(subtransactions=True):
             net = super(MidonetPluginV2, self).create_network(context, network)
             self._process_l3_create(context, net, net_data)
+            self.api_cli.create_network(net)
 
-        LOG.debug(_("MidonetPluginV2.create_network exiting: net=%r"), net)
+        LOG.debug("MidonetPluginV2.create_network exiting: net=%r", net)
         return net
 
+    @handle_api_error
     def update_network(self, context, id, network):
         """Update Neutron network.
 
         Update an existing Neutron network and its corresponding MidoNet
         bridge.
         """
-        LOG.debug(_("MidonetPluginV2.update_network called: id=%(id)r, "
-                    "network=%(network)r"), {'id': id, 'network': network})
-        session = context.session
-        with session.begin(subtransactions=True):
+        LOG.debug("MidonetPluginV2.update_network called: id=%(id)r, "
+                  "network=%(network)r", {'id': id, 'network': network})
+
+        with context.session.begin(subtransactions=True):
             net = super(MidonetPluginV2, self).update_network(
                 context, id, network)
             self._process_l3_update(context, net, network['network'])
-            self.client.update_bridge(id, **network['network'])
+            self.api_cli.update_network(id, net)
 
-        LOG.debug(_("MidonetPluginV2.update_network exiting: net=%r"), net)
+        LOG.debug("MidonetPluginV2.update_network exiting: net=%r", net)
         return net
 
-    def get_network(self, context, id, fields=None):
-        """Get Neutron network.
-
-        Retrieves a Neutron network and its corresponding MidoNet bridge.
-        """
-        LOG.debug(_("MidonetPluginV2.get_network called: id=%(id)r, "
-                    "fields=%(fields)r"), {'id': id, 'fields': fields})
-        qnet = super(MidonetPluginV2, self).get_network(context, id, fields)
-        self.client.get_bridge(id)
-
-        LOG.debug(_("MidonetPluginV2.get_network exiting: qnet=%r"), qnet)
-        return qnet
-
+    @handle_api_error
     def delete_network(self, context, id):
         """Delete a network and its corresponding MidoNet bridge."""
-        LOG.debug(_("MidonetPluginV2.delete_network called: id=%r"), id)
-        self.client.delete_bridge(id)
-        try:
-            with context.session.begin(subtransactions=True):
-                self._process_l3_delete(context, id)
-                super(MidonetPluginV2, self).delete_network(context, id)
-        except Exception:
-            with excutils.save_and_reraise_exception():
-                LOG.error(_('Failed to delete neutron db, while Midonet '
-                            'bridge=%r had been deleted'), id)
+        LOG.debug("MidonetPluginV2.delete_network called: id=%r", id)
+
+        with context.session.begin(subtransactions=True):
+            self._process_l3_delete(context, id)
+            super(MidonetPluginV2, self).delete_network(context, id)
+            self.api_cli.delete_network(id)
+
+        LOG.debug("MidonetPluginV2.delete_network exiting: id=%r", id)
 
     def create_port(self, context, port):
         """Create a L2 port in Neutron/MidoNet."""
index 80a6cb9727d4ae327dfa0eb609d65d7ad5c3a65d..5129fef063a7051d1f264c9a286d2c92accace2e 100644 (file)
@@ -53,12 +53,27 @@ class MidonetPluginV2TestCase(test_plugin.NeutronDbPluginV2TestCase):
         self.instance = self.mock_api.start()
         mock_cfg = mock_lib.MidonetLibMockConfig(self.instance.return_value)
         mock_cfg.setup()
-        super(MidonetPluginV2TestCase, self).setUp(plugin=plugin,
-                                                   ext_mgr=ext_mgr)
 
-    def tearDown(self):
-        super(MidonetPluginV2TestCase, self).tearDown()
-        self.mock_api.stop()
+        self.midoclient_mock = mock.MagicMock()
+        self.midoclient_mock.midonetclient.neutron.client.return_value = True
+        modules = {
+            'midonetclient': self.midoclient_mock,
+            'midonetclient.neutron': self.midoclient_mock.neutron,
+            'midonetclient.neutron.client': self.midoclient_mock.client,
+        }
+
+        self.module_patcher = mock.patch.dict('sys.modules', modules)
+        self.module_patcher.start()
+        self.addCleanup(self.module_patcher.stop)
+
+        # import midonetclient here because it needs proper mock objects to be
+        # assigned to this module first.  'midoclient_mock' object is the
+        # mock object used for this module.
+        from midonetclient.neutron.client import MidonetClient
+        client_class = MidonetClient
+        self.mock_class = client_class()
+
+        super(MidonetPluginV2TestCase, self).setUp(plugin=plugin)
 
 
 class TestMidonetNetworksV2(test_plugin.TestNetworksV2,
@@ -131,6 +146,9 @@ class TestMidonetL3NatTestCase(MidonetPluginV2TestCase,
                                                   None)
         self.assertTrue(self.instance.return_value.add_static_nat.called)
 
+    def test_delete_ext_net_with_disassociated_floating_ips(self):
+        pass
+
 
 class TestMidonetSecurityGroupsTestCase(sg.SecurityGroupDBTestCase):
 
@@ -150,6 +168,25 @@ class TestMidonetSecurityGroupsTestCase(sg.SecurityGroupDBTestCase):
         p.start()
         # dict patches must be explicitly stopped
         self.addCleanup(p.stop)
+        self.midoclient_mock = mock.MagicMock()
+        self.midoclient_mock.midonetclient.neutron.client.return_value = True
+        modules = {
+            'midonetclient': self.midoclient_mock,
+            'midonetclient.neutron': self.midoclient_mock.neutron,
+            'midonetclient.neutron.client': self.midoclient_mock.client,
+        }
+
+        self.module_patcher = mock.patch.dict('sys.modules', modules)
+        self.module_patcher.start()
+        self.addCleanup(self.module_patcher.stop)
+
+        # import midonetclient here because it needs proper mock objects to be
+        # assigned to this module first.  'midoclient_mock' object is the
+        # mock object used for this module.
+        from midonetclient.neutron.client import MidonetClient
+        client_class = MidonetClient
+        self.mock_class = client_class()
+
         super(TestMidonetSecurityGroupsTestCase, self).setUp(self._plugin_name)