Merge "Multiple pods share the same physical network name"
This commit is contained in:
commit
1eae571e56
@ -15,6 +15,7 @@
|
|||||||
|
|
||||||
import collections
|
import collections
|
||||||
import copy
|
import copy
|
||||||
|
import re
|
||||||
import six
|
import six
|
||||||
|
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
@ -26,6 +27,7 @@ from neutron.api.v2 import attributes
|
|||||||
from neutron.callbacks import events
|
from neutron.callbacks import events
|
||||||
from neutron.callbacks import registry
|
from neutron.callbacks import registry
|
||||||
from neutron.callbacks import resources
|
from neutron.callbacks import resources
|
||||||
|
import neutron.common.exceptions as ml2_exceptions
|
||||||
from neutron.db import api as q_db_api
|
from neutron.db import api as q_db_api
|
||||||
from neutron.db.availability_zone import router as router_az
|
from neutron.db.availability_zone import router as router_az
|
||||||
from neutron.db import common_db_mixin
|
from neutron.db import common_db_mixin
|
||||||
@ -314,8 +316,17 @@ class TricirclePlugin(db_base_plugin_v2.NeutronDbPluginV2,
|
|||||||
# rollback
|
# rollback
|
||||||
if is_external:
|
if is_external:
|
||||||
self._fill_provider_info(res, net_data)
|
self._fill_provider_info(res, net_data)
|
||||||
self._create_bottom_external_network(
|
try:
|
||||||
context, net_data, res['id'])
|
self._create_bottom_external_network(
|
||||||
|
context, net_data, res['id'])
|
||||||
|
except q_cli_exceptions.Conflict as e:
|
||||||
|
pattern = re.compile('Physical network (.*) is in use')
|
||||||
|
match = pattern.search(e.message)
|
||||||
|
if not match:
|
||||||
|
raise
|
||||||
|
else:
|
||||||
|
raise ml2_exceptions.FlatNetworkInUse(
|
||||||
|
physical_network=match.groups()[0])
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def delete_network(self, context, network_id):
|
def delete_network(self, context, network_id):
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
from oslo_log import log
|
from oslo_log import log
|
||||||
|
|
||||||
|
from neutron.common import exceptions
|
||||||
from neutron.plugins.ml2 import driver_api
|
from neutron.plugins.ml2 import driver_api
|
||||||
from neutron.plugins.ml2.drivers import type_flat
|
from neutron.plugins.ml2.drivers import type_flat
|
||||||
|
|
||||||
@ -36,8 +37,15 @@ class FlatTypeDriver(type_flat.FlatTypeDriver):
|
|||||||
LOG.info("FlatTypeDriver initialization complete")
|
LOG.info("FlatTypeDriver initialization complete")
|
||||||
|
|
||||||
def reserve_provider_segment(self, context, segment):
|
def reserve_provider_segment(self, context, segment):
|
||||||
res = super(FlatTypeDriver,
|
try:
|
||||||
self).reserve_provider_segment(context, segment)
|
res = super(FlatTypeDriver,
|
||||||
|
self).reserve_provider_segment(context, segment)
|
||||||
|
except exceptions.FlatNetworkInUse:
|
||||||
|
# to support multiple regions sharing the same physical network
|
||||||
|
# for external network, we ignore this exception and let local
|
||||||
|
# Neutron judge whether the physical network is valid
|
||||||
|
res = segment
|
||||||
|
res[driver_api.MTU] = None
|
||||||
res[driver_api.NETWORK_TYPE] = self.get_type()
|
res[driver_api.NETWORK_TYPE] = self.get_type()
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
@ -28,13 +28,13 @@ from sqlalchemy.sql import elements
|
|||||||
from sqlalchemy.sql import selectable
|
from sqlalchemy.sql import selectable
|
||||||
|
|
||||||
from neutron_lib.api.definitions import portbindings
|
from neutron_lib.api.definitions import portbindings
|
||||||
|
from neutron_lib.api.definitions import provider_net
|
||||||
import neutron_lib.constants as q_constants
|
import neutron_lib.constants as q_constants
|
||||||
import neutron_lib.context as q_context
|
import neutron_lib.context as q_context
|
||||||
import neutron_lib.exceptions as q_lib_exc
|
import neutron_lib.exceptions as q_lib_exc
|
||||||
from neutron_lib.plugins import directory
|
from neutron_lib.plugins import directory
|
||||||
|
|
||||||
import neutron.conf.common as q_config
|
import neutron.conf.common as q_config
|
||||||
|
|
||||||
from neutron.db import _utils
|
from neutron.db import _utils
|
||||||
from neutron.db import db_base_plugin_common
|
from neutron.db import db_base_plugin_common
|
||||||
from neutron.db import db_base_plugin_v2
|
from neutron.db import db_base_plugin_v2
|
||||||
@ -42,6 +42,7 @@ from neutron.db import ipam_pluggable_backend
|
|||||||
from neutron.db import l3_db
|
from neutron.db import l3_db
|
||||||
from neutron.db import models_v2
|
from neutron.db import models_v2
|
||||||
from neutron.db import rbac_db_models as rbac_db
|
from neutron.db import rbac_db_models as rbac_db
|
||||||
|
import neutron.objects.exceptions as q_obj_exceptions
|
||||||
|
|
||||||
from neutron.extensions import availability_zone as az_ext
|
from neutron.extensions import availability_zone as az_ext
|
||||||
|
|
||||||
@ -66,6 +67,7 @@ import tricircle.db.api as db_api
|
|||||||
from tricircle.db import core
|
from tricircle.db import core
|
||||||
from tricircle.db import models
|
from tricircle.db import models
|
||||||
import tricircle.network.central_plugin as plugin
|
import tricircle.network.central_plugin as plugin
|
||||||
|
from tricircle.network.drivers import type_flat
|
||||||
from tricircle.network.drivers import type_local
|
from tricircle.network.drivers import type_local
|
||||||
from tricircle.network.drivers import type_vlan
|
from tricircle.network.drivers import type_vlan
|
||||||
from tricircle.network.drivers import type_vxlan
|
from tricircle.network.drivers import type_vxlan
|
||||||
@ -84,6 +86,7 @@ TOP_SUBNETPOOLPREFIXES = []
|
|||||||
TOP_IPALLOCATIONS = []
|
TOP_IPALLOCATIONS = []
|
||||||
TOP_VLANALLOCATIONS = []
|
TOP_VLANALLOCATIONS = []
|
||||||
TOP_VXLANALLOCATIONS = []
|
TOP_VXLANALLOCATIONS = []
|
||||||
|
TOP_FLATALLOCATIONS = []
|
||||||
TOP_SEGMENTS = []
|
TOP_SEGMENTS = []
|
||||||
TOP_EXTNETS = []
|
TOP_EXTNETS = []
|
||||||
TOP_FLOATINGIPS = []
|
TOP_FLOATINGIPS = []
|
||||||
@ -106,8 +109,8 @@ BOTTOM2_SGS = []
|
|||||||
BOTTOM2_FIPS = []
|
BOTTOM2_FIPS = []
|
||||||
RES_LIST = [TOP_NETS, TOP_SUBNETS, TOP_PORTS, TOP_ROUTERS, TOP_ROUTERPORT,
|
RES_LIST = [TOP_NETS, TOP_SUBNETS, TOP_PORTS, TOP_ROUTERS, TOP_ROUTERPORT,
|
||||||
TOP_SUBNETPOOLS, TOP_SUBNETPOOLPREFIXES, TOP_IPALLOCATIONS,
|
TOP_SUBNETPOOLS, TOP_SUBNETPOOLPREFIXES, TOP_IPALLOCATIONS,
|
||||||
TOP_VLANALLOCATIONS, TOP_VXLANALLOCATIONS, TOP_SEGMENTS,
|
TOP_VLANALLOCATIONS, TOP_VXLANALLOCATIONS, TOP_FLOATINGIPS,
|
||||||
TOP_EXTNETS, TOP_FLOATINGIPS, TOP_SGS, TOP_SG_RULES,
|
TOP_SEGMENTS, TOP_EXTNETS, TOP_FLOATINGIPS, TOP_SGS, TOP_SG_RULES,
|
||||||
TOP_NETWORK_RBAC, TOP_SUBNETROUTES, TOP_DNSNAMESERVERS,
|
TOP_NETWORK_RBAC, TOP_SUBNETROUTES, TOP_DNSNAMESERVERS,
|
||||||
BOTTOM1_NETS, BOTTOM1_SUBNETS, BOTTOM1_PORTS, BOTTOM1_ROUTERS,
|
BOTTOM1_NETS, BOTTOM1_SUBNETS, BOTTOM1_PORTS, BOTTOM1_ROUTERS,
|
||||||
BOTTOM1_SGS, BOTTOM1_FIPS,
|
BOTTOM1_SGS, BOTTOM1_FIPS,
|
||||||
@ -123,6 +126,7 @@ RES_MAP = {'networks': TOP_NETS,
|
|||||||
'subnetpoolprefixes': TOP_SUBNETPOOLPREFIXES,
|
'subnetpoolprefixes': TOP_SUBNETPOOLPREFIXES,
|
||||||
'ml2_vlan_allocations': TOP_VLANALLOCATIONS,
|
'ml2_vlan_allocations': TOP_VLANALLOCATIONS,
|
||||||
'ml2_vxlan_allocations': TOP_VXLANALLOCATIONS,
|
'ml2_vxlan_allocations': TOP_VXLANALLOCATIONS,
|
||||||
|
'ml2_flat_allocations': TOP_FLATALLOCATIONS,
|
||||||
'networksegments': TOP_SEGMENTS,
|
'networksegments': TOP_SEGMENTS,
|
||||||
'externalnetworks': TOP_EXTNETS,
|
'externalnetworks': TOP_EXTNETS,
|
||||||
'floatingips': TOP_FLOATINGIPS,
|
'floatingips': TOP_FLOATINGIPS,
|
||||||
@ -996,6 +1000,13 @@ class FakeSession(object):
|
|||||||
subnet['dns_nameservers'].append(dnsnameservers)
|
subnet['dns_nameservers'].append(dnsnameservers)
|
||||||
break
|
break
|
||||||
|
|
||||||
|
if model_obj.__tablename__ == 'ml2_flat_allocations':
|
||||||
|
for alloc in TOP_FLATALLOCATIONS:
|
||||||
|
if alloc['physical_network'] == model_dict['physical_network']:
|
||||||
|
raise q_obj_exceptions.NeutronDbObjectDuplicateEntry(
|
||||||
|
model_obj.__class__,
|
||||||
|
DotDict({'columns': '', 'value': ''}))
|
||||||
|
|
||||||
self._extend_standard_attr(model_dict)
|
self._extend_standard_attr(model_dict)
|
||||||
|
|
||||||
RES_MAP[model_obj.__tablename__].append(model_dict)
|
RES_MAP[model_obj.__tablename__].append(model_dict)
|
||||||
@ -1114,6 +1125,8 @@ class FakeTypeManager(managers.TricircleTypeManager):
|
|||||||
self.drivers[constants.NT_VLAN] = FakeExtension(vlan_driver)
|
self.drivers[constants.NT_VLAN] = FakeExtension(vlan_driver)
|
||||||
vxlan_driver = type_vxlan.VxLANTypeDriver()
|
vxlan_driver = type_vxlan.VxLANTypeDriver()
|
||||||
self.drivers[constants.NT_VxLAN] = FakeExtension(vxlan_driver)
|
self.drivers[constants.NT_VxLAN] = FakeExtension(vxlan_driver)
|
||||||
|
local_driver = type_flat.FlatTypeDriver()
|
||||||
|
self.drivers[constants.NT_FLAT] = FakeExtension(local_driver)
|
||||||
|
|
||||||
def extend_network_dict_provider(self, cxt, net):
|
def extend_network_dict_provider(self, cxt, net):
|
||||||
target_net = None
|
target_net = None
|
||||||
@ -2899,6 +2912,38 @@ class PluginTest(unittest.TestCase,
|
|||||||
t_ctx, top_net['id'], constants.RT_NETWORK)
|
t_ctx, top_net['id'], constants.RT_NETWORK)
|
||||||
self.assertEqual(mappings[0][1], bottom_net['id'])
|
self.assertEqual(mappings[0][1], bottom_net['id'])
|
||||||
|
|
||||||
|
@patch.object(directory, 'get_plugin', new=fake_get_plugin)
|
||||||
|
@patch.object(context, 'get_context_from_neutron_context')
|
||||||
|
def test_create_flat_external_network(self, mock_context):
|
||||||
|
self._basic_pod_route_setup()
|
||||||
|
|
||||||
|
fake_plugin = FakePlugin()
|
||||||
|
q_ctx = FakeNeutronContext()
|
||||||
|
t_ctx = context.get_db_context()
|
||||||
|
mock_context.return_value = t_ctx
|
||||||
|
|
||||||
|
body = {
|
||||||
|
'network': {
|
||||||
|
'name': 'ext-net1',
|
||||||
|
'admin_state_up': True,
|
||||||
|
'shared': False,
|
||||||
|
'tenant_id': TEST_TENANT_ID,
|
||||||
|
'router:external': True,
|
||||||
|
'availability_zone_hints': ['pod_1'],
|
||||||
|
provider_net.PHYSICAL_NETWORK: 'extern',
|
||||||
|
provider_net.NETWORK_TYPE: 'flat'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fake_plugin.create_network(q_ctx, body)
|
||||||
|
body['network']['name'] = ['ext-net2']
|
||||||
|
body['network']['availability_zone_hints'] = ['pod_2']
|
||||||
|
fake_plugin.create_network(q_ctx, body)
|
||||||
|
# we have ignore the FlatNetworkInUse exception, so only one allocation
|
||||||
|
# record is created, and both pods have one external network
|
||||||
|
self.assertEqual(1, len(TOP_FLATALLOCATIONS))
|
||||||
|
self.assertEqual(1, len(BOTTOM1_NETS))
|
||||||
|
self.assertEqual(1, len(BOTTOM2_NETS))
|
||||||
|
|
||||||
def _prepare_external_net_router_test(self, q_ctx, fake_plugin,
|
def _prepare_external_net_router_test(self, q_ctx, fake_plugin,
|
||||||
router_az_hints=None):
|
router_az_hints=None):
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user