This patch introduces the following: - data models and related schema migrations - first stub at DB operations - trunk module structure This is a tepid attempt to land the first functional code for this sorely needed feature. Partially-implements: blueprint vlan-aware-vms Change-Id: I84b2a7604b6a282ec7cb953482bf7b567ae2344dchanges/51/279251/12
parent
77844f08f3
commit
67b621de73
@ -1 +1 @@
|
||||
45f8dd33480b
|
||||
5abc0278ca73
|
||||
|
@ -0,0 +1,49 @@
|
||||
# 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.
|
||||
#
|
||||
|
||||
revision = '5abc0278ca73'
|
||||
down_revision = '45f8dd33480b'
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
def upgrade():
|
||||
op.create_table('trunks',
|
||||
sa.Column('tenant_id', sa.String(length=255), nullable=True,
|
||||
index=True),
|
||||
sa.Column('id', sa.String(length=36), nullable=False),
|
||||
sa.Column('port_id', sa.String(length=36), nullable=False),
|
||||
sa.Column('standard_attr_id', sa.BigInteger(), nullable=False),
|
||||
sa.ForeignKeyConstraint(['port_id'], ['ports.id'],
|
||||
ondelete='CASCADE'),
|
||||
sa.ForeignKeyConstraint(['standard_attr_id'],
|
||||
['standardattributes.id'],
|
||||
ondelete='CASCADE'),
|
||||
sa.PrimaryKeyConstraint('id'),
|
||||
sa.UniqueConstraint('port_id'),
|
||||
sa.UniqueConstraint('standard_attr_id')
|
||||
)
|
||||
op.create_table('subports',
|
||||
sa.Column('port_id', sa.String(length=36), nullable=False),
|
||||
sa.Column('trunk_id', sa.String(length=36), nullable=False),
|
||||
sa.Column('segmentation_type', sa.String(length=32), nullable=False),
|
||||
sa.Column('segmentation_id', sa.Integer(), nullable=False),
|
||||
sa.ForeignKeyConstraint(['port_id'], ['ports.id'], ondelete='CASCADE'),
|
||||
sa.ForeignKeyConstraint(['trunk_id'], ['trunks.id'],
|
||||
ondelete='CASCADE'),
|
||||
sa.PrimaryKeyConstraint('port_id', 'trunk_id'),
|
||||
sa.UniqueConstraint('port_id'),
|
||||
sa.UniqueConstraint('trunk_id', 'segmentation_type', 'segmentation_id',
|
||||
name='uniq_subport0trunk_id0segmentation_type0segmentation_id')
|
||||
)
|
@ -0,0 +1,35 @@
|
||||
# Copyright 2016 Hewlett Packard Enterprise Development Company, LP
|
||||
#
|
||||
# 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 oslo_utils import uuidutils
|
||||
|
||||
from neutron.services.trunk import exceptions
|
||||
from neutron.services.trunk import models
|
||||
|
||||
|
||||
def create_trunk(context, port_id, description=None):
|
||||
"""Create a trunk (with description) given the parent port uuid."""
|
||||
try:
|
||||
with context.session.begin(subtransactions=True):
|
||||
context.session.add(
|
||||
models.Trunk(
|
||||
id=uuidutils.generate_uuid(),
|
||||
tenant_id=context.tenant_id,
|
||||
port_id=port_id,
|
||||
description=description))
|
||||
except db_exc.DBDuplicateEntry:
|
||||
raise exceptions.TrunkPortInUse(port_id=port_id)
|
@ -0,0 +1,22 @@
|
||||
# Copyright 2016 Hewlett Packard Enterprise Development Company, LP
|
||||
#
|
||||
# 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 neutron._i18n import _
|
||||
from neutron_lib import exceptions as n_exc
|
||||
|
||||
|
||||
class TrunkPortInUse(n_exc.InUse):
|
||||
message = _("Port %(port_id)s is in use by another trunk.")
|
@ -0,0 +1,73 @@
|
||||
# Copyright 2016 Red Hat Inc.
|
||||
# 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 sqlalchemy as sa
|
||||
|
||||
from neutron.db import model_base
|
||||
from neutron.db import models_v2
|
||||
|
||||
|
||||
class Trunk(model_base.HasStandardAttributes, model_base.BASEV2,
|
||||
model_base.HasId, model_base.HasTenant):
|
||||
|
||||
port_id = sa.Column(sa.String(36),
|
||||
sa.ForeignKey('ports.id',
|
||||
ondelete='CASCADE'),
|
||||
nullable=False,
|
||||
unique=True)
|
||||
port = sa.orm.relationship(
|
||||
models_v2.Port,
|
||||
backref=sa.orm.backref('trunk_port', lazy='joined', uselist=False,
|
||||
cascade='delete'))
|
||||
|
||||
|
||||
class SubPort(model_base.BASEV2):
|
||||
|
||||
port_id = sa.Column(sa.String(36),
|
||||
sa.ForeignKey('ports.id',
|
||||
ondelete='CASCADE'),
|
||||
nullable=False,
|
||||
unique=True,
|
||||
primary_key=True)
|
||||
port = sa.orm.relationship(
|
||||
models_v2.Port,
|
||||
backref=sa.orm.backref('sub_port', lazy='joined', uselist=False,
|
||||
cascade='delete'))
|
||||
|
||||
trunk_id = sa.Column(sa.String(36),
|
||||
sa.ForeignKey('trunks.id',
|
||||
ondelete='CASCADE'),
|
||||
nullable=False,
|
||||
primary_key=True)
|
||||
|
||||
segmentation_type = sa.Column(sa.String(32), nullable=False)
|
||||
segmentation_id = sa.Column(sa.Integer, nullable=False)
|
||||
|
||||
__table_args__ = (
|
||||
sa.UniqueConstraint(
|
||||
'trunk_id',
|
||||
'segmentation_type',
|
||||
'segmentation_id',
|
||||
name='uniq_subport0trunk_id0segmentation_type0segmentation_id'),
|
||||
model_base.BASEV2.__table_args__
|
||||
)
|
||||
|
||||
# NOTE(armax) constraints like the following are implemented via
|
||||
# business logic rules:
|
||||
#
|
||||
# Deletion of a trunk automatically deletes all of its subports;
|
||||
# Deletion of a (child) port referred by a subport is forbidden;
|
||||
# Deletion of a (parent) port referred by a trunk is forbidden;
|
||||
# A port cannot be a subport and a trunk port at the same time (nested).
|
@ -0,0 +1,50 @@
|
||||
# Copyright 2016 Hewlett Packard Enterprise Development Company, LP
|
||||
#
|
||||
# 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 neutron import context
|
||||
from neutron.db import models_v2
|
||||
from neutron.services.trunk import db
|
||||
from neutron.services.trunk import exceptions
|
||||
from neutron.tests.unit import testlib_api
|
||||
|
||||
|
||||
class TrunkDBTestCase(testlib_api.SqlTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TrunkDBTestCase, self).setUp()
|
||||
self.ctx = context.get_admin_context()
|
||||
|
||||
def _add_network(self, net_id):
|
||||
with self.ctx.session.begin(subtransactions=True):
|
||||
self.ctx.session.add(models_v2.Network(id=net_id))
|
||||
|
||||
def _add_port(self, net_id, port_id):
|
||||
with self.ctx.session.begin(subtransactions=True):
|
||||
port = models_v2.Port(id=port_id,
|
||||
network_id=net_id,
|
||||
mac_address='foo_mac_%s' % port_id,
|
||||
admin_state_up=True,
|
||||
status='DOWN',
|
||||
device_id='',
|
||||
device_owner='')
|
||||
self.ctx.session.add(port)
|
||||
|
||||
def test_create_trunk_raise_port_in_use(self):
|
||||
self._add_network('foo_net')
|
||||
self._add_port('foo_net', 'foo_port')
|
||||
db.create_trunk(self.ctx, 'foo_port')
|
||||
self.assertRaises(exceptions.TrunkPortInUse,
|
||||
db.create_trunk,
|
||||
self.ctx, 'foo_port')
|
Loading…
Reference in new issue