Merge "Add partial specs support in ML2 for vlan provider networks"

This commit is contained in:
Jenkins 2014-07-21 04:51:53 +00:00 committed by Gerrit Code Review
commit e693d5be17
16 changed files with 424 additions and 99 deletions

View File

@ -179,6 +179,11 @@ class NoNetworkAvailable(ResourceExhausted):
"No tenant network is available for allocation.")
class NoNetworkFoundInMaximumAllowedAttempts(ServiceUnavailable):
message = _("Unable to create the network. "
"No available network found in maximum allowed attempts.")
class SubnetMismatchForPort(BadRequest):
message = _("Subnet on port %(port_id)s does not match "
"the requested subnet %(subnet_id)s")

View File

@ -88,7 +88,8 @@ class TypeDriver(object):
"""Reserve resource associated with a provider network segment.
:param session: database session
:param segment: segment dictionary using keys defined above
:param segment: segment dictionary
:returns: segment dictionary
Called inside transaction context on session to reserve the
type-specific resource for a provider network segment. The

View File

@ -0,0 +1,140 @@
# Copyright (c) 2014 Thales Services SAS
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from oslo.db import exception as db_exc
from neutron.common import exceptions as exc
from neutron.openstack.common import log
from neutron.plugins.ml2 import driver_api as api
# Number of retries to find a valid segment candidate and allocate it
DB_MAX_RETRIES = 10
LOG = log.getLogger(__name__)
class TypeDriverHelper(api.TypeDriver):
"""TypeDriver Helper for segment allocation.
Provide methods helping to perform segment allocation fully or partially
specified.
"""
def __init__(self, model):
self.model = model
self.primary_keys = set(dict(model.__table__.columns))
self.primary_keys.remove("allocated")
def allocate_fully_specified_segment(self, session, **raw_segment):
"""Allocate segment fully specified by raw_segment.
If segment exists, then try to allocate it and return db object
If segment does not exists, then try to create it and return db object
If allocation/creation failed, then return None
"""
network_type = self.get_type()
try:
with session.begin(subtransactions=True):
alloc = (session.query(self.model).filter_by(**raw_segment).
first())
if alloc:
if alloc.allocated:
# Segment already allocated
return
else:
# Segment not allocated
LOG.debug("%(type)s segment %(segment)s allocate "
"started ",
type=network_type, segment=raw_segment)
count = (session.query(self.model).
filter_by(allocated=False, **raw_segment).
update({"allocated": True}))
if count:
LOG.debug("%(type)s segment %(segment)s allocate "
"done ",
type=network_type, segment=raw_segment)
return alloc
# Segment allocated or deleted since select
LOG.debug("%(type)s segment %(segment)s allocate "
"failed: segment has been allocated or "
"deleted",
type=network_type, segment=raw_segment)
# Segment to create or already allocated
LOG.debug("%(type)s segment %(segment)s create started",
type=network_type, segment=raw_segment)
alloc = self.model(allocated=True, **raw_segment)
alloc.save(session)
LOG.debug("%(type)s segment %(segment)s create done",
type=network_type, segment=raw_segment)
except db_exc.DBDuplicateEntry:
# Segment already allocated (insert failure)
alloc = None
LOG.debug("%(type)s segment %(segment)s create failed",
type=network_type, segment=raw_segment)
return alloc
def allocate_partially_specified_segment(self, session, **filters):
"""Allocate model segment from pool partially specified by filters.
Return allocated db object or None.
"""
network_type = self.get_type()
with session.begin(subtransactions=True):
select = (session.query(self.model).
filter_by(allocated=False, **filters))
# Selected segment can be allocated before update by someone else,
# We retry until update success or DB_MAX_RETRIES retries
for attempt in range(1, DB_MAX_RETRIES + 1):
alloc = select.first()
if not alloc:
# No resource available
return
raw_segment = dict((k, alloc[k]) for k in self.primary_keys)
LOG.debug("%(type)s segment allocate from pool, attempt "
"%(attempt)s started with %(segment)s ",
type=network_type, attempt=attempt,
segment=raw_segment)
count = (session.query(self.model).
filter_by(allocated=False, **raw_segment).
update({"allocated": True}))
if count:
LOG.debug("%(type)s segment allocate from pool, attempt "
"%(attempt)s success with %(segment)s ",
type=network_type, attempt=attempt,
segment=raw_segment)
return alloc
# Segment allocated since select
LOG.debug("Allocate %(type)s segment from pool, "
"attempt %(attempt)s failed with segment "
"%(segment)s",
type=network_type, attempt=attempt,
segment=raw_segment)
LOG.warning(_("Allocate %(type)s segment from pool failed "
"after %(number)s failed attempts"),
{"type": network_type, "number": DB_MAX_RETRIES})
raise exc.NoNetworkFoundInMaximumAllowedAttempts

View File

@ -14,6 +14,7 @@
# under the License.
from oslo.config import cfg
from oslo.db import exception as db_exc
import sqlalchemy as sa
from neutron.common import exceptions as exc
@ -100,17 +101,14 @@ class FlatTypeDriver(api.TypeDriver):
physical_network = segment[api.PHYSICAL_NETWORK]
with session.begin(subtransactions=True):
try:
alloc = (session.query(FlatAllocation).
filter_by(physical_network=physical_network).
with_lockmode('update').
one())
raise exc.FlatNetworkInUse(
physical_network=physical_network)
except sa.orm.exc.NoResultFound:
LOG.debug(_("Reserving flat network on physical "
"network %s"), physical_network)
alloc = FlatAllocation(physical_network=physical_network)
session.add(alloc)
alloc.save(session)
except db_exc.DBDuplicateEntry:
raise exc.FlatNetworkInUse(
physical_network=physical_network)
return segment
def allocate_tenant_segment(self, session):
# Tenant flat networks are not supported.

View File

@ -93,6 +93,7 @@ class GreTypeDriver(type_tunnel.TunnelTypeDriver):
alloc = GreAllocation(gre_id=segmentation_id)
alloc.allocated = True
session.add(alloc)
return segment
def allocate_tenant_segment(self, session):
with session.begin(subtransactions=True):

View File

@ -48,7 +48,7 @@ class LocalTypeDriver(api.TypeDriver):
def reserve_provider_segment(self, session, segment):
# No resources to reserve
pass
return segment
def allocate_tenant_segment(self, session):
# No resources to allocate

View File

@ -28,6 +28,7 @@ from neutron.openstack.common import log
from neutron.plugins.common import constants as p_const
from neutron.plugins.common import utils as plugin_utils
from neutron.plugins.ml2 import driver_api as api
from neutron.plugins.ml2.drivers import helpers
LOG = log.getLogger(__name__)
@ -67,7 +68,7 @@ class VlanAllocation(model_base.BASEV2):
allocated = sa.Column(sa.Boolean, nullable=False)
class VlanTypeDriver(api.TypeDriver):
class VlanTypeDriver(helpers.TypeDriverHelper):
"""Manage state for VLAN networks with ML2.
The VlanTypeDriver implements the 'vlan' network_type. VLAN
@ -79,6 +80,7 @@ class VlanTypeDriver(api.TypeDriver):
"""
def __init__(self):
super(VlanTypeDriver, self).__init__(VlanAllocation)
self._parse_network_vlan_ranges()
def _parse_network_vlan_ranges(self):
@ -160,25 +162,27 @@ class VlanTypeDriver(api.TypeDriver):
self._sync_vlan_allocations()
LOG.info(_("VlanTypeDriver initialization complete"))
def is_partial_segment(self, segment):
return segment.get(api.SEGMENTATION_ID) is None
def validate_provider_segment(self, segment):
physical_network = segment.get(api.PHYSICAL_NETWORK)
if not physical_network:
msg = _("physical_network required for VLAN provider network")
raise exc.InvalidInput(error_message=msg)
if physical_network not in self.network_vlan_ranges:
msg = (_("physical_network '%s' unknown for VLAN provider network")
% physical_network)
raise exc.InvalidInput(error_message=msg)
segmentation_id = segment.get(api.SEGMENTATION_ID)
if segmentation_id is None:
msg = _("segmentation_id required for VLAN provider network")
raise exc.InvalidInput(error_message=msg)
if not utils.is_valid_vlan_tag(segmentation_id):
msg = (_("segmentation_id out of range (%(min)s through "
"%(max)s)") %
{'min': q_const.MIN_VLAN_TAG,
'max': q_const.MAX_VLAN_TAG})
if physical_network:
if physical_network not in self.network_vlan_ranges:
msg = (_("physical_network '%s' unknown "
" for VLAN provider network") % physical_network)
raise exc.InvalidInput(error_message=msg)
if segmentation_id:
if not utils.is_valid_vlan_tag(segmentation_id):
msg = (_("segmentation_id out of range (%(min)s through "
"%(max)s)") %
{'min': q_const.MIN_VLAN_TAG,
'max': q_const.MAX_VLAN_TAG})
raise exc.InvalidInput(error_message=msg)
elif segmentation_id:
msg = _("segmentation_id requires physical_network for VLAN "
"provider network")
raise exc.InvalidInput(error_message=msg)
for key, value in segment.items():
@ -189,48 +193,36 @@ class VlanTypeDriver(api.TypeDriver):
raise exc.InvalidInput(error_message=msg)
def reserve_provider_segment(self, session, segment):
physical_network = segment[api.PHYSICAL_NETWORK]
vlan_id = segment[api.SEGMENTATION_ID]
with session.begin(subtransactions=True):
try:
alloc = (session.query(VlanAllocation).
filter_by(physical_network=physical_network,
vlan_id=vlan_id).
with_lockmode('update').
one())
if alloc.allocated:
raise exc.VlanIdInUse(vlan_id=vlan_id,
physical_network=physical_network)
LOG.debug(_("Reserving specific vlan %(vlan_id)s on physical "
"network %(physical_network)s from pool"),
{'vlan_id': vlan_id,
'physical_network': physical_network})
alloc.allocated = True
except sa.orm.exc.NoResultFound:
LOG.debug(_("Reserving specific vlan %(vlan_id)s on physical "
"network %(physical_network)s outside pool"),
{'vlan_id': vlan_id,
'physical_network': physical_network})
alloc = VlanAllocation(physical_network=physical_network,
vlan_id=vlan_id,
allocated=True)
session.add(alloc)
filters = {}
physical_network = segment.get(api.PHYSICAL_NETWORK)
if physical_network is not None:
filters['physical_network'] = physical_network
vlan_id = segment.get(api.SEGMENTATION_ID)
if vlan_id is not None:
filters['vlan_id'] = vlan_id
if self.is_partial_segment(segment):
alloc = self.allocate_partially_specified_segment(
session, **filters)
if not alloc:
raise exc.NoNetworkAvailable
else:
alloc = self.allocate_fully_specified_segment(
session, **filters)
if not alloc:
raise exc.VlanIdInUse(**filters)
return {api.NETWORK_TYPE: p_const.TYPE_VLAN,
api.PHYSICAL_NETWORK: alloc.physical_network,
api.SEGMENTATION_ID: alloc.vlan_id}
def allocate_tenant_segment(self, session):
with session.begin(subtransactions=True):
alloc = (session.query(VlanAllocation).
filter_by(allocated=False).
with_lockmode('update').
first())
if alloc:
LOG.debug(_("Allocating vlan %(vlan_id)s on physical network "
"%(physical_network)s from pool"),
{'vlan_id': alloc.vlan_id,
'physical_network': alloc.physical_network})
alloc.allocated = True
return {api.NETWORK_TYPE: p_const.TYPE_VLAN,
api.PHYSICAL_NETWORK: alloc.physical_network,
api.SEGMENTATION_ID: alloc.vlan_id}
alloc = self.allocate_partially_specified_segment(session)
if not alloc:
return
return {api.NETWORK_TYPE: p_const.TYPE_VLAN,
api.PHYSICAL_NETWORK: alloc.physical_network,
api.SEGMENTATION_ID: alloc.vlan_id}
def release_segment(self, session, segment):
physical_network = segment[api.PHYSICAL_NETWORK]

View File

@ -101,6 +101,7 @@ class VxlanTypeDriver(type_tunnel.TunnelTypeDriver):
alloc = VxlanAllocation(vxlan_vni=segmentation_id)
alloc.allocated = True
session.add(alloc)
return segment
def allocate_tenant_segment(self, session):
with session.begin(subtransactions=True):

View File

@ -85,7 +85,7 @@ class TypeManager(stevedore.named.NamedExtensionManager):
def reserve_provider_segment(self, session, segment):
network_type = segment.get(api.NETWORK_TYPE)
driver = self.drivers.get(network_type)
driver.obj.reserve_provider_segment(session, segment)
return driver.obj.reserve_provider_segment(session, segment)
def allocate_tenant_segment(self, session):
for network_type in self.tenant_network_types:

View File

@ -504,8 +504,8 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
# to TypeManager.
if segments:
for segment in segments:
self.type_manager.reserve_provider_segment(session,
segment)
segment = self.type_manager.reserve_provider_segment(
session, segment)
db.add_network_segment(session, network_id, segment)
else:
segment = self.type_manager.allocate_tenant_segment(session)

View File

@ -0,0 +1,141 @@
# Copyright (c) 2014 Thales Services SAS
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import mock
from sqlalchemy.orm import query
from neutron.common import exceptions as exc
import neutron.db.api as db
from neutron.plugins.ml2.drivers import helpers
from neutron.plugins.ml2.drivers import type_vlan
from neutron.tests import base
TENANT_NET = 'phys_net2'
VLAN_MIN = 200
VLAN_MAX = 209
VLAN_OUTSIDE = 100
NETWORK_VLAN_RANGES = {
TENANT_NET: [(VLAN_MIN, VLAN_MAX)],
}
class HelpersTest(base.BaseTestCase):
def setUp(self):
super(HelpersTest, self).setUp()
db.configure_db()
self.driver = type_vlan.VlanTypeDriver()
self.driver.network_vlan_ranges = NETWORK_VLAN_RANGES
self.driver._sync_vlan_allocations()
self.session = db.get_session()
self.addCleanup(db.clear_db)
def check_raw_segment(self, expected, observed):
for key, value in expected.items():
self.assertEqual(value, observed[key])
def test_primary_keys(self):
self.assertEqual(set(['physical_network', 'vlan_id']),
self.driver.primary_keys)
def test_allocate_specific_unallocated_segment_in_pools(self):
expected = dict(physical_network=TENANT_NET, vlan_id=VLAN_MIN)
observed = self.driver.allocate_fully_specified_segment(self.session,
**expected)
self.check_raw_segment(expected, observed)
def test_allocate_specific_allocated_segment_in_pools(self):
raw_segment = dict(physical_network=TENANT_NET, vlan_id=VLAN_MIN)
self.driver.allocate_fully_specified_segment(self.session,
**raw_segment)
observed = self.driver.allocate_fully_specified_segment(self.session,
**raw_segment)
self.assertIsNone(observed)
def test_allocate_specific_finally_allocated_segment_in_pools(self):
# Test case: allocate a specific unallocated segment in pools but
# the segment is allocated concurrently between select and update
raw_segment = dict(physical_network=TENANT_NET, vlan_id=VLAN_MIN)
with mock.patch.object(query.Query, 'update', return_value=0):
observed = self.driver.allocate_fully_specified_segment(
self.session, **raw_segment)
self.assertIsNone(observed)
def test_allocate_specific_unallocated_segment_outside_pools(self):
expected = dict(physical_network=TENANT_NET, vlan_id=VLAN_OUTSIDE)
observed = self.driver.allocate_fully_specified_segment(self.session,
**expected)
self.check_raw_segment(expected, observed)
def test_allocate_specific_allocated_segment_outside_pools(self):
raw_segment = dict(physical_network=TENANT_NET, vlan_id=VLAN_OUTSIDE)
self.driver.allocate_fully_specified_segment(self.session,
**raw_segment)
observed = self.driver.allocate_fully_specified_segment(self.session,
**raw_segment)
self.assertIsNone(observed)
def test_allocate_specific_finally_unallocated_segment_outside_pools(self):
# Test case: allocate a specific allocated segment in pools but
# the segment is concurrently unallocated after select or update
expected = dict(physical_network=TENANT_NET, vlan_id=VLAN_MIN)
with mock.patch.object(self.driver.model, 'save'):
observed = self.driver.allocate_fully_specified_segment(
self.session, **expected)
self.check_raw_segment(expected, observed)
def test_allocate_partial_segment_without_filters(self):
expected = dict(physical_network=TENANT_NET)
observed = self.driver.allocate_partially_specified_segment(
self.session)
self.check_raw_segment(expected, observed)
def test_allocate_partial_segment_with_filter(self):
expected = dict(physical_network=TENANT_NET)
observed = self.driver.allocate_partially_specified_segment(
self.session, **expected)
self.check_raw_segment(expected, observed)
def test_allocate_partial_segment_no_resource_available(self):
for i in range(VLAN_MIN, VLAN_MAX + 1):
self.driver.allocate_partially_specified_segment(self.session)
observed = self.driver.allocate_partially_specified_segment(
self.session)
self.assertIsNone(observed)
def test_allocate_partial_segment_outside_pools(self):
raw_segment = dict(physical_network='other_phys_net')
observed = self.driver.allocate_partially_specified_segment(
self.session, **raw_segment)
self.assertIsNone(observed)
def test_allocate_partial_segment_first_attempt_fails(self):
expected = dict(physical_network=TENANT_NET)
with mock.patch.object(query.Query, 'update', side_effect=[0, 1]):
observed = self.driver.allocate_partially_specified_segment(
self.session, **expected)
self.check_raw_segment(expected, observed)
def test_allocate_partial_segment_all_attempts_fail(self):
with mock.patch.object(query.Query, 'update', return_value=0):
with mock.patch.object(helpers.LOG, 'warning') as log_warning:
self.assertRaises(
exc.NoNetworkFoundInMaximumAllowedAttempts,
self.driver.allocate_partially_specified_segment,
self.session)
log_warning.assert_called_once_with(mock.ANY, mock.ANY)

View File

@ -85,8 +85,8 @@ class FlatTypeTest(base.BaseTestCase):
def test_reserve_provider_segment(self):
segment = {api.NETWORK_TYPE: p_const.TYPE_FLAT,
api.PHYSICAL_NETWORK: 'flat_net1'}
self.driver.reserve_provider_segment(self.session, segment)
alloc = self._get_allocation(self.session, segment)
observed = self.driver.reserve_provider_segment(self.session, segment)
alloc = self._get_allocation(self.session, observed)
self.assertEqual(segment[api.PHYSICAL_NETWORK], alloc.physical_network)
def test_release_segment(self):

View File

@ -112,9 +112,9 @@ class GreTypeTest(base.BaseTestCase):
segment = {api.NETWORK_TYPE: 'gre',
api.PHYSICAL_NETWORK: 'None',
api.SEGMENTATION_ID: 101}
self.driver.reserve_provider_segment(self.session, segment)
observed = self.driver.reserve_provider_segment(self.session, segment)
alloc = self.driver.get_gre_allocation(self.session,
segment[api.SEGMENTATION_ID])
observed[api.SEGMENTATION_ID])
self.assertTrue(alloc.allocated)
with testtools.ExpectedException(exc.TunnelIdInUse):
@ -122,18 +122,18 @@ class GreTypeTest(base.BaseTestCase):
self.driver.release_segment(self.session, segment)
alloc = self.driver.get_gre_allocation(self.session,
segment[api.SEGMENTATION_ID])
observed[api.SEGMENTATION_ID])
self.assertFalse(alloc.allocated)
segment[api.SEGMENTATION_ID] = 1000
self.driver.reserve_provider_segment(self.session, segment)
observed = self.driver.reserve_provider_segment(self.session, segment)
alloc = self.driver.get_gre_allocation(self.session,
segment[api.SEGMENTATION_ID])
observed[api.SEGMENTATION_ID])
self.assertTrue(alloc.allocated)
self.driver.release_segment(self.session, segment)
alloc = self.driver.get_gre_allocation(self.session,
segment[api.SEGMENTATION_ID])
observed[api.SEGMENTATION_ID])
self.assertIsNone(alloc)
def test_allocate_tenant_segment(self):

View File

@ -47,8 +47,13 @@ class LocalTypeTest(base.BaseTestCase):
def test_reserve_provider_segment(self):
segment = {api.NETWORK_TYPE: p_const.TYPE_LOCAL}
self.driver.reserve_provider_segment(self.session, segment)
self.driver.release_segment(self.session, segment)
observed = self.driver.reserve_provider_segment(self.session, segment)
self.assertEqual(segment, observed)
def test_release_provider_segment(self):
segment = {api.NETWORK_TYPE: p_const.TYPE_LOCAL}
observed = self.driver.reserve_provider_segment(self.session, segment)
self.driver.release_segment(self.session, observed)
def test_allocate_tenant_segment(self):
expected = {api.NETWORK_TYPE: p_const.TYPE_LOCAL}

View File

@ -53,12 +53,31 @@ class VlanTypeTest(base.BaseTestCase):
physical_network=segment[api.PHYSICAL_NETWORK],
vlan_id=segment[api.SEGMENTATION_ID]).first()
def test_partial_segment_is_partial_segment(self):
segment = {api.NETWORK_TYPE: p_const.TYPE_VLAN}
self.assertTrue(self.driver.is_partial_segment(segment))
def test_specific_segment_is_not_partial_segment(self):
segment = {api.NETWORK_TYPE: p_const.TYPE_VLAN,
api.PHYSICAL_NETWORK: PROVIDER_NET,
api.SEGMENTATION_ID: 1}
self.assertFalse(self.driver.is_partial_segment(segment))
def test_validate_provider_segment(self):
segment = {api.NETWORK_TYPE: p_const.TYPE_VLAN,
api.PHYSICAL_NETWORK: PROVIDER_NET,
api.SEGMENTATION_ID: 1}
self.assertIsNone(self.driver.validate_provider_segment(segment))
def test_validate_provider_segment_without_segmentation_id(self):
segment = {api.NETWORK_TYPE: p_const.TYPE_VLAN,
api.PHYSICAL_NETWORK: TENANT_NET}
self.driver.validate_provider_segment(segment)
def test_validate_provider_segment_without_physical_network(self):
segment = {api.NETWORK_TYPE: p_const.TYPE_VLAN}
self.driver.validate_provider_segment(segment)
def test_validate_provider_segment_with_missing_physical_network(self):
segment = {api.NETWORK_TYPE: p_const.TYPE_VLAN,
api.SEGMENTATION_ID: 1}
@ -66,13 +85,6 @@ class VlanTypeTest(base.BaseTestCase):
self.driver.validate_provider_segment,
segment)
def test_validate_provider_segment_with_missing_segmentation_id(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_validate_provider_segment_with_invalid_physical_network(self):
segment = {api.NETWORK_TYPE: p_const.TYPE_VLAN,
api.PHYSICAL_NETWORK: 'other_phys_net',
@ -129,19 +141,19 @@ class VlanTypeTest(base.BaseTestCase):
api.SEGMENTATION_ID: 101}
alloc = self._get_allocation(self.session, segment)
self.assertIsNone(alloc)
self.driver.reserve_provider_segment(self.session, segment)
alloc = self._get_allocation(self.session, segment)
observed = self.driver.reserve_provider_segment(self.session, segment)
alloc = self._get_allocation(self.session, observed)
self.assertTrue(alloc.allocated)
def test_reserve_provider_segment_already_allocated(self):
segment = {api.NETWORK_TYPE: p_const.TYPE_VLAN,
api.PHYSICAL_NETWORK: PROVIDER_NET,
api.SEGMENTATION_ID: 101}
self.driver.reserve_provider_segment(self.session, segment)
observed = self.driver.reserve_provider_segment(self.session, segment)
self.assertRaises(exc.VlanIdInUse,
self.driver.reserve_provider_segment,
self.session,
segment)
observed)
def test_reserve_provider_segment_in_tenant_pools(self):
segment = {api.NETWORK_TYPE: p_const.TYPE_VLAN,
@ -149,10 +161,39 @@ class VlanTypeTest(base.BaseTestCase):
api.SEGMENTATION_ID: VLAN_MIN}
alloc = self._get_allocation(self.session, segment)
self.assertFalse(alloc.allocated)
self.driver.reserve_provider_segment(self.session, segment)
alloc = self._get_allocation(self.session, segment)
observed = self.driver.reserve_provider_segment(self.session, segment)
alloc = self._get_allocation(self.session, observed)
self.assertTrue(alloc.allocated)
def test_reserve_provider_segment_without_segmentation_id(self):
segment = {api.NETWORK_TYPE: p_const.TYPE_VLAN,
api.PHYSICAL_NETWORK: TENANT_NET}
observed = self.driver.reserve_provider_segment(self.session, segment)
alloc = self._get_allocation(self.session, observed)
self.assertTrue(alloc.allocated)
vlan_id = observed[api.SEGMENTATION_ID]
self.assertThat(vlan_id, matchers.GreaterThan(VLAN_MIN - 1))
self.assertThat(vlan_id, matchers.LessThan(VLAN_MAX + 1))
def test_reserve_provider_segment_without_physical_network(self):
segment = {api.NETWORK_TYPE: p_const.TYPE_VLAN}
observed = self.driver.reserve_provider_segment(self.session, segment)
alloc = self._get_allocation(self.session, observed)
self.assertTrue(alloc.allocated)
vlan_id = observed[api.SEGMENTATION_ID]
self.assertThat(vlan_id, matchers.GreaterThan(VLAN_MIN - 1))
self.assertThat(vlan_id, matchers.LessThan(VLAN_MAX + 1))
self.assertEqual(TENANT_NET, observed[api.PHYSICAL_NETWORK])
def test_reserve_provider_segment_all_allocateds(self):
for __ in range(VLAN_MIN, VLAN_MAX + 1):
self.driver.allocate_tenant_segment(self.session)
segment = {api.NETWORK_TYPE: p_const.TYPE_VLAN}
self.assertRaises(exc.NoNetworkAvailable,
self.driver.reserve_provider_segment,
self.session,
segment)
def test_allocate_tenant_segment(self):
for __ in range(VLAN_MIN, VLAN_MAX + 1):
segment = self.driver.allocate_tenant_segment(self.session)

View File

@ -120,9 +120,9 @@ class VxlanTypeTest(base.BaseTestCase):
segment = {api.NETWORK_TYPE: 'vxlan',
api.PHYSICAL_NETWORK: 'None',
api.SEGMENTATION_ID: 101}
self.driver.reserve_provider_segment(self.session, segment)
observed = self.driver.reserve_provider_segment(self.session, segment)
alloc = self.driver.get_vxlan_allocation(self.session,
segment[api.SEGMENTATION_ID])
observed[api.SEGMENTATION_ID])
self.assertTrue(alloc.allocated)
with testtools.ExpectedException(exc.TunnelIdInUse):
@ -130,18 +130,18 @@ class VxlanTypeTest(base.BaseTestCase):
self.driver.release_segment(self.session, segment)
alloc = self.driver.get_vxlan_allocation(self.session,
segment[api.SEGMENTATION_ID])
observed[api.SEGMENTATION_ID])
self.assertFalse(alloc.allocated)
segment[api.SEGMENTATION_ID] = 1000
self.driver.reserve_provider_segment(self.session, segment)
observed = self.driver.reserve_provider_segment(self.session, segment)
alloc = self.driver.get_vxlan_allocation(self.session,
segment[api.SEGMENTATION_ID])
observed[api.SEGMENTATION_ID])
self.assertTrue(alloc.allocated)
self.driver.release_segment(self.session, segment)
alloc = self.driver.get_vxlan_allocation(self.session,
segment[api.SEGMENTATION_ID])
observed[api.SEGMENTATION_ID])
self.assertIsNone(alloc)
def test_allocate_tenant_segment(self):