Fix VLAN driver tests

Since [1], the physical network VLAN ranges parser populates the
ranges for those entries without a defined range, allowing all
valid VLAN ranges ([1, 4094]).

Some VLAN driver tests, relying on the previous implementation,
considered that the physical network without a defined VLAN
range does not have segments to allocated (those segments
are created on the fly by
"SegmentTypeDriverallocate_fully_specified_segment).

Since [1], all physical network segments are stored in the
"ml2_vlan_allocations" table and set as non allocated.

This patch also reverts [2]. When the physical networks are defined
in "network_vlan_ranges", there is no distinction between tenant
and provided networks; the physical network segments are assigned
by the user. It is possible to create a provider network without
defining the segmentation ID, it will be provided by the Neutron
VLAN driver, if there are free segments for the required physical
network.

[1]https://review.opendev.org/c/openstack/neutron-lib/+/779515
[2]1376df7873c2ac77c256ab2fed928de41a2c1d58

Closes-Bug: #1919280
Related-Bug: #1918274
Related-Bug: #1649750

Change-Id: I191e020ddb97dcf8fb41139d35bfd699e125379b
This commit is contained in:
Rodolfo Alonso Hernandez 2021-03-16 10:09:27 +00:00
parent 5f6fbcb155
commit f628905279
5 changed files with 46 additions and 46 deletions

View File

@ -50,7 +50,7 @@ msgpack-python==0.4.0
munch==2.1.0 munch==2.1.0
netaddr==0.7.18 netaddr==0.7.18
netifaces==0.10.4 netifaces==0.10.4
neutron-lib==2.9.0 neutron-lib==2.10.0
openstacksdk==0.31.2 openstacksdk==0.31.2
os-client-config==1.28.0 os-client-config==1.28.0
os-ken==0.3.0 os-ken==0.3.0

View File

@ -226,12 +226,6 @@ class VlanTypeDriver(helpers.SegmentTypeDriver):
{'min': p_const.MIN_VLAN_TAG, {'min': p_const.MIN_VLAN_TAG,
'max': p_const.MAX_VLAN_TAG}) 'max': p_const.MAX_VLAN_TAG})
raise exc.InvalidInput(error_message=msg) raise exc.InvalidInput(error_message=msg)
else:
if not ranges.get(physical_network):
msg = (_("Physical network %s requires segmentation_id "
"to be specified when creating a provider "
"network") % physical_network)
raise exc.InvalidInput(error_message=msg)
elif segmentation_id is not None: elif segmentation_id is not None:
msg = _("segmentation_id requires physical_network for VLAN " msg = _("segmentation_id requires physical_network for VLAN "
"provider network") "provider network")

View File

@ -32,7 +32,7 @@ VLAN_OUTSIDE = 100
NETWORK_VLAN_RANGES = { NETWORK_VLAN_RANGES = {
TENANT_NET: [(VLAN_MIN, VLAN_MAX)], TENANT_NET: [(VLAN_MIN, VLAN_MAX)],
} }
NETWORK_VLAN_RANGES_CFG_ENTRIES = [TENANT_NET, "%s:%s:%s" % NETWORK_VLAN_RANGES_CFG_ENTRIES = ["%s:%s:%s" %
(TENANT_NET, VLAN_MIN, VLAN_MAX)] (TENANT_NET, VLAN_MIN, VLAN_MAX)]
SERVICE_PLUGIN_KLASS = ('neutron.services.network_segment_range.plugin.' SERVICE_PLUGIN_KLASS = ('neutron.services.network_segment_range.plugin.'
'NetworkSegmentRangePlugin') 'NetworkSegmentRangePlugin')

View File

@ -34,17 +34,17 @@ TENANT_NET = 'phys_net2'
UNCONFIGURED_NET = 'no_net' UNCONFIGURED_NET = 'no_net'
VLAN_MIN = 200 VLAN_MIN = 200
VLAN_MAX = 209 VLAN_MAX = 209
NETWORK_VLAN_RANGES = [PROVIDER_NET, "%s:%s:%s" % TENANT_VLAN_RANGES = ["%s:%s:%s" % (TENANT_NET, VLAN_MIN, VLAN_MAX)]
(TENANT_NET, VLAN_MIN, VLAN_MAX)] NETWORK_VLAN_RANGES = [PROVIDER_NET] + TENANT_VLAN_RANGES
UPDATED_VLAN_RANGES = { UPDATED_VLAN_RANGES = {
PROVIDER_NET: [], PROVIDER_NET: [(p_const.MIN_VLAN_TAG, p_const.MAX_VLAN_TAG)],
TENANT_NET: [(VLAN_MIN + 5, VLAN_MAX + 5)], TENANT_NET: [(VLAN_MIN + 5, VLAN_MAX + 5)],
} }
EMPTY_VLAN_RANGES = { EMPTY_VLAN_RANGES = {
PROVIDER_NET: [] PROVIDER_NET: [(p_const.MIN_VLAN_TAG, p_const.MAX_VLAN_TAG)]
} }
NETWORK_VLAN_RANGES_WITH_UNCONFIG = { NETWORK_VLAN_RANGES_WITH_UNCONFIG = {
PROVIDER_NET: [], PROVIDER_NET: [(p_const.MIN_VLAN_TAG, p_const.MAX_VLAN_TAG)],
TENANT_NET: [(VLAN_MIN + 5, VLAN_MAX + 5)], TENANT_NET: [(VLAN_MIN + 5, VLAN_MAX + 5)],
UNCONFIGURED_NET: [(VLAN_MIN, VLAN_MAX)] UNCONFIGURED_NET: [(VLAN_MIN, VLAN_MAX)]
} }
@ -151,13 +151,6 @@ class VlanTypeTest(testlib_api.SqlTestCase):
self.driver.validate_provider_segment, self.driver.validate_provider_segment,
segment) segment)
def test_validate_provider_segment_with_physical_network_only(self):
segment = {api.NETWORK_TYPE: p_const.TYPE_VLAN,
api.PHYSICAL_NETWORK: PROVIDER_NET}
self.assertRaises(exc.InvalidInput,
self.driver.validate_provider_segment,
segment)
def test_sync_vlan_allocations(self): def test_sync_vlan_allocations(self):
def check_in_ranges(network_vlan_ranges): def check_in_ranges(network_vlan_ranges):
vlan_min, vlan_max = network_vlan_ranges[TENANT_NET][0] vlan_min, vlan_max = network_vlan_ranges[TENANT_NET][0]
@ -212,7 +205,9 @@ class VlanTypeTest(testlib_api.SqlTestCase):
api.PHYSICAL_NETWORK: PROVIDER_NET, api.PHYSICAL_NETWORK: PROVIDER_NET,
api.SEGMENTATION_ID: 101} api.SEGMENTATION_ID: 101}
alloc = self._get_allocation(self.context, segment) alloc = self._get_allocation(self.context, segment)
self.assertIsNone(alloc) expected = vlan_alloc_obj.VlanAllocation(
allocated=False, physical_network=PROVIDER_NET, vlan_id=101)
self.assertEqual(expected.__repr__(), alloc.__repr__())
observed = self.driver.reserve_provider_segment(self.context, segment) observed = self.driver.reserve_provider_segment(self.context, segment)
alloc = self._get_allocation(self.context, observed) alloc = self._get_allocation(self.context, observed)
self.assertTrue(alloc.allocated) self.assertTrue(alloc.allocated)
@ -252,19 +247,11 @@ class VlanTypeTest(testlib_api.SqlTestCase):
observed = self.driver.reserve_provider_segment(self.context, segment) observed = self.driver.reserve_provider_segment(self.context, segment)
alloc = self._get_allocation(self.context, observed) alloc = self._get_allocation(self.context, observed)
self.assertTrue(alloc.allocated) self.assertTrue(alloc.allocated)
vlan_id = observed[api.SEGMENTATION_ID] # NOTE(ralonsoh): first network provided in the configuration is
self.assertThat(vlan_id, matchers.GreaterThan(VLAN_MIN - 1)) # PROVIDER_NET.
self.assertThat(vlan_id, matchers.LessThan(VLAN_MAX + 1)) self.assertEqual(PROVIDER_NET, observed[api.PHYSICAL_NETWORK])
self.assertEqual(TENANT_NET, observed[api.PHYSICAL_NETWORK]) self.assertIn(observed[api.SEGMENTATION_ID],
range(p_const.MIN_VLAN_TAG, p_const.MAX_VLAN_TAG + 1))
def test_reserve_provider_segment_all_allocateds(self):
for __ in range(VLAN_MIN, VLAN_MAX + 1):
self.driver.allocate_tenant_segment(self.context)
segment = {api.NETWORK_TYPE: p_const.TYPE_VLAN}
self.assertRaises(exc.NoNetworkAvailable,
self.driver.reserve_provider_segment,
self.context,
segment)
def test_get_mtu(self): def test_get_mtu(self):
cfg.CONF.set_override('global_physnet_mtu', 1475) cfg.CONF.set_override('global_physnet_mtu', 1475)
@ -288,20 +275,27 @@ class VlanTypeTest(testlib_api.SqlTestCase):
self.assertEqual(0, self.driver.get_mtu('physnet1')) self.assertEqual(0, self.driver.get_mtu('physnet1'))
def test_allocate_tenant_segment(self): def test_allocate_tenant_segment(self):
cfg.CONF.set_override('network_vlan_ranges', TENANT_VLAN_RANGES,
group='ml2_type_vlan')
driver = type_vlan.VlanTypeDriver()
driver._sync_vlan_allocations()
for __ in range(VLAN_MIN, VLAN_MAX + 1): for __ in range(VLAN_MIN, VLAN_MAX + 1):
segment = self.driver.allocate_tenant_segment(self.context) segment = self.driver.allocate_tenant_segment(self.context)
alloc = self._get_allocation(self.context, segment) alloc = self._get_allocation(self.context, segment)
self.assertTrue(alloc.allocated) self.assertTrue(alloc.allocated)
vlan_id = segment[api.SEGMENTATION_ID] vlan_id = segment[api.SEGMENTATION_ID]
self.assertThat(vlan_id, matchers.GreaterThan(VLAN_MIN - 1)) self.assertGreater(vlan_id, VLAN_MIN - 1)
self.assertThat(vlan_id, matchers.LessThan(VLAN_MAX + 1)) self.assertLess(vlan_id, VLAN_MAX + 1)
self.assertEqual(TENANT_NET, segment[api.PHYSICAL_NETWORK]) self.assertEqual(TENANT_NET, segment[api.PHYSICAL_NETWORK])
def test_allocate_tenant_segment_no_available(self): def test_allocate_tenant_segment_no_available(self):
cfg.CONF.set_override('network_vlan_ranges', TENANT_VLAN_RANGES,
group='ml2_type_vlan')
driver = type_vlan.VlanTypeDriver()
driver._sync_vlan_allocations()
for __ in range(VLAN_MIN, VLAN_MAX + 1): for __ in range(VLAN_MIN, VLAN_MAX + 1):
self.driver.allocate_tenant_segment(self.context) driver.allocate_tenant_segment(self.context)
segment = self.driver.allocate_tenant_segment(self.context) self.assertIsNone(driver.allocate_tenant_segment(self.context))
self.assertIsNone(segment)
def test_release_segment(self): def test_release_segment(self):
segment = self.driver.allocate_tenant_segment(self.context) segment = self.driver.allocate_tenant_segment(self.context)
@ -311,14 +305,14 @@ class VlanTypeTest(testlib_api.SqlTestCase):
def test_release_segment_unallocated(self): def test_release_segment_unallocated(self):
segment = {api.NETWORK_TYPE: p_const.TYPE_VLAN, segment = {api.NETWORK_TYPE: p_const.TYPE_VLAN,
api.PHYSICAL_NETWORK: PROVIDER_NET, api.PHYSICAL_NETWORK: 'non_existing_physnet',
api.SEGMENTATION_ID: 101} api.SEGMENTATION_ID: 101}
with mock.patch.object(type_vlan.LOG, 'warning') as log_warn: with mock.patch.object(type_vlan.LOG, 'warning') as log_warn:
self.driver.release_segment(self.context, segment) self.driver.release_segment(self.context, segment)
log_warn.assert_called_once_with( log_warn.assert_called_once_with(
"No vlan_id %(vlan_id)s found on physical network " "No vlan_id %(vlan_id)s found on physical network "
"%(physical_network)s", "%(physical_network)s",
{'vlan_id': 101, 'physical_network': PROVIDER_NET}) {'vlan_id': 101, 'physical_network': 'non_existing_physnet'})
class VlanTypeAllocationTest(testlib_api.SqlTestCase): class VlanTypeAllocationTest(testlib_api.SqlTestCase):
@ -347,11 +341,15 @@ class VlanTypeAllocationTest(testlib_api.SqlTestCase):
for vlan in range(10): for vlan in range(10):
# then physnet2 # then physnet2
self.assertEqual( self.assertEqual(
{'network_type': 'vlan', 'physical_network': 'phys_net2', {'network_type': 'vlan', 'physical_network': TENANT_NET,
'segmentation_id': mock.ANY, 'mtu': 1500}, 'segmentation_id': mock.ANY, 'mtu': 1500},
driver.allocate_tenant_segment(ctx)) driver.allocate_tenant_segment(ctx))
# then nothing # NOTE(ralonsoh): to save time, this test won't allocate 4094 segments
self.assertFalse(driver.allocate_tenant_segment(ctx)) # for PROVIDER_NET.
self.assertEqual(
{'network_type': 'vlan', 'physical_network': PROVIDER_NET,
'segmentation_id': p_const.MIN_VLAN_TAG, 'mtu': 1500},
driver.allocate_tenant_segment(ctx))
class VlanTypeTestWithNetworkSegmentRange(testlib_api.SqlTestCase): class VlanTypeTestWithNetworkSegmentRange(testlib_api.SqlTestCase):
@ -375,12 +373,20 @@ class VlanTypeTestWithNetworkSegmentRange(testlib_api.SqlTestCase):
# one of the `service_plugins` # one of the `service_plugins`
ret = obj_network_segment_range.NetworkSegmentRange.get_objects( ret = obj_network_segment_range.NetworkSegmentRange.get_objects(
self.context) self.context)
self.assertEqual(1, len(ret)) self.assertEqual(2, len(ret))
network_segment_range = ret[0] network_segment_range = ret[0]
self.assertTrue(network_segment_range.default) self.assertTrue(network_segment_range.default)
self.assertTrue(network_segment_range.shared) self.assertTrue(network_segment_range.shared)
self.assertIsNone(network_segment_range.project_id) self.assertIsNone(network_segment_range.project_id)
self.assertEqual(p_const.TYPE_VLAN, network_segment_range.network_type) self.assertEqual(p_const.TYPE_VLAN, network_segment_range.network_type)
self.assertEqual(PROVIDER_NET, network_segment_range.physical_network)
self.assertEqual(p_const.MIN_VLAN_TAG, network_segment_range.minimum)
self.assertEqual(p_const.MAX_VLAN_TAG, network_segment_range.maximum)
network_segment_range = ret[1]
self.assertTrue(network_segment_range.default)
self.assertTrue(network_segment_range.shared)
self.assertIsNone(network_segment_range.project_id)
self.assertEqual(p_const.TYPE_VLAN, network_segment_range.network_type)
self.assertEqual(TENANT_NET, network_segment_range.physical_network) self.assertEqual(TENANT_NET, network_segment_range.physical_network)
self.assertEqual(VLAN_MIN, network_segment_range.minimum) self.assertEqual(VLAN_MIN, network_segment_range.minimum)
self.assertEqual(VLAN_MAX, network_segment_range.maximum) self.assertEqual(VLAN_MAX, network_segment_range.maximum)

View File

@ -16,7 +16,7 @@ Jinja2>=2.10 # BSD License (3 clause)
keystonemiddleware>=5.1.0 # Apache-2.0 keystonemiddleware>=5.1.0 # Apache-2.0
netaddr>=0.7.18 # BSD netaddr>=0.7.18 # BSD
netifaces>=0.10.4 # MIT netifaces>=0.10.4 # MIT
neutron-lib>=2.9.0 # Apache-2.0 neutron-lib>=2.10.0 # Apache-2.0
python-neutronclient>=6.7.0 # Apache-2.0 python-neutronclient>=6.7.0 # Apache-2.0
tenacity>=6.0.0 # Apache-2.0 tenacity>=6.0.0 # Apache-2.0
SQLAlchemy>=1.2.0 # MIT SQLAlchemy>=1.2.0 # MIT