Implement L3 support in Metaplugin

Added flavor:route property for router
Rename flavor:id to flavor:network
Fixes bug 1038778

Change-Id: Ia358b4f03c1b96ade2d1b7323298b117b2cbe52a
This commit is contained in:
Nachi Ueno 2012-08-20 05:00:14 +00:00
parent efa4316f64
commit 34d3e21a40
14 changed files with 282 additions and 76 deletions

View 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'

View 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)

View 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):

View 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):

View 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.

View 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='')
]

View 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

View 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)

View File

@ -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 <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]

View 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:

View 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)

View File

@ -16,17 +16,19 @@
# under the License.
import os
import mox
import mock
import uuid
import unittest
import mock
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())

View 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()}],

View 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'}]}