Merge "Multiple pods share the same physical network name"

This commit is contained in:
Jenkins 2017-04-21 01:28:48 +00:00 committed by Gerrit Code Review
commit 1eae571e56
3 changed files with 71 additions and 7 deletions

View File

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

View File

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

View File

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