Add name and desc to networksegments table

This patch adds the name and description column to the
networksegments table.

Change-Id: I7edc224e25e604dfd7613b945a4ca16d9e385760
Partially-Implements: blueprint routed-networks
This commit is contained in:
Reedip 2016-06-07 13:23:57 +05:30 committed by Carl Baldwin
parent 0eec50b12f
commit 5ef869b3bc
10 changed files with 207 additions and 6 deletions

View File

@ -1 +1 @@
b12a3ef66e62
97c25b0d2353

View File

@ -0,0 +1,99 @@
# Copyright 2016 NEC Technologies Limited
#
# 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.
#
"""Add Name and Description to the networksegments table """
# revision identifiers, used by Alembic.
revision = '97c25b0d2353'
down_revision = 'b12a3ef66e62'
depends_on = ('89ab9a816d70',)
# As this script depends on another migration which was a contract script,
# therefore the following column addition ( which should have been in an
# expand phase ) is also submitted in the contract phase. For information
# about the expand and contract scripts and how the depends_on works, please
# refer <http://docs.openstack.org/developer/neutron/devref/
# alembic_migrations.html#expand-and-contract-scripts>
from alembic import op
import sqlalchemy as sa
TBL = 'networksegments'
TBL_MODEL = sa.Table(TBL, sa.MetaData(),
sa.Column('id', sa.String(length=36), nullable=False),
sa.Column('standard_attr_id', sa.BigInteger(),
nullable=True))
standardattrs = sa.Table(
'standardattributes', sa.MetaData(),
sa.Column('id', sa.BigInteger(), primary_key=True, autoincrement=True),
sa.Column('resource_type', sa.String(length=255), nullable=False))
def update_existing_records():
session = sa.orm.Session(bind=op.get_bind())
values = []
with session.begin(subtransactions=True):
for row in session.query(TBL_MODEL):
# NOTE from kevinbenton: without this disabled, pylint complains
# about a missing 'dml' argument.
#pylint: disable=no-value-for-parameter
res = session.execute(
standardattrs.insert().values(resource_type=TBL)
)
session.execute(
TBL_MODEL.update().values(
standard_attr_id=res.inserted_primary_key).where(
TBL_MODEL.c.id == row[0])
)
# this commit is necessary to allow further operations
session.commit()
return values
def upgrade():
op.add_column(TBL, sa.Column('standard_attr_id', sa.BigInteger(),
nullable=True))
op.add_column(TBL,
sa.Column('name', sa.String(255),
nullable=True))
update_existing_records()
# add the constraint now that everything is populated on that table
op.create_foreign_key(
constraint_name=None, source_table=TBL,
referent_table='standardattributes',
local_cols=['standard_attr_id'], remote_cols=['id'],
ondelete='CASCADE')
op.alter_column(TBL, 'standard_attr_id', nullable=False,
existing_type=sa.BigInteger(), existing_nullable=True,
existing_server_default=False)
op.create_unique_constraint(
constraint_name='uniq_%s0standard_attr_id' % TBL,
table_name=TBL, columns=['standard_attr_id'])
def contract_creation_exceptions():
"""
Return create exceptions.
These elements depend on the networksegments table which are added
in the contract branch.
"""
return {
sa.Column: ['networksegments.name',
'networksegments.standard_attr_id'],
}

View File

@ -17,9 +17,11 @@ import sqlalchemy as sa
from sqlalchemy.orm import exc
from neutron._i18n import _LI
from neutron.api.v2 import attributes
from neutron.callbacks import events
from neutron.callbacks import registry
from neutron.callbacks import resources
from neutron.db import standard_attr
LOG = logging.getLogger(__name__)
@ -31,7 +33,8 @@ but in Mitaka the ML2 NetworkSegment table was promoted here.
"""
class NetworkSegment(model_base.BASEV2, model_base.HasId):
class NetworkSegment(standard_attr.HasStandardAttributes,
model_base.BASEV2, model_base.HasId):
"""Represent persistent state of a network segment.
A network segment is a portion of a neutron network with a
@ -48,6 +51,8 @@ class NetworkSegment(model_base.BASEV2, model_base.HasId):
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')
name = sa.Column(sa.String(attributes.NAME_MAX_LEN),
nullable=True)
NETWORK_TYPE = NetworkSegment.network_type.name

View File

@ -31,6 +31,8 @@ SEGMENT_ID = 'segment_id'
NETWORK_TYPE = 'network_type'
PHYSICAL_NETWORK = 'physical_network'
SEGMENTATION_ID = 'segmentation_id'
NAME_LEN = attributes.NAME_MAX_LEN
DESC_LEN = attributes.DESCRIPTION_MAX_LEN
# Attribute Map
RESOURCE_ATTRIBUTE_MAP = {
@ -65,6 +67,16 @@ RESOURCE_ATTRIBUTE_MAP = {
'default': constants.ATTR_NOT_SPECIFIED,
'convert_to': converters.convert_to_int,
'is_visible': True},
'name': {'allow_post': True,
'allow_put': True,
'default': constants.ATTR_NOT_SPECIFIED,
'validate': {'type:string_or_none': NAME_LEN},
'is_visible': True},
'description': {'allow_post': True,
'allow_put': True,
'default': constants.ATTR_NOT_SPECIFIED,
'validate': {'type:string_or_none': DESC_LEN},
'is_visible': True},
},
attributes.SUBNETS: {
SEGMENT_ID: {'allow_post': True,

View File

@ -27,6 +27,7 @@ class NetworkSegment(base.NeutronDbObject):
fields = {
'id': obj_fields.UUIDField(),
'network_id': obj_fields.UUIDField(),
'name': obj_fields.StringField(),
'network_type': obj_fields.StringField(),
'physical_network': obj_fields.StringField(nullable=True),
'segmentation_id': obj_fields.IntegerField(nullable=True),

View File

@ -65,6 +65,8 @@ class SegmentDbMixin(common_db_mixin.CommonDbMixin):
def _make_segment_dict(self, segment_db, fields=None):
res = {'id': segment_db['id'],
'network_id': segment_db['network_id'],
'name': segment_db['name'],
'description': segment_db['description'],
db.PHYSICAL_NETWORK: segment_db[db.PHYSICAL_NETWORK],
db.NETWORK_TYPE: segment_db[db.NETWORK_TYPE],
db.SEGMENTATION_ID: segment_db[db.SEGMENTATION_ID],
@ -103,8 +105,16 @@ class SegmentDbMixin(common_db_mixin.CommonDbMixin):
segmentation_id = segment[extension.SEGMENTATION_ID]
if segmentation_id == constants.ATTR_NOT_SPECIFIED:
segmentation_id = None
name = segment['name']
if name == constants.ATTR_NOT_SPECIFIED:
name = None
description = segment['description']
if description == constants.ATTR_NOT_SPECIFIED:
description = None
args = {'id': segment_id,
'network_id': network_id,
'name': name,
'description': description,
db.PHYSICAL_NETWORK: physical_network,
db.NETWORK_TYPE: network_type,
db.SEGMENTATION_ID: segmentation_id}

View File

@ -80,7 +80,7 @@ class SegmentTestCase(test_db_base_plugin_v2.NeutronDbPluginV2TestCase):
def _create_segment(self, fmt, expected_res_status=None, **kwargs):
segment = {'segment': {}}
for k, v in kwargs.items():
segment['segment'][k] = str(v)
segment['segment'][k] = None if v is None else str(v)
segment_req = self.new_create_request(
'segments', segment, fmt)
@ -141,6 +141,73 @@ class SegmentTestPlugin(db_base_plugin_v2.NeutronDbPluginV2,
return port_dict
class TestSegmentNameDescription(SegmentTestCase):
def setUp(self):
super(TestSegmentNameDescription, self).setUp()
with self.network() as network:
self.network = network['network']
def _test_create_segment(self, expected=None, **kwargs):
for d in (kwargs, expected):
if d is None:
continue
d.setdefault('network_id', self.network['id'])
d.setdefault('name', None)
d.setdefault('description', None)
d.setdefault('physical_network', 'phys_net')
d.setdefault('network_type', 'net_type')
d.setdefault('segmentation_id', 200)
return super(TestSegmentNameDescription, self)._test_create_segment(
expected, **kwargs)
def test_create_segment_no_name_description(self):
self._test_create_segment(expected={})
def test_create_segment_with_name(self):
expected_segment = {'name': 'segment_name'}
self._test_create_segment(name='segment_name',
expected=expected_segment)
def test_create_segment_with_description(self):
expected_segment = {'description': 'A segment'}
self._test_create_segment(description='A segment',
expected=expected_segment)
def test_update_segment_set_name(self):
segment = self._test_create_segment()
result = self._update('segments',
segment['segment']['id'],
{'segment': {'name': 'Segment name'}},
expected_code=webob.exc.HTTPOk.code)
self.assertEqual('Segment name', result['segment']['name'])
def test_update_segment_set_description(self):
segment = self._test_create_segment()
result = self._update('segments',
segment['segment']['id'],
{'segment': {'description': 'Segment desc'}},
expected_code=webob.exc.HTTPOk.code)
self.assertEqual('Segment desc', result['segment']['description'])
def test_update_segment_set_name_to_none(self):
segment = self._test_create_segment(
description='A segment', name='segment')
result = self._update('segments',
segment['segment']['id'],
{'segment': {'name': None}},
expected_code=webob.exc.HTTPOk.code)
self.assertEqual(None, result['segment']['name'])
def test_update_segment_set_description_to_none(self):
segment = self._test_create_segment(
description='A segment', name='segment')
result = self._update('segments',
segment['segment']['id'],
{'segment': {'description': None}},
expected_code=webob.exc.HTTPOk.code)
self.assertEqual(None, result['segment']['description'])
class TestSegment(SegmentTestCase):
def test_create_segment(self):

View File

@ -32,7 +32,7 @@ object_data = {
'ExtraDhcpOpt': '1.0-632f689cbeb36328995a7aed1d0a78d3',
'IPAllocationPool': '1.0-371016a6480ed0b4299319cb46d9215d',
'NetworkPortSecurity': '1.0-b30802391a87945ee9c07582b4ff95e3',
'NetworkSegment': '1.0-865567a6f70eb85cf33fb7a5575a4eab',
'NetworkSegment': '1.0-40707ef6bd9a0bf095038158d995cc7d',
'PortSecurity': '1.0-b30802391a87945ee9c07582b4ff95e3',
'AllowedAddressPair': '1.0-9f9186b6f952fbf31d257b0458b852c0',
'QosBandwidthLimitRule': '1.2-4e44a8f5c2895ab1278399f87b40a13d',

View File

@ -61,6 +61,10 @@ class Ml2DBTestCase(testlib_api.SqlTestCase):
vif_type=vif_type,
host=host))
@staticmethod
def _sort_segments(segments):
return sorted(segments, key=lambda d: d['segmentation_id'])
def _create_segments(self, segments, is_seg_dynamic=False,
network_id='foo-network-id'):
self._setup_neutron_network(network_id)
@ -72,6 +76,7 @@ class Ml2DBTestCase(testlib_api.SqlTestCase):
net_segments = segments_db.get_network_segments(
self.ctx.session, network_id,
filter_dynamic=is_seg_dynamic)
net_segments = self._sort_segments(net_segments)
for segment_index, segment in enumerate(segments):
self.assertEqual(segment, net_segments[segment_index])
@ -116,8 +121,8 @@ class Ml2DBTestCase(testlib_api.SqlTestCase):
net2segs = self._create_segments(segments2, network_id='net2')
segs = segments_db.get_networks_segments(
self.ctx.session, ['net1', 'net2'])
self.assertEqual(net1segs, segs['net1'])
self.assertEqual(net2segs, segs['net2'])
self.assertEqual(net1segs, self._sort_segments(segs['net1']))
self.assertEqual(net2segs, self._sort_segments(segs['net2']))
def test_get_networks_segments_no_segments(self):
self._create_segments([], network_id='net1')

View File

@ -316,6 +316,7 @@ class TestAutoScheduleSegments(test_plugin.Ml2PluginV2TestCase,
seg = self.segments_plugin.create_segment(
self.ctx,
{'segment': {'network_id': network_id,
'name': None, 'description': None,
'physical_network': 'physnet1',
'network_type': 'vlan',
'segmentation_id': constants.ATTR_NOT_SPECIFIED}})
@ -529,6 +530,7 @@ class DHCPAgentWeightSchedulerTestCase(test_plugin.Ml2PluginV2TestCase):
seg = self.segments_plugin.create_segment(
self.ctx,
{'segment': {'network_id': network_id,
'name': None, 'description': None,
'physical_network': 'physnet1',
'network_type': 'vlan',
'segmentation_id': constants.ATTR_NOT_SPECIFIED}})