Fix segment allocation tables in Cisco N1kv plugin

The segment allocation table is emptied on deleting any network profile.
This change allows the use of segment range from the network profile table.
By using the network profile UUID as a foreign key in the segment allocations table,
tables are cleaned up only for the segments associated with
the deleted network profile via CASCADE, leaving no inconsistencies.

Change-Id: I507041fac3768a7b688ddcf28c4d97c618bfe3f9
Closes-Bug: #1288407
This commit is contained in:
Abhishek Raut 2014-03-05 19:02:40 -08:00
parent 9f04b6e202
commit 3cb1c3f30c
8 changed files with 322 additions and 376 deletions

View File

@ -0,0 +1,83 @@
# Copyright 2014 OpenStack Foundation
#
# 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.
#
"""n1kv segment allocs for cisco n1kv plugin
Revision ID: 5ac1c354a051
Revises: 538732fa21e1
Create Date: 2014-03-05 17:36:52.952608
"""
# revision identifiers, used by Alembic.
revision = '5ac1c354a051'
down_revision = '538732fa21e1'
# Change to ['*'] if this migration applies to all plugins
migration_for_plugins = [
'neutron.plugins.cisco.network_plugin.PluginV2'
]
from alembic import op
import sqlalchemy as sa
from neutron.db import migration
def upgrade(active_plugins=None, options=None):
if not migration.should_run(active_plugins, migration_for_plugins):
return
op.add_column(
'cisco_n1kv_vlan_allocations',
sa.Column('network_profile_id',
sa.String(length=36),
nullable=False)
)
op.create_foreign_key(
'cisco_n1kv_vlan_allocations_ibfk_1',
source='cisco_n1kv_vlan_allocations',
referent='cisco_network_profiles',
local_cols=['network_profile_id'], remote_cols=['id'],
ondelete='CASCADE'
)
op.add_column(
'cisco_n1kv_vxlan_allocations',
sa.Column('network_profile_id',
sa.String(length=36),
nullable=False)
)
op.create_foreign_key(
'cisco_n1kv_vxlan_allocations_ibfk_1',
source='cisco_n1kv_vxlan_allocations',
referent='cisco_network_profiles',
local_cols=['network_profile_id'], remote_cols=['id'],
ondelete='CASCADE'
)
def downgrade(active_plugins=None, options=None):
if not migration.should_run(active_plugins, migration_for_plugins):
return
op.drop_constraint('cisco_n1kv_vxlan_allocations_ibfk_1',
'cisco_n1kv_vxlan_allocations',
'foreignkey')
op.drop_column('cisco_n1kv_vxlan_allocations', 'network_profile_id')
op.drop_constraint('cisco_n1kv_vlan_allocations_ibfk_1',
'cisco_n1kv_vlan_allocations',
'foreignkey')
op.drop_column('cisco_n1kv_vlan_allocations', 'network_profile_id')

View File

@ -1 +1 @@
538732fa21e1
5ac1c354a051

View File

@ -180,12 +180,23 @@ class VMNetworkNotFound(exceptions.NotFound):
message = _("VM Network %(name)s could not be found.")
class VxlanIdInUse(exceptions.InUse):
class VxlanIDInUse(exceptions.InUse):
"""VXLAN ID is in use."""
message = _("Unable to create the network. "
"The VXLAN ID %(vxlan_id)s is in use.")
class VxlanIDNotFound(exceptions.NotFound):
"""VXLAN ID cannot be found."""
message = _("Vxlan ID %(vxlan_id)s not found.")
class VxlanIDOutsidePool(exceptions.NeutronException):
"""VXLAN ID cannot be allocated, as it is outside the configured pool."""
message = _("Unable to complete operation. VXLAN ID exists outside of the "
"configured network segment range.")
class VSMConnectionFailed(exceptions.ServiceUnavailable):
"""Connection to VSM failed."""
message = _("Connection to VSM failed: %(reason)s.")

View File

@ -21,7 +21,6 @@
import netaddr
import re
from six.moves import xrange
from sqlalchemy.orm import exc
from sqlalchemy.sql import and_
@ -395,71 +394,30 @@ def add_port_binding(db_session, port_id, policy_profile_id):
db_session.add(binding)
def _get_sorted_vlan_ids(vlan_ranges):
"""Return sorted allocatable VLAN IDs."""
vlan_ids = set()
for vlan_range in vlan_ranges:
vlan_ids |= set(xrange(vlan_range[0], vlan_range[1] + 1))
return sorted(vlan_ids)
def sync_vlan_allocations(db_session, network_vlan_ranges):
def sync_vlan_allocations(db_session, net_p):
"""
Synchronize vlan_allocations table with configured VLAN ranges.
Sync the network profile range with the vlan_allocations table for each
physical network.
:param db_session: database session
:param network_vlan_ranges: dictionary of network vlan ranges with the
physical network name as key.
:param net_p: network profile dictionary
"""
with db_session.begin():
# process vlan ranges for each physical network separately
for physical_network, vlan_ranges in network_vlan_ranges.items():
# determine current configured allocatable vlans for this
# physical network
vlan_ids = _get_sorted_vlan_ids(vlan_ranges)
# add missing allocatable vlans to table
for vlan_id in vlan_ids:
with db_session.begin(subtransactions=True):
seg_min, seg_max = get_segment_range(net_p)
for vlan_id in range(seg_min, seg_max + 1):
try:
alloc = get_vlan_allocation(db_session,
physical_network,
get_vlan_allocation(db_session,
net_p['physical_network'],
vlan_id)
except c_exc.VlanIDNotFound:
alloc = n1kv_models_v2.N1kvVlanAllocation(
physical_network=physical_network, vlan_id=vlan_id)
physical_network=net_p['physical_network'],
vlan_id=vlan_id,
network_profile_id=net_p['id'])
db_session.add(alloc)
def delete_vlan_allocations(db_session, network_vlan_ranges):
"""
Delete vlan_allocations for deleted network profile range.
:param db_session: database session
:param network_vlan_ranges: dictionary of network vlan ranges with the
physical network name as key.
"""
with db_session.begin():
# process vlan ranges for each physical network separately
for physical_network, vlan_ranges in network_vlan_ranges.items():
# Determine the set of vlan ids which need to be deleted.
vlan_ids = _get_sorted_vlan_ids(vlan_ranges)
allocs = (db_session.query(n1kv_models_v2.N1kvVlanAllocation).
filter_by(physical_network=physical_network).
filter_by(allocated=False))
for alloc in allocs:
if alloc.vlan_id in vlan_ids:
LOG.debug(_("Removing vlan %(vlan)s on physical "
"network %(network)s from pool"),
{"vlan": alloc.vlan_id,
"network": physical_network})
db_session.delete(alloc)
def get_vlan_allocation(db_session, physical_network, vlan_id):
"""
Retrieve vlan allocation.
@ -578,25 +536,19 @@ def reserve_specific_vlan(db_session, physical_network, vlan_id):
LOG.debug(_("Reserving specific vlan %(vlan)s on physical "
"network %(network)s from pool"),
{"vlan": vlan_id, "network": physical_network})
except exc.NoResultFound:
LOG.debug(_("Reserving specific vlan %(vlan)s on physical "
"network %(network)s outside pool"),
{"vlan": vlan_id, "network": physical_network})
alloc = n1kv_models_v2.N1kvVlanAllocation(
physical_network=physical_network, vlan_id=vlan_id)
db_session.add(alloc)
alloc.allocated = True
db_session.add(alloc)
except exc.NoResultFound:
raise c_exc.VlanIDOutsidePool
def release_vlan(db_session, physical_network, vlan_id, network_vlan_ranges):
def release_vlan(db_session, physical_network, vlan_id):
"""
Release a given VLAN ID.
:param db_session: database session
:param physical_network: string representing the name of physical network
:param vlan_id: integer value of the segmentation ID to be released
:param network_vlan_ranges: dictionary of network vlan ranges with the
physical network name as key.
"""
with db_session.begin(subtransactions=True):
try:
@ -605,70 +557,34 @@ def release_vlan(db_session, physical_network, vlan_id, network_vlan_ranges):
vlan_id=vlan_id).
one())
alloc.allocated = False
for vlan_range in network_vlan_ranges.get(physical_network, []):
if vlan_range[0] <= vlan_id <= vlan_range[1]:
msg = _("Releasing vlan %(vlan)s on physical "
"network %(network)s to pool")
break
else:
db_session.delete(alloc)
msg = _("Releasing vlan %(vlan)s on physical "
"network %(network)s outside pool")
LOG.debug(msg, {"vlan": vlan_id, "network": physical_network})
except exc.NoResultFound:
LOG.warning(_("vlan_id %(vlan)s on physical network %(network)s "
"not found"),
{"vlan": vlan_id, "network": physical_network})
def _get_sorted_vxlan_ids(vxlan_id_ranges):
"""Return sorted VXLAN IDs."""
vxlan_ids = set()
for vxlan_min, vxlan_max in vxlan_id_ranges:
if vxlan_max + 1 - vxlan_min > c_const.MAX_VXLAN_RANGE:
LOG.error(_("Skipping unreasonable vxlan ID range %(vxlan_min)s - "
"%(vxlan_max)s"),
{"vxlan_min": vxlan_min, "vxlan_max": vxlan_max})
else:
vxlan_ids |= set(xrange(vxlan_min, vxlan_max + 1))
return sorted(vxlan_ids)
def sync_vxlan_allocations(db_session, vxlan_id_ranges):
def sync_vxlan_allocations(db_session, net_p):
"""
Synchronize vxlan_allocations table with configured vxlan ranges.
:param db_session: database session
:param vxlan_id_ranges: list of segment range tuples
:param net_p: network profile dictionary
"""
vxlan_ids = _get_sorted_vxlan_ids(vxlan_id_ranges)
with db_session.begin():
for vxlan_id in vxlan_ids:
alloc = get_vxlan_allocation(db_session, vxlan_id)
if not alloc:
alloc = n1kv_models_v2.N1kvVxlanAllocation(vxlan_id=vxlan_id)
seg_min, seg_max = get_segment_range(net_p)
if seg_max + 1 - seg_min > c_const.MAX_VXLAN_RANGE:
msg = (_("Unreasonable vxlan ID range %(vxlan_min)s - %(vxlan_max)s"),
{"vxlan_min": seg_min, "vxlan_max": seg_max})
raise n_exc.InvalidInput(error_message=msg)
with db_session.begin(subtransactions=True):
for vxlan_id in range(seg_min, seg_max + 1):
try:
get_vxlan_allocation(db_session, vxlan_id)
except c_exc.VxlanIDNotFound:
alloc = n1kv_models_v2.N1kvVxlanAllocation(
network_profile_id=net_p['id'], vxlan_id=vxlan_id)
db_session.add(alloc)
def delete_vxlan_allocations(db_session, vxlan_id_ranges):
"""
Delete vxlan_allocations for deleted network profile range.
:param db_session: database session
:param vxlan_id_ranges: list of segment range tuples
"""
vxlan_ids = _get_sorted_vxlan_ids(vxlan_id_ranges)
with db_session.begin():
allocs = (db_session.query(n1kv_models_v2.N1kvVxlanAllocation).
filter_by(allocated=False))
for alloc in allocs:
if alloc.vxlan_id in vxlan_ids:
LOG.debug(_("Removing vxlan %s from pool"),
alloc.vxlan_id)
db_session.delete(alloc)
def get_vxlan_allocation(db_session, vxlan_id):
"""
Retrieve VXLAN allocation for the given VXLAN ID.
@ -677,8 +593,11 @@ def get_vxlan_allocation(db_session, vxlan_id):
:param vxlan_id: integer value representing the segmentation ID
:returns: allocation object
"""
try:
return (db_session.query(n1kv_models_v2.N1kvVxlanAllocation).
filter_by(vxlan_id=vxlan_id).first())
filter_by(vxlan_id=vxlan_id).one())
except exc.NoResultFound:
raise c_exc.VxlanIDNotFound(vxlan_id=vxlan_id)
def reserve_specific_vxlan(db_session, vxlan_id):
@ -694,22 +613,20 @@ def reserve_specific_vxlan(db_session, vxlan_id):
filter_by(vxlan_id=vxlan_id).
one())
if alloc.allocated:
raise c_exc.VxlanIdInUse(vxlan_id=vxlan_id)
raise c_exc.VxlanIDInUse(vxlan_id=vxlan_id)
LOG.debug(_("Reserving specific vxlan %s from pool"), vxlan_id)
except exc.NoResultFound:
LOG.debug(_("Reserving specific vxlan %s outside pool"), vxlan_id)
alloc = n1kv_models_v2.N1kvVxlanAllocation(vxlan_id=vxlan_id)
db_session.add(alloc)
alloc.allocated = True
db_session.add(alloc)
except exc.NoResultFound:
raise c_exc.VxlanIDOutsidePool
def release_vxlan(db_session, vxlan_id, vxlan_id_ranges):
def release_vxlan(db_session, vxlan_id):
"""
Release a given VXLAN ID.
:param db_session: database session
:param vxlan_id: integer value representing the segmentation ID
:param vxlan_id_ranges: list of the segment range tuples.
"""
with db_session.begin(subtransactions=True):
try:
@ -717,14 +634,6 @@ def release_vxlan(db_session, vxlan_id, vxlan_id_ranges):
filter_by(vxlan_id=vxlan_id).
one())
alloc.allocated = False
for vxlan_id_range in vxlan_id_ranges:
if vxlan_id_range[0] <= vxlan_id <= vxlan_id_range[1]:
msg = _("Releasing vxlan %s to pool")
break
else:
db_session.delete(alloc)
msg = _("Releasing vxlan %s outside pool")
LOG.debug(msg, vxlan_id)
except exc.NoResultFound:
LOG.warning(_("vxlan_id %s not found"), vxlan_id)
@ -1087,7 +996,12 @@ class NetworkProfile_db_mixin(object):
self._replace_fake_tenant_id_with_real(context)
p = network_profile["network_profile"]
self._validate_network_profile_args(context, p)
with context.session.begin(subtransactions=True):
net_profile = create_network_profile(context.session, p)
if net_profile.segment_type == c_const.NETWORK_TYPE_VLAN:
sync_vlan_allocations(context.session, net_profile)
elif net_profile.segment_type == c_const.NETWORK_TYPE_OVERLAY:
sync_vxlan_allocations(context.session, net_profile)
create_profile_binding(context.session,
context.tenant_id,
net_profile.id,

View File

@ -39,6 +39,10 @@ class N1kvVlanAllocation(model_base.BASEV2):
vlan_id = sa.Column(sa.Integer, nullable=False, primary_key=True,
autoincrement=False)
allocated = sa.Column(sa.Boolean, nullable=False, default=False)
network_profile_id = sa.Column(sa.String(36),
sa.ForeignKey('cisco_network_profiles.id',
ondelete="CASCADE"),
nullable=False)
class N1kvVxlanAllocation(model_base.BASEV2):
@ -49,6 +53,10 @@ class N1kvVxlanAllocation(model_base.BASEV2):
vxlan_id = sa.Column(sa.Integer, nullable=False, primary_key=True,
autoincrement=False)
allocated = sa.Column(sa.Boolean, nullable=False, default=False)
network_profile_id = sa.Column(sa.String(36),
sa.ForeignKey('cisco_network_profiles.id',
ondelete="CASCADE"),
nullable=False)
class N1kvPortBinding(model_base.BASEV2):

View File

@ -117,7 +117,6 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
portbindings.CAP_PORT_FILTER:
'security-group' in self.supported_extension_aliases}}
c_cred.Store.initialize()
self._initialize_network_ranges()
self._setup_vsm()
self._setup_rpc()
@ -214,28 +213,6 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
cisco_exceptions.VSMConnectionFailed):
LOG.warning(_('No policy profile updated from VSM'))
def _initialize_network_ranges(self):
self.network_vlan_ranges = {}
self.vxlan_id_ranges = []
network_profiles = n1kv_db_v2._get_network_profiles()
for network_profile in network_profiles:
seg_min, seg_max = self._get_segment_range(
network_profile['segment_range'])
if network_profile['segment_type'] == c_const.NETWORK_TYPE_VLAN:
self._add_network_vlan_range(network_profile[
'physical_network'], int(seg_min), int(seg_max))
elif network_profile['segment_type'] == (c_const.
NETWORK_TYPE_OVERLAY):
self.vxlan_id_ranges.append((int(seg_min), int(seg_max)))
def _add_network_vlan_range(self, physical_network, vlan_min, vlan_max):
self._add_network(physical_network)
self.network_vlan_ranges[physical_network].append((vlan_min, vlan_max))
def _add_network(self, physical_network):
if physical_network not in self.network_vlan_ranges:
self.network_vlan_ranges[physical_network] = []
def _extend_network_dict_provider(self, context, network):
"""Add extended network parameters."""
binding = n1kv_db_v2.get_network_binding(context.session,
@ -301,12 +278,15 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
if network_type == c_const.NETWORK_TYPE_VLAN:
if physical_network_set:
if physical_network not in self.network_vlan_ranges:
msg = (_("Unknown provider:physical_network %s") %
network_profiles = n1kv_db_v2.get_network_profiles()
for network_profile in network_profiles:
if physical_network == network_profile[
'physical_network']:
break
else:
msg = (_("Unknown provider:physical_network %s"),
physical_network)
raise n_exc.InvalidInput(error_message=msg)
elif 'default' in self.network_vlan_ranges:
physical_network = 'default'
else:
msg = _("provider:physical_network required")
raise n_exc.InvalidInput(error_message=msg)
@ -1113,22 +1093,15 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
msg = _("Cannot delete network '%s' that is a member of a "
"multi-segment network") % network['name']
raise n_exc.InvalidInput(error_message=msg)
if self.agent_vsm:
try:
self._send_delete_network_request(context, network)
except(cisco_exceptions.VSMError,
cisco_exceptions.VSMConnectionFailed):
LOG.debug(_('Delete failed in VSM'))
super(N1kvNeutronPluginV2, self).delete_network(context, id)
if binding.network_type == c_const.NETWORK_TYPE_OVERLAY:
n1kv_db_v2.release_vxlan(session, binding.segmentation_id,
self.vxlan_id_ranges)
n1kv_db_v2.release_vxlan(session, binding.segmentation_id)
elif binding.network_type == c_const.NETWORK_TYPE_VLAN:
n1kv_db_v2.release_vlan(session, binding.physical_network,
binding.segmentation_id,
self.network_vlan_ranges)
binding.segmentation_id)
# the network_binding record is deleted via cascade from
# the network record, so explicit removal is not necessary
self._send_delete_network_request(context, network)
super(N1kvNeutronPluginV2, self).delete_network(context, id)
LOG.debug(_("Deleted network: %s"), id)
def get_network(self, context, id, fields=None):
@ -1390,40 +1363,27 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
:returns: network profile object
"""
self._replace_fake_tenant_id_with_real(context)
_network_profile = super(
N1kvNeutronPluginV2, self).create_network_profile(context,
with context.session.begin(subtransactions=True):
net_p = super(N1kvNeutronPluginV2,
self).create_network_profile(context,
network_profile)
if _network_profile['segment_type'] in [c_const.NETWORK_TYPE_VLAN,
c_const.NETWORK_TYPE_OVERLAY]:
seg_min, seg_max = self._get_segment_range(
_network_profile['segment_range'])
if _network_profile['segment_type'] == c_const.NETWORK_TYPE_VLAN:
self._add_network_vlan_range(
_network_profile['physical_network'], int(seg_min),
int(seg_max))
n1kv_db_v2.sync_vlan_allocations(context.session,
self.network_vlan_ranges)
else:
self.vxlan_id_ranges = [(int(seg_min), int(seg_max))]
n1kv_db_v2.sync_vxlan_allocations(context.session,
self.vxlan_id_ranges)
try:
self._send_create_logical_network_request(_network_profile,
self._send_create_logical_network_request(net_p,
context.tenant_id)
except(cisco_exceptions.VSMError,
cisco_exceptions.VSMConnectionFailed):
super(N1kvNeutronPluginV2, self).delete_network_profile(
context, _network_profile['id'])
n1kv_db_v2.delete_profile_binding(context.session,
context.tenant_id,
net_p['id'])
try:
self._send_create_network_profile_request(context,
_network_profile)
self._send_create_network_profile_request(context, net_p)
except(cisco_exceptions.VSMError,
cisco_exceptions.VSMConnectionFailed):
self._send_delete_logical_network_request(_network_profile)
super(N1kvNeutronPluginV2, self).delete_network_profile(
context, _network_profile['id'])
else:
return _network_profile
n1kv_db_v2.delete_profile_binding(context.session,
context.tenant_id,
net_p['id'])
self._send_delete_logical_network_request(net_p)
return net_p
def delete_network_profile(self, context, id):
"""
@ -1433,22 +1393,11 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
:param id: UUID of the network profile to delete
:returns: deleted network profile object
"""
_network_profile = super(
N1kvNeutronPluginV2, self).delete_network_profile(context, id)
seg_min, seg_max = self._get_segment_range(
_network_profile['segment_range'])
if _network_profile['segment_type'] == c_const.NETWORK_TYPE_VLAN:
self._add_network_vlan_range(_network_profile['physical_network'],
int(seg_min),
int(seg_max))
n1kv_db_v2.delete_vlan_allocations(context.session,
self.network_vlan_ranges)
elif _network_profile['segment_type'] == c_const.NETWORK_TYPE_OVERLAY:
self.delete_vxlan_ranges = []
self.delete_vxlan_ranges.append((int(seg_min), int(seg_max)))
n1kv_db_v2.delete_vxlan_allocations(context.session,
self.delete_vxlan_ranges)
self._send_delete_network_profile_request(_network_profile)
with context.session.begin(subtransactions=True):
net_p = super(N1kvNeutronPluginV2,
self).delete_network_profile(context, id)
self._send_delete_network_profile_request(net_p)
self._send_delete_logical_network_request(net_p)
def update_network_profile(self, context, net_profile_id, network_profile):
"""

View File

@ -38,13 +38,8 @@ PHYS_NET = 'physnet1'
PHYS_NET_2 = 'physnet2'
VLAN_MIN = 10
VLAN_MAX = 19
VLAN_RANGES = {PHYS_NET: [(VLAN_MIN, VLAN_MAX)]}
UPDATED_VLAN_RANGES = {PHYS_NET: [(VLAN_MIN + 20, VLAN_MAX + 20)],
PHYS_NET_2: [(VLAN_MIN + 40, VLAN_MAX + 40)]}
VXLAN_MIN = 5000
VXLAN_MAX = 5009
VXLAN_RANGES = [(VXLAN_MIN, VXLAN_MAX)]
UPDATED_VXLAN_RANGES = [(VXLAN_MIN + 20, VXLAN_MAX + 20)]
SEGMENT_RANGE = '200-220'
SEGMENT_RANGE_MIN_OVERLAP = '210-230'
SEGMENT_RANGE_MAX_OVERLAP = '190-209'
@ -103,7 +98,8 @@ class VlanAllocationsTest(base.BaseTestCase):
super(VlanAllocationsTest, self).setUp()
db.configure_db()
self.session = db.get_session()
n1kv_db_v2.sync_vlan_allocations(self.session, VLAN_RANGES)
self.net_p = _create_test_network_profile_if_not_there(self.session)
n1kv_db_v2.sync_vlan_allocations(self.session, self.net_p)
self.addCleanup(db.clear_db)
def test_sync_vlan_allocations_outside_segment_range(self):
@ -117,28 +113,6 @@ class VlanAllocationsTest(base.BaseTestCase):
self.session,
PHYS_NET,
VLAN_MAX + 1)
n1kv_db_v2.sync_vlan_allocations(self.session, UPDATED_VLAN_RANGES)
self.assertRaises(c_exc.VlanIDNotFound,
n1kv_db_v2.get_vlan_allocation,
self.session,
PHYS_NET,
VLAN_MIN + 20 - 1)
self.assertRaises(c_exc.VlanIDNotFound,
n1kv_db_v2.get_vlan_allocation,
self.session,
PHYS_NET,
VLAN_MAX + 20 + 1)
self.assertRaises(c_exc.VlanIDNotFound,
n1kv_db_v2.get_vlan_allocation,
self.session,
PHYS_NET_2,
VLAN_MIN + 40 - 1)
self.assertRaises(c_exc.VlanIDNotFound,
n1kv_db_v2.get_vlan_allocation,
self.session,
PHYS_NET_2,
VLAN_MAX + 40 + 1)
n1kv_db_v2.sync_vlan_allocations(self.session, VLAN_RANGES)
self.assertRaises(c_exc.VlanIDNotFound,
n1kv_db_v2.get_vlan_allocation,
self.session,
@ -170,45 +144,12 @@ class VlanAllocationsTest(base.BaseTestCase):
self.assertFalse(n1kv_db_v2.get_vlan_allocation(self.session,
PHYS_NET,
VLAN_MAX).allocated)
n1kv_db_v2.sync_vlan_allocations(self.session, UPDATED_VLAN_RANGES)
self.assertFalse(n1kv_db_v2.get_vlan_allocation(self.session,
PHYS_NET,
VLAN_MIN + 20).
allocated)
self.assertFalse(n1kv_db_v2.get_vlan_allocation(self.session,
PHYS_NET,
VLAN_MIN + 20 + 1).
allocated)
self.assertFalse(n1kv_db_v2.get_vlan_allocation(self.session,
PHYS_NET,
VLAN_MAX + 20 - 1).
allocated)
self.assertFalse(n1kv_db_v2.get_vlan_allocation(self.session, PHYS_NET,
VLAN_MAX + 20).
allocated)
self.assertFalse(n1kv_db_v2.get_vlan_allocation(self.session,
PHYS_NET_2,
VLAN_MIN + 40).
allocated)
self.assertFalse(n1kv_db_v2.get_vlan_allocation(self.session,
PHYS_NET_2,
VLAN_MIN + 40 + 1).
allocated)
self.assertFalse(n1kv_db_v2.get_vlan_allocation(self.session,
PHYS_NET_2,
VLAN_MAX + 40 - 1).
allocated)
self.assertFalse(n1kv_db_v2.get_vlan_allocation(self.session,
PHYS_NET_2,
VLAN_MAX + 40).
allocated)
def test_vlan_pool(self):
vlan_ids = set()
p = _create_test_network_profile_if_not_there(self.session)
for x in xrange(VLAN_MIN, VLAN_MAX + 1):
(physical_network, seg_type,
vlan_id, m_ip) = n1kv_db_v2.reserve_vlan(self.session, p)
vlan_id, m_ip) = n1kv_db_v2.reserve_vlan(self.session, self.net_p)
self.assertEqual(physical_network, PHYS_NET)
self.assertThat(vlan_id, matchers.GreaterThan(VLAN_MIN - 1))
self.assertThat(vlan_id, matchers.LessThan(VLAN_MAX + 1))
@ -217,20 +158,18 @@ class VlanAllocationsTest(base.BaseTestCase):
self.assertRaises(n_exc.NoNetworkAvailable,
n1kv_db_v2.reserve_vlan,
self.session,
p)
self.net_p)
n1kv_db_v2.release_vlan(self.session, PHYS_NET, vlan_ids.pop(),
VLAN_RANGES)
n1kv_db_v2.release_vlan(self.session, PHYS_NET, vlan_ids.pop())
physical_network, seg_type, vlan_id, m_ip = (n1kv_db_v2.reserve_vlan(
self.session, p))
self.session, self.net_p))
self.assertEqual(physical_network, PHYS_NET)
self.assertThat(vlan_id, matchers.GreaterThan(VLAN_MIN - 1))
self.assertThat(vlan_id, matchers.LessThan(VLAN_MAX + 1))
vlan_ids.add(vlan_id)
for vlan_id in vlan_ids:
n1kv_db_v2.release_vlan(self.session, PHYS_NET, vlan_id,
VLAN_RANGES)
n1kv_db_v2.release_vlan(self.session, PHYS_NET, vlan_id)
def test_specific_vlan_inside_pool(self):
vlan_id = VLAN_MIN + 5
@ -248,7 +187,7 @@ class VlanAllocationsTest(base.BaseTestCase):
PHYS_NET,
vlan_id)
n1kv_db_v2.release_vlan(self.session, PHYS_NET, vlan_id, VLAN_RANGES)
n1kv_db_v2.release_vlan(self.session, PHYS_NET, vlan_id)
self.assertFalse(n1kv_db_v2.get_vlan_allocation(self.session,
PHYS_NET,
vlan_id).allocated)
@ -260,23 +199,12 @@ class VlanAllocationsTest(base.BaseTestCase):
self.session,
PHYS_NET,
vlan_id)
n1kv_db_v2.reserve_specific_vlan(self.session, PHYS_NET, vlan_id)
self.assertTrue(n1kv_db_v2.get_vlan_allocation(self.session, PHYS_NET,
vlan_id).allocated)
self.assertRaises(n_exc.VlanIdInUse,
self.assertRaises(c_exc.VlanIDOutsidePool,
n1kv_db_v2.reserve_specific_vlan,
self.session,
PHYS_NET,
vlan_id)
n1kv_db_v2.release_vlan(self.session, PHYS_NET, vlan_id, VLAN_RANGES)
self.assertRaises(c_exc.VlanIDNotFound,
n1kv_db_v2.get_vlan_allocation,
self.session,
PHYS_NET,
vlan_id)
class VxlanAllocationsTest(base.BaseTestCase,
n1kv_db_v2.NetworkProfile_db_mixin):
@ -285,19 +213,20 @@ class VxlanAllocationsTest(base.BaseTestCase,
super(VxlanAllocationsTest, self).setUp()
db.configure_db()
self.session = db.get_session()
n1kv_db_v2.sync_vxlan_allocations(self.session, VXLAN_RANGES)
self.net_p = _create_test_network_profile_if_not_there(
self.session, TEST_NETWORK_PROFILE_VXLAN)
n1kv_db_v2.sync_vxlan_allocations(self.session, self.net_p)
self.addCleanup(db.clear_db)
def test_sync_vxlan_allocations_outside_segment_range(self):
self.assertIsNone(n1kv_db_v2.get_vxlan_allocation(self.session,
VXLAN_MIN - 1))
self.assertIsNone(n1kv_db_v2.get_vxlan_allocation(self.session,
VXLAN_MAX + 1))
n1kv_db_v2.sync_vxlan_allocations(self.session, UPDATED_VXLAN_RANGES)
self.assertIsNone(n1kv_db_v2.get_vxlan_allocation(self.session,
VXLAN_MIN + 20 - 1))
self.assertIsNone(n1kv_db_v2.get_vxlan_allocation(self.session,
VXLAN_MAX + 20 + 1))
self.assertRaises(c_exc.VxlanIDNotFound,
n1kv_db_v2.get_vxlan_allocation,
self.session,
VXLAN_MIN - 1)
self.assertRaises(c_exc.VxlanIDNotFound,
n1kv_db_v2.get_vxlan_allocation,
self.session,
VXLAN_MAX + 1)
def test_sync_vxlan_allocations_unallocated_vxlans(self):
self.assertFalse(n1kv_db_v2.get_vxlan_allocation(self.session,
@ -310,26 +239,11 @@ class VxlanAllocationsTest(base.BaseTestCase,
allocated)
self.assertFalse(n1kv_db_v2.get_vxlan_allocation(self.session,
VXLAN_MAX).allocated)
n1kv_db_v2.sync_vxlan_allocations(self.session, UPDATED_VXLAN_RANGES)
self.assertFalse(n1kv_db_v2.get_vxlan_allocation(self.session,
VXLAN_MIN + 20).
allocated)
self.assertFalse(n1kv_db_v2.get_vxlan_allocation(self.session,
VXLAN_MIN + 20 + 1).
allocated)
self.assertFalse(n1kv_db_v2.get_vxlan_allocation(self.session,
VXLAN_MAX + 20 - 1).
allocated)
self.assertFalse(n1kv_db_v2.get_vxlan_allocation(self.session,
VXLAN_MAX + 20).
allocated)
def test_vxlan_pool(self):
vxlan_ids = set()
profile = n1kv_db_v2.create_network_profile(self.session,
TEST_NETWORK_PROFILE_VXLAN)
for x in xrange(VXLAN_MIN, VXLAN_MAX + 1):
vxlan = n1kv_db_v2.reserve_vxlan(self.session, profile)
vxlan = n1kv_db_v2.reserve_vxlan(self.session, self.net_p)
vxlan_id = vxlan[2]
self.assertThat(vxlan_id, matchers.GreaterThan(VXLAN_MIN - 1))
self.assertThat(vxlan_id, matchers.LessThan(VXLAN_MAX + 1))
@ -338,17 +252,17 @@ class VxlanAllocationsTest(base.BaseTestCase,
self.assertRaises(n_exc.NoNetworkAvailable,
n1kv_db_v2.reserve_vxlan,
self.session,
profile)
n1kv_db_v2.release_vxlan(self.session, vxlan_ids.pop(), VXLAN_RANGES)
vxlan = n1kv_db_v2.reserve_vxlan(self.session, profile)
self.net_p)
n1kv_db_v2.release_vxlan(self.session, vxlan_ids.pop())
vxlan = n1kv_db_v2.reserve_vxlan(self.session, self.net_p)
vxlan_id = vxlan[2]
self.assertThat(vxlan_id, matchers.GreaterThan(VXLAN_MIN - 1))
self.assertThat(vxlan_id, matchers.LessThan(VXLAN_MAX + 1))
vxlan_ids.add(vxlan_id)
for vxlan_id in vxlan_ids:
n1kv_db_v2.release_vxlan(self.session, vxlan_id, VXLAN_RANGES)
n1kv_db_v2.delete_network_profile(self.session, profile.id)
n1kv_db_v2.release_vxlan(self.session, vxlan_id)
n1kv_db_v2.delete_network_profile(self.session, self.net_p.id)
def test_specific_vxlan_inside_pool(self):
vxlan_id = VXLAN_MIN + 5
@ -358,32 +272,26 @@ class VxlanAllocationsTest(base.BaseTestCase,
self.assertTrue(n1kv_db_v2.get_vxlan_allocation(self.session,
vxlan_id).allocated)
self.assertRaises(c_exc.VxlanIdInUse,
self.assertRaises(c_exc.VxlanIDInUse,
n1kv_db_v2.reserve_specific_vxlan,
self.session,
vxlan_id)
n1kv_db_v2.release_vxlan(self.session, vxlan_id, VXLAN_RANGES)
n1kv_db_v2.release_vxlan(self.session, vxlan_id)
self.assertFalse(n1kv_db_v2.get_vxlan_allocation(self.session,
vxlan_id).allocated)
def test_specific_vxlan_outside_pool(self):
vxlan_id = VXLAN_MAX + 5
self.assertIsNone(n1kv_db_v2.get_vxlan_allocation(self.session,
vxlan_id))
n1kv_db_v2.reserve_specific_vxlan(self.session, vxlan_id)
self.assertTrue(n1kv_db_v2.get_vxlan_allocation(self.session,
vxlan_id).allocated)
self.assertRaises(c_exc.VxlanIdInUse,
self.assertRaises(c_exc.VxlanIDNotFound,
n1kv_db_v2.get_vxlan_allocation,
self.session,
vxlan_id)
self.assertRaises(c_exc.VxlanIDOutsidePool,
n1kv_db_v2.reserve_specific_vxlan,
self.session,
vxlan_id)
n1kv_db_v2.release_vxlan(self.session, vxlan_id, VXLAN_RANGES)
self.assertIsNone(n1kv_db_v2.get_vxlan_allocation(self.session,
vxlan_id))
class NetworkBindingsTest(test_plugin.NeutronDbPluginV2TestCase):
@ -943,8 +851,7 @@ class ProfileBindingTests(base.BaseTestCase,
test_profile_id,
test_profile_type)
network_profile = {"network_profile": TEST_NETWORK_PROFILE}
test_network_profile = self.create_network_profile(ctx,
network_profile)
self.create_network_profile(ctx, network_profile)
binding = n1kv_db_v2.get_profile_binding(self.session,
ctx.tenant_id,
test_profile_id)
@ -954,5 +861,3 @@ class ProfileBindingTests(base.BaseTestCase,
test_profile_id))
self.assertNotEqual(binding.tenant_id,
cisco_constants.TENANT_ID_NOT_SET)
n1kv_db_v2.delete_network_profile(self.session,
test_network_profile['id'])

View File

@ -24,6 +24,7 @@ from neutron.api.v2 import attributes
from neutron import context
import neutron.db.api as db
from neutron.extensions import portbindings
from neutron.plugins.cisco.common import cisco_exceptions as c_exc
from neutron.plugins.cisco.db import n1kv_db_v2
from neutron.plugins.cisco.db import network_db_v2 as cdb
from neutron.plugins.cisco import extensions
@ -36,6 +37,11 @@ from neutron.tests.unit import test_api_v2
from neutron.tests.unit import test_db_plugin as test_plugin
PHYS_NET = 'some-phys-net'
VLAN_MIN = 100
VLAN_MAX = 110
class FakeResponse(object):
"""
@ -105,23 +111,27 @@ class N1kvPluginTestCase(test_plugin.NeutronDbPluginV2TestCase):
'name': name}
return n1kv_db_v2.create_policy_profile(profile)
def _make_test_profile(self, name='default_network_profile'):
def _make_test_profile(self,
name='default_network_profile',
segment_range='386-400'):
"""
Create a profile record for testing purposes.
:param name: string representing the name of the network profile to
create. Default argument value chosen to correspond to the
default name specified in config.py file.
:param segment_range: string representing the segment range for network
profile.
"""
db_session = db.get_session()
profile = {'name': name,
'segment_type': 'vlan',
'physical_network': 'phsy1',
'segment_range': '3968-4047'}
self.network_vlan_ranges = {profile[
'physical_network']: [(3968, 4047)]}
n1kv_db_v2.sync_vlan_allocations(db_session, self.network_vlan_ranges)
return n1kv_db_v2.create_network_profile(db_session, profile)
'physical_network': PHYS_NET,
'tenant_id': self.tenant_id,
'segment_range': segment_range}
net_p = n1kv_db_v2.create_network_profile(db_session, profile)
n1kv_db_v2.sync_vlan_allocations(db_session, net_p)
return net_p
def setUp(self):
"""
@ -244,8 +254,8 @@ class TestN1kvNetworkProfiles(N1kvPluginTestCase):
'segment_type': segment_type,
'tenant_id': self.tenant_id}}
if segment_type == 'vlan':
netp['network_profile']['segment_range'] = '100-180'
netp['network_profile']['physical_network'] = 'phys1'
netp['network_profile']['segment_range'] = '100-110'
netp['network_profile']['physical_network'] = PHYS_NET
elif segment_type == 'overlay':
netp['network_profile']['segment_range'] = '10000-10010'
netp['network_profile']['sub_type'] = 'enhanced' or 'native_vxlan'
@ -253,15 +263,40 @@ class TestN1kvNetworkProfiles(N1kvPluginTestCase):
"224.1.1.10")
return netp
def test_create_network_profile_plugin(self):
def test_create_network_profile_vlan(self):
data = self._prepare_net_profile_data('vlan')
net_p_req = self.new_create_request('network_profiles', data)
res = net_p_req.get_response(self.ext_api)
self.assertEqual(res.status_int, 201)
def test_create_network_profile_overlay(self):
data = self._prepare_net_profile_data('overlay')
net_p_req = self.new_create_request('network_profiles', data)
res = net_p_req.get_response(self.ext_api)
self.assertEqual(res.status_int, 201)
def test_create_network_profile_overlay_unreasonable_seg_range(self):
data = self._prepare_net_profile_data('overlay')
data['network_profile']['segment_range'] = '10000-100000000001'
net_p_req = self.new_create_request('network_profiles', data)
res = net_p_req.get_response(self.ext_api)
self.assertEqual(res.status_int, 400)
def test_update_network_profile_plugin(self):
net_p_dict = self._prepare_net_profile_data('overlay')
net_p_req = self.new_create_request('network_profiles', net_p_dict)
net_p = self.deserialize(self.fmt,
net_p_req.get_response(self.ext_api))
data = {'network_profile': {'name': 'netp2'}}
update_req = self.new_update_request('network_profiles',
data,
net_p['network_profile']['id'])
update_res = update_req.get_response(self.ext_api)
self.assertEqual(update_res.status_int, 200)
def test_update_network_profile_physical_network_fail(self):
net_p = self._make_test_profile(name='netp1')
data = {'network_profile': {'physical_network': 'some-phys-net'}}
data = {'network_profile': {'physical_network': PHYS_NET}}
net_p_req = self.new_update_request('network_profiles',
data,
net_p['id'])
@ -343,6 +378,47 @@ class TestN1kvNetworkProfiles(N1kvPluginTestCase):
res = net_p_req.get_response(self.ext_api)
self.assertEqual(res.status_int, 201)
def test_create_network_profile_populate_vlan_segment_pool(self):
db_session = db.get_session()
net_p_dict = self._prepare_net_profile_data('vlan')
net_p_req = self.new_create_request('network_profiles', net_p_dict)
self.deserialize(self.fmt,
net_p_req.get_response(self.ext_api))
for vlan in range(VLAN_MIN, VLAN_MAX + 1):
self.assertIsNotNone(n1kv_db_v2.get_vlan_allocation(db_session,
PHYS_NET,
vlan))
self.assertFalse(n1kv_db_v2.get_vlan_allocation(db_session,
PHYS_NET,
vlan).allocated)
self.assertRaises(c_exc.VlanIDNotFound,
n1kv_db_v2.get_vlan_allocation,
db_session,
PHYS_NET,
VLAN_MIN - 1)
self.assertRaises(c_exc.VlanIDNotFound,
n1kv_db_v2.get_vlan_allocation,
db_session,
PHYS_NET,
VLAN_MAX + 1)
def test_delete_network_profile_deallocate_vlan_segment_pool(self):
db_session = db.get_session()
net_p_dict = self._prepare_net_profile_data('vlan')
net_p_req = self.new_create_request('network_profiles', net_p_dict)
net_p = self.deserialize(self.fmt,
net_p_req.get_response(self.ext_api))
self.assertIsNotNone(n1kv_db_v2.get_vlan_allocation(db_session,
PHYS_NET,
VLAN_MIN))
self._delete('network_profiles', net_p['network_profile']['id'])
for vlan in range(VLAN_MIN, VLAN_MAX + 1):
self.assertRaises(c_exc.VlanIDNotFound,
n1kv_db_v2.get_vlan_allocation,
db_session,
PHYS_NET,
vlan)
class TestN1kvBasicGet(test_plugin.TestBasicGet,
N1kvPluginTestCase):