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:
parent
efa4316f64
commit
34d3e21a40
@ -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'
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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):
|
||||
|
@ -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):
|
||||
|
@ -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.
|
||||
|
||||
|
||||
|
||||
|
@ -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='')
|
||||
]
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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]
|
||||
|
@ -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:
|
||||
|
@ -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)
|
||||
|
||||
|
||||
|
@ -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())
|
||||
|
@ -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()}],
|
||||
|
@ -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'}]}
|
||||
|
Loading…
Reference in New Issue
Block a user