From: Nachi Ueno Date: Mon, 20 Aug 2012 05:00:14 +0000 (+0000) Subject: Implement L3 support in Metaplugin X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=34d3e21a408c96632ec94742ad0e30796b0b4968;p=openstack-build%2Fneutron-build.git Implement L3 support in Metaplugin Added flavor:route property for router Rename flavor:id to flavor:network Fixes bug 1038778 Change-Id: Ia358b4f03c1b96ade2d1b7323298b117b2cbe52a --- diff --git a/etc/quantum/plugins/metaplugin/metaplugin.ini b/etc/quantum/plugins/metaplugin/metaplugin.ini index 93366ca1f..5a8a65123 100644 --- a/etc/quantum/plugins/metaplugin/metaplugin.ini +++ b/etc/quantum/plugins/metaplugin/metaplugin.ini @@ -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' diff --git a/quantum/agent/l3_agent.py b/quantum/agent/l3_agent.py index 3aed6fc7d..6e26b7e29 100644 --- a/quantum/agent/l3_agent.py +++ b/quantum/agent/l3_agent.py @@ -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) diff --git a/quantum/agent/linux/interface.py b/quantum/agent/linux/interface.py index d4e2479d6..7abfa696d 100644 --- a/quantum/agent/linux/interface.py +++ b/quantum/agent/linux/interface.py @@ -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): diff --git a/quantum/extensions/flavor.py b/quantum/extensions/flavor.py index 61f084154..f3940f526 100644 --- a/quantum/extensions/flavor.py +++ b/quantum/extensions/flavor.py @@ -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): diff --git a/quantum/plugins/metaplugin/README b/quantum/plugins/metaplugin/README index 7fc0a6d00..94cf4f266 100644 --- a/quantum/plugins/metaplugin/README +++ b/quantum/plugins/metaplugin/README @@ -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. diff --git a/quantum/plugins/metaplugin/common/config.py b/quantum/plugins/metaplugin/common/config.py index f5a4103c7..9d212bcc4 100644 --- a/quantum/plugins/metaplugin/common/config.py +++ b/quantum/plugins/metaplugin/common/config.py @@ -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='') ] diff --git a/quantum/plugins/metaplugin/meta_db_v2.py b/quantum/plugins/metaplugin/meta_db_v2.py index 5d2fcc685..836f6692d 100644 --- a/quantum/plugins/metaplugin/meta_db_v2.py +++ b/quantum/plugins/metaplugin/meta_db_v2.py @@ -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 diff --git a/quantum/plugins/metaplugin/meta_models_v2.py b/quantum/plugins/metaplugin/meta_models_v2.py index 6f91dfae2..50c3a4361 100644 --- a/quantum/plugins/metaplugin/meta_models_v2.py +++ b/quantum/plugins/metaplugin/meta_models_v2.py @@ -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 "" % (self.flavor, self.network_id) + return "" % (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 "" % (self.flavor, self.router_id) diff --git a/quantum/plugins/metaplugin/meta_quantum_plugin.py b/quantum/plugins/metaplugin/meta_quantum_plugin.py index 973d5f371..9c52e3346 100644 --- a/quantum/plugins/metaplugin/meta_quantum_plugin.py +++ b/quantum/plugins/metaplugin/meta_quantum_plugin.py @@ -17,24 +17,37 @@ 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 \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] diff --git a/quantum/plugins/metaplugin/proxy_quantum_plugin.py b/quantum/plugins/metaplugin/proxy_quantum_plugin.py index 70f861551..80f78a3e7 100644 --- a/quantum/plugins/metaplugin/proxy_quantum_plugin.py +++ b/quantum/plugins/metaplugin/proxy_quantum_plugin.py @@ -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: diff --git a/quantum/tests/unit/metaplugin/fake_plugin.py b/quantum/tests/unit/metaplugin/fake_plugin.py index 8fd252c47..9b9ebe696 100644 --- a/quantum/tests/unit/metaplugin/fake_plugin.py +++ b/quantum/tests/unit/metaplugin/fake_plugin.py @@ -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) diff --git a/quantum/tests/unit/metaplugin/test_metaplugin.py b/quantum/tests/unit/metaplugin/test_metaplugin.py index 8b3ef73d7..7bd55ac72 100644 --- a/quantum/tests/unit/metaplugin/test_metaplugin.py +++ b/quantum/tests/unit/metaplugin/test_metaplugin.py @@ -16,17 +16,19 @@ # 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()) diff --git a/quantum/tests/unit/test_l3_agent.py b/quantum/tests/unit/test_l3_agent.py index 76fe97520..8b3fd4c9a 100644 --- a/quantum/tests/unit/test_l3_agent.py +++ b/quantum/tests/unit/test_l3_agent.py @@ -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()}], diff --git a/quantum/tests/unit/test_linux_interface.py b/quantum/tests/unit/test_linux_interface.py index f7dfaa187..8f9b9ba1e 100644 --- a/quantum/tests/unit/test_linux_interface.py +++ b/quantum/tests/unit/test_linux_interface.py @@ -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'}]}