Merge "Fixes enable taas id reuse"
This commit is contained in:
commit
a69e2f47fa
|
@ -1 +1 @@
|
||||||
4086b3cffc01
|
bac61f603e39
|
||||||
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
# Copyright 2016-17
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
"""Alter TapIdAssociations to support tap id reuse
|
||||||
|
|
||||||
|
Revision ID: bac61f603e39
|
||||||
|
Revises: 4086b3cffc01
|
||||||
|
Create Date: 2016-07-27 09:31:54.200165
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = 'bac61f603e39'
|
||||||
|
down_revision = '4086b3cffc01'
|
||||||
|
|
||||||
|
from alembic import op
|
||||||
|
from sqlalchemy.engine import reflection
|
||||||
|
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
TABLE_NAME = 'tap_id_associations'
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
inspector = reflection.Inspector.from_engine(op.get_bind())
|
||||||
|
fk_constraints = inspector.get_foreign_keys(TABLE_NAME)
|
||||||
|
for fk in fk_constraints:
|
||||||
|
op.drop_constraint(fk['name'], TABLE_NAME, type_='foreignkey')
|
||||||
|
|
||||||
|
op.create_foreign_key('fk_tap_id_assoc_tap_service', TABLE_NAME,
|
||||||
|
'tap_services', ['tap_service_id'], ['id'],
|
||||||
|
ondelete='SET NULL')
|
||||||
|
|
||||||
|
op.alter_column(TABLE_NAME, 'taas_id', autoincrement=False,
|
||||||
|
existing_type=sa.INTEGER, nullable=False)
|
||||||
|
op.alter_column(TABLE_NAME, 'tap_service_id',
|
||||||
|
existing_type=sa.String(36), nullable=True)
|
||||||
|
op.create_unique_constraint('unique_taas_id', TABLE_NAME,
|
||||||
|
['taas_id'])
|
|
@ -23,10 +23,10 @@ from neutron_lib import constants
|
||||||
from neutron_lib.db import model_base
|
from neutron_lib.db import model_base
|
||||||
from neutron_lib.plugins import directory
|
from neutron_lib.plugins import directory
|
||||||
from neutron_taas.extensions import taas
|
from neutron_taas.extensions import taas
|
||||||
|
from oslo_config import cfg
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
from oslo_utils import uuidutils
|
from oslo_utils import uuidutils
|
||||||
|
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
@ -68,12 +68,13 @@ class TapIdAssociation(model_base.BASEV2):
|
||||||
__tablename__ = 'tap_id_associations'
|
__tablename__ = 'tap_id_associations'
|
||||||
tap_service_id = sa.Column(sa.String(36),
|
tap_service_id = sa.Column(sa.String(36),
|
||||||
sa.ForeignKey("tap_services.id",
|
sa.ForeignKey("tap_services.id",
|
||||||
ondelete='CASCADE'))
|
ondelete='SET NULL'),
|
||||||
taas_id = sa.Column(sa.Integer, primary_key=True, autoincrement=True)
|
nullable=True)
|
||||||
|
taas_id = sa.Column(sa.Integer, primary_key=True, unique=True)
|
||||||
tap_service = orm.relationship(
|
tap_service = orm.relationship(
|
||||||
TapService,
|
TapService,
|
||||||
backref=orm.backref("tap_service_id",
|
backref=orm.backref("tap_service_id",
|
||||||
lazy="joined", cascade="delete"),
|
lazy="joined"),
|
||||||
primaryjoin='TapService.id==TapIdAssociation.tap_service_id')
|
primaryjoin='TapService.id==TapIdAssociation.tap_service_id')
|
||||||
|
|
||||||
|
|
||||||
|
@ -147,14 +148,47 @@ class Taas_db_Mixin(taas.TaasPluginBase, base_db.CommonDbMixin):
|
||||||
|
|
||||||
return self._make_tap_service_dict(tap_service_db)
|
return self._make_tap_service_dict(tap_service_db)
|
||||||
|
|
||||||
|
def _rebuild_taas_id_allocation_range(self, context):
|
||||||
|
query = context.session.query(
|
||||||
|
TapIdAssociation).all()
|
||||||
|
|
||||||
|
allocate_taas_id_list = [_q.taas_id for _q in query]
|
||||||
|
first_taas_id = cfg.CONF.taas.vlan_range_start
|
||||||
|
# Exclude range end
|
||||||
|
last_taas_id = cfg.CONF.taas.vlan_range_end
|
||||||
|
all_taas_id_set = set(range(first_taas_id, last_taas_id))
|
||||||
|
vaild_taas_id_set = all_taas_id_set - set(allocate_taas_id_list)
|
||||||
|
|
||||||
|
for _id in vaild_taas_id_set:
|
||||||
|
# new taas id
|
||||||
|
context.session.add(TapIdAssociation(
|
||||||
|
taas_id=_id))
|
||||||
|
|
||||||
|
def _allocate_taas_id_with_tap_service_id(self, context, tap_service_id):
|
||||||
|
query = context.session.query(TapIdAssociation).filter_by(
|
||||||
|
tap_service_id=None).first()
|
||||||
|
if not query:
|
||||||
|
self._rebuild_taas_id_allocation_range(context)
|
||||||
|
# try again
|
||||||
|
query = context.session.query(TapIdAssociation).filter_by(
|
||||||
|
tap_service_id=None).first()
|
||||||
|
|
||||||
|
if query:
|
||||||
|
query.update({"tap_service_id": tap_service_id})
|
||||||
|
return query
|
||||||
|
# not found
|
||||||
|
raise taas.TapServiceLimitReached()
|
||||||
|
|
||||||
def create_tap_id_association(self, context, tap_service_id):
|
def create_tap_id_association(self, context, tap_service_id):
|
||||||
LOG.debug("create_tap_id_association() called")
|
LOG.debug("create_tap_id_association() called")
|
||||||
# create the TapIdAssociation object
|
# create the TapIdAssociation object
|
||||||
with context.session.begin(subtransactions=True):
|
with context.session.begin(subtransactions=True):
|
||||||
tap_id_association_db = TapIdAssociation(
|
# allocate Taas id.
|
||||||
tap_service_id=tap_service_id
|
# if conflict happened, it will raise db.DBDuplicateEntry.
|
||||||
)
|
# this will be retry request again in neutron controller framework.
|
||||||
context.session.add(tap_id_association_db)
|
# so we just make sure TapIdAssociation field taas_id is unique
|
||||||
|
tap_id_association_db = self._allocate_taas_id_with_tap_service_id(
|
||||||
|
context, tap_service_id)
|
||||||
|
|
||||||
return self._make_tap_id_association_dict(tap_id_association_db)
|
return self._make_tap_id_association_dict(tap_id_association_db)
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,6 @@
|
||||||
from neutron.common import rpc as n_rpc
|
from neutron.common import rpc as n_rpc
|
||||||
from neutron_lib import exceptions as n_exc
|
from neutron_lib import exceptions as n_exc
|
||||||
from neutron_taas.common import topics
|
from neutron_taas.common import topics
|
||||||
from neutron_taas.extensions import taas as taas_ex
|
|
||||||
from neutron_taas.services.taas import service_drivers
|
from neutron_taas.services.taas import service_drivers
|
||||||
from neutron_taas.services.taas.service_drivers import taas_agent_api
|
from neutron_taas.services.taas.service_drivers import taas_agent_api
|
||||||
|
|
||||||
|
@ -52,8 +51,7 @@ class TaasRpcDriver(service_drivers.TaasBaseDriver):
|
||||||
tf['tap_service_id'])
|
tf['tap_service_id'])
|
||||||
taas_id = (self.service_plugin.get_tap_id_association(
|
taas_id = (self.service_plugin.get_tap_id_association(
|
||||||
context,
|
context,
|
||||||
tap_service_id=ts['id'])['taas_id'] +
|
tap_service_id=ts['id']))['taas_id']
|
||||||
cfg.CONF.taas.vlan_range_start)
|
|
||||||
return taas_id
|
return taas_id
|
||||||
|
|
||||||
def create_tap_service_precommit(self, context):
|
def create_tap_service_precommit(self, context):
|
||||||
|
@ -71,15 +69,11 @@ class TaasRpcDriver(service_drivers.TaasBaseDriver):
|
||||||
# Get taas id associated with the Tap Service
|
# Get taas id associated with the Tap Service
|
||||||
ts = context.tap_service
|
ts = context.tap_service
|
||||||
tap_id_association = context.tap_id_association
|
tap_id_association = context.tap_id_association
|
||||||
taas_vlan_id = (tap_id_association['taas_id'] +
|
taas_vlan_id = tap_id_association['taas_id']
|
||||||
cfg.CONF.taas.vlan_range_start)
|
|
||||||
port = self.service_plugin._get_port_details(context._plugin_context,
|
port = self.service_plugin._get_port_details(context._plugin_context,
|
||||||
ts['port_id'])
|
ts['port_id'])
|
||||||
host = port['binding:host_id']
|
host = port['binding:host_id']
|
||||||
|
|
||||||
if taas_vlan_id > cfg.CONF.taas.vlan_range_end:
|
|
||||||
raise taas_ex.TapServiceLimitReached()
|
|
||||||
|
|
||||||
rpc_msg = {'tap_service': ts,
|
rpc_msg = {'tap_service': ts,
|
||||||
'taas_id': taas_vlan_id,
|
'taas_id': taas_vlan_id,
|
||||||
'port': port}
|
'port': port}
|
||||||
|
@ -99,8 +93,8 @@ class TaasRpcDriver(service_drivers.TaasBaseDriver):
|
||||||
"""
|
"""
|
||||||
ts = context.tap_service
|
ts = context.tap_service
|
||||||
tap_id_association = context.tap_id_association
|
tap_id_association = context.tap_id_association
|
||||||
taas_vlan_id = (tap_id_association['taas_id'] +
|
taas_vlan_id = tap_id_association['taas_id']
|
||||||
cfg.CONF.taas.vlan_range_start)
|
|
||||||
try:
|
try:
|
||||||
port = self.service_plugin._get_port_details(
|
port = self.service_plugin._get_port_details(
|
||||||
context._plugin_context,
|
context._plugin_context,
|
||||||
|
|
|
@ -20,6 +20,7 @@ import testtools
|
||||||
|
|
||||||
from neutron_lib import context
|
from neutron_lib import context
|
||||||
from neutron_lib.utils import net as n_utils
|
from neutron_lib.utils import net as n_utils
|
||||||
|
from oslo_config import cfg
|
||||||
from oslo_utils import uuidutils
|
from oslo_utils import uuidutils
|
||||||
|
|
||||||
import neutron.common.rpc as n_rpc
|
import neutron.common.rpc as n_rpc
|
||||||
|
@ -130,6 +131,33 @@ class TestTaasPlugin(testlib_api.SqlTestCase):
|
||||||
with self.tap_service():
|
with self.tap_service():
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def test_verify_taas_id_reused(self):
|
||||||
|
# make small range id
|
||||||
|
cfg.CONF.set_override("vlan_range_start", 1, group="taas")
|
||||||
|
cfg.CONF.set_override("vlan_range_end", 3, group="taas")
|
||||||
|
with self.tap_service() as ts_1, self.tap_service() as ts_2, \
|
||||||
|
self.tap_service() as ts_3, self.tap_service() as ts_4:
|
||||||
|
ts_id_1 = ts_1['id']
|
||||||
|
ts_id_2 = ts_2['id']
|
||||||
|
ts_id_3 = ts_3['id']
|
||||||
|
tap_id_assoc_1 = self._plugin.create_tap_id_association(
|
||||||
|
self._context, ts_id_1)
|
||||||
|
tap_id_assoc_2 = self._plugin.create_tap_id_association(
|
||||||
|
self._context, ts_id_2)
|
||||||
|
self.assertEqual(set([1, 2]), set([tap_id_assoc_1['taas_id'],
|
||||||
|
tap_id_assoc_2['taas_id']]))
|
||||||
|
with testtools.ExpectedException(taas_ext.TapServiceLimitReached):
|
||||||
|
self._plugin.create_tap_id_association(
|
||||||
|
self._context,
|
||||||
|
ts_4['id']
|
||||||
|
)
|
||||||
|
# free an tap_id and verify could reallocate same taas id
|
||||||
|
self._plugin.delete_tap_service(self._context, ts_id_1)
|
||||||
|
tap_id_assoc_3 = self._plugin.create_tap_id_association(
|
||||||
|
self._context, ts_id_3)
|
||||||
|
self.assertEqual(set([1, 2]), set([tap_id_assoc_3['taas_id'],
|
||||||
|
tap_id_assoc_2['taas_id']]))
|
||||||
|
|
||||||
def test_create_tap_service_wrong_tenant_id(self):
|
def test_create_tap_service_wrong_tenant_id(self):
|
||||||
self._port_details['tenant_id'] = 'other-tenant'
|
self._port_details['tenant_id'] = 'other-tenant'
|
||||||
with testtools.ExpectedException(taas_ext.PortDoesNotBelongToTenant), \
|
with testtools.ExpectedException(taas_ext.PortDoesNotBelongToTenant), \
|
||||||
|
|
Loading…
Reference in New Issue