]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
Implement L3 support in Metaplugin
authorNachi Ueno <nachi@nttmcl.com>
Mon, 20 Aug 2012 05:00:14 +0000 (05:00 +0000)
committerNachi Ueno <nachi@nttmcl.com>
Mon, 3 Sep 2012 06:56:42 +0000 (06:56 +0000)
Added flavor:route property for router
Rename flavor:id to flavor:network
Fixes bug 1038778

Change-Id: Ia358b4f03c1b96ade2d1b7323298b117b2cbe52a

14 files changed:
etc/quantum/plugins/metaplugin/metaplugin.ini
quantum/agent/l3_agent.py
quantum/agent/linux/interface.py
quantum/extensions/flavor.py
quantum/plugins/metaplugin/README
quantum/plugins/metaplugin/common/config.py
quantum/plugins/metaplugin/meta_db_v2.py
quantum/plugins/metaplugin/meta_models_v2.py
quantum/plugins/metaplugin/meta_quantum_plugin.py
quantum/plugins/metaplugin/proxy_quantum_plugin.py
quantum/tests/unit/metaplugin/fake_plugin.py
quantum/tests/unit/metaplugin/test_metaplugin.py
quantum/tests/unit/test_l3_agent.py
quantum/tests/unit/test_linux_interface.py

index 93366ca1fe72cfa9dcfb83f9b7162d8570b9d4ce..5a8a65123f6d3700ecc32dba47019515596f2839 100644 (file)
@@ -16,9 +16,11 @@ reconnect_interval = 2
 ## This is list of flavor:quantum_plugins
 # extension method is used in the order of this list
 plugin_list= 'openvswitch:quantum.plugins.openvswitch.ovs_quantum_plugin.OVSQuantumPluginV2,linuxbridge:quantum.plugins.linuxbridge.lb_quantum_plugin.LinuxBridgePluginV2'
+l3_plugin_list= 'openvswitch:quantum.plugins.openvswitch.ovs_quantum_plugin.OVSQuantumPluginV2,linuxbridge:quantum.plugins.linuxbridge.lb_quantum_plugin.LinuxBridgePluginV2'
 
 # Default value of flavor
 default_flavor = 'openvswitch'
+default_l3_flavor = 'openvswitch'
 
 # supported extentions
 supported_extension_aliases = 'providernet'
index 3aed6fc7d2d0727ff66ba0d2823941f2f97b8603..6e26b7e29bfe9696b7c7cc6275dc16debd4ca44c 100644 (file)
@@ -219,7 +219,8 @@ class L3NATAgent(object):
         for p in new_ports:
             self._set_subnet_info(p)
             ri.internal_ports.append(p)
-            self.internal_network_added(ri, ex_gw_port, p['id'],
+            self.internal_network_added(ri, ex_gw_port,
+                                        p['network_id'], p['id'],
                                         p['ip_cidr'], p['mac_address'])
 
         for p in old_ports:
@@ -305,7 +306,8 @@ class L3NATAgent(object):
         if not ip_lib.device_exists(interface_name,
                                     root_helper=self.conf.root_helper,
                                     namespace=ri.ns_name()):
-            self.driver.plug(None, ex_gw_port['id'], interface_name,
+            self.driver.plug(ex_gw_port['network_id'],
+                             ex_gw_port['id'], interface_name,
                              ex_gw_port['mac_address'],
                              bridge=self.conf.external_network_bridge,
                              namespace=ri.ns_name(),
@@ -367,13 +369,13 @@ class L3NATAgent(object):
             rules.extend(self.internal_network_nat_rules(ex_gw_ip, cidr))
         return rules
 
-    def internal_network_added(self, ri, ex_gw_port, port_id,
+    def internal_network_added(self, ri, ex_gw_port, network_id, port_id,
                                internal_cidr, mac_address):
         interface_name = self.get_internal_device_name(port_id)
         if not ip_lib.device_exists(interface_name,
                                     root_helper=self.conf.root_helper,
                                     namespace=ri.ns_name()):
-            self.driver.plug(None, port_id, interface_name, mac_address,
+            self.driver.plug(network_id, port_id, interface_name, mac_address,
                              namespace=ri.ns_name(),
                              prefix=INTERNAL_DEV_PREFIX)
 
index d4e2479d6b5ae71a5da58e955f2cf40802f1982c..7abfa696d9ac2eb25400336cd13c472ed38e8fdd 100644 (file)
@@ -24,6 +24,7 @@ from quantum.agent.linux import ip_lib
 from quantum.agent.linux import ovs_lib
 from quantum.agent.linux import utils
 from quantum.common import exceptions
+from quantum.extensions.flavor import (FLAVOR_NETWORK)
 from quantum.openstack.common import cfg
 from quantum.openstack.common import importutils
 
@@ -244,7 +245,7 @@ class MetaInterfaceDriver(LinuxInterfaceDriver):
 
     def _get_driver_by_network_id(self, network_id):
         network = self.quantum.show_network(network_id)
-        flavor = network['network']['flavor:id']
+        flavor = network['network'][FLAVOR_NETWORK]
         return self.flavor_driver_map[flavor]
 
     def _get_driver_by_device_name(self, device_name, namespace=None):
index 61f08415443a096ea64c74a1a30f6ea363b690a8..f3940f5262b944266709fcd25bdc2290c338fcd7 100644 (file)
@@ -21,12 +21,21 @@ from quantum.api.v2 import attributes
 
 LOG = logging.getLogger(__name__)
 
+FLAVOR_NETWORK = 'flavor:network'
+FLAVOR_ROUTER = 'flavor:router'
+
 FLAVOR_ATTRIBUTE = {
     'networks': {
-    'flavor:id': {'allow_post': True,
-                  'allow_put': False,
-                  'is_visible': True,
-                  'default': attributes.ATTR_NOT_SPECIFIED}
+    FLAVOR_NETWORK: {'allow_post': True,
+                     'allow_put': False,
+                     'is_visible': True,
+                     'default': attributes.ATTR_NOT_SPECIFIED}
+    },
+    'routers': {
+    FLAVOR_ROUTER: {'allow_post': True,
+                    'allow_put': False,
+                    'is_visible': True,
+                    'default': attributes.ATTR_NOT_SPECIFIED}
     }
 }
 
@@ -34,7 +43,7 @@ FLAVOR_ATTRIBUTE = {
 class Flavor(object):
     @classmethod
     def get_name(cls):
-        return "Flavor for each network"
+        return "Flavor support for network and router"
 
     @classmethod
     def get_alias(cls):
index 7fc0a6d000e9e47c2ea0e8575196c92913aa6093..94cf4f26646c38d29de3457cb71580e2c9ce62cd 100644 (file)
@@ -1,8 +1,9 @@
 # -- Background
 
-This plugin support multiple plugin at same time. This plugin is for L3 connectivility
-between networks which are realized by different plugins.This plugin add new attribute 'flavor:id'.
-flavor:id correspond to specific plugin ( flavor-plugin mapping could be configureable by plugin_list config.
+This plugin supports multiple plugin at same time. This plugin is for L3 connectivility
+between networks which are realized by different plugins.This plugin adds new attributes 'flavor:network' and 'flavor:router".
+flavor:network corresponds to specific l2 plugin ( flavor-plugin mapping could be configureable by plugin_list config.
+flavor:router corresponds to specific l3 plugin ( flavor-plugin mapping could be configureable by l3_plugin_list config. Note that Metaplugin can provide l3 functionaliteis for l2 plugin which didn't support l3 extension yet.
 This plugin also support extensions. We can map extension to plugin by using extension_map config.
 
 [DATABASE]
@@ -23,9 +24,13 @@ reconnect_interval = 2
 ## This is list of flavor:quantum_plugins
 # extension method is used in the order of this list
 plugin_list= 'openvswitch:quantum.plugins.openvswitch.ovs_quantum_plugin.OVSQuantumPluginV2,linuxbridge:quantum.plugins.linuxbridge.lb_quantum_plugin.LinuxBridgePluginV2'
+# plugin for l3
+l3_plugin_list= 'openvswitch:quantum.plugins.openvswitch.ovs_quantum_plugin.OVSQuantumPluginV2,linuxbridge:quantum.plugins.linuxbridge.lb_quantum_plugin.LinuxBridgePluginV2'
 
 # Default value of flavor
 default_flavor = 'openvswitch'
+# Default value for l3
+default_l3_flavor = 'openvswitch'
 
 # supported extentions
 supported_extension_aliases = 'providernet'
@@ -42,6 +47,14 @@ meta_flavor_driver_mappings = openvswitch:quantum.agent.linux.interface.OVSInter
 # interface driver for MetaPlugin
 interface_driver = quantum.agent.linux.interface.MetaInterfaceDriver
 
+[Proxy]
+auth_url = http://10.0.0.1:35357/v2.0
+auth_region = RegionOne
+admin_tenant_name = service
+admin_user =      quantum
+admin_password = password
+
+
 # -- Agent
 Agents for Metaplugin are in quantum/plugins/metaplugin/agent
 linuxbridge_quantum_agent and ovs_quantum_agent is available.
@@ -70,12 +83,10 @@ Example flavor configration for ProxyPluginV2
 
 meta_flavor_driver_mappings = "openvswitch:quantum.agent.linux.interface.OVSInterfaceDriver,proxy:quantum.plugins.metaplugin.proxy_quantum_plugin.ProxyPluginV2"
 
-[Proxy]
-auth_url = http://10.0.0.1:35357/v2.0
-auth_region = RegionOne
-admin_tenant_name = service
-admin_user =      quantum
-admin_password = password
+- Limited L3 support
+In folsom version, l3 is an extension. There is no way to extend exntension attributes.
+so you can set flavor:router value but you can't get flavor:router value in API output.
+L3 agent dont's support flavor:router.
 
 
 
index f5a4103c7606b843d1e28833898be0c12dc2d457..9d212bcc405cf499531e3beb9c2357cf50b1a2f8 100644 (file)
@@ -26,7 +26,9 @@ database_opts = [
 
 meta_plugin_opts = [
     cfg.StrOpt('plugin_list', default=''),
+    cfg.StrOpt('l3_plugin_list', default=''),
     cfg.StrOpt('default_flavor', default=''),
+    cfg.StrOpt('default_l3_flavor', default=''),
     cfg.StrOpt('supported_extension_aliases', default=''),
     cfg.StrOpt('extension_map', default='')
 ]
index 5d2fcc685b42397d3c8d2903c85d959c13622470..836f6692da8bdbc43953bfb423b953033def78f9 100644 (file)
@@ -24,7 +24,7 @@ from quantum.plugins.metaplugin import meta_models_v2
 def get_flavor_by_network(net_id):
     session = db.get_session()
     try:
-        binding = (session.query(meta_models_v2.Flavor).
+        binding = (session.query(meta_models_v2.NetworkFlavor).
                    filter_by(network_id=net_id).
                    one())
     except exc.NoResultFound:
@@ -32,9 +32,28 @@ def get_flavor_by_network(net_id):
     return binding.flavor
 
 
-def add_flavor_binding(flavor, net_id):
+def add_network_flavor_binding(flavor, net_id):
     session = db.get_session()
-    binding = meta_models_v2.Flavor(flavor=flavor, network_id=net_id)
+    binding = meta_models_v2.NetworkFlavor(flavor=flavor, network_id=net_id)
+    session.add(binding)
+    session.flush()
+    return binding
+
+
+def get_flavor_by_router(router_id):
+    session = db.get_session()
+    try:
+        binding = (session.query(meta_models_v2.RouterFlavor).
+                   filter_by(router_id=router_id).
+                   one())
+    except exc.NoResultFound:
+        return None
+    return binding.flavor
+
+
+def add_router_flavor_binding(flavor, router_id):
+    session = db.get_session()
+    binding = meta_models_v2.RouterFlavor(flavor=flavor, router_id=router_id)
     session.add(binding)
     session.flush()
     return binding
index 6f91dfae2ef25159b4b4a57cd33198a0bce38e22..50c3a4361d51f42b1de9b6bf3505628edc0d57d8 100644 (file)
@@ -21,7 +21,7 @@ from sqlalchemy import Column, String
 from quantum.db import models_v2
 
 
-class Flavor(models_v2.model_base.BASEV2):
+class NetworkFlavor(models_v2.model_base.BASEV2):
     """Represents a binding of network_id to flavor."""
     flavor = Column(String(255))
     network_id = sa.Column(sa.String(36), sa.ForeignKey('networks.id',
@@ -29,4 +29,15 @@ class Flavor(models_v2.model_base.BASEV2):
                            primary_key=True)
 
     def __repr__(self):
-        return "<Flavor(%s,%s)>" % (self.flavor, self.network_id)
+        return "<NetworkFlavor(%s,%s)>" % (self.flavor, self.network_id)
+
+
+class RouterFlavor(models_v2.model_base.BASEV2):
+    """Represents a binding of router_id to flavor."""
+    flavor = Column(String(255))
+    router_id = sa.Column(sa.String(36), sa.ForeignKey('routers.id',
+                                                       ondelete="CASCADE"),
+                          primary_key=True)
+
+    def __repr__(self):
+        return "<RouterFlavor(%s,%s)>" % (self.flavor, self.router_id)
index 973d5f3719acbdf67fded5ed80bf2342b8185818..9c52e33460ca2bde13bf49f21f83b67b56dcbc7b 100644 (file)
 
 import logging
 
-from quantum.common import exceptions as exc
-
 from quantum.api.v2 import attributes
+from quantum.common import exceptions as exc
 from quantum.common.utils import find_config_file
 from quantum.db import api as db
 from quantum.db import db_base_plugin_v2
+from quantum.db import l3_db
 from quantum.db import models_v2
+from quantum.extensions.flavor import (FLAVOR_NETWORK, FLAVOR_ROUTER)
 from quantum.openstack.common import cfg
 from quantum.openstack.common import importutils
 from quantum.plugins.metaplugin.common import config
 from quantum.plugins.metaplugin import meta_db_v2
-from quantum.plugins.metaplugin.meta_models_v2 import Flavor
+from quantum.plugins.metaplugin.meta_models_v2 import (NetworkFlavor,
+                                                       RouterFlavor)
 from quantum import policy
 
 LOG = logging.getLogger("metaplugin")
 
 
-class MetaPluginV2(db_base_plugin_v2.QuantumDbPluginV2):
+# Metaplugin  Exceptions
+class FlavorNotFound(exc.NotFound):
+    message = _("Flavor %(flavor)s could not be found")
+
+
+class FaildToAddFlavorBinding(exc.QuantumException):
+    message = _("Failed to add flavor binding")
+
+
+class MetaPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
+                   l3_db.L3_NAT_db_mixin):
+
     def __init__(self, configfile=None):
         LOG.debug("Start initializing metaplugin")
         options = {"sql_connection": cfg.CONF.DATABASE.sql_connection}
@@ -45,7 +58,7 @@ class MetaPluginV2(db_base_plugin_v2.QuantumDbPluginV2):
         options.update({"reconnect_interval": reconnect_interval})
         self.supported_extension_aliases = \
             cfg.CONF.META.supported_extension_aliases.split(',')
-        self.supported_extension_aliases.append('flavor')
+        self.supported_extension_aliases += ['flavor', 'os-quantum-router']
 
         # Ignore config option overapping
         def _is_opt_registered(opts, opt):
@@ -69,7 +82,30 @@ class MetaPluginV2(db_base_plugin_v2.QuantumDbPluginV2):
             # Needed to clear _ENGINE for each plugin
             db._ENGINE = None
 
+        self.l3_plugins = {}
+        l3_plugin_list = [plugin_set.split(':')
+                          for plugin_set
+                          in cfg.CONF.META.l3_plugin_list.split(',')]
+        for flavor, plugin_provider in l3_plugin_list:
+            if flavor in self.plugins:
+                self.l3_plugins[flavor] = self.plugins[flavor]
+            else:
+                # For l3 only plugin
+                self.l3_plugins[flavor] = self._load_plugin(plugin_provider)
+                db._ENGINE = None
+
+        self.default_flavor = cfg.CONF.META.default_flavor
+        if not self.default_flavor in self.plugins:
+            raise exc.Invalid('default_flavor %s is not plugin list' %
+                              self.default_flavor)
+
+        self.default_l3_flavor = cfg.CONF.META.default_l3_flavor
+        if not self.default_l3_flavor in self.l3_plugins:
+            raise exc.Invalid('default_l3_flavor %s is not plugin list' %
+                              self.default_l3_flavor)
+
         db.configure_db(options)
+
         self.extension_map = {}
         if not cfg.CONF.META.extension_map == '':
             extension_list = [method_set.split(':')
@@ -80,28 +116,21 @@ class MetaPluginV2(db_base_plugin_v2.QuantumDbPluginV2):
 
         self.default_flavor = cfg.CONF.META.default_flavor
 
-        if not self.default_flavor in self.plugins:
-            raise exc.Invalid('default_flavor %s is not plugin list' %
-                              self.default_flavor)
-
     def _load_plugin(self, plugin_provider):
         LOG.debug("Plugin location:%s", plugin_provider)
-        # If the plugin can't be found let them know gracefully
-        try:
-            LOG.info("Loading Plugin: %s" % plugin_provider)
-            plugin_klass = importutils.import_class(plugin_provider)
-        except exc.ClassNotFound:
-            LOG.exception("Error loading plugin")
-            raise Exception("Plugin not found.  You can install a "
-                            "plugin with: pip install <plugin-name>\n"
-                            "Example: pip install quantum-sample-plugin")
+        plugin_klass = importutils.import_class(plugin_provider)
         return plugin_klass()
 
     def _get_plugin(self, flavor):
         if not flavor in self.plugins:
-            raise Exception("Plugin for flavor %s not found." % flavor)
+            raise FlavorNotFound(flavor=flavor)
         return self.plugins[flavor]
 
+    def _get_l3_plugin(self, flavor):
+        if not flavor in self.l3_plugins:
+            raise FlavorNotFound(flavor=flavor)
+        return self.l3_plugins[flavor]
+
     def __getattr__(self, key):
         # At first,  try to pickup extension command from extension_map
 
@@ -111,8 +140,7 @@ class MetaPluginV2(db_base_plugin_v2.QuantumDbPluginV2):
             if plugin and hasattr(plugin, key):
                 return getattr(plugin, key)
 
-        # Second, try to match extension method in order of pluign list
-
+        # Second, try to match extension method in order of plugin list
         for flavor, plugin in self.plugins.items():
             if hasattr(plugin, key):
                 return getattr(plugin, key)
@@ -121,22 +149,23 @@ class MetaPluginV2(db_base_plugin_v2.QuantumDbPluginV2):
         raise AttributeError
 
     def _extend_network_dict(self, context, network):
-        network['flavor:id'] = self._get_flavor_by_network_id(network['id'])
+        flavor = self._get_flavor_by_network_id(network['id'])
+        network[FLAVOR_NETWORK] = flavor
 
     def create_network(self, context, network):
         n = network['network']
-        flavor = n.get('flavor:id')
+        flavor = n.get(FLAVOR_NETWORK)
         if not str(flavor) in self.plugins:
             flavor = self.default_flavor
         plugin = self._get_plugin(flavor)
         net = plugin.create_network(context, network)
         LOG.debug("Created network: %s with flavor %s " % (net['id'], flavor))
         try:
-            meta_db_v2.add_flavor_binding(flavor, str(net['id']))
-        except Exception as e:
-            LOG.error('failed to add flavor bindings')
+            meta_db_v2.add_network_flavor_binding(flavor, str(net['id']))
+        except:
+            LOG.exception('failed to add flavor bindings')
             plugin.delete_network(context, net['id'])
-            raise Exception('Failed to create network')
+            raise FaildToAddFlavorBinding()
 
         LOG.debug("Created network: %s" % net['id'])
         self._extend_network_dict(context, net)
@@ -151,19 +180,20 @@ class MetaPluginV2(db_base_plugin_v2.QuantumDbPluginV2):
         flavor = meta_db_v2.get_flavor_by_network(id)
         plugin = self._get_plugin(flavor)
         net = plugin.get_network(context, id, fields)
-        if not fields or 'flavor:id' in fields:
+        if not fields or FLAVOR_NETWORK in fields:
             self._extend_network_dict(context, net)
         return net
 
     def get_networks_with_flavor(self, context, filters=None,
                                  fields=None):
         collection = self._model_query(context, models_v2.Network)
-        collection = collection.join(Flavor,
-                                     models_v2.Network.id == Flavor.network_id)
+        model = NetworkFlavor
+        collection = collection.join(model,
+                                     models_v2.Network.id == model.network_id)
         if filters:
             for key, value in filters.iteritems():
-                if key == 'flavor:id':
-                    column = Flavor.flavor
+                if key == FLAVOR_NETWORK:
+                    column = NetworkFlavor.flavor
                 else:
                     column = getattr(models_v2.Network, key, None)
                 if column:
@@ -178,6 +208,9 @@ class MetaPluginV2(db_base_plugin_v2.QuantumDbPluginV2):
     def _get_flavor_by_network_id(self, network_id):
         return meta_db_v2.get_flavor_by_network(network_id)
 
+    def _get_flavor_by_router_id(self, router_id):
+        return meta_db_v2.get_flavor_by_router(router_id)
+
     def _get_plugin_by_network_id(self, network_id):
         flavor = self._get_flavor_by_network_id(network_id)
         return self._get_plugin(flavor)
@@ -194,7 +227,10 @@ class MetaPluginV2(db_base_plugin_v2.QuantumDbPluginV2):
         plugin = self._get_plugin_by_network_id(port_in_db['network_id'])
         return plugin.update_port(context, id, port)
 
-    def delete_port(self, context, id):
+    def delete_port(self, context, id, l3_port_check=True):
+        if l3_port_check:
+            self.prevent_l3_port_deletion(context, id)
+        self.disassociate_floatingips(context, id)
         port_in_db = self.get_port(context, id)
         plugin = self._get_plugin_by_network_id(port_in_db['network_id'])
         return plugin.delete_port(context, id)
@@ -215,3 +251,68 @@ class MetaPluginV2(db_base_plugin_v2.QuantumDbPluginV2):
         s = self.get_subnet(context, id)
         plugin = self._get_plugin_by_network_id(s['network_id'])
         return plugin.delete_subnet(context, id)
+
+    def _extend_router_dict(self, context, router):
+        flavor = self._get_flavor_by_router_id(router['id'])
+        router[FLAVOR_ROUTER] = flavor
+
+    def create_router(self, context, router):
+        r = router['router']
+        flavor = r.get(FLAVOR_ROUTER)
+        if not str(flavor) in self.l3_plugins:
+            flavor = self.default_l3_flavor
+        plugin = self._get_l3_plugin(flavor)
+        r_in_db = plugin.create_router(context, router)
+        LOG.debug("Created router: %s with flavor %s " % (r_in_db['id'],
+                                                          flavor))
+        try:
+            meta_db_v2.add_router_flavor_binding(flavor, str(r_in_db['id']))
+        except:
+            LOG.exception('failed to add flavor bindings')
+            plugin.delete_router(context, r_in_db['id'])
+            raise FaildToAddFlavorBinding()
+
+        LOG.debug("Created router: %s" % r_in_db['id'])
+        self._extend_router_dict(context, r_in_db)
+        return r_in_db
+
+    def update_router(self, context, id, router):
+        flavor = meta_db_v2.get_flavor_by_router(id)
+        plugin = self._get_l3_plugin(flavor)
+        return plugin.update_router(context, id, router)
+
+    def delete_router(self, context, id):
+        flavor = meta_db_v2.get_flavor_by_router(id)
+        plugin = self._get_l3_plugin(flavor)
+        return plugin.delete_router(context, id)
+
+    def get_router(self, context, id, fields=None):
+        flavor = meta_db_v2.get_flavor_by_router(id)
+        plugin = self._get_l3_plugin(flavor)
+        router = plugin.get_router(context, id, fields)
+        if not fields or FLAVOR_ROUTER in fields:
+            self._extend_router_dict(context, router)
+        return router
+
+    def get_routers_with_flavor(self, context, filters=None,
+                                fields=None):
+        collection = self._model_query(context, l3_db.Router)
+        r_model = RouterFlavor
+        collection = collection.join(r_model,
+                                     l3_db.Router.id == r_model.router_id)
+        if filters:
+            for key, value in filters.iteritems():
+                if key == FLAVOR_ROUTER:
+                    column = RouterFlavor.flavor
+                else:
+                    column = getattr(l3_db.Router, key, None)
+                if column:
+                    collection = collection.filter(column.in_(value))
+        return [self._make_router_dict(c, fields) for c in collection.all()]
+
+    def get_routers(self, context, filters=None, fields=None):
+        routers = self.get_routers_with_flavor(context, filters,
+                                               None)
+        return [self.get_router(context, router['id'],
+                                fields)
+                for router in routers]
index 70f8615511248b936dc7677d489a1375f9b20ec7..80f78a3e7ff0f0667387f12fda5f41cd7b79f5c1 100644 (file)
@@ -19,6 +19,7 @@ import logging
 
 from quantum.db import api as db
 from quantum.db import db_base_plugin_v2
+from quantum.db import l3_db
 from quantum.db import models_v2
 from quantum.openstack.common import cfg
 from quantumclient.common import exceptions
@@ -28,7 +29,8 @@ from quantumclient.v2_0 import client
 LOG = logging.getLogger(__name__)
 
 
-class ProxyPluginV2(db_base_plugin_v2.QuantumDbPluginV2):
+class ProxyPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
+                    l3_db.L3_NAT_db_mixin):
     def __init__(self, configfile=None):
         options = {"sql_connection": cfg.CONF.DATABASE.sql_connection}
         options.update({'base': models_v2.model_base.BASEV2})
@@ -126,7 +128,11 @@ class ProxyPluginV2(db_base_plugin_v2.QuantumDbPluginV2):
             LOG.error("update port failed: %e" % e)
         return port_in_db
 
-    def delete_port(self, context, id):
+    def delete_port(self, context, id, l3_port_check=True):
+        if l3_port_check:
+            self.prevent_l3_port_deletion(context, id)
+        self.disassociate_floatingips(context, id)
+
         try:
             self._get_client().delete_port(id)
         except exceptions.PortNotFoundClient:
index 8fd252c4738877d9b590a938218602b6d87dc889..9b9ebe69630a81ef1306917f404fe61b4c497442 100644 (file)
@@ -18,10 +18,12 @@ from quantum.common import exceptions as q_exc
 from quantum.common.utils import find_config_file
 from quantum.db import api as db
 from quantum.db import db_base_plugin_v2
+from quantum.db import l3_db
 from quantum.db import models_v2
 
 
-class Fake1(db_base_plugin_v2.QuantumDbPluginV2):
+class Fake1(db_base_plugin_v2.QuantumDbPluginV2,
+            l3_db.L3_NAT_db_mixin):
     def fake_func(self):
         return 'fake1'
 
@@ -45,7 +47,7 @@ class Fake1(db_base_plugin_v2.QuantumDbPluginV2):
         port = super(Fake1, self).update_port(context, id, port)
         return port
 
-    def delete_port(self, context, id):
+    def delete_port(self, context, id, l3_port_check=True):
         return super(Fake1, self).delete_port(context, id)
 
 
index 8b3ef73d7ae6d33d22050d389351ea5ddd67f1eb..7bd55ac721f53182dc697a286ae54d37aba8a036 100644 (file)
 #    under the License.
 
 import os
+import uuid
 
-import mox
 import mock
-import uuid
-import unittest
+import mox
 import stubout
+import unittest2 as unittest
 
 from quantum.common import config
 from quantum.common.exceptions import NotImplementedError
 from quantum.db import api as db
 from quantum.db import models_v2
+from quantum.extensions.flavor import (FLAVOR_NETWORK, FLAVOR_ROUTER)
+from quantum.extensions import l3
 from quantum.openstack.common import cfg
 from quantum.plugins.metaplugin.meta_quantum_plugin import MetaPluginV2
 from quantum.plugins.metaplugin.proxy_quantum_plugin import ProxyPluginV2
@@ -39,9 +41,12 @@ ETCDIR = os.path.join(ROOTDIR, 'etc')
 META_PATH = "quantum.plugins.metaplugin"
 FAKE_PATH = "quantum.tests.unit.metaplugin"
 PROXY_PATH = "%s.proxy_quantum_plugin.ProxyPluginV2" % META_PATH
-PLUGIN_LIST = \
-    'fake1:%s.fake_plugin.Fake1,fake2:%s.fake_plugin.Fake2,proxy:%s' % \
-    (FAKE_PATH, FAKE_PATH, PROXY_PATH)
+PLUGIN_LIST = """
+fake1:%s.fake_plugin.Fake1,fake2:%s.fake_plugin.Fake2,proxy:%s
+""".strip() % (FAKE_PATH, FAKE_PATH, PROXY_PATH)
+L3_PLUGIN_LIST = """
+fake1:%s.fake_plugin.Fake1,fake2:%s.fake_plugin.Fake2
+""".strip() % (FAKE_PATH, FAKE_PATH)
 
 
 def etcdir(*p):
@@ -75,7 +80,9 @@ class MetaQuantumPluginV2Test(unittest.TestCase):
         cfg.CONF.set_override('admin_password', 'password', 'PROXY')
         cfg.CONF.set_override('admin_tenant_name', 'service', 'PROXY')
         cfg.CONF.set_override('plugin_list', PLUGIN_LIST, 'META')
+        cfg.CONF.set_override('l3_plugin_list', L3_PLUGIN_LIST, 'META')
         cfg.CONF.set_override('default_flavor', 'fake2', 'META')
+        cfg.CONF.set_override('default_l3_flavor', 'fake1', 'META')
         cfg.CONF.set_override('base_mac', "12:34:56:78:90:ab")
         #TODO(nati) remove this after subnet quota change is merged
         cfg.CONF.max_dns_nameservers = 10
@@ -105,7 +112,7 @@ class MetaQuantumPluginV2Test(unittest.TestCase):
                             'admin_state_up': True,
                             'shared': False,
                             'tenant_id': self.fake_tenant_id,
-                            'flavor:id': flavor}}
+                            FLAVOR_NETWORK: flavor}}
         return data
 
     def _fake_port(self, net_id):
@@ -134,18 +141,25 @@ class MetaQuantumPluginV2Test(unittest.TestCase):
                            'enable_dhcp': True,
                            'ip_version': 4}}
 
+    def _fake_router(self, flavor):
+        data = {'router': {'name': flavor, 'admin_state_up': True,
+                           'tenant_id': self.fake_tenant_id,
+                           FLAVOR_ROUTER: flavor,
+                           'external_gateway_info': None}}
+        return data
+
     def test_create_delete_network(self):
         network1 = self._fake_network('fake1')
         ret1 = self.plugin.create_network(self.context, network1)
-        self.assertEqual('fake1', ret1['flavor:id'])
+        self.assertEqual('fake1', ret1[FLAVOR_NETWORK])
 
         network2 = self._fake_network('fake2')
         ret2 = self.plugin.create_network(self.context, network2)
-        self.assertEqual('fake2', ret2['flavor:id'])
+        self.assertEqual('fake2', ret2[FLAVOR_NETWORK])
 
         network3 = self._fake_network('proxy')
         ret3 = self.plugin.create_network(self.context, network3)
-        self.assertEqual('proxy', ret3['flavor:id'])
+        self.assertEqual('proxy', ret3[FLAVOR_NETWORK])
 
         db_ret1 = self.plugin.get_network(self.context, ret1['id'])
         self.assertEqual('fake1', db_ret1['name'])
@@ -160,7 +174,7 @@ class MetaQuantumPluginV2Test(unittest.TestCase):
         self.assertEqual(3, len(db_ret4))
 
         db_ret5 = self.plugin.get_networks(self.context,
-                                           {'flavor:id': ['fake1']})
+                                           {FLAVOR_NETWORK: ['fake1']})
         self.assertEqual(1, len(db_ret5))
         self.assertEqual('fake1', db_ret5[0]['name'])
         self.plugin.delete_network(self.context, ret1['id'])
@@ -268,6 +282,26 @@ class MetaQuantumPluginV2Test(unittest.TestCase):
         self.plugin.delete_network(self.context, network_ret2['id'])
         self.plugin.delete_network(self.context, network_ret3['id'])
 
+    def test_create_delete_router(self):
+        router1 = self._fake_router('fake1')
+        router_ret1 = self.plugin.create_router(self.context, router1)
+        router2 = self._fake_router('fake2')
+        router_ret2 = self.plugin.create_router(self.context, router2)
+
+        self.assertEqual('fake1', router_ret1[FLAVOR_ROUTER])
+        self.assertEqual('fake2', router_ret2[FLAVOR_ROUTER])
+
+        router_in_db1 = self.plugin.get_router(self.context, router_ret1['id'])
+        router_in_db2 = self.plugin.get_router(self.context, router_ret2['id'])
+
+        self.assertEqual('fake1', router_in_db1[FLAVOR_ROUTER])
+        self.assertEqual('fake2', router_in_db2[FLAVOR_ROUTER])
+
+        self.plugin.delete_router(self.context, router_ret1['id'])
+        self.plugin.delete_router(self.context, router_ret2['id'])
+        with self.assertRaises(l3.RouterNotFound):
+            self.plugin.get_router(self.context, router_ret1['id'])
+
     def test_extension_method(self):
         self.assertEqual('fake1', self.plugin.fake_func())
         self.assertEqual('fake2', self.plugin.fake_func2())
index 76fe97520d5cd53929501744047f9055393006e3..8b3fd4c9a125693ed64cfa0ea8cd23dd2fab0ace 100644 (file)
@@ -86,6 +86,7 @@ class TestBasicRouterOperations(unittest.TestCase):
     def _test_internal_network_action(self, action):
         port_id = _uuid()
         router_id = _uuid()
+        network_id = _uuid()
         ri = l3_agent.RouterInfo(router_id, self.conf.root_helper)
         agent = l3_agent.L3NATAgent(self.conf)
         interface_name = agent.get_internal_device_name(port_id)
@@ -95,7 +96,8 @@ class TestBasicRouterOperations(unittest.TestCase):
 
         if action == 'add':
             self.device_exists.return_value = False
-            agent.internal_network_added(ri, ex_gw_port, port_id, cidr, mac)
+            agent.internal_network_added(ri, ex_gw_port, network_id,
+                                         port_id, cidr, mac)
             self.assertEquals(self.mock_driver.plug.call_count, 1)
             self.assertEquals(self.mock_driver.init_l3.call_count, 1)
         elif action == 'remove':
@@ -120,6 +122,7 @@ class TestBasicRouterOperations(unittest.TestCase):
                                      'subnet_id': _uuid()}],
                       'subnet': {'gateway_ip': '20.0.0.1'},
                       'id': _uuid(),
+                      'network_id': _uuid(),
                       'mac_address': 'ca:fe:de:ad:be:ef',
                       'ip_cidr': '20.0.0.30/24'}
 
@@ -180,9 +183,11 @@ class TestBasicRouterOperations(unittest.TestCase):
 
         # return data so that state is built up
         ex_gw_port = {'id': _uuid(),
+                      'network_id': _uuid(),
                       'fixed_ips': [{'ip_address': '19.4.4.4',
                                      'subnet_id': _uuid()}]}
         internal_port = {'id': _uuid(),
+                         'network_id': _uuid(),
                          'admin_state_up': True,
                          'fixed_ips': [{'ip_address': '35.4.4.4',
                                         'subnet_id': _uuid()}],
index f7dfaa1873f8b684c76aaeea901ff01c27c0127d..8f9b9ba1e6b010ff49b2195a5792d81ae8d34a2a 100644 (file)
@@ -23,8 +23,9 @@ from quantum.agent.common import config
 from quantum.agent.linux import interface
 from quantum.agent.linux import ip_lib
 from quantum.agent.linux import utils
-from quantum.openstack.common import cfg
 from quantum.agent.dhcp_agent import DeviceManager
+from quantum.extensions.flavor import (FLAVOR_NETWORK)
+from quantum.openstack.common import cfg
 
 
 class BaseChild(interface.LinuxInterfaceDriver):
@@ -345,7 +346,7 @@ class TestMetaInterfaceDriver(TestBase):
         self.client_inst = mock.Mock()
         client_cls.return_value = self.client_inst
 
-        fake_network = {'network': {'flavor:id': 'fake1'}}
+        fake_network = {'network': {FLAVOR_NETWORK: 'fake1'}}
         fake_port = {'ports':
                      [{'mac_address':
                       'aa:bb:cc:dd:ee:ffa', 'network_id': 'test'}]}