Schema enhancement to support MultiSegment Network

Description:
Currently, there is nothing in the schema that ensures segments
for a network are returned in the same order they were specified
when the network was created, or even in a deterministic order.

Solution:
We need to add another field named 'segment_index' in
'ml2_network_segment' table containing a numeric position index.
With segment_index field we can retrieve the segments in the
order in which user created.

This patch set also fixes ML2 invalid unit test case in
test_create_network_multiprovider().

Closes-Bug: #1224978
Closes-Bug: #1377346

Change-Id: I560c34c6fe1c5425469ccdf9b8b4905c123d496d
This commit is contained in:
Romil Gupta 2014-06-30 05:35:08 -07:00
parent 1aaa8b3446
commit db5e370b0d
6 changed files with 60 additions and 11 deletions

View File

@ -0,0 +1,40 @@
# 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.
#
"""ml2_network_segments models change for multi-segment network.
Revision ID: 1f71e54a85e7
Revises: 44621190bc02
Create Date: 2014-10-15 18:30:51.395295
"""
# revision identifiers, used by Alembic.
revision = '1f71e54a85e7'
down_revision = '44621190bc02'
from alembic import op
import sqlalchemy as sa
def upgrade():
op.add_column('ml2_network_segments',
sa.Column('segment_index', sa.Integer(), nullable=False,
server_default='0'))
def downgrade():
op.drop_column('ml2_network_segments', 'segment_index')

View File

@ -1 +1 @@
44621190bc02
1f71e54a85e7

View File

@ -39,7 +39,8 @@ def _make_segment_dict(record):
api.SEGMENTATION_ID: record.segmentation_id}
def add_network_segment(session, network_id, segment, is_dynamic=False):
def add_network_segment(session, network_id, segment, segment_index=0,
is_dynamic=False):
with session.begin(subtransactions=True):
record = models.NetworkSegment(
id=uuidutils.generate_uuid(),
@ -47,6 +48,7 @@ def add_network_segment(session, network_id, segment, is_dynamic=False):
network_type=segment.get(api.NETWORK_TYPE),
physical_network=segment.get(api.PHYSICAL_NETWORK),
segmentation_id=segment.get(api.SEGMENTATION_ID),
segment_index=segment_index,
is_dynamic=is_dynamic
)
session.add(record)
@ -61,7 +63,8 @@ def add_network_segment(session, network_id, segment, is_dynamic=False):
def get_network_segments(session, network_id, filter_dynamic=False):
with session.begin(subtransactions=True):
query = (session.query(models.NetworkSegment).
filter_by(network_id=network_id))
filter_by(network_id=network_id).
order_by(models.NetworkSegment.segment_index))
if filter_dynamic is not None:
query = query.filter_by(is_dynamic=filter_dynamic)
records = query.all()

View File

@ -152,10 +152,11 @@ class TypeManager(stevedore.named.NamedExtensionManager):
with session.begin(subtransactions=True):
network_id = network['id']
if segments:
for segment in segments:
for segment_index, segment in enumerate(segments):
segment = self.reserve_provider_segment(
session, segment)
db.add_network_segment(session, network_id, segment)
db.add_network_segment(session, network_id,
segment, segment_index)
else:
segment = self.allocate_tenant_segment(session)
db.add_network_segment(session, network_id, segment)

View File

@ -41,6 +41,7 @@ class NetworkSegment(model_base.BASEV2, models_v2.HasId):
segmentation_id = sa.Column(sa.Integer)
is_dynamic = sa.Column(sa.Boolean, default=False, nullable=False,
server_default=sa.sql.false())
segment_index = sa.Column(sa.Integer, nullable=False, server_default='0')
class PortBinding(model_base.BASEV2):

View File

@ -583,20 +583,24 @@ class TestMultiSegmentNetworks(Ml2PluginV2TestCase):
network_req = self.new_create_request('networks', data)
network = self.deserialize(self.fmt,
network_req.get_response(self.api))
tz = network['network'][mpnet.SEGMENTS]
for tz in data['network'][mpnet.SEGMENTS]:
segments = network['network'][mpnet.SEGMENTS]
for segment_index, segment in enumerate(data['network']
[mpnet.SEGMENTS]):
for field in [pnet.NETWORK_TYPE, pnet.PHYSICAL_NETWORK,
pnet.SEGMENTATION_ID]:
self.assertEqual(tz.get(field), tz.get(field))
self.assertEqual(segment.get(field),
segments[segment_index][field])
# Tests get_network()
net_req = self.new_show_request('networks', network['network']['id'])
network = self.deserialize(self.fmt, net_req.get_response(self.api))
tz = network['network'][mpnet.SEGMENTS]
for tz in data['network'][mpnet.SEGMENTS]:
segments = network['network'][mpnet.SEGMENTS]
for segment_index, segment in enumerate(data['network']
[mpnet.SEGMENTS]):
for field in [pnet.NETWORK_TYPE, pnet.PHYSICAL_NETWORK,
pnet.SEGMENTATION_ID]:
self.assertEqual(tz.get(field), tz.get(field))
self.assertEqual(segment.get(field),
segments[segment_index][field])
def test_create_network_with_provider_and_multiprovider_fail(self):
data = {'network': {'name': 'net1',