]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
MidoNet: Added support for the admin_state_up flag
authorDuarte Nunes <duarte@midokura.com>
Thu, 3 Oct 2013 14:03:14 +0000 (16:03 +0200)
committerDuarte Nunes <duarte@midokura.com>
Mon, 18 Nov 2013 17:39:42 +0000 (17:39 +0000)
This commit enhances the port, bridge and router resources with the
admin_state_up flag in the MidoNet plugin.

Implements: blueprint midonet-admin-state
Change-Id: I67f4f9ad4099a05f8161aae79331ebba84f561b8

neutron/plugins/midonet/midonet_lib.py
neutron/plugins/midonet/plugin.py
neutron/tests/unit/midonet/mock_lib.py
neutron/tests/unit/midonet/test_midonet_lib.py

index 8f40b3986d6170d3f79102a3776e1d6fc7dcb9dc..74d2bae6ad7c5772208d961c81c9f1e44316f5a7 100644 (file)
@@ -19,7 +19,7 @@
 # @author: Tomoe Sugihara, Midokura Japan KK
 # @author: Ryu Ishimoto, Midokura Japan KK
 # @author: Rossella Sblendido, Midokura Japan KK
-
+# @author: Duarte Nunes, Midokura Japan KK
 
 from midonetclient import exc
 from webob import exc as w_exc
@@ -55,19 +55,35 @@ class MidoClient:
     def __init__(self, mido_api):
         self.mido_api = mido_api
 
+    @classmethod
+    def _fill_dto(cls, dto, fields):
+        for field_name, field_value in fields.iteritems():
+            # We assume the setters are named the
+            # same way as the attributes themselves.
+            try:
+                getattr(dto, field_name)(field_value)
+            except AttributeError:
+                pass
+        return dto
+
+    @classmethod
+    def _create_dto(cls, dto, fields):
+        return cls._fill_dto(dto, fields).create()
+
+    @classmethod
+    def _update_dto(cls, dto, fields):
+        return cls._fill_dto(dto, fields).update()
+
     @handle_api_error
-    def create_bridge(self, tenant_id, name):
+    def create_bridge(self, **kwargs):
         """Create a new bridge
 
-        :param tenant_id: id of tenant creating the bridge
-        :param name: name of the bridge
+        :param \**kwargs: configuration of the new bridge
         :returns: newly created bridge
         """
         LOG.debug(_("MidoClient.create_bridge called: "
-                    "tenant_id=%(tenant_id)s, name=%(name)s"),
-                  {'tenant_id': tenant_id, 'name': name})
-        return self.mido_api.add_bridge().name(name).tenant_id(
-            tenant_id).create()
+                    "kwargs=%(kwargs)s"), {'kwargs': kwargs})
+        return self._create_dto(self.mido_api.add_bridge(), kwargs)
 
     @handle_api_error
     def delete_bridge(self, id):
@@ -92,17 +108,18 @@ class MidoClient:
             raise MidonetResourceNotFound(resource_type='Bridge', id=id)
 
     @handle_api_error
-    def update_bridge(self, id, name):
-        """Update a bridge of the given id with the new name
+    def update_bridge(self, id, **kwargs):
+        """Update a bridge of the given id with the new fields
 
         :param id: id of the bridge
-        :param name: name of the bridge to set to
+        :param \**kwargs: the fields to update and their values
         :returns: bridge object
         """
         LOG.debug(_("MidoClient.update_bridge called: "
-                    "id=%(id)s, name=%(name)s"), {'id': id, 'name': name})
+                    "id=%(id)s, kwargs=%(kwargs)s"),
+                  {'id': id, 'kwargs': kwargs})
         try:
-            return self.mido_api.get_bridge(id).name(name).update()
+            return self._update_dto(self.mido_api.get_bridge(id), kwargs)
         except w_exc.HTTPNotFound:
             raise MidonetResourceNotFound(resource_type='Bridge', id=id)
 
@@ -234,38 +251,53 @@ class MidoClient:
             raise MidonetResourceNotFound(resource_type='Port', id=id)
 
     @handle_api_error
-    def add_bridge_port(self, bridge):
+    def add_bridge_port(self, bridge, **kwargs):
         """Add a port on a bridge
 
-        :param bridge: Bridge to add a new port to
+        :param bridge: bridge to add a new port to
+        :param \**kwargs: configuration of the new port
         :returns: newly created port
         """
         LOG.debug(_("MidoClient.add_bridge_port called: "
-                    "bridge=%(bridge)s"), {'bridge': bridge})
-        return self.mido_api.add_bridge_port(bridge)
+                    "bridge=%(bridge)s, kwargs=%(kwargs)s"),
+                  {'bridge': bridge, 'kwargs': kwargs})
+        return self._create_dto(self.mido_api.add_bridge_port(bridge), kwargs)
 
     @handle_api_error
-    def add_router_port(self, router, port_address=None,
-                        network_address=None, network_length=None):
-        """Add a new port to an existing router."""
-        return self.mido_api.add_router_port(router,
-                                             port_address=port_address,
-                                             network_address=network_address,
-                                             network_length=network_length)
+    def update_port(self, id, **kwargs):
+        """Update a port of the given id with the new fields
+
+        :param id: id of the port
+        :param \**kwargs: the fields to update and their values
+        """
+        LOG.debug(_("MidoClient.update_port called: "
+                    "id=%(id)s, kwargs=%(kwargs)s"),
+                  {'id': id, 'kwargs': kwargs})
+        try:
+            return self._update_dto(self.mido_api.get_port(id), kwargs)
+        except w_exc.HTTPNotFound:
+            raise MidonetResourceNotFound(resource_type='Port', id=id)
+
+    @handle_api_error
+    def add_router_port(self, router, **kwargs):
+        """Add a new port to an existing router.
+
+        :param router: router to add a new port to
+        :param \**kwargs: configuration of the new port
+        :returns: newly created port
+        """
+        return self._create_dto(self.mido_api.add_router_port(router), kwargs)
 
     @handle_api_error
-    def create_router(self, tenant_id, name):
+    def create_router(self, **kwargs):
         """Create a new router
 
-        :param tenant_id: id of tenant creating the router
-        :param name: name of the router
+        :param \**kwargs: configuration of the new router
         :returns: newly created router
         """
         LOG.debug(_("MidoClient.create_router called: "
-                    "tenant_id=%(tenant_id)s, name=%(name)s"),
-                  {'tenant_id': tenant_id, 'name': name})
-        return self.mido_api.add_router().name(name).tenant_id(
-            tenant_id).create()
+                    "kwargs=%(kwargs)s"), {'kwargs': kwargs})
+        return self._create_dto(self.mido_api.add_router(), kwargs)
 
     @handle_api_error
     def delete_router(self, id):
@@ -290,17 +322,18 @@ class MidoClient:
             raise MidonetResourceNotFound(resource_type='Router', id=id)
 
     @handle_api_error
-    def update_router(self, id, name):
+    def update_router(self, id, **kwargs):
         """Update a router of the given id with the new name
 
         :param id: id of the router
-        :param name: name of the router to set to
+        :param \**kwargs: the fields to update and their values
         :returns: router object
         """
         LOG.debug(_("MidoClient.update_router called: "
-                    "id=%(id)s, name=%(name)s"), {'id': id, 'name': name})
+                    "id=%(id)s, kwargs=%(kwargs)s"),
+                  {'id': id, 'kwargs': kwargs})
         try:
-            return self.mido_api.get_router(id).name(name).update()
+            return self._update_dto(self.mido_api.get_router(id), kwargs)
         except w_exc.HTTPNotFound:
             raise MidonetResourceNotFound(resource_type='Router', id=id)
 
index ca2cb9c186769ab432c62ca00381ac7651f36854..d2f758b92cd750bc0cf117477a98a271ed995d6d 100644 (file)
@@ -20,6 +20,7 @@
 # @author: Tomoe Sugihara, Midokura Japan KK
 # @author: Ryu Ishimoto, Midokura Japan KK
 # @author: Rossella Sblendido, Midokura Japan KK
+# @author: Duarte Nunes, Midokura Japan KK
 
 from midonetclient import api
 from oslo.config import cfg
@@ -458,17 +459,18 @@ class MidonetPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
         """
         LOG.debug(_('MidonetPluginV2.create_network called: network=%r'),
                   network)
-        tenant_id = self._get_tenant_id_for_create(context, network['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(tenant_id,
-                                           network['network']['name'])
-        network['network']['id'] = bridge.get_id()
+        bridge = self.client.create_bridge(**net_data)
+        net_data['id'] = bridge.get_id()
 
         session = context.session
         with session.begin(subtransactions=True):
             net = super(MidonetPluginV2, self).create_network(context, network)
-            self._process_l3_create(context, net, network['network'])
+            self._process_l3_create(context, net, net_data)
 
         LOG.debug(_("MidonetPluginV2.create_network exiting: net=%r"), net)
         return net
@@ -486,7 +488,7 @@ class MidonetPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
             net = super(MidonetPluginV2, self).update_network(
                 context, id, network)
             self._process_l3_update(context, net, network['network'])
-            self.client.update_bridge(id, net['name'])
+            self.client.update_bridge(id, **network['network'])
 
         LOG.debug(_("MidonetPluginV2.update_network exiting: net=%r"), net)
         return net
@@ -524,8 +526,11 @@ class MidonetPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
         # port ID in Neutron.
         bridge = self.client.get_bridge(port_data["network_id"])
         tenant_id = bridge.get_tenant_id()
-        bridge_port = self.client.add_bridge_port(bridge)
+        asu = port_data.get("admin_state_up", True)
+        bridge_port = self.client.add_bridge_port(bridge,
+                                                  admin_state_up=asu)
         port_data["id"] = bridge_port.get_id()
+
         try:
             session = context.session
             with session.begin(subtransactions=True):
@@ -661,6 +666,17 @@ class MidonetPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
             # update the port DB
             p = super(MidonetPluginV2, self).update_port(context, id, port)
 
+            if "admin_state_up" in port["port"]:
+                asu = port["port"]["admin_state_up"]
+                mido_port = self.client.update_port(id, admin_state_up=asu)
+
+                # If we're changing the admin_state_up flag and the port is
+                # associated with a router, then we also need to update the
+                # peer port.
+                if _is_router_interface_port(p):
+                    self.client.update_port(mido_port.get_peer_id(),
+                                            admin_state_up=asu)
+
             new_ips = p["fixed_ips"]
             if new_ips:
                 bridge = self.client.get_bridge(net_id)
@@ -698,7 +714,7 @@ class MidonetPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
 
         When a new Neutron router is created, its corresponding MidoNet router
         is also created.  In MidoNet, this router is initialized with chains
-        for inbuond and outbound traffic, which will be used to hold other
+        for inbound and outbound traffic, which will be used to hold other
         chains that include various rules, such as NAT.
 
         :param router: Router information provided to create a new router.
@@ -710,19 +726,17 @@ class MidonetPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
         # 3rd parties to specify IDs as we do with l2 plugin
         LOG.debug(_("MidonetPluginV2.create_router called: router=%(router)s"),
                   {"router": router})
-        tenant_id = self._get_tenant_id_for_create(context, router['router'])
-        mido_router = self.client.create_router(tenant_id,
-                                                router['router']['name'])
+        r = router['router']
+        tenant_id = self._get_tenant_id_for_create(context, r)
+        r['tenant_id'] = tenant_id
+        mido_router = self.client.create_router(**r)
         mido_router_id = mido_router.get_id()
 
         try:
-            r = router['router']
             has_gw_info = False
             if EXTERNAL_GW_INFO in r:
                 has_gw_info = True
-                gw_info = r[EXTERNAL_GW_INFO]
-                del r[EXTERNAL_GW_INFO]
-            tenant_id = self._get_tenant_id_for_create(context, r)
+                gw_info = r.pop(EXTERNAL_GW_INFO)
             with context.session.begin(subtransactions=True):
                 # pre-generate id so it will be available when
                 # configuring external gw port
@@ -868,10 +882,7 @@ class MidonetPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
                                                  chain_names['post-routing'],
                                                  gw_ip, gw_port["id"], **props)
 
-            # Update the name if changed
-            changed_name = router_data.get('name')
-            if changed_name:
-                self.client.update_router(id, changed_name)
+            self.client.update_router(id, **router_data)
 
         LOG.debug(_("MidonetPluginV2.update_router exiting: router=%r"), r)
         return r
@@ -945,12 +956,12 @@ class MidonetPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
         for port in bridge_ports_to_delete:
             self.client.delete_port(port.get_id())
 
-    def _link_bridge_to_router(self, router, bridge_port_id, net_addr, net_len,
+    def _link_bridge_to_router(self, router, bridge_port, net_addr, net_len,
                                gw_ip, metadata_gw_ip):
         router_port = self.client.add_router_port(
-            router, port_address=gw_ip, network_address=net_addr,
-            network_length=net_len)
-        self.client.link(router_port, bridge_port_id)
+            router, network_length=net_len, network_address=net_addr,
+            port_address=gw_ip, admin_state_up=bridge_port['admin_state_up'])
+        self.client.link(router_port, bridge_port['id'])
         self.client.add_router_route(router, type='Normal',
                                      src_network_addr='0.0.0.0',
                                      src_network_length=0,
@@ -999,7 +1010,7 @@ class MidonetPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
             net_addr, net_len = net_util.net_addr(cidr)
             router = self.client.get_router(router_id)
 
-            # Get the metadatat GW IP
+            # Get the metadata GW IP
             metadata_gw_ip = None
             rport_qry = context.session.query(models_v2.Port)
             dhcp_ports = rport_qry.filter_by(
@@ -1011,7 +1022,9 @@ class MidonetPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
                 LOG.warn(_("DHCP agent is not working correctly. No port "
                            "to reach the Metadata server on this network"))
             # Link the router and the bridge
-            self._link_bridge_to_router(router, info["port_id"], net_addr,
+            port = super(MidonetPluginV2, self).get_port(context,
+                                                         info["port_id"])
+            self._link_bridge_to_router(router, port, net_addr,
                                         net_len, subnet["gateway_ip"],
                                         metadata_gw_ip)
         except Exception:
index dc1d5ed25f0891fe68de64c3c0cb7a2d529459af..9fdae9cd6b48d586bca8f66983825147635365b3 100644 (file)
@@ -21,21 +21,21 @@ import mock
 import uuid
 
 
-def get_bridge_mock(id=None, tenant_id='test-tenant', name='net'):
+def get_bridge_mock(id=None, **kwargs):
     if id is None:
         id = str(uuid.uuid4())
 
     bridge = mock.Mock()
     bridge.get_id.return_value = id
-    bridge.get_tenant_id.return_value = tenant_id
-    bridge.get_name.return_value = name
+    bridge.get_tenant_id.return_value = kwargs.get("tenant_id", "test-tenant")
+    bridge.get_name.return_value = kwargs.get("name", "net")
     bridge.get_ports.return_value = []
     bridge.get_peer_ports.return_value = []
+    bridge.get_admin_state_up.return_value = kwargs.get("admin_state_up", True)
     return bridge
 
 
-def get_bridge_port_mock(id=None, bridge_id=None,
-                         type='ExteriorBridge'):
+def get_bridge_port_mock(id=None, bridge_id=None, **kwargs):
     if id is None:
         id = str(uuid.uuid4())
     if bridge_id is None:
@@ -43,8 +43,10 @@ def get_bridge_port_mock(id=None, bridge_id=None,
 
     port = mock.Mock()
     port.get_id.return_value = id
-    port.get_brige_id.return_value = bridge_id
-    port.get_type.return_value = type
+    port.get_bridge_id.return_value = bridge_id
+    port.get_admin_state_up.return_value = kwargs.get("admin_state_up", True)
+    port.get_type.return_value = "Bridge"
+    port.create.return_value = port
     return port
 
 
@@ -75,17 +77,18 @@ def get_port_group_mock(id=None, tenant_id='test-tenant', name='pg'):
     return port_group
 
 
-def get_router_mock(id=None, tenant_id='test-tenant', name='router'):
+def get_router_mock(id=None, **kwargs):
     if id is None:
         id = str(uuid.uuid4())
 
     router = mock.Mock()
     router.get_id.return_value = id
-    router.get_tenant_id.return_value = tenant_id
-    router.get_name.return_value = name
+    router.get_tenant_id.return_value = kwargs.get("tenant_id", "test-tenant")
+    router.get_name.return_value = kwargs.get("name", "router")
     router.get_ports.return_value = []
     router.get_peer_ports.return_value = []
     router.get_routes.return_value = []
+    router.get_admin_state_up.return_value = kwargs.get("admin_state_up", True)
     return router
 
 
@@ -125,19 +128,19 @@ class MidonetLibMockConfig():
     def __init__(self, inst):
         self.inst = inst
 
-    def _create_bridge(self, tenant_id, name):
-        return get_bridge_mock(tenant_id=tenant_id, name=name)
+    def _create_bridge(self, **kwargs):
+        return get_bridge_mock(**kwargs)
 
-    def _create_router(self, tenant_id, name):
-        return get_router_mock(tenant_id=tenant_id, name=name)
+    def _create_router(self, **kwargs):
+        return get_router_mock(**kwargs)
 
     def _create_subnet(self, bridge, gateway_ip, subnet_prefix, subnet_len):
         return get_subnet_mock(bridge.get_id(), gateway_ip=gateway_ip,
                                subnet_prefix=subnet_prefix,
                                subnet_len=subnet_len)
 
-    def _add_bridge_port(self, bridge):
-        return get_bridge_port_mock(bridge_id=bridge.get_id())
+    def _add_bridge_port(self, bridge, **kwargs):
+        return get_bridge_port_mock(bridge_id=bridge.get_id(), **kwargs)
 
     def _get_bridge(self, id):
         return get_bridge_mock(id=id)
@@ -148,8 +151,8 @@ class MidonetLibMockConfig():
     def _get_router(self, id):
         return get_router_mock(id=id)
 
-    def _update_bridge(self, id, name):
-        return get_bridge_mock(id=id, name=name)
+    def _update_bridge(self, id, **kwargs):
+        return get_bridge_mock(id=id, **kwargs)
 
     def setup(self):
         # Bridge methods side effects
@@ -250,9 +253,13 @@ class MidoClientMockConfig():
     def _get_router(self, id):
         return get_router_mock(id=id)
 
+    def _add_bridge_port(self, bridge):
+        return get_bridge_port_mock(bridge_id=bridge.get_id())
+
     def setup(self):
         self.inst.get_bridge.side_effect = self._get_bridge
         self.inst.get_chains.side_effect = self._get_chains
         self.inst.get_chain.side_effect = self._get_chain
         self.inst.get_port_groups.side_effect = self._get_port_groups
         self.inst.get_router.side_effect = self._get_router
+        self.inst.add_bridge_port.side_effect = self._add_bridge_port
index bc489e1a1e3a800ca486eac9513554c6b1ac3c84..f9e42990a485f989346f9467516296aafcbaf02b 100644 (file)
@@ -166,3 +166,25 @@ class MidoClientTestCase(testtools.TestCase):
 
         self.assertIsNotNone(bridge)
         self.assertEqual(bridge.get_id(), bridge_id)
+        self.assertTrue(bridge.get_admin_state_up())
+
+    def test_add_bridge_port(self):
+        bridge_id = uuidutils.generate_uuid()
+
+        bridge = self.client.get_bridge(bridge_id)
+
+        self.assertIsNotNone(bridge)
+
+        port = self.client.add_bridge_port(bridge)
+
+        self.assertEqual(bridge.get_id(), port.get_bridge_id())
+        self.assertTrue(port.get_admin_state_up())
+
+    def test_get_router(self):
+        router_id = uuidutils.generate_uuid()
+
+        router = self.client.get_router(router_id)
+
+        self.assertIsNotNone(router)
+        self.assertEqual(router.get_id(), router_id)
+        self.assertTrue(router.get_admin_state_up())