"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")
"""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
--- /dev/null
+# 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
# 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
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.
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):
def reserve_provider_segment(self, session, segment):
# No resources to reserve
- pass
+ return segment
def allocate_tenant_segment(self, session):
# No resources to allocate
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__)
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
"""
def __init__(self):
+ super(VlanTypeDriver, self).__init__(VlanAllocation)
self._parse_network_vlan_ranges()
def _parse_network_vlan_ranges(self):
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():
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]
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):
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:
# 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)
--- /dev/null
+# 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)
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):
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):
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):
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}
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_with_missing_physical_network(self):
+ def test_validate_provider_segment_without_segmentation_id(self):
segment = {api.NETWORK_TYPE: p_const.TYPE_VLAN,
- api.SEGMENTATION_ID: 1}
- self.assertRaises(exc.InvalidInput,
- self.driver.validate_provider_segment,
- segment)
+ api.PHYSICAL_NETWORK: TENANT_NET}
+ self.driver.validate_provider_segment(segment)
- def test_validate_provider_segment_with_missing_segmentation_id(self):
+ 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.PHYSICAL_NETWORK: PROVIDER_NET}
+ api.SEGMENTATION_ID: 1}
self.assertRaises(exc.InvalidInput,
self.driver.validate_provider_segment,
segment)
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,
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 = {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):
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):