]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
Midonet plugin decomposition
authorJaume Devesa <devvesa@gmail.com>
Wed, 24 Dec 2014 09:45:05 +0000 (09:45 +0000)
committerJaume Devesa <devvesa@gmail.com>
Tue, 13 Jan 2015 17:22:15 +0000 (17:22 +0000)
Remove the midonet plugin code and add the requirements.txt file to
set the dependency to the vendor plugin. Dependency is not pinned: we
will use the newest library during the Kilo cycle and we will submit a
patch with the pinned version a bit before the Kilo code freeze.

Vendor plugin code is available here:
https://github.com/midonet/python-neutron-plugin-midonet

Plugin already available in pypi:
https://pypi.python.org/pypi/neutron-plugin-midonet/

DocImpact
Partially-implements: blueprint core-vendor-decomposition
Closes-bug: #1408339

Change-Id: I867ab6753cd45abb65e850cd6aaef7bb0c5bbddb

14 files changed:
neutron/plugins/midonet/agent/__init__.py [deleted file]
neutron/plugins/midonet/agent/midonet_driver.py [deleted file]
neutron/plugins/midonet/common/__init__.py [deleted file]
neutron/plugins/midonet/common/config.py [deleted file]
neutron/plugins/midonet/common/net_util.py [deleted file]
neutron/plugins/midonet/midonet_lib.py [deleted file]
neutron/plugins/midonet/plugin.py
neutron/plugins/midonet/requirements.txt [new file with mode: 0644]
neutron/tests/unit/midonet/__init__.py [deleted file]
neutron/tests/unit/midonet/etc/midonet.ini.test [deleted file]
neutron/tests/unit/midonet/mock_lib.py [deleted file]
neutron/tests/unit/midonet/test_midonet_driver.py [deleted file]
neutron/tests/unit/midonet/test_midonet_lib.py [deleted file]
neutron/tests/unit/midonet/test_midonet_plugin.py [deleted file]

diff --git a/neutron/plugins/midonet/agent/__init__.py b/neutron/plugins/midonet/agent/__init__.py
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/neutron/plugins/midonet/agent/midonet_driver.py b/neutron/plugins/midonet/agent/midonet_driver.py
deleted file mode 100644 (file)
index 29930b8..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-# Copyright (C) 2013 Midokura PTE LTD
-# 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.
-
-from neutron.agent.linux import dhcp
-from neutron.openstack.common import log as logging
-from neutron.plugins.midonet.common import config  # noqa
-
-LOG = logging.getLogger(__name__)
-
-
-class DhcpNoOpDriver(dhcp.DhcpLocalProcess):
-
-    @classmethod
-    def existing_dhcp_networks(cls, conf, root_helper):
-        """Return a list of existing networks ids that we have configs for."""
-        return []
-
-    @classmethod
-    def check_version(cls):
-        """Execute version checks on DHCP server."""
-        return float(1.0)
-
-    def disable(self, retain_port=False):
-        """Disable DHCP for this network."""
-        if not retain_port:
-            self.device_manager.destroy(self.network, self.interface_name)
-        self._remove_config_files()
-
-    def reload_allocations(self):
-        """Force the DHCP server to reload the assignment database."""
-        pass
-
-    def spawn_process(self):
-        pass
diff --git a/neutron/plugins/midonet/common/__init__.py b/neutron/plugins/midonet/common/__init__.py
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/neutron/plugins/midonet/common/config.py b/neutron/plugins/midonet/common/config.py
deleted file mode 100644 (file)
index d4db12e..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-# Copyright (C) 2012 Midokura Japan K.K.
-# Copyright (C) 2013 Midokura PTE LTD
-# 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.
-
-from oslo.config import cfg
-
-midonet_opts = [
-    cfg.StrOpt('midonet_uri', default='http://localhost:8080/midonet-api',
-               help=_('MidoNet API server URI.')),
-    cfg.StrOpt('username', default='admin',
-               help=_('MidoNet admin username.')),
-    cfg.StrOpt('password', default='passw0rd',
-               secret=True,
-               help=_('MidoNet admin password.')),
-    cfg.StrOpt('project_id',
-               default='77777777-7777-7777-7777-777777777777',
-               help=_('ID of the project that MidoNet admin user'
-                      'belongs to.')),
-    cfg.StrOpt('provider_router_id',
-               help=_('Virtual provider router ID.')),
-    cfg.StrOpt('mode',
-               default='dev',
-               help=_('Operational mode. Internal dev use only.')),
-    cfg.StrOpt('midonet_host_uuid_path',
-               default='/etc/midolman/host_uuid.properties',
-               help=_('Path to midonet host uuid file'))
-]
-
-
-cfg.CONF.register_opts(midonet_opts, "MIDONET")
diff --git a/neutron/plugins/midonet/common/net_util.py b/neutron/plugins/midonet/common/net_util.py
deleted file mode 100644 (file)
index 69706d3..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-# Copyright (C) 2013 Midokura PTE LTD
-# 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.
-
-
-from neutron.common import constants
-
-
-def subnet_str(cidr):
-    """Convert the cidr string to x.x.x.x_y format
-
-    :param cidr: CIDR in x.x.x.x/y format
-    """
-    if cidr is None:
-        return None
-    return cidr.replace("/", "_")
-
-
-def net_addr(addr):
-    """Get network address prefix and length from a given address."""
-    if addr is None:
-        return (None, None)
-    nw_addr, nw_len = addr.split('/')
-    nw_len = int(nw_len)
-    return nw_addr, nw_len
-
-
-def get_ethertype_value(ethertype):
-    """Convert string representation of ethertype to the numerical."""
-    if ethertype is None:
-        return None
-    mapping = {
-        'ipv4': 0x0800,
-        'ipv6': 0x86DD,
-        'arp': 0x806
-    }
-    return mapping.get(ethertype.lower())
-
-
-def get_protocol_value(protocol):
-    """Convert string representation of protocol to the numerical."""
-    if protocol is None:
-        return None
-
-    if isinstance(protocol, int):
-        return protocol
-
-    mapping = {
-        constants.PROTO_NAME_TCP: constants.PROTO_NUM_TCP,
-        constants.PROTO_NAME_UDP: constants.PROTO_NUM_UDP,
-        constants.PROTO_NAME_ICMP: constants.PROTO_NUM_ICMP
-    }
-    return mapping.get(protocol.lower())
diff --git a/neutron/plugins/midonet/midonet_lib.py b/neutron/plugins/midonet/midonet_lib.py
deleted file mode 100644 (file)
index be806c1..0000000
+++ /dev/null
@@ -1,691 +0,0 @@
-# Copyright (C) 2012 Midokura Japan K.K.
-# Copyright (C) 2013 Midokura PTE LTD
-# 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.
-
-from midonetclient import exc
-from webob import exc as w_exc
-
-from neutron.common import exceptions as n_exc
-from neutron.i18n import _LW
-from neutron.openstack.common import log as logging
-from neutron.plugins.midonet.common import net_util
-
-LOG = logging.getLogger(__name__)
-
-
-def handle_api_error(fn):
-    """Wrapper for methods that throws custom exceptions."""
-    def wrapped(*args, **kwargs):
-        try:
-            return fn(*args, **kwargs)
-        except (w_exc.HTTPException,
-                exc.MidoApiConnectionError) as ex:
-            raise MidonetApiException(msg=ex)
-    return wrapped
-
-
-class MidonetResourceNotFound(n_exc.NotFound):
-    message = _('MidoNet %(resource_type)s %(id)s could not be found')
-
-
-class MidonetApiException(n_exc.NeutronException):
-    message = _("MidoNet API error: %(msg)s")
-
-
-class MidoClient(object):
-
-    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, **kwargs):
-        """Create a new bridge
-
-        :param kwargs: configuration of the new bridge
-        :returns: newly created bridge
-        """
-        LOG.debug("MidoClient.create_bridge called: "
-                  "kwargs=%(kwargs)s", {'kwargs': kwargs})
-        return self._create_dto(self.mido_api.add_bridge(), kwargs)
-
-    @handle_api_error
-    def delete_bridge(self, id):
-        """Delete a bridge
-
-        :param id: id of the bridge
-        """
-        LOG.debug("MidoClient.delete_bridge called: id=%(id)s", {'id': id})
-        return self.mido_api.delete_bridge(id)
-
-    @handle_api_error
-    def get_bridge(self, id):
-        """Get a bridge
-
-        :param id: id of the bridge
-        :returns: requested bridge. None if bridge does not exist.
-        """
-        LOG.debug("MidoClient.get_bridge called: id=%s", id)
-        try:
-            return self.mido_api.get_bridge(id)
-        except w_exc.HTTPNotFound:
-            raise MidonetResourceNotFound(resource_type='Bridge', id=id)
-
-    @handle_api_error
-    def update_bridge(self, id, **kwargs):
-        """Update a bridge of the given id with the new fields
-
-        :param id: id of the bridge
-        :param kwargs: the fields to update and their values
-        :returns: bridge object
-        """
-        LOG.debug("MidoClient.update_bridge called: "
-                  "id=%(id)s, kwargs=%(kwargs)s",
-                  {'id': id, 'kwargs': kwargs})
-        try:
-            return self._update_dto(self.mido_api.get_bridge(id), kwargs)
-        except w_exc.HTTPNotFound:
-            raise MidonetResourceNotFound(resource_type='Bridge', id=id)
-
-    @handle_api_error
-    def create_dhcp(self, bridge, gateway_ip, cidr, host_rts=None,
-                    dns_servers=None):
-        """Create a new DHCP entry
-
-        :param bridge: bridge object to add dhcp to
-        :param gateway_ip: IP address of gateway
-        :param cidr: subnet represented as x.x.x.x/y
-        :param host_rts: list of routes set in the host
-        :param dns_servers: list of dns servers
-        :returns: newly created dhcp
-        """
-        LOG.debug("MidoClient.create_dhcp called: bridge=%(bridge)s, "
-                  "cidr=%(cidr)s, gateway_ip=%(gateway_ip)s, "
-                  "host_rts=%(host_rts)s, dns_servers=%(dns_servers)s",
-                  {'bridge': bridge, 'cidr': cidr, 'gateway_ip': gateway_ip,
-                   'host_rts': host_rts, 'dns_servers': dns_servers})
-        self.mido_api.add_bridge_dhcp(bridge, gateway_ip, cidr,
-                                      host_rts=host_rts,
-                                      dns_nservers=dns_servers)
-
-    @handle_api_error
-    def add_dhcp_host(self, bridge, cidr, ip, mac):
-        """Add DHCP host entry
-
-        :param bridge: bridge the DHCP is configured for
-        :param cidr: subnet represented as x.x.x.x/y
-        :param ip: IP address
-        :param mac: MAC address
-        """
-        LOG.debug("MidoClient.add_dhcp_host called: bridge=%(bridge)s, "
-                  "cidr=%(cidr)s, ip=%(ip)s, mac=%(mac)s",
-                  {'bridge': bridge, 'cidr': cidr, 'ip': ip, 'mac': mac})
-        subnet = bridge.get_dhcp_subnet(net_util.subnet_str(cidr))
-        if subnet is None:
-            raise MidonetApiException(msg=_("Tried to add to"
-                                            "non-existent DHCP"))
-
-        subnet.add_dhcp_host().ip_addr(ip).mac_addr(mac).create()
-
-    @handle_api_error
-    def remove_dhcp_host(self, bridge, cidr, ip, mac):
-        """Remove DHCP host entry
-
-        :param bridge: bridge the DHCP is configured for
-        :param cidr: subnet represented as x.x.x.x/y
-        :param ip: IP address
-        :param mac: MAC address
-        """
-        LOG.debug("MidoClient.remove_dhcp_host called: bridge=%(bridge)s, "
-                  "cidr=%(cidr)s, ip=%(ip)s, mac=%(mac)s",
-                  {'bridge': bridge, 'cidr': cidr, 'ip': ip, 'mac': mac})
-        subnet = bridge.get_dhcp_subnet(net_util.subnet_str(cidr))
-        if subnet is None:
-            LOG.warn(_LW("Tried to delete mapping from non-existent subnet"))
-            return
-
-        for dh in subnet.get_dhcp_hosts():
-            if dh.get_mac_addr() == mac and dh.get_ip_addr() == ip:
-                LOG.debug("MidoClient.remove_dhcp_host: Deleting %(dh)r",
-                          {"dh": dh})
-                dh.delete()
-
-    @handle_api_error
-    def delete_dhcp_host(self, bridge_id, cidr, ip, mac):
-        """Delete DHCP host entry
-
-        :param bridge_id: id of the bridge of the DHCP
-        :param cidr: subnet represented as x.x.x.x/y
-        :param ip: IP address
-        :param mac: MAC address
-        """
-        LOG.debug("MidoClient.delete_dhcp_host called: "
-                  "bridge_id=%(bridge_id)s, cidr=%(cidr)s, ip=%(ip)s, "
-                  "mac=%(mac)s", {'bridge_id': bridge_id,
-                                  'cidr': cidr,
-                                  'ip': ip, 'mac': mac})
-        bridge = self.get_bridge(bridge_id)
-        self.remove_dhcp_host(bridge, net_util.subnet_str(cidr), ip, mac)
-
-    @handle_api_error
-    def delete_dhcp(self, bridge, cidr):
-        """Delete a DHCP entry
-
-        :param bridge: bridge to remove DHCP from
-        :param cidr: subnet represented as x.x.x.x/y
-        """
-        LOG.debug("MidoClient.delete_dhcp called: bridge=%(bridge)s, "
-                  "cidr=%(cidr)s",
-                  {'bridge': bridge, 'cidr': cidr})
-        dhcp_subnets = bridge.get_dhcp_subnets()
-        net_addr, net_len = net_util.net_addr(cidr)
-        if not dhcp_subnets:
-            raise MidonetApiException(
-                msg=_("Tried to delete non-existent DHCP"))
-        for dhcp in dhcp_subnets:
-            if (dhcp.get_subnet_prefix() == net_addr and
-                dhcp.get_subnet_length() == str(net_len)):
-                dhcp.delete()
-                break
-
-    @handle_api_error
-    def delete_port(self, id, delete_chains=False):
-        """Delete a port
-
-        :param id: id of the port
-        """
-        LOG.debug("MidoClient.delete_port called: id=%(id)s, "
-                  "delete_chains=%(delete_chains)s",
-                  {'id': id, 'delete_chains': delete_chains})
-        if delete_chains:
-            self.delete_port_chains(id)
-
-        self.mido_api.delete_port(id)
-
-    @handle_api_error
-    def get_port(self, id):
-        """Get a port
-
-        :param id: id of the port
-        :returns: requested port. None if it does not exist
-        """
-        LOG.debug("MidoClient.get_port called: id=%(id)s", {'id': id})
-        try:
-            return self.mido_api.get_port(id)
-        except w_exc.HTTPNotFound:
-            raise MidonetResourceNotFound(resource_type='Port', id=id)
-
-    @handle_api_error
-    def add_bridge_port(self, bridge, **kwargs):
-        """Add a port on a bridge
-
-        :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, kwargs=%(kwargs)s",
-                  {'bridge': bridge, 'kwargs': kwargs})
-        return self._create_dto(self.mido_api.add_bridge_port(bridge), kwargs)
-
-    @handle_api_error
-    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, **kwargs):
-        """Create a new router
-
-        :param kwargs: configuration of the new router
-        :returns: newly created router
-        """
-        LOG.debug("MidoClient.create_router called: "
-                  "kwargs=%(kwargs)s", {'kwargs': kwargs})
-        return self._create_dto(self.mido_api.add_router(), kwargs)
-
-    @handle_api_error
-    def delete_router(self, id):
-        """Delete a router
-
-        :param id: id of the router
-        """
-        LOG.debug("MidoClient.delete_router called: id=%(id)s", {'id': id})
-        return self.mido_api.delete_router(id)
-
-    @handle_api_error
-    def get_router(self, id):
-        """Get a router with the given id
-
-        :param id: id of the router
-        :returns: requested router object.  None if it does not exist.
-        """
-        LOG.debug("MidoClient.get_router called: id=%(id)s", {'id': id})
-        try:
-            return self.mido_api.get_router(id)
-        except w_exc.HTTPNotFound:
-            raise MidonetResourceNotFound(resource_type='Router', id=id)
-
-    @handle_api_error
-    def update_router(self, id, **kwargs):
-        """Update a router of the given id with the new name
-
-        :param id: id of the router
-        :param kwargs: the fields to update and their values
-        :returns: router object
-        """
-        LOG.debug("MidoClient.update_router called: "
-                  "id=%(id)s, kwargs=%(kwargs)s",
-                  {'id': id, 'kwargs': kwargs})
-        try:
-            return self._update_dto(self.mido_api.get_router(id), kwargs)
-        except w_exc.HTTPNotFound:
-            raise MidonetResourceNotFound(resource_type='Router', id=id)
-
-    @handle_api_error
-    def delete_route(self, id):
-        return self.mido_api.delete_route(id)
-
-    @handle_api_error
-    def add_dhcp_route_option(self, bridge, cidr, gw_ip, dst_ip):
-        """Add Option121 route to subnet
-
-        :param bridge: Bridge to add the option route to
-        :param cidr: subnet represented as x.x.x.x/y
-        :param gw_ip: IP address of the next hop
-        :param dst_ip: IP address of the destination, in x.x.x.x/y format
-        """
-        LOG.debug("MidoClient.add_dhcp_route_option called: "
-                  "bridge=%(bridge)s, cidr=%(cidr)s, gw_ip=%(gw_ip)s"
-                  "dst_ip=%(dst_ip)s",
-                  {"bridge": bridge, "cidr": cidr, "gw_ip": gw_ip,
-                   "dst_ip": dst_ip})
-        subnet = bridge.get_dhcp_subnet(net_util.subnet_str(cidr))
-        if subnet is None:
-            raise MidonetApiException(
-                msg=_("Tried to access non-existent DHCP"))
-        prefix, length = dst_ip.split("/")
-        routes = [{'destinationPrefix': prefix, 'destinationLength': length,
-                   'gatewayAddr': gw_ip}]
-        cur_routes = subnet.get_opt121_routes()
-        if cur_routes:
-            routes = routes + cur_routes
-        subnet.opt121_routes(routes).update()
-
-    @handle_api_error
-    def link(self, port, peer_id):
-        """Link a port to a given peerId."""
-        self.mido_api.link(port, peer_id)
-
-    @handle_api_error
-    def delete_port_routes(self, routes, port_id):
-        """Remove routes whose next hop port is the given port ID."""
-        for route in routes:
-            if route.get_next_hop_port() == port_id:
-                self.mido_api.delete_route(route.get_id())
-
-    @handle_api_error
-    def get_router_routes(self, router_id):
-        """Get all routes for the given router."""
-        return self.mido_api.get_router_routes(router_id)
-
-    @handle_api_error
-    def unlink(self, port):
-        """Unlink a port
-
-        :param port: port object
-        """
-        LOG.debug("MidoClient.unlink called: port=%(port)s",
-                  {'port': port})
-        if port.get_peer_id():
-            self.mido_api.unlink(port)
-        else:
-            LOG.warn(_LW("Attempted to unlink a port that was not linked. %s"),
-                     port.get_id())
-
-    @handle_api_error
-    def remove_rules_by_property(self, tenant_id, chain_name, key, value):
-        """Remove all the rules that match the provided key and value."""
-        LOG.debug("MidoClient.remove_rules_by_property called: "
-                  "tenant_id=%(tenant_id)s, chain_name=%(chain_name)s"
-                  "key=%(key)s, value=%(value)s",
-                  {'tenant_id': tenant_id, 'chain_name': chain_name,
-                   'key': key, 'value': value})
-        chain = self.get_chain_by_name(tenant_id, chain_name)
-        if chain is None:
-            raise MidonetResourceNotFound(resource_type='Chain',
-                                          id=chain_name)
-
-        for r in chain.get_rules():
-            if key in r.get_properties():
-                if r.get_properties()[key] == value:
-                    self.mido_api.delete_rule(r.get_id())
-
-    @handle_api_error
-    def add_router_chains(self, router, inbound_chain_name,
-                          outbound_chain_name):
-        """Create chains for a new router.
-
-        Creates inbound and outbound chains for the router with the given
-        names, and the new chains are set on the router.
-
-        :param router: router to set chains for
-        :param inbound_chain_name: Name of the inbound chain
-        :param outbound_chain_name: Name of the outbound chain
-        """
-        LOG.debug("MidoClient.create_router_chains called: "
-                  "router=%(router)s, inbound_chain_name=%(in_chain)s, "
-                  "outbound_chain_name=%(out_chain)s",
-                  {"router": router, "in_chain": inbound_chain_name,
-                   "out_chain": outbound_chain_name})
-        tenant_id = router.get_tenant_id()
-
-        inbound_chain = self.mido_api.add_chain().tenant_id(tenant_id).name(
-            inbound_chain_name,).create()
-        outbound_chain = self.mido_api.add_chain().tenant_id(tenant_id).name(
-            outbound_chain_name).create()
-
-        # set chains to in/out filters
-        router.inbound_filter_id(inbound_chain.get_id()).outbound_filter_id(
-            outbound_chain.get_id()).update()
-        return inbound_chain, outbound_chain
-
-    @handle_api_error
-    def delete_router_chains(self, id):
-        """Deletes chains of a router.
-
-        :param id: router ID to delete chains of
-        """
-        LOG.debug("MidoClient.delete_router_chains called: "
-                  "id=%(id)s", {'id': id})
-        router = self.get_router(id)
-        if (router.get_inbound_filter_id()):
-            self.mido_api.delete_chain(router.get_inbound_filter_id())
-
-        if (router.get_outbound_filter_id()):
-            self.mido_api.delete_chain(router.get_outbound_filter_id())
-
-    @handle_api_error
-    def delete_port_chains(self, id):
-        """Deletes chains of a port.
-
-        :param id: port ID to delete chains of
-        """
-        LOG.debug("MidoClient.delete_port_chains called: "
-                  "id=%(id)s", {'id': id})
-        port = self.get_port(id)
-        if (port.get_inbound_filter_id()):
-            self.mido_api.delete_chain(port.get_inbound_filter_id())
-
-        if (port.get_outbound_filter_id()):
-            self.mido_api.delete_chain(port.get_outbound_filter_id())
-
-    @handle_api_error
-    def get_link_port(self, router, peer_router_id):
-        """Setup a route on the router to the next hop router."""
-        LOG.debug("MidoClient.get_link_port called: "
-                  "router=%(router)s, peer_router_id=%(peer_router_id)s",
-                  {'router': router, 'peer_router_id': peer_router_id})
-        # Find the port linked between the two routers
-        link_port = None
-        for p in router.get_peer_ports():
-            if p.get_device_id() == peer_router_id:
-                link_port = p
-                break
-        return link_port
-
-    @handle_api_error
-    def add_router_route(self, router, type='Normal',
-                         src_network_addr=None, src_network_length=None,
-                         dst_network_addr=None, dst_network_length=None,
-                         next_hop_port=None, next_hop_gateway=None,
-                         weight=100):
-        """Setup a route on the router."""
-        return self.mido_api.add_router_route(
-            router, type=type, src_network_addr=src_network_addr,
-            src_network_length=src_network_length,
-            dst_network_addr=dst_network_addr,
-            dst_network_length=dst_network_length,
-            next_hop_port=next_hop_port, next_hop_gateway=next_hop_gateway,
-            weight=weight)
-
-    @handle_api_error
-    def add_static_nat(self, tenant_id, chain_name, from_ip, to_ip, port_id,
-                       nat_type='dnat', **kwargs):
-        """Add a static NAT entry
-
-        :param tenant_id: owner fo the chain to add a NAT to
-        :param chain_name: name of the chain to add a NAT to
-        :param from_ip: IP to translate from
-        :param from_ip: IP to translate from
-        :param to_ip: IP to translate to
-        :param port_id: port to match on
-        :param nat_type: 'dnat' or 'snat'
-        """
-        LOG.debug("MidoClient.add_static_nat called: "
-                  "tenant_id=%(tenant_id)s, chain_name=%(chain_name)s, "
-                  "from_ip=%(from_ip)s, to_ip=%(to_ip)s, "
-                  "port_id=%(port_id)s, nat_type=%(nat_type)s",
-                  {'tenant_id': tenant_id, 'chain_name': chain_name,
-                   'from_ip': from_ip, 'to_ip': to_ip,
-                   'port_id': port_id, 'nat_type': nat_type})
-        if nat_type not in ['dnat', 'snat']:
-            raise ValueError(_("Invalid NAT type passed in %s") % nat_type)
-
-        chain = self.get_chain_by_name(tenant_id, chain_name)
-        nat_targets = []
-        nat_targets.append(
-            {'addressFrom': to_ip, 'addressTo': to_ip,
-             'portFrom': 0, 'portTo': 0})
-
-        rule = chain.add_rule().type(nat_type).flow_action('accept').position(
-            1).nat_targets(nat_targets).properties(kwargs)
-
-        if nat_type == 'dnat':
-            rule = rule.nw_dst_address(from_ip).nw_dst_length(32).in_ports(
-                [port_id])
-        else:
-            rule = rule.nw_src_address(from_ip).nw_src_length(32).out_ports(
-                [port_id])
-
-        return rule.create()
-
-    @handle_api_error
-    def add_dynamic_snat(self, tenant_id, pre_chain_name, post_chain_name,
-                         snat_ip, port_id, **kwargs):
-        """Add SNAT masquerading rule
-
-        MidoNet requires two rules on the router, one to do NAT to a range of
-        ports, and another to retrieve back the original IP in the return
-        flow.
-        """
-        pre_chain = self.get_chain_by_name(tenant_id, pre_chain_name)
-        post_chain = self.get_chain_by_name(tenant_id, post_chain_name)
-
-        pre_chain.add_rule().nw_dst_address(snat_ip).nw_dst_length(
-            32).type('rev_snat').flow_action('accept').in_ports(
-                [port_id]).properties(kwargs).position(1).create()
-
-        nat_targets = []
-        nat_targets.append(
-            {'addressFrom': snat_ip, 'addressTo': snat_ip,
-             'portFrom': 1, 'portTo': 65535})
-
-        post_chain.add_rule().type('snat').flow_action(
-            'accept').nat_targets(nat_targets).out_ports(
-                [port_id]).properties(kwargs).position(1).create()
-
-    @handle_api_error
-    def remove_static_route(self, router, ip):
-        """Remove static route for the IP
-
-        :param router: next hop router to remove the routes to
-        :param ip: IP address of the route to remove
-        """
-        LOG.debug("MidoClient.remote_static_route called: "
-                  "router=%(router)s, ip=%(ip)s",
-                  {'router': router, 'ip': ip})
-        for r in router.get_routes():
-            if (r.get_dst_network_addr() == ip and
-                    r.get_dst_network_length() == 32):
-                self.mido_api.delete_route(r.get_id())
-
-    @handle_api_error
-    def update_port_chains(self, port, inbound_chain_id, outbound_chain_id):
-        """Bind inbound and outbound chains to the port."""
-        LOG.debug("MidoClient.update_port_chains called: port=%(port)s"
-                  "inbound_chain_id=%(inbound_chain_id)s, "
-                  "outbound_chain_id=%(outbound_chain_id)s",
-                  {"port": port, "inbound_chain_id": inbound_chain_id,
-                   "outbound_chain_id": outbound_chain_id})
-        port.inbound_filter_id(inbound_chain_id).outbound_filter_id(
-            outbound_chain_id).update()
-
-    @handle_api_error
-    def create_chain(self, tenant_id, name):
-        """Create a new chain."""
-        LOG.debug("MidoClient.create_chain called: tenant_id=%(tenant_id)s "
-                  " name=%(name)s", {"tenant_id": tenant_id, "name": name})
-        return self.mido_api.add_chain().tenant_id(tenant_id).name(
-            name).create()
-
-    @handle_api_error
-    def delete_chain(self, id):
-        """Delete chain matching the ID."""
-        LOG.debug("MidoClient.delete_chain called: id=%(id)s", {"id": id})
-        self.mido_api.delete_chain(id)
-
-    @handle_api_error
-    def delete_chains_by_names(self, tenant_id, names):
-        """Delete chains matching the names given for a tenant."""
-        LOG.debug("MidoClient.delete_chains_by_names called: "
-                  "tenant_id=%(tenant_id)s names=%(names)s ",
-                  {"tenant_id": tenant_id, "names": names})
-        chains = self.mido_api.get_chains({'tenant_id': tenant_id})
-        for c in chains:
-            if c.get_name() in names:
-                self.mido_api.delete_chain(c.get_id())
-
-    @handle_api_error
-    def get_chain_by_name(self, tenant_id, name):
-        """Get the chain by its name."""
-        LOG.debug("MidoClient.get_chain_by_name called: "
-                  "tenant_id=%(tenant_id)s name=%(name)s ",
-                  {"tenant_id": tenant_id, "name": name})
-        for c in self.mido_api.get_chains({'tenant_id': tenant_id}):
-            if c.get_name() == name:
-                return c
-        return None
-
-    @handle_api_error
-    def get_port_group_by_name(self, tenant_id, name):
-        """Get the port group by name."""
-        LOG.debug("MidoClient.get_port_group_by_name called: "
-                  "tenant_id=%(tenant_id)s name=%(name)s ",
-                  {"tenant_id": tenant_id, "name": name})
-        for p in self.mido_api.get_port_groups({'tenant_id': tenant_id}):
-            if p.get_name() == name:
-                return p
-        return None
-
-    @handle_api_error
-    def create_port_group(self, tenant_id, name):
-        """Create a port group
-
-        Create a new port group for a given name and ID.
-        """
-        LOG.debug("MidoClient.create_port_group called: "
-                  "tenant_id=%(tenant_id)s name=%(name)s",
-                  {"tenant_id": tenant_id, "name": name})
-        return self.mido_api.add_port_group().tenant_id(tenant_id).name(
-            name).create()
-
-    @handle_api_error
-    def delete_port_group_by_name(self, tenant_id, name):
-        """Delete port group matching the name given for a tenant."""
-        LOG.debug("MidoClient.delete_port_group_by_name called: "
-                  "tenant_id=%(tenant_id)s name=%(name)s ",
-                  {"tenant_id": tenant_id, "name": name})
-        pgs = self.mido_api.get_port_groups({'tenant_id': tenant_id})
-        for pg in pgs:
-            if pg.get_name() == name:
-                LOG.debug("Deleting pg %(id)s", {"id": pg.get_id()})
-                self.mido_api.delete_port_group(pg.get_id())
-
-    @handle_api_error
-    def add_port_to_port_group_by_name(self, tenant_id, name, port_id):
-        """Add a port to a port group with the given name."""
-        LOG.debug("MidoClient.add_port_to_port_group_by_name called: "
-                  "tenant_id=%(tenant_id)s name=%(name)s "
-                  "port_id=%(port_id)s",
-                  {"tenant_id": tenant_id, "name": name, "port_id": port_id})
-        pg = self.get_port_group_by_name(tenant_id, name)
-        if pg is None:
-            raise MidonetResourceNotFound(resource_type='PortGroup', id=name)
-
-        pg = pg.add_port_group_port().port_id(port_id).create()
-        return pg
-
-    @handle_api_error
-    def remove_port_from_port_groups(self, port_id):
-        """Remove a port binding from all the port groups."""
-        LOG.debug("MidoClient.remove_port_from_port_groups called: "
-                  "port_id=%(port_id)s", {"port_id": port_id})
-        port = self.get_port(port_id)
-        for pg in port.get_port_groups():
-            pg.delete()
-
-    @handle_api_error
-    def add_chain_rule(self, chain, action='accept', **kwargs):
-        """Create a new accept chain rule."""
-        self.mido_api.add_chain_rule(chain, action, **kwargs)
index b538625fe793505597c7897489661dc005ce382a..0082ecd32e943e45f96321d32c4a9ab3149c0904 100644 (file)
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import functools
-
-from midonetclient import api
-from midonetclient import exc
-from midonetclient.neutron import client as n_client
 from oslo.config import cfg
-from oslo.utils import excutils
-from sqlalchemy.orm import exc as sa_exc
-from webob import exc as w_exc
-
-from neutron.api.rpc.handlers import dhcp_rpc
-from neutron.api.rpc.handlers import metadata_rpc
-from neutron.api.v2 import attributes
-from neutron.common import constants
-from neutron.common import exceptions as n_exc
-from neutron.common import rpc as n_rpc
-from neutron.common import topics
-from neutron.db import agents_db
-from neutron.db import agentschedulers_db
-from neutron.db import db_base_plugin_v2
-from neutron.db import external_net_db
-from neutron.db import l3_db
-from neutron.db import models_v2
-from neutron.db import portbindings_db
-from neutron.db import securitygroups_db
-from neutron.extensions import external_net as ext_net
-from neutron.extensions import l3
-from neutron.extensions import portbindings
-from neutron.extensions import securitygroup as ext_sg
-from neutron.i18n import _LE, _LW
-from neutron.openstack.common import log as logging
-from neutron.plugins.midonet.common import config  # noqa
-from neutron.plugins.midonet.common import net_util
-from neutron.plugins.midonet import midonet_lib
-
-LOG = logging.getLogger(__name__)
-
-EXTERNAL_GW_INFO = l3.EXTERNAL_GW_INFO
-
-METADATA_DEFAULT_IP = "169.254.169.254/32"
-OS_FLOATING_IP_RULE_KEY = 'OS_FLOATING_IP'
-OS_SG_RULE_KEY = 'OS_SG_RULE_ID'
-OS_TENANT_ROUTER_RULE_KEY = 'OS_TENANT_ROUTER_RULE'
-PRE_ROUTING_CHAIN_NAME = "OS_PRE_ROUTING_%s"
-PORT_INBOUND_CHAIN_NAME = "OS_PORT_%s_INBOUND"
-PORT_OUTBOUND_CHAIN_NAME = "OS_PORT_%s_OUTBOUND"
-POST_ROUTING_CHAIN_NAME = "OS_POST_ROUTING_%s"
-SG_INGRESS_CHAIN_NAME = "OS_SG_%s_INGRESS"
-SG_EGRESS_CHAIN_NAME = "OS_SG_%s_EGRESS"
-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.
-
-    From the route type given, determine the source and target IP addresses
-    from the provided floating IP DB object.
-    """
-    if type == 'pre-routing':
-        return fip["floating_ip_address"], fip["fixed_ip_address"]
-    elif type == 'post-routing':
-        return fip["fixed_ip_address"], fip["floating_ip_address"]
-    else:
-        raise ValueError(_("Invalid nat_type %s") % type)
-
-
-def _nat_chain_names(router_id):
-    """Get the chain names for NAT.
-
-    These names are used to associate MidoNet chains to the NAT rules
-    applied to the router.  For each of these, there are two NAT types,
-    'dnat' and 'snat' that are returned as keys, and the corresponding
-    chain names as their values.
-    """
-    pre_routing_name = PRE_ROUTING_CHAIN_NAME % router_id
-    post_routing_name = POST_ROUTING_CHAIN_NAME % router_id
-    return {'pre-routing': pre_routing_name, 'post-routing': post_routing_name}
-
-
-def _sg_chain_names(sg_id):
-    """Get the chain names for security group.
-
-    These names are used to associate a security group to MidoNet chains.
-    There are two names for ingress and egress security group directions.
-    """
-    ingress = SG_INGRESS_CHAIN_NAME % sg_id
-    egress = SG_EGRESS_CHAIN_NAME % sg_id
-    return {'ingress': ingress, 'egress': egress}
-
-
-def _port_chain_names(port_id):
-    """Get the chain names for a port.
-
-    These are chains to hold security group chains.
-    """
-    inbound = PORT_INBOUND_CHAIN_NAME % port_id
-    outbound = PORT_OUTBOUND_CHAIN_NAME % port_id
-    return {'inbound': inbound, 'outbound': outbound}
-
-
-def _sg_port_group_name(sg_id):
-    """Get the port group name for security group..
-
-    This name is used to associate a security group to MidoNet  port groups.
-    """
-    return SG_PORT_GROUP_NAME % sg_id
-
-
-def _rule_direction(sg_direction):
-    """Convert the SG direction to MidoNet direction
 
-    MidoNet terms them 'inbound' and 'outbound' instead of 'ingress' and
-    'egress'.  Also, the direction is reversed since MidoNet sees it
-    from the network port's point of view, not the VM's.
-    """
-    if sg_direction == 'ingress':
-        return 'outbound'
-    elif sg_direction == 'egress':
-        return 'inbound'
-    else:
-        raise ValueError(_("Unrecognized direction %s") % sg_direction)
+from midonet.neutron import plugin
 
+midonet_opts = [
+    cfg.StrOpt('midonet_uri', default='http://localhost:8080/midonet-api',
+               help=_('MidoNet API server URI.')),
+    cfg.StrOpt('username', default='admin',
+               help=_('MidoNet admin username.')),
+    cfg.StrOpt('password', default='passw0rd',
+               secret=True,
+               help=_('MidoNet admin password.')),
+    cfg.StrOpt('project_id',
+               default='77777777-7777-7777-7777-777777777777',
+               help=_('ID of the project that MidoNet admin user'
+                      'belongs to.'))
+]
 
-def _is_router_interface_port(port):
-    """Check whether the given port is a router interface port."""
-    device_owner = port['device_owner']
-    return (device_owner in l3_db.DEVICE_OWNER_ROUTER_INTF)
 
+cfg.CONF.register_opts(midonet_opts, "MIDONET")
 
-def _is_router_gw_port(port):
-    """Check whether the given port is a router gateway port."""
-    device_owner = port['device_owner']
-    return (device_owner in l3_db.DEVICE_OWNER_ROUTER_GW)
 
+class MidonetPluginV2(plugin.MidonetMixin):
 
-def _is_vif_port(port):
-    """Check whether the given port is a standard VIF port."""
-    device_owner = port['device_owner']
-    return (not _is_dhcp_port(port) and
-            device_owner not in (l3_db.DEVICE_OWNER_ROUTER_GW,
-                                 l3_db.DEVICE_OWNER_ROUTER_INTF))
-
-
-def _is_dhcp_port(port):
-    """Check whether the given port is a DHCP port."""
-    device_owner = port['device_owner']
-    return device_owner.startswith(constants.DEVICE_OWNER_DHCP)
-
-
-def _check_resource_exists(func, id, name, raise_exc=False):
-    """Check whether the given resource exists in MidoNet data store."""
-    try:
-        func(id)
-    except midonet_lib.MidonetResourceNotFound as exc:
-        LOG.error(_LE("There is no %(name)s with ID %(id)s in MidoNet."),
-                  {"name": name, "id": id})
-        if raise_exc:
-            raise MidonetPluginException(msg=exc)
-
-
-class MidonetPluginException(n_exc.NeutronException):
-    message = _("%(msg)s")
-
-
-class MidonetPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
-                      portbindings_db.PortBindingMixin,
-                      external_net_db.External_net_db_mixin,
-                      l3_db.L3_NAT_db_mixin,
-                      agentschedulers_db.DhcpAgentSchedulerDbMixin,
-                      securitygroups_db.SecurityGroupDbMixin):
-
+    vendor_extensions = plugin.MidonetMixin.supported_extension_aliases
     supported_extension_aliases = ['external-net', 'router', 'security-group',
                                    'agent', 'dhcp_agent_scheduler', 'binding',
-                                   'quotas']
-    __native_bulk_support = False
+                                   'quotas'] + vendor_extensions
+
+    __native_bulk_support = True
 
     def __init__(self):
         super(MidonetPluginV2, self).__init__()
-        # Read config values
-        midonet_conf = cfg.CONF.MIDONET
-        midonet_uri = midonet_conf.midonet_uri
-        admin_user = midonet_conf.username
-        admin_pass = midonet_conf.password
-        admin_project_id = midonet_conf.project_id
-        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)
-        self.client = midonet_lib.MidoClient(self.mido_api)
-
-        # self.provider_router_id should have been set.
-        if self.provider_router_id is None:
-            msg = _('provider_router_id should be configured in the plugin '
-                    'config file')
-            LOG.exception(msg)
-            raise MidonetPluginException(msg=msg)
-
-        self.setup_rpc()
-
-        self.base_binding_dict = {
-            portbindings.VIF_TYPE: portbindings.VIF_TYPE_MIDONET,
-            portbindings.VIF_DETAILS: {
-                # TODO(rkukura): Replace with new VIF security details
-                portbindings.CAP_PORT_FILTER:
-                'security-group' in self.supported_extension_aliases}}
-
-    def _get_provider_router(self):
-        if self.provider_router is None:
-            self.provider_router = self.client.get_router(
-                self.provider_router_id)
-        return self.provider_router
-
-    def _dhcp_mappings(self, context, fixed_ips, mac):
-        for fixed_ip in fixed_ips:
-            subnet = self._get_subnet(context, fixed_ip["subnet_id"])
-            if subnet["ip_version"] == 6:
-                # TODO(ryu) handle IPv6
-                continue
-            if not subnet["enable_dhcp"]:
-                # Skip if DHCP is disabled
-                continue
-            yield subnet['cidr'], fixed_ip["ip_address"], mac
-
-    def _metadata_subnets(self, context, fixed_ips):
-        for fixed_ip in fixed_ips:
-            subnet = self._get_subnet(context, fixed_ip["subnet_id"])
-            if subnet["ip_version"] == 6:
-                continue
-            yield subnet['cidr'], fixed_ip["ip_address"]
-
-    def _initialize_port_chains(self, port, in_chain, out_chain, sg_ids):
-
-        tenant_id = port["tenant_id"]
-
-        position = 1
-        # mac spoofing protection
-        self._add_chain_rule(in_chain, action='drop',
-                             dl_src=port["mac_address"], inv_dl_src=True,
-                             position=position)
-
-        # ip spoofing protection
-        for fixed_ip in port["fixed_ips"]:
-            position += 1
-            self._add_chain_rule(in_chain, action="drop",
-                                 src_addr=fixed_ip["ip_address"] + "/32",
-                                 inv_nw_src=True, dl_type=0x0800,  # IPv4
-                                 position=position)
-
-        # conntrack
-        position += 1
-        self._add_chain_rule(in_chain, action='accept',
-                             match_forward_flow=True,
-                             position=position)
-
-        # Reset the position to process egress
-        position = 1
-
-        # Add rule for SGs
-        if sg_ids:
-            for sg_id in sg_ids:
-                chain_name = _sg_chain_names(sg_id)["ingress"]
-                chain = self.client.get_chain_by_name(tenant_id, chain_name)
-                self._add_chain_rule(out_chain, action='jump',
-                                     jump_chain_id=chain.get_id(),
-                                     jump_chain_name=chain_name,
-                                     position=position)
-                position += 1
-
-        # add reverse flow matching at the end
-        self._add_chain_rule(out_chain, action='accept',
-                             match_return_flow=True,
-                             position=position)
-        position += 1
-
-        # fall back DROP rule at the end except for ARP
-        self._add_chain_rule(out_chain, action='drop',
-                             dl_type=0x0806,  # ARP
-                             inv_dl_type=True, position=position)
-
-    def _bind_port_to_sgs(self, context, port, sg_ids):
-        self._process_port_create_security_group(context, port, sg_ids)
-        if sg_ids is not None:
-            for sg_id in sg_ids:
-                pg_name = _sg_port_group_name(sg_id)
-                self.client.add_port_to_port_group_by_name(
-                    port["tenant_id"], pg_name, port["id"])
-
-    def _unbind_port_from_sgs(self, context, port_id):
-        self._delete_port_security_group_bindings(context, port_id)
-        self.client.remove_port_from_port_groups(port_id)
-
-    def _create_accept_chain_rule(self, context, sg_rule, chain=None):
-        direction = sg_rule["direction"]
-        tenant_id = sg_rule["tenant_id"]
-        sg_id = sg_rule["security_group_id"]
-        chain_name = _sg_chain_names(sg_id)[direction]
-
-        if chain is None:
-            chain = self.client.get_chain_by_name(tenant_id, chain_name)
-
-        pg_id = None
-        if sg_rule["remote_group_id"] is not None:
-            pg_name = _sg_port_group_name(sg_id)
-            pg = self.client.get_port_group_by_name(tenant_id, pg_name)
-            pg_id = pg.get_id()
-
-        props = {OS_SG_RULE_KEY: str(sg_rule["id"])}
-
-        # Determine source or destination address by looking at direction
-        src_pg_id = dst_pg_id = None
-        src_addr = dst_addr = None
-        src_port_to = dst_port_to = None
-        src_port_from = dst_port_from = None
-        if direction == "egress":
-            dst_pg_id = pg_id
-            dst_addr = sg_rule["remote_ip_prefix"]
-            dst_port_from = sg_rule["port_range_min"]
-            dst_port_to = sg_rule["port_range_max"]
-        else:
-            src_pg_id = pg_id
-            src_addr = sg_rule["remote_ip_prefix"]
-            src_port_from = sg_rule["port_range_min"]
-            src_port_to = sg_rule["port_range_max"]
-
-        return self._add_chain_rule(
-            chain, action='accept', port_group_src=src_pg_id,
-            port_group_dst=dst_pg_id,
-            src_addr=src_addr, src_port_from=src_port_from,
-            src_port_to=src_port_to,
-            dst_addr=dst_addr, dst_port_from=dst_port_from,
-            dst_port_to=dst_port_to,
-            nw_proto=net_util.get_protocol_value(sg_rule["protocol"]),
-            dl_type=net_util.get_ethertype_value(sg_rule["ethertype"]),
-            properties=props)
-
-    def _remove_nat_rules(self, context, fip):
-        router = self.client.get_router(fip["router_id"])
-        self.client.remove_static_route(self._get_provider_router(),
-                                        fip["floating_ip_address"])
-
-        chain_names = _nat_chain_names(router.get_id())
-        for _type, name in chain_names.iteritems():
-            self.client.remove_rules_by_property(
-                router.get_tenant_id(), name,
-                OS_FLOATING_IP_RULE_KEY, fip["id"])
-
-    def setup_rpc(self):
-        # RPC support
-        self.topic = topics.PLUGIN
-        self.conn = n_rpc.create_connection(new=True)
-        self.endpoints = [dhcp_rpc.DhcpRpcCallback(),
-                          agents_db.AgentExtRpcCallback(),
-                          metadata_rpc.MetadataRpcCallback()]
-        self.conn.create_consumer(self.topic, self.endpoints,
-                                  fanout=False)
-        # Consume from all consumers in threads
-        self.conn.consume_in_threads()
-
-    def create_subnet(self, context, subnet):
-        """Create Neutron subnet.
-
-        Creates a Neutron subnet and a DHCP entry in MidoNet bridge.
-        """
-        LOG.debug("MidonetPluginV2.create_subnet called: subnet=%r", subnet)
-
-        s = subnet["subnet"]
-        net = super(MidonetPluginV2, self).get_network(
-            context, subnet['subnet']['network_id'], fields=None)
-
-        session = context.session
-        with session.begin(subtransactions=True):
-            sn_entry = super(MidonetPluginV2, self).create_subnet(context,
-                                                                  subnet)
-            bridge = self.client.get_bridge(sn_entry['network_id'])
-
-            gateway_ip = s['gateway_ip']
-            cidr = s['cidr']
-            if s['enable_dhcp']:
-                dns_nameservers = None
-                host_routes = None
-                if s['dns_nameservers'] is not attributes.ATTR_NOT_SPECIFIED:
-                    dns_nameservers = s['dns_nameservers']
-
-                if s['host_routes'] is not attributes.ATTR_NOT_SPECIFIED:
-                    host_routes = s['host_routes']
-
-                self.client.create_dhcp(bridge, gateway_ip, cidr,
-                                        host_rts=host_routes,
-                                        dns_servers=dns_nameservers)
-
-            # For external network, link the bridge to the provider router.
-            if net['router:external']:
-                self._link_bridge_to_gw_router(
-                    bridge, self._get_provider_router(), gateway_ip, cidr)
-
-        LOG.debug("MidonetPluginV2.create_subnet exiting: sn_entry=%r",
-                  sn_entry)
-        return sn_entry
-
-    def delete_subnet(self, context, id):
-        """Delete Neutron subnet.
-
-        Delete neutron network and its corresponding MidoNet bridge.
-        """
-        LOG.debug("MidonetPluginV2.delete_subnet called: id=%s", id)
-        subnet = super(MidonetPluginV2, self).get_subnet(context, id,
-                                                         fields=None)
-        net = super(MidonetPluginV2, self).get_network(context,
-                                                       subnet['network_id'],
-                                                       fields=None)
-        session = context.session
-        with session.begin(subtransactions=True):
-
-            super(MidonetPluginV2, self).delete_subnet(context, id)
-            bridge = self.client.get_bridge(subnet['network_id'])
-            if subnet['enable_dhcp']:
-                self.client.delete_dhcp(bridge, subnet['cidr'])
-
-            # If the network is external, clean up routes, links, ports
-            if net[ext_net.EXTERNAL]:
-                self._unlink_bridge_from_gw_router(
-                    bridge, self._get_provider_router())
-
-            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',
-                  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)
-
-        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)
-        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})
-
-        with context.session.begin(subtransactions=True):
-            net = super(MidonetPluginV2, self).update_network(
-                context, id, network)
-            self._process_l3_update(context, net, network['network'])
-            self.api_cli.update_network(id, net)
-
-        LOG.debug("MidonetPluginV2.update_network exiting: net=%r", net)
-        return net
-
-    @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)
-
-        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."""
-        LOG.debug("MidonetPluginV2.create_port called: port=%r", port)
-        port_data = port['port']
-
-        # Create a bridge port in MidoNet and set the bridge port ID as the
-        # port ID in Neutron.
-        bridge = self.client.get_bridge(port_data["network_id"])
-        tenant_id = bridge.get_tenant_id()
-        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):
-                # Create a Neutron port
-                new_port = super(MidonetPluginV2, self).create_port(context,
-                                                                    port)
-                port_data.update(new_port)
-                self._ensure_default_security_group_on_port(context,
-                                                            port)
-                if _is_vif_port(port_data):
-                    # Bind security groups to the port
-                    sg_ids = self._get_security_groups_on_port(context, port)
-                    self._bind_port_to_sgs(context, new_port, sg_ids)
-
-                    # Create port chains
-                    port_chains = {}
-                    for d, name in _port_chain_names(
-                            new_port["id"]).iteritems():
-                        port_chains[d] = self.client.create_chain(tenant_id,
-                                                                  name)
-
-                    self._initialize_port_chains(port_data,
-                                                 port_chains['inbound'],
-                                                 port_chains['outbound'],
-                                                 sg_ids)
-
-                    # Update the port with the chain
-                    self.client.update_port_chains(
-                        bridge_port, port_chains["inbound"].get_id(),
-                        port_chains["outbound"].get_id())
-
-                    # DHCP mapping is only for VIF ports
-                    for cidr, ip, mac in self._dhcp_mappings(
-                            context, port_data["fixed_ips"],
-                            port_data["mac_address"]):
-                        self.client.add_dhcp_host(bridge, cidr, ip, mac)
-
-                elif _is_dhcp_port(port_data):
-                    # For DHCP port, add a metadata route
-                    for cidr, ip in self._metadata_subnets(
-                            context, port_data["fixed_ips"]):
-                        self.client.add_dhcp_route_option(bridge, cidr, ip,
-                                                          METADATA_DEFAULT_IP)
-
-            self._process_portbindings_create_and_update(context,
-                                                         port_data, new_port)
-        except Exception as ex:
-            # Try removing the MidoNet port before raising an exception.
-            with excutils.save_and_reraise_exception():
-                LOG.error(_LE("Failed to create a port on network %(net_id)s: "
-                            "%(err)s"),
-                          {"net_id": port_data["network_id"], "err": ex})
-                self.client.delete_port(bridge_port.get_id())
-
-        LOG.debug("MidonetPluginV2.create_port exiting: port=%r", new_port)
-        return new_port
-
-    def get_port(self, context, id, fields=None):
-        """Retrieve port."""
-        LOG.debug("MidonetPluginV2.get_port called: id=%(id)s "
-                  "fields=%(fields)r", {'id': id, 'fields': fields})
-        port = super(MidonetPluginV2, self).get_port(context, id, fields)
-        # Check if the port exists in MidoNet DB
-        try:
-            self.client.get_port(id)
-        except midonet_lib.MidonetResourceNotFound as exc:
-            LOG.error(_LE("There is no port with ID %(id)s in MidoNet."),
-                      {"id": id})
-            port['status'] = constants.PORT_STATUS_ERROR
-            raise exc
-        LOG.debug("MidonetPluginV2.get_port exiting: port=%r", port)
-        return port
-
-    def get_ports(self, context, filters=None, fields=None):
-        """List neutron ports and verify that they exist in MidoNet."""
-        LOG.debug("MidonetPluginV2.get_ports called: filters=%(filters)s "
-                  "fields=%(fields)r",
-                  {'filters': filters, 'fields': fields})
-        ports = super(MidonetPluginV2, self).get_ports(context, filters,
-                                                       fields)
-        return ports
-
-    def delete_port(self, context, id, l3_port_check=True):
-        """Delete a neutron port and corresponding MidoNet bridge port."""
-        LOG.debug("MidonetPluginV2.delete_port called: id=%(id)s "
-                  "l3_port_check=%(l3_port_check)r",
-                  {'id': id, 'l3_port_check': l3_port_check})
-        # if needed, check to see if this is a port owned by
-        # and l3-router.  If so, we should prevent deletion.
-        if l3_port_check:
-            self.prevent_l3_port_deletion(context, id)
-
-        self.disassociate_floatingips(context, id)
-        port = self.get_port(context, id)
-        device_id = port['device_id']
-        # If this port is for router interface/gw, unlink and delete.
-        if _is_router_interface_port(port):
-            self._unlink_bridge_from_router(device_id, id)
-        elif _is_router_gw_port(port):
-            # Gateway removed
-            # Remove all the SNAT rules that are tagged.
-            router = self._get_router(context, device_id)
-            tenant_id = router["tenant_id"]
-            chain_names = _nat_chain_names(device_id)
-            for _type, name in chain_names.iteritems():
-                self.client.remove_rules_by_property(
-                    tenant_id, name, OS_TENANT_ROUTER_RULE_KEY,
-                    SNAT_RULE)
-            # Remove the default routes and unlink
-            self._remove_router_gateway(port['device_id'])
-
-        self.client.delete_port(id, delete_chains=True)
-        try:
-            for cidr, ip, mac in self._dhcp_mappings(
-                    context, port["fixed_ips"], port["mac_address"]):
-                self.client.delete_dhcp_host(port["network_id"], cidr, ip,
-                                             mac)
-        except Exception:
-            LOG.error(_LE("Failed to delete DHCP mapping for port %(id)s"),
-                      {"id": id})
-
-        super(MidonetPluginV2, self).delete_port(context, id)
-
-    def update_port(self, context, id, port):
-        """Handle port update, including security groups and fixed IPs."""
-        with context.session.begin(subtransactions=True):
-
-            # Get the port and save the fixed IPs
-            old_port = self._get_port(context, id)
-            net_id = old_port["network_id"]
-            mac = old_port["mac_address"]
-            old_ips = old_port["fixed_ips"]
-            # 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)
-                # If it's a DHCP port, add a route to reach the MD server
-                if _is_dhcp_port(p):
-                    for cidr, ip in self._metadata_subnets(
-                        context, new_ips):
-                        self.client.add_dhcp_route_option(
-                            bridge, cidr, ip, METADATA_DEFAULT_IP)
-                else:
-                    # IPs have changed.  Re-map the DHCP entries
-                    for cidr, ip, mac in self._dhcp_mappings(
-                            context, old_ips, mac):
-                        self.client.remove_dhcp_host(
-                            bridge, cidr, ip, mac)
-
-                    for cidr, ip, mac in self._dhcp_mappings(
-                        context, new_ips, mac):
-                        self.client.add_dhcp_host(
-                            bridge, cidr, ip, mac)
-
-            if (self._check_update_deletes_security_groups(port) or
-                    self._check_update_has_security_groups(port)):
-                self._unbind_port_from_sgs(context, p["id"])
-                sg_ids = self._get_security_groups_on_port(context, port)
-                self._bind_port_to_sgs(context, p, sg_ids)
-
-            self._process_portbindings_create_and_update(context,
-                                                         port['port'],
-                                                         p)
-        return p
-
-    def create_router(self, context, router):
-        """Handle router creation.
-
-        When a new Neutron router is created, its corresponding MidoNet router
-        is also created.  In MidoNet, this router is initialized with chains
-        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.
-        """
-
-        # NOTE(dcahill): Similar to the NSX plugin, we completely override
-        # this method in order to be able to use the MidoNet ID as Neutron ID
-        # TODO(dcahill): Propose upstream patch for allowing
-        # 3rd parties to specify IDs as we do with l2 plugin
-        LOG.debug("MidonetPluginV2.create_router called: router=%(router)s",
-                  {"router": router})
-        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:
-            has_gw_info = False
-            if EXTERNAL_GW_INFO in r:
-                has_gw_info = True
-                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
-                router_db = l3_db.Router(id=mido_router_id,
-                                         tenant_id=tenant_id,
-                                         name=r['name'],
-                                         admin_state_up=r['admin_state_up'],
-                                         status="ACTIVE")
-                context.session.add(router_db)
-                if has_gw_info:
-                    self._update_router_gw_info(context, router_db['id'],
-                                                gw_info)
-
-            router_data = self._make_router_dict(router_db)
-
-        except Exception:
-            # Try removing the midonet router
-            with excutils.save_and_reraise_exception():
-                self.client.delete_router(mido_router_id)
-
-        # Create router chains
-        chain_names = _nat_chain_names(mido_router_id)
-        try:
-            self.client.add_router_chains(mido_router,
-                                          chain_names["pre-routing"],
-                                          chain_names["post-routing"])
-        except Exception:
-            # Set the router status to Error
-            with context.session.begin(subtransactions=True):
-                r = self._get_router(context, router_data["id"])
-                router_data['status'] = constants.NET_STATUS_ERROR
-                r['status'] = router_data['status']
-                context.session.add(r)
-
-        LOG.debug("MidonetPluginV2.create_router exiting: "
-                  "router_data=%(router_data)s.",
-                  {"router_data": router_data})
-        return router_data
-
-    def _set_router_gateway(self, id, gw_router, gw_ip):
-        """Set router uplink gateway
-
-        :param ID: ID of the router
-        :param gw_router: gateway router to link to
-        :param gw_ip: gateway IP address
-        """
-        LOG.debug("MidonetPluginV2.set_router_gateway called: id=%(id)s, "
-                  "gw_router=%(gw_router)s, gw_ip=%(gw_ip)s",
-                  {'id': id, 'gw_router': gw_router, 'gw_ip': gw_ip}),
-
-        router = self.client.get_router(id)
-
-        # Create a port in the gw router
-        gw_port = self.client.add_router_port(gw_router,
-                                              port_address='169.254.255.1',
-                                              network_address='169.254.255.0',
-                                              network_length=30)
-
-        # Create a port in the router
-        port = self.client.add_router_port(router,
-                                           port_address='169.254.255.2',
-                                           network_address='169.254.255.0',
-                                           network_length=30)
-
-        # Link them
-        self.client.link(gw_port, port.get_id())
-
-        # Add a route for gw_ip to bring it down to the router
-        self.client.add_router_route(gw_router, type='Normal',
-                                     src_network_addr='0.0.0.0',
-                                     src_network_length=0,
-                                     dst_network_addr=gw_ip,
-                                     dst_network_length=32,
-                                     next_hop_port=gw_port.get_id(),
-                                     weight=100)
-
-        # Add default route to uplink in the router
-        self.client.add_router_route(router, type='Normal',
-                                     src_network_addr='0.0.0.0',
-                                     src_network_length=0,
-                                     dst_network_addr='0.0.0.0',
-                                     dst_network_length=0,
-                                     next_hop_port=port.get_id(),
-                                     weight=100)
-
-    def _remove_router_gateway(self, id):
-        """Clear router gateway
-
-        :param ID: ID of the router
-        """
-        LOG.debug("MidonetPluginV2.remove_router_gateway called: "
-                  "id=%(id)s", {'id': id})
-        router = self.client.get_router(id)
-
-        # delete the port that is connected to the gateway router
-        for p in router.get_ports():
-            if p.get_port_address() == '169.254.255.2':
-                peer_port_id = p.get_peer_id()
-                if peer_port_id is not None:
-                    self.client.unlink(p)
-                    self.client.delete_port(peer_port_id)
-
-        # delete default route
-        for r in router.get_routes():
-            if (r.get_dst_network_addr() == '0.0.0.0' and
-                    r.get_dst_network_length() == 0):
-                self.client.delete_route(r.get_id())
-
-    def update_router(self, context, id, router):
-        """Handle router updates."""
-        LOG.debug("MidonetPluginV2.update_router called: id=%(id)s "
-                  "router=%(router)r", {"id": id, "router": router})
-
-        router_data = router["router"]
-
-        # Check if the update included changes to the gateway.
-        gw_updated = l3_db.EXTERNAL_GW_INFO in router_data
-        with context.session.begin(subtransactions=True):
-
-            # Update the Neutron DB
-            r = super(MidonetPluginV2, self).update_router(context, id,
-                                                           router)
-            tenant_id = r["tenant_id"]
-            if gw_updated:
-                if (l3_db.EXTERNAL_GW_INFO in r and
-                        r[l3_db.EXTERNAL_GW_INFO] is not None):
-                    # Gateway created
-                    gw_port_neutron = self._get_port(
-                        context.elevated(), r["gw_port_id"])
-                    gw_ip = gw_port_neutron['fixed_ips'][0]['ip_address']
-
-                    # First link routers and set up the routes
-                    self._set_router_gateway(r["id"],
-                                             self._get_provider_router(),
-                                             gw_ip)
-                    gw_port_midonet = self.client.get_link_port(
-                        self._get_provider_router(), r["id"])
-
-                    # Get the NAT chains and add dynamic SNAT rules.
-                    chain_names = _nat_chain_names(r["id"])
-                    props = {OS_TENANT_ROUTER_RULE_KEY: SNAT_RULE}
-                    self.client.add_dynamic_snat(tenant_id,
-                                                 chain_names['pre-routing'],
-                                                 chain_names['post-routing'],
-                                                 gw_ip,
-                                                 gw_port_midonet.get_id(),
-                                                 **props)
-
-            self.client.update_router(id, **router_data)
-
-        LOG.debug("MidonetPluginV2.update_router exiting: router=%r", r)
-        return r
-
-    def delete_router(self, context, id):
-        """Handler for router deletion.
-
-        Deleting a router on Neutron simply means deleting its corresponding
-        router in MidoNet.
-
-        :param id: router ID to remove
-        """
-        LOG.debug("MidonetPluginV2.delete_router called: id=%s", id)
-
-        self.client.delete_router_chains(id)
-        self.client.delete_router(id)
-
-        super(MidonetPluginV2, self).delete_router(context, id)
-
-    def _link_bridge_to_gw_router(self, bridge, gw_router, gw_ip, cidr):
-        """Link a bridge to the gateway router
-
-        :param bridge:  bridge
-        :param gw_router: gateway router to link to
-        :param gw_ip: IP address of gateway
-        :param cidr: network CIDR
-        """
-        net_addr, net_len = net_util.net_addr(cidr)
-
-        # create a port on the gateway router
-        gw_port = self.client.add_router_port(gw_router, port_address=gw_ip,
-                                              network_address=net_addr,
-                                              network_length=net_len)
-
-        # create a bridge port, then link it to the router.
-        port = self.client.add_bridge_port(bridge)
-        self.client.link(gw_port, port.get_id())
-
-        # add a route for the subnet in the gateway router
-        self.client.add_router_route(gw_router, type='Normal',
-                                     src_network_addr='0.0.0.0',
-                                     src_network_length=0,
-                                     dst_network_addr=net_addr,
-                                     dst_network_length=net_len,
-                                     next_hop_port=gw_port.get_id(),
-                                     weight=100)
-
-    def _unlink_bridge_from_gw_router(self, bridge, gw_router):
-        """Unlink a bridge from the gateway router
-
-        :param bridge: bridge to unlink
-        :param gw_router: gateway router to unlink from
-        """
-        # Delete routes and unlink the router and the bridge.
-        routes = self.client.get_router_routes(gw_router.get_id())
-
-        bridge_ports_to_delete = [
-            p for p in gw_router.get_peer_ports()
-            if p.get_device_id() == bridge.get_id()]
-
-        for p in bridge.get_peer_ports():
-            if p.get_device_id() == gw_router.get_id():
-                # delete the routes going to the bridge
-                for r in routes:
-                    if r.get_next_hop_port() == p.get_id():
-                        self.client.delete_route(r.get_id())
-                self.client.unlink(p)
-                self.client.delete_port(p.get_id())
-
-        # delete bridge port
-        for port in bridge_ports_to_delete:
-            self.client.delete_port(port.get_id())
-
-    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, 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,
-                                     dst_network_addr=net_addr,
-                                     dst_network_length=net_len,
-                                     next_hop_port=router_port.get_id(),
-                                     weight=100)
-
-        if metadata_gw_ip:
-            # Add a route for the metadata server.
-            # Not all VM images supports DHCP option 121.  Add a route for the
-            # Metadata server in the router to forward the packet to the bridge
-            # that will send them to the Metadata Proxy.
-            md_net_addr, md_net_len = net_util.net_addr(METADATA_DEFAULT_IP)
-            self.client.add_router_route(
-                router, type='Normal', src_network_addr=net_addr,
-                src_network_length=net_len,
-                dst_network_addr=md_net_addr,
-                dst_network_length=md_net_len,
-                next_hop_port=router_port.get_id(),
-                next_hop_gateway=metadata_gw_ip)
-
-    def _unlink_bridge_from_router(self, router_id, bridge_port_id):
-        """Unlink a bridge from a router."""
-
-        # Remove the routes to the port and unlink the port
-        bridge_port = self.client.get_port(bridge_port_id)
-        routes = self.client.get_router_routes(router_id)
-        self.client.delete_port_routes(routes, bridge_port.get_peer_id())
-        self.client.unlink(bridge_port)
-
-    def add_router_interface(self, context, router_id, interface_info):
-        """Handle router linking with network."""
-        LOG.debug("MidonetPluginV2.add_router_interface called: "
-                  "router_id=%(router_id)s "
-                  "interface_info=%(interface_info)r",
-                  {'router_id': router_id, 'interface_info': interface_info})
-
-        with context.session.begin(subtransactions=True):
-            info = super(MidonetPluginV2, self).add_router_interface(
-                context, router_id, interface_info)
-
-        try:
-            subnet = self._get_subnet(context, info["subnet_id"])
-            cidr = subnet["cidr"]
-            net_addr, net_len = net_util.net_addr(cidr)
-            router = self.client.get_router(router_id)
-
-            # Get the metadata GW IP
-            metadata_gw_ip = None
-            rport_qry = context.session.query(models_v2.Port)
-            dhcp_ports = rport_qry.filter_by(
-                network_id=subnet["network_id"],
-                device_owner=constants.DEVICE_OWNER_DHCP).all()
-            if dhcp_ports and dhcp_ports[0].fixed_ips:
-                metadata_gw_ip = dhcp_ports[0].fixed_ips[0].ip_address
-            else:
-                LOG.warn(_LW("DHCP agent is not working correctly. No port "
-                             "to reach the Metadata server on this network"))
-            # Link the router and the bridge
-            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:
-            LOG.error(_LE("Failed to create MidoNet resources to add router "
-                          "interface. info=%(info)s, router_id=%(router_id)s"),
-                      {"info": info, "router_id": router_id})
-            with excutils.save_and_reraise_exception():
-                with context.session.begin(subtransactions=True):
-                    self.remove_router_interface(context, router_id, info)
-
-        LOG.debug("MidonetPluginV2.add_router_interface exiting: "
-                  "info=%r", info)
-        return info
-
-    def _assoc_fip(self, fip):
-        router = self.client.get_router(fip["router_id"])
-        link_port = self.client.get_link_port(
-            self._get_provider_router(), router.get_id())
-        self.client.add_router_route(
-            self._get_provider_router(),
-            src_network_addr='0.0.0.0',
-            src_network_length=0,
-            dst_network_addr=fip["floating_ip_address"],
-            dst_network_length=32,
-            next_hop_port=link_port.get_peer_id())
-        props = {OS_FLOATING_IP_RULE_KEY: fip['id']}
-        tenant_id = router.get_tenant_id()
-        chain_names = _nat_chain_names(router.get_id())
-        for chain_type, name in chain_names.items():
-            src_ip, target_ip = _get_nat_ips(chain_type, fip)
-            if chain_type == 'pre-routing':
-                nat_type = 'dnat'
-            else:
-                nat_type = 'snat'
-            self.client.add_static_nat(tenant_id, name, src_ip,
-                                       target_ip,
-                                       link_port.get_id(),
-                                       nat_type, **props)
-
-    def create_floatingip(self, context, floatingip):
-        session = context.session
-        with session.begin(subtransactions=True):
-            fip = super(MidonetPluginV2, self).create_floatingip(
-                context, floatingip)
-            if fip['port_id']:
-                self._assoc_fip(fip)
-        return fip
-
-    def update_floatingip(self, context, id, floatingip):
-        """Handle floating IP association and disassociation."""
-        LOG.debug("MidonetPluginV2.update_floatingip called: id=%(id)s "
-                  "floatingip=%(floatingip)s ",
-                  {'id': id, 'floatingip': floatingip})
-
-        session = context.session
-        with session.begin(subtransactions=True):
-            if floatingip['floatingip']['port_id']:
-                fip = super(MidonetPluginV2, self).update_floatingip(
-                    context, id, floatingip)
-
-                self._assoc_fip(fip)
-
-            # disassociate floating IP
-            elif floatingip['floatingip']['port_id'] is None:
-                fip = super(MidonetPluginV2, self).get_floatingip(context, id)
-                self._remove_nat_rules(context, fip)
-                super(MidonetPluginV2, self).update_floatingip(context, id,
-                                                               floatingip)
-
-        LOG.debug("MidonetPluginV2.update_floating_ip exiting: fip=%s", fip)
-        return fip
-
-    def disassociate_floatingips(self, context, port_id):
-        """Disassociate floating IPs (if any) from this port."""
-        try:
-            fip_qry = context.session.query(l3_db.FloatingIP)
-            fip_dbs = fip_qry.filter_by(fixed_port_id=port_id)
-            for fip_db in fip_dbs:
-                self._remove_nat_rules(context, fip_db)
-        except sa_exc.NoResultFound:
-            pass
-
-        super(MidonetPluginV2, self).disassociate_floatingips(context, port_id)
-
-    def create_security_group(self, context, security_group, default_sg=False):
-        """Create security group.
-
-        Create a new security group, including the default security group.
-        In MidoNet, this means creating a pair of chains, inbound and outbound,
-        as well as a new port group.
-        """
-        LOG.debug("MidonetPluginV2.create_security_group called: "
-                  "security_group=%(security_group)s "
-                  "default_sg=%(default_sg)s ",
-                  {'security_group': security_group, 'default_sg': default_sg})
-
-        sg = security_group.get('security_group')
-        tenant_id = self._get_tenant_id_for_create(context, sg)
-        if not default_sg:
-            self._ensure_default_security_group(context, tenant_id)
-
-        # Create the Neutron sg first
-        sg = super(MidonetPluginV2, self).create_security_group(
-            context, security_group, default_sg)
-
-        try:
-            # Process the MidoNet side
-            self.client.create_port_group(tenant_id,
-                                          _sg_port_group_name(sg["id"]))
-            chain_names = _sg_chain_names(sg["id"])
-            chains = {}
-            for direction, chain_name in chain_names.iteritems():
-                c = self.client.create_chain(tenant_id, chain_name)
-                chains[direction] = c
-
-            # Create all the rules for this SG.  Only accept rules are created
-            for r in sg['security_group_rules']:
-                self._create_accept_chain_rule(context, r,
-                                               chain=chains[r['direction']])
-        except Exception:
-            LOG.error(_LE("Failed to create MidoNet resources for sg %(sg)r"),
-                      {"sg": sg})
-            with excutils.save_and_reraise_exception():
-                with context.session.begin(subtransactions=True):
-                    sg = self._get_security_group(context, sg["id"])
-                    context.session.delete(sg)
-
-        LOG.debug("MidonetPluginV2.create_security_group exiting: sg=%r",
-                  sg)
-        return sg
-
-    def delete_security_group(self, context, id):
-        """Delete chains for Neutron security group."""
-        LOG.debug("MidonetPluginV2.delete_security_group called: id=%s", id)
-
-        with context.session.begin(subtransactions=True):
-            sg = super(MidonetPluginV2, self).get_security_group(context, id)
-            if not sg:
-                raise ext_sg.SecurityGroupNotFound(id=id)
-
-            if sg["name"] == 'default' and not context.is_admin:
-                raise ext_sg.SecurityGroupCannotRemoveDefault()
-
-            sg_id = sg['id']
-            filters = {'security_group_id': [sg_id]}
-            if super(MidonetPluginV2, self)._get_port_security_group_bindings(
-                    context, filters):
-                raise ext_sg.SecurityGroupInUse(id=sg_id)
-
-            # Delete MidoNet Chains and portgroup for the SG
-            tenant_id = sg['tenant_id']
-            self.client.delete_chains_by_names(
-                tenant_id, _sg_chain_names(sg["id"]).values())
-
-            self.client.delete_port_group_by_name(
-                tenant_id, _sg_port_group_name(sg["id"]))
-
-            super(MidonetPluginV2, self).delete_security_group(context, id)
-
-    def create_security_group_rule(self, context, security_group_rule):
-        """Create a security group rule
-
-        Create a security group rule in the Neutron DB and corresponding
-        MidoNet resources in its data store.
-        """
-        LOG.debug("MidonetPluginV2.create_security_group_rule called: "
-                  "security_group_rule=%(security_group_rule)r",
-                  {'security_group_rule': security_group_rule})
-
-        with context.session.begin(subtransactions=True):
-            rule = super(MidonetPluginV2, self).create_security_group_rule(
-                context, security_group_rule)
-
-            self._create_accept_chain_rule(context, rule)
-
-            LOG.debug("MidonetPluginV2.create_security_group_rule exiting: "
-                      "rule=%r", rule)
-            return rule
-
-    def delete_security_group_rule(self, context, sg_rule_id):
-        """Delete a security group rule
-
-        Delete a security group rule from the Neutron DB and corresponding
-        MidoNet resources from its data store.
-        """
-        LOG.debug("MidonetPluginV2.delete_security_group_rule called: "
-                  "sg_rule_id=%s", sg_rule_id)
-        with context.session.begin(subtransactions=True):
-            rule = super(MidonetPluginV2, self).get_security_group_rule(
-                context, sg_rule_id)
-
-            if not rule:
-                raise ext_sg.SecurityGroupRuleNotFound(id=sg_rule_id)
-
-            sg = self._get_security_group(context,
-                                          rule["security_group_id"])
-            chain_name = _sg_chain_names(sg["id"])[rule["direction"]]
-            self.client.remove_rules_by_property(rule["tenant_id"], chain_name,
-                                                 OS_SG_RULE_KEY,
-                                                 str(rule["id"]))
-            super(MidonetPluginV2, self).delete_security_group_rule(
-                context, sg_rule_id)
-
-    def _add_chain_rule(self, chain, action, **kwargs):
-
-        nw_proto = kwargs.get("nw_proto")
-        src_addr = kwargs.pop("src_addr", None)
-        dst_addr = kwargs.pop("dst_addr", None)
-        src_port_from = kwargs.pop("src_port_from", None)
-        src_port_to = kwargs.pop("src_port_to", None)
-        dst_port_from = kwargs.pop("dst_port_from", None)
-        dst_port_to = kwargs.pop("dst_port_to", None)
-
-        # Convert to the keys and values that midonet client understands
-        if src_addr:
-            kwargs["nw_src_addr"], kwargs["nw_src_length"] = net_util.net_addr(
-                src_addr)
-
-        if dst_addr:
-            kwargs["nw_dst_addr"], kwargs["nw_dst_length"] = net_util.net_addr(
-                dst_addr)
-
-        kwargs["tp_src"] = {"start": src_port_from, "end": src_port_to}
-
-        kwargs["tp_dst"] = {"start": dst_port_from, "end": dst_port_to}
-
-        if nw_proto == 1:  # ICMP
-            # Overwrite port fields regardless of the direction
-            kwargs["tp_src"] = {"start": src_port_from, "end": src_port_from}
-            kwargs["tp_dst"] = {"start": dst_port_to, "end": dst_port_to}
-
-        return self.client.add_chain_rule(chain, action=action, **kwargs)
diff --git a/neutron/plugins/midonet/requirements.txt b/neutron/plugins/midonet/requirements.txt
new file mode 100644 (file)
index 0000000..fb9c6a5
--- /dev/null
@@ -0,0 +1 @@
+neutron-plugin-midonet
diff --git a/neutron/tests/unit/midonet/__init__.py b/neutron/tests/unit/midonet/__init__.py
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/neutron/tests/unit/midonet/etc/midonet.ini.test b/neutron/tests/unit/midonet/etc/midonet.ini.test
deleted file mode 100644 (file)
index 8e4fc84..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-[midonet]
-
-# MidoNet API server URI
-midonet_uri = http://localhost:8080/midonet-api
-
-# MidoNet admin username
-username = admin
-
-# MidoNet admin password
-password = passw0rd
-
-# Virtual provider router ID
-provider_router_id = 00112233-0011-0011-0011-001122334455
-
-# Virtual metadata router ID
-metadata_router_id = ffeeddcc-ffee-ffee-ffee-ffeeddccbbaa
diff --git a/neutron/tests/unit/midonet/mock_lib.py b/neutron/tests/unit/midonet/mock_lib.py
deleted file mode 100644 (file)
index 8013ae5..0000000
+++ /dev/null
@@ -1,261 +0,0 @@
-# Copyright (C) 2013 Midokura PTE LTD
-# 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 mock
-import uuid
-
-
-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 = 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, **kwargs):
-    if id is None:
-        id = str(uuid.uuid4())
-    if bridge_id is None:
-        bridge_id = str(uuid.uuid4())
-
-    port = mock.Mock()
-    port.get_id.return_value = id
-    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
-
-
-def get_chain_mock(id=None, tenant_id='test-tenant', name='chain',
-                   rules=None):
-    if id is None:
-        id = str(uuid.uuid4())
-
-    if rules is None:
-        rules = []
-
-    chain = mock.Mock()
-    chain.get_id.return_value = id
-    chain.get_tenant_id.return_value = tenant_id
-    chain.get_name.return_value = name
-    chain.get_rules.return_value = rules
-    return chain
-
-
-def get_port_group_mock(id=None, tenant_id='test-tenant', name='pg'):
-    if id is None:
-        id = str(uuid.uuid4())
-
-    port_group = mock.Mock()
-    port_group.get_id.return_value = id
-    port_group.get_tenant_id.return_value = tenant_id
-    port_group.get_name.return_value = name
-    return port_group
-
-
-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 = 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
-
-
-def get_rule_mock(id=None, chain_id=None, properties=None):
-    if id is None:
-        id = str(uuid.uuid4())
-
-    if chain_id is None:
-        chain_id = str(uuid.uuid4())
-
-    if properties is None:
-        properties = {}
-
-    rule = mock.Mock()
-    rule.get_id.return_value = id
-    rule.get_chain_id.return_value = chain_id
-    rule.get_properties.return_value = properties
-    return rule
-
-
-def get_subnet_mock(bridge_id=None, gateway_ip='10.0.0.1',
-                    subnet_prefix='10.0.0.0', subnet_len=int(24)):
-    if bridge_id is None:
-        bridge_id = str(uuid.uuid4())
-
-    subnet = mock.Mock()
-    subnet.get_id.return_value = subnet_prefix + '/' + str(subnet_len)
-    subnet.get_bridge_id.return_value = bridge_id
-    subnet.get_default_gateway.return_value = gateway_ip
-    subnet.get_subnet_prefix.return_value = subnet_prefix
-    subnet.get_subnet_length.return_value = subnet_len
-    return subnet
-
-
-class MidonetLibMockConfig(object):
-
-    def __init__(self, inst):
-        self.inst = inst
-
-    def _create_bridge(self, **kwargs):
-        return get_bridge_mock(**kwargs)
-
-    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, **kwargs):
-        return get_bridge_port_mock(bridge_id=bridge.get_id(), **kwargs)
-
-    def _get_bridge(self, id):
-        return get_bridge_mock(id=id)
-
-    def _get_port(self, id):
-        return get_bridge_port_mock(id=id)
-
-    def _get_router(self, id):
-        return get_router_mock(id=id)
-
-    def _update_bridge(self, id, **kwargs):
-        return get_bridge_mock(id=id, **kwargs)
-
-    def setup(self):
-        # Bridge methods side effects
-        self.inst.create_bridge.side_effect = self._create_bridge
-        self.inst.get_bridge.side_effect = self._get_bridge
-        self.inst.update_bridge.side_effect = self._update_bridge
-
-        # Subnet methods side effects
-        self.inst.create_subnet.side_effect = self._create_subnet
-
-        # Port methods side effects
-        ex_bp = self.inst.add_bridge_port
-        ex_bp.side_effect = self._add_bridge_port
-        self.inst.get_port.side_effect = self._get_port
-
-        # Router methods side effects
-        self.inst.create_router.side_effect = self._create_router
-        self.inst.get_router.side_effect = self._get_router
-
-
-class MidoClientMockConfig(object):
-
-    def __init__(self, inst):
-        self.inst = inst
-        self.chains_in = None
-        self.port_groups_in = None
-        self.chains_out = None
-        self.rules_out = None
-        self.port_groups_out = None
-
-    def _get_query_tenant_id(self, query):
-        if query is not None and query['tenant_id']:
-            tenant_id = query['tenant_id']
-        else:
-            tenant_id = 'test-tenant'
-        return tenant_id
-
-    def _get_bridge(self, id):
-        return get_bridge_mock(id=id)
-
-    def _get_chain(self, id, query=None):
-        if not self.chains_in:
-            return []
-
-        tenant_id = self._get_query_tenant_id(query)
-        for chain in self.chains_in:
-            chain_id = chain['id']
-            if chain_id is id:
-                rule_mocks = []
-                if 'rules' in chain:
-                    for rule in chain['rules']:
-                        rule_mocks.append(
-                            get_rule_mock(id=rule['id'],
-                                          chain_id=id,
-                                          properties=rule['properties']))
-
-                return get_chain_mock(id=chain_id, name=chain['name'],
-                                      tenant_id=tenant_id, rules=rule_mocks)
-        return None
-
-    def _get_chains(self, query=None):
-        if not self.chains_in:
-            return []
-
-        tenant_id = self._get_query_tenant_id(query)
-        self.chains_out = []
-        self.rules_out = []
-        for chain in self.chains_in:
-            chain_id = chain['id']
-
-            rule_mocks = []
-            if 'rules' in chain:
-                for rule in chain['rules']:
-                    rule_mocks.append(
-                        get_rule_mock(id=rule['id'],
-                                      chain_id=id,
-                                      properties=rule['properties']))
-                    self.rules_out += rule_mocks
-
-            self.chains_out.append(get_chain_mock(id=chain_id,
-                                                  name=chain['name'],
-                                                  tenant_id=tenant_id,
-                                                  rules=rule_mocks))
-        return self.chains_out
-
-    def _get_port_groups(self, query=None):
-        if not self.port_groups_in:
-            return []
-
-        tenant_id = self._get_query_tenant_id(query)
-        self.port_groups_out = []
-        for port_group in self.port_groups_in:
-            self.port_groups_out.append(get_port_group_mock(
-                id=port_group['id'], name=port_group['name'],
-                tenant_id=tenant_id))
-        return self.port_groups_out
-
-    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
diff --git a/neutron/tests/unit/midonet/test_midonet_driver.py b/neutron/tests/unit/midonet/test_midonet_driver.py
deleted file mode 100644 (file)
index 9816cf8..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-# Copyright (C) 2012 Midokura Japan K.K.
-# Copyright (C) 2013 Midokura PTE LTD
-# 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 mock
-
-from neutron.agent.common import config
-from neutron.agent.linux import dhcp
-from neutron.common import config as base_config
-import neutron.plugins.midonet.agent.midonet_driver as driver
-from neutron.tests import base
-
-
-class FakeNetwork(object):
-    id = 'aaaabbbb-cccc-dddd-eeee-ffff00001111'
-    namespace = 'qdhcp-ns'
-
-
-class TestDhcpNoOpDriver(base.BaseTestCase):
-    def setUp(self):
-        super(TestDhcpNoOpDriver, self).setUp()
-        self.conf = config.setup_conf()
-        config.register_interface_driver_opts_helper(self.conf)
-        self.conf.register_opts(base_config.core_opts)
-        self.conf.register_opts(dhcp.OPTS)
-        self.conf.enable_isolated_metadata = True
-        self.conf.use_namespaces = True
-        instance = mock.patch("neutron.agent.linux.dhcp.DeviceManager")
-        self.mock_mgr = instance.start()
-        self.makedirs = mock.patch('os.makedirs').start()
-
-    def test_disable_no_retain_port(self):
-        dhcp_driver = driver.DhcpNoOpDriver(self.conf, FakeNetwork())
-        dhcp_driver.disable(retain_port=False)
-        self.assertTrue(self.mock_mgr.return_value.destroy.called)
-
-    def test_disable_retain_port(self):
-        dhcp_driver = driver.DhcpNoOpDriver(self.conf, FakeNetwork())
-        dhcp_driver.disable(retain_port=True)
-        self.assertFalse(self.mock_mgr.return_value.destroy.called)
diff --git a/neutron/tests/unit/midonet/test_midonet_lib.py b/neutron/tests/unit/midonet/test_midonet_lib.py
deleted file mode 100644 (file)
index b581493..0000000
+++ /dev/null
@@ -1,188 +0,0 @@
-# Copyright (C) 2012 Midokura Japan K.K.
-# Copyright (C) 2013 Midokura PTE LTD
-# 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 sys
-
-import mock
-import testtools
-import webob.exc as w_exc
-
-from neutron.openstack.common import uuidutils
-with mock.patch.dict(sys.modules, {'midonetclient': mock.Mock()}):
-    from neutron.plugins.midonet import midonet_lib
-import neutron.tests.unit.midonet.mock_lib as mock_lib
-
-
-def _create_test_chain(id, name, tenant_id):
-    return {'id': id, 'name': name, 'tenant_id': tenant_id}
-
-
-def _create_test_port_group(id, name, tenant_id):
-    return {"id": id, "name": name, "tenant_id": tenant_id}
-
-
-class MidoClientTestCase(testtools.TestCase):
-
-    def setUp(self):
-        super(MidoClientTestCase, self).setUp()
-        self._tenant_id = 'test-tenant'
-        self.mock_api = mock.Mock()
-        self.mock_api_cfg = mock_lib.MidoClientMockConfig(self.mock_api)
-        self.mock_api_cfg.setup()
-        self.client = midonet_lib.MidoClient(self.mock_api)
-
-    def test_delete_chains_by_names(self):
-
-        tenant_id = uuidutils.generate_uuid()
-        chain1_id = uuidutils.generate_uuid()
-        chain1 = _create_test_chain(chain1_id, "chain1", tenant_id)
-
-        chain2_id = uuidutils.generate_uuid()
-        chain2 = _create_test_chain(chain2_id, "chain2", tenant_id)
-
-        calls = [mock.call.delete_chain(chain1_id),
-                 mock.call.delete_chain(chain2_id)]
-        self.mock_api_cfg.chains_in = [chain2, chain1]
-        self.client.delete_chains_by_names(tenant_id, ["chain1", "chain2"])
-
-        self.mock_api.assert_has_calls(calls, any_order=True)
-
-    def test_delete_port_group_by_name(self):
-
-        tenant_id = uuidutils.generate_uuid()
-        pg1_id = uuidutils.generate_uuid()
-        pg1 = _create_test_port_group(pg1_id, "pg1", tenant_id)
-        pg2_id = uuidutils.generate_uuid()
-        pg2 = _create_test_port_group(pg2_id, "pg2", tenant_id)
-
-        self.mock_api_cfg.port_groups_in = [pg1, pg2]
-        self.client.delete_port_group_by_name(tenant_id, "pg1")
-        self.mock_api.delete_port_group.assert_called_once_with(pg1_id)
-
-    def test_create_dhcp(self):
-
-        bridge = mock.Mock()
-
-        gateway_ip = "192.168.1.1"
-        cidr = "192.168.1.0/24"
-        host_rts = [{'destination': '10.0.0.0/24', 'nexthop': '10.0.0.1'},
-                    {'destination': '10.0.1.0/24', 'nexthop': '10.0.1.1'}]
-        dns_servers = ["8.8.8.8", "8.8.4.4"]
-
-        dhcp_call = mock.call.add_bridge_dhcp(bridge, gateway_ip, cidr,
-                                              host_rts=host_rts,
-                                              dns_nservers=dns_servers)
-
-        self.client.create_dhcp(bridge, gateway_ip, cidr, host_rts=host_rts,
-                                dns_servers=dns_servers)
-        self.mock_api.assert_has_calls([dhcp_call])
-
-    def test_delete_dhcp(self):
-
-        bridge = mock.Mock()
-        subnet1 = mock.Mock()
-        subnet1.get_subnet_prefix.return_value = "10.0.0.0"
-        subnet1.get_subnet_length.return_value = "16"
-        subnet2 = mock.Mock()
-        subnet2.get_subnet_prefix.return_value = "10.0.0.0"
-        subnet2.get_subnet_length.return_value = "24"
-        subnets = mock.MagicMock(return_value=[subnet1, subnet2])
-        bridge.get_dhcp_subnets.side_effect = subnets
-        self.client.delete_dhcp(bridge, "10.0.0.0/24")
-        bridge.assert_has_calls(mock.call.get_dhcp_subnets)
-        self.assertFalse(subnet1.delete.called)
-        subnet2.delete.assert_called_once_with()
-
-    def test_add_dhcp_host(self):
-
-        bridge = mock.Mock()
-        dhcp_subnet_call = mock.call.get_dhcp_subnet("10.0.0.0_24")
-        ip_addr_call = dhcp_subnet_call.add_dhcp_host().ip_addr("10.0.0.10")
-        mac_addr_call = ip_addr_call.mac_addr("2A:DB:6B:8C:19:99")
-        calls = [dhcp_subnet_call, ip_addr_call, mac_addr_call,
-                 mac_addr_call.create()]
-
-        self.client.add_dhcp_host(bridge, "10.0.0.0/24", "10.0.0.10",
-                                  "2A:DB:6B:8C:19:99")
-        bridge.assert_has_calls(calls, any_order=True)
-
-    def test_add_dhcp_route_option(self):
-
-        bridge = mock.Mock()
-        subnet = bridge.get_dhcp_subnet.return_value
-        subnet.get_opt121_routes.return_value = None
-        dhcp_subnet_call = mock.call.get_dhcp_subnet("10.0.0.0_24")
-        dst_ip = "10.0.0.3/24"
-        gw_ip = "10.0.0.1"
-        prefix, length = dst_ip.split("/")
-        routes = [{'destinationPrefix': prefix, 'destinationLength': length,
-                   'gatewayAddr': gw_ip}]
-        opt121_routes_call = dhcp_subnet_call.opt121_routes(routes)
-        calls = [dhcp_subnet_call, opt121_routes_call,
-                 opt121_routes_call.update()]
-
-        self.client.add_dhcp_route_option(bridge, "10.0.0.0/24",
-                                          gw_ip, dst_ip)
-        bridge.assert_has_calls(calls, any_order=True)
-
-    def test_get_router_error(self):
-        self.mock_api.get_router.side_effect = w_exc.HTTPInternalServerError()
-        self.assertRaises(midonet_lib.MidonetApiException,
-                          self.client.get_router, uuidutils.generate_uuid())
-
-    def test_get_router_not_found(self):
-        self.mock_api.get_router.side_effect = w_exc.HTTPNotFound()
-        self.assertRaises(midonet_lib.MidonetResourceNotFound,
-                          self.client.get_router, uuidutils.generate_uuid())
-
-    def test_get_bridge_error(self):
-        self.mock_api.get_bridge.side_effect = w_exc.HTTPInternalServerError()
-        self.assertRaises(midonet_lib.MidonetApiException,
-                          self.client.get_bridge, uuidutils.generate_uuid())
-
-    def test_get_bridge_not_found(self):
-        self.mock_api.get_bridge.side_effect = w_exc.HTTPNotFound()
-        self.assertRaises(midonet_lib.MidonetResourceNotFound,
-                          self.client.get_bridge, uuidutils.generate_uuid())
-
-    def test_get_bridge(self):
-        bridge_id = uuidutils.generate_uuid()
-
-        bridge = self.client.get_bridge(bridge_id)
-
-        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())
diff --git a/neutron/tests/unit/midonet/test_midonet_plugin.py b/neutron/tests/unit/midonet/test_midonet_plugin.py
deleted file mode 100644 (file)
index 6a24782..0000000
+++ /dev/null
@@ -1,249 +0,0 @@
-# Copyright (C) 2012 Midokura Japan K.K.
-# Copyright (C) 2013 Midokura PTE LTD
-# 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 mock
-import os
-import sys
-
-import neutron.common.test_lib as test_lib
-from neutron.extensions import portbindings
-from neutron.tests.unit import _test_extension_portbindings as test_bindings
-import neutron.tests.unit.midonet.mock_lib as mock_lib
-import neutron.tests.unit.test_db_plugin as test_plugin
-import neutron.tests.unit.test_extension_security_group as sg
-import neutron.tests.unit.test_l3_plugin as test_l3_plugin
-
-MIDOKURA_PKG_PATH = "neutron.plugins.midonet.plugin"
-MIDONET_PLUGIN_NAME = ('%s.MidonetPluginV2' % MIDOKURA_PKG_PATH)
-
-
-class MidonetPluginV2TestCase(test_plugin.NeutronDbPluginV2TestCase):
-
-    def setUp(self,
-              plugin=MIDONET_PLUGIN_NAME,
-              ext_mgr=None,
-              service_plugins=None):
-        self.mock_api = mock.patch(
-            'neutron.plugins.midonet.midonet_lib.MidoClient')
-        etc_path = os.path.join(os.path.dirname(__file__), 'etc')
-        test_lib.test_config['config_files'] = [os.path.join(
-            etc_path, 'midonet.ini.test')]
-
-        p = mock.patch.dict(sys.modules, {'midonetclient': mock.Mock()})
-        p.start()
-        # dict patches must be explicitly stopped
-        self.addCleanup(p.stop)
-        self.instance = self.mock_api.start()
-        mock_cfg = mock_lib.MidonetLibMockConfig(self.instance.return_value)
-        mock_cfg.setup()
-
-        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,
-                            MidonetPluginV2TestCase):
-
-    pass
-
-
-class TestMidonetL3NatTestCase(MidonetPluginV2TestCase,
-                               test_l3_plugin.L3NatDBIntTestCase):
-    def setUp(self,
-              plugin=MIDONET_PLUGIN_NAME,
-              ext_mgr=None,
-              service_plugins=None):
-        super(TestMidonetL3NatTestCase, self).setUp(plugin=plugin,
-                                                    ext_mgr=None,
-                                                    service_plugins=None)
-
-    def test_floatingip_with_invalid_create_port(self):
-        self._test_floatingip_with_invalid_create_port(MIDONET_PLUGIN_NAME)
-
-    def test_floatingip_assoc_no_port(self):
-        with self.subnet(cidr='200.0.0.0/24') as public_sub:
-            self._set_net_external(public_sub['subnet']['network_id'])
-            res = super(TestMidonetL3NatTestCase, self)._create_floatingip(
-                self.fmt, public_sub['subnet']['network_id'])
-            # Cleanup
-            floatingip = self.deserialize(self.fmt, res)
-            self._delete('floatingips', floatingip['floatingip']['id'])
-        self.assertFalse(self.instance.return_value.add_static_nat.called)
-
-    def test_floatingip_assoc_with_port(self):
-        with self.subnet(cidr='200.0.0.0/24') as public_sub:
-            self._set_net_external(public_sub['subnet']['network_id'])
-            with self.port() as private_port:
-                with self.router() as r:
-                    # We need to hook up the private subnet to the external
-                    # network in order to associate the fip.
-                    sid = private_port['port']['fixed_ips'][0]['subnet_id']
-                    private_sub = {'subnet': {'id': sid}}
-                    self._add_external_gateway_to_router(
-                        r['router']['id'],
-                        public_sub['subnet']['network_id'])
-
-                    # Check that get_link_port was called - if not, Source NAT
-                    # will not be set up correctly on the MidoNet side
-                    self.assertTrue(
-                        self.instance.return_value.get_link_port.called)
-
-                    self._router_interface_action('add', r['router']['id'],
-                                                  private_sub['subnet']['id'],
-                                                  None)
-
-                    # Create the fip.
-                    res = super(TestMidonetL3NatTestCase,
-                                self)._create_floatingip(
-                                    self.fmt,
-                                    public_sub['subnet']['network_id'],
-                                    port_id=private_port['port']['id'])
-
-                    # Cleanup the resources used for the test
-                    floatingip = self.deserialize(self.fmt, res)
-                    self._delete('floatingips', floatingip['floatingip']['id'])
-                    self._remove_external_gateway_from_router(
-                        r['router']['id'],
-                        public_sub['subnet']['network_id'])
-                    self._router_interface_action('remove',
-                                                  r['router']['id'],
-                                                  private_sub['subnet']['id'],
-                                                  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):
-
-    _plugin_name = ('%s.MidonetPluginV2' % MIDOKURA_PKG_PATH)
-
-    def setUp(self):
-        self.mock_api = mock.patch(
-            'neutron.plugins.midonet.midonet_lib.MidoClient')
-        etc_path = os.path.join(os.path.dirname(__file__), 'etc')
-        test_lib.test_config['config_files'] = [os.path.join(
-            etc_path, 'midonet.ini.test')]
-
-        self.instance = self.mock_api.start()
-        mock_cfg = mock_lib.MidonetLibMockConfig(self.instance.return_value)
-        mock_cfg.setup()
-        p = mock.patch.dict(sys.modules, {'midonetclient': mock.Mock()})
-        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)
-
-
-class TestMidonetSecurityGroup(sg.TestSecurityGroups,
-                               TestMidonetSecurityGroupsTestCase):
-
-    pass
-
-
-class TestMidonetSubnetsV2(test_plugin.TestSubnetsV2,
-                           MidonetPluginV2TestCase):
-
-    # IPv6 is not supported by MidoNet yet.  Ignore tests that attempt to
-    # create IPv6 subnet.
-    def test_create_subnet_inconsistent_ipv6_cidrv4(self):
-        pass
-
-    def test_create_subnet_inconsistent_ipv6_dns_v4(self):
-        pass
-
-    def test_create_subnet_with_v6_allocation_pool(self):
-        pass
-
-    def test_update_subnet_inconsistent_ipv6_gatewayv4(self):
-        pass
-
-    def test_update_subnet_inconsistent_ipv6_hostroute_dst_v4(self):
-        pass
-
-    def test_update_subnet_inconsistent_ipv6_hostroute_np_v4(self):
-        pass
-
-    def test_create_subnet_inconsistent_ipv6_gatewayv4(self):
-        pass
-
-    def test_create_subnet_dhcp_disabled(self):
-        super(TestMidonetSubnetsV2, self)._test_create_subnet(
-            enable_dhcp=False)
-        self.assertFalse(self.instance.return_value.create_dhcp.called)
-
-
-class TestMidonetPortsV2(test_plugin.TestPortsV2,
-                         MidonetPluginV2TestCase):
-
-    # IPv6 is not supported by MidoNet yet.  Ignore tests that attempt to
-    # create IPv6 subnet.
-
-    def test_requested_subnet_id_v4_and_v6(self):
-        pass
-
-    def test_vif_port_binding(self):
-        with self.port(name='myname') as port:
-            self.assertEqual('midonet', port['port']['binding:vif_type'])
-            self.assertTrue(port['port']['admin_state_up'])
-
-
-class TestMidonetPluginPortBinding(test_bindings.PortBindingsTestCase,
-                                   MidonetPluginV2TestCase):
-
-    VIF_TYPE = portbindings.VIF_TYPE_MIDONET
-    HAS_PORT_FILTER = True
-
-    def setUp(self):
-        super(TestMidonetPluginPortBinding, self).setUp()