Make network segment table available for standalone plugin
Some standalone plugins, such as networking-ovn, are expecting to store provider network information in neutron database, but we have no table, like other extensions do, for provider network extension defined. This patch moves NetworkSegment table out of the ML2 code tree. The API methods to operate segments are also moved, but stub methods are still kept in the ml2 db API. Co-Author: Miguel Lavalle <malavall@us.ibm.com> Change-Id: I2c4f78fce591486ded63252af13fc0c60d02a3e8 Partially-Implements: blueprint routed-networks
This commit is contained in:
parent
af8d0573ce
commit
c8fca1c96f
|
@ -1 +1 @@
|
|||
7bbb25278f53
|
||||
89ab9a816d70
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
# 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.
|
||||
|
||||
"""Rename ml2_network_segments table
|
||||
|
||||
Revision ID: 89ab9a816d70
|
||||
Revises: 7bbb25278f53
|
||||
Create Date: 2016-03-22 00:22:47.618593
|
||||
|
||||
"""
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '89ab9a816d70'
|
||||
down_revision = '7bbb25278f53'
|
||||
|
||||
from alembic import op
|
||||
from sqlalchemy.engine import reflection
|
||||
|
||||
|
||||
TABLE_NAME = 'ml2_port_binding_levels'
|
||||
OLD_REFERRED_TABLE_NAME = 'ml2_network_segments'
|
||||
NEW_REFERRED_TABLE_NAME = 'networksegments'
|
||||
|
||||
|
||||
def upgrade():
|
||||
fk_name = delete_foreign_key_constraint()
|
||||
op.rename_table(OLD_REFERRED_TABLE_NAME, NEW_REFERRED_TABLE_NAME)
|
||||
op.create_foreign_key(
|
||||
constraint_name=fk_name,
|
||||
source_table=TABLE_NAME,
|
||||
referent_table=NEW_REFERRED_TABLE_NAME,
|
||||
local_cols=['segment_id'],
|
||||
remote_cols=['id'],
|
||||
ondelete="SET NULL"
|
||||
)
|
||||
|
||||
|
||||
def delete_foreign_key_constraint():
|
||||
inspector = reflection.Inspector.from_engine(op.get_bind())
|
||||
fk_constraints = inspector.get_foreign_keys(TABLE_NAME)
|
||||
for fk in fk_constraints:
|
||||
if fk['referred_table'] == OLD_REFERRED_TABLE_NAME:
|
||||
op.drop_constraint(
|
||||
constraint_name=fk['name'],
|
||||
table_name=TABLE_NAME,
|
||||
type_='foreignkey'
|
||||
)
|
||||
return fk['name']
|
|
@ -48,6 +48,7 @@ from neutron.db.qos import models as qos_models # noqa
|
|||
from neutron.db.quota import models # noqa
|
||||
from neutron.db import rbac_db_models # noqa
|
||||
from neutron.db import securitygroups_db # noqa
|
||||
from neutron.db import segments_db # noqa
|
||||
from neutron.db import servicetype_db # noqa
|
||||
from neutron.db import tag_db # noqa
|
||||
from neutron.ipam.drivers.neutrondb_ipam import db_models # noqa
|
||||
|
|
|
@ -0,0 +1,143 @@
|
|||
# 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_log import log as logging
|
||||
from oslo_utils import uuidutils
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy.orm import exc
|
||||
|
||||
from neutron._i18n import _LI
|
||||
from neutron.db import model_base
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
"""
|
||||
Some standalone plugins need a DB table to store provider
|
||||
network information. Initially there was no such table,
|
||||
but in Mitaka the ML2 NetworkSegment table was promoted here.
|
||||
"""
|
||||
|
||||
|
||||
class NetworkSegment(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
|
||||
specific physical realization. A neutron network can consist of
|
||||
one or more segments.
|
||||
"""
|
||||
|
||||
network_id = sa.Column(sa.String(36),
|
||||
sa.ForeignKey('networks.id', ondelete="CASCADE"),
|
||||
nullable=False)
|
||||
network_type = sa.Column(sa.String(32), nullable=False)
|
||||
physical_network = sa.Column(sa.String(64))
|
||||
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')
|
||||
|
||||
|
||||
NETWORK_TYPE = NetworkSegment.network_type.name
|
||||
PHYSICAL_NETWORK = NetworkSegment.physical_network.name
|
||||
SEGMENTATION_ID = NetworkSegment.segmentation_id.name
|
||||
|
||||
|
||||
def _make_segment_dict(record):
|
||||
"""Make a segment dictionary out of a DB record."""
|
||||
return {'id': record.id,
|
||||
NETWORK_TYPE: record.network_type,
|
||||
PHYSICAL_NETWORK: record.physical_network,
|
||||
SEGMENTATION_ID: record.segmentation_id}
|
||||
|
||||
|
||||
def add_network_segment(session, network_id, segment, segment_index=0,
|
||||
is_dynamic=False):
|
||||
with session.begin(subtransactions=True):
|
||||
record = NetworkSegment(
|
||||
id=uuidutils.generate_uuid(),
|
||||
network_id=network_id,
|
||||
network_type=segment.get(NETWORK_TYPE),
|
||||
physical_network=segment.get(PHYSICAL_NETWORK),
|
||||
segmentation_id=segment.get(SEGMENTATION_ID),
|
||||
segment_index=segment_index,
|
||||
is_dynamic=is_dynamic
|
||||
)
|
||||
session.add(record)
|
||||
segment['id'] = record.id
|
||||
LOG.info(_LI("Added segment %(id)s of type %(network_type)s for network "
|
||||
"%(network_id)s"),
|
||||
{'id': record.id,
|
||||
'network_type': record.network_type,
|
||||
'network_id': record.network_id})
|
||||
|
||||
|
||||
def get_network_segments(session, network_id, filter_dynamic=False):
|
||||
return get_networks_segments(
|
||||
session, [network_id], filter_dynamic)[network_id]
|
||||
|
||||
|
||||
def get_networks_segments(session, network_ids, filter_dynamic=False):
|
||||
with session.begin(subtransactions=True):
|
||||
query = (session.query(NetworkSegment).
|
||||
filter(NetworkSegment.network_id.in_(network_ids)).
|
||||
order_by(NetworkSegment.segment_index))
|
||||
if filter_dynamic is not None:
|
||||
query = query.filter_by(is_dynamic=filter_dynamic)
|
||||
records = query.all()
|
||||
result = {net_id: [] for net_id in network_ids}
|
||||
for record in records:
|
||||
result[record.network_id].append(_make_segment_dict(record))
|
||||
return result
|
||||
|
||||
|
||||
def get_segment_by_id(session, segment_id):
|
||||
with session.begin(subtransactions=True):
|
||||
try:
|
||||
record = (session.query(NetworkSegment).
|
||||
filter_by(id=segment_id).
|
||||
one())
|
||||
return _make_segment_dict(record)
|
||||
except exc.NoResultFound:
|
||||
return
|
||||
|
||||
|
||||
def get_dynamic_segment(session, network_id, physical_network=None,
|
||||
segmentation_id=None):
|
||||
"""Return a dynamic segment for the filters provided if one exists."""
|
||||
with session.begin(subtransactions=True):
|
||||
query = (session.query(NetworkSegment).
|
||||
filter_by(network_id=network_id, is_dynamic=True))
|
||||
if physical_network:
|
||||
query = query.filter_by(physical_network=physical_network)
|
||||
if segmentation_id:
|
||||
query = query.filter_by(segmentation_id=segmentation_id)
|
||||
record = query.first()
|
||||
|
||||
if record:
|
||||
return _make_segment_dict(record)
|
||||
else:
|
||||
LOG.debug("No dynamic segment found for "
|
||||
"Network:%(network_id)s, "
|
||||
"Physical network:%(physnet)s, "
|
||||
"segmentation_id:%(segmentation_id)s",
|
||||
{'network_id': network_id,
|
||||
'physnet': physical_network,
|
||||
'segmentation_id': segmentation_id})
|
||||
return None
|
||||
|
||||
|
||||
def delete_network_segment(session, segment_id):
|
||||
"""Release a dynamic segment for the params provided if one exists."""
|
||||
with session.begin(subtransactions=True):
|
||||
(session.query(NetworkSegment).
|
||||
filter_by(id=segment_id).delete())
|
|
@ -20,13 +20,13 @@ import six
|
|||
from sqlalchemy import or_
|
||||
from sqlalchemy.orm import exc
|
||||
|
||||
from neutron._i18n import _LE, _LI
|
||||
from neutron._i18n import _LE
|
||||
from neutron.common import constants as n_const
|
||||
from neutron.db import models_v2
|
||||
from neutron.db import securitygroups_db as sg_db
|
||||
from neutron.db import segments_db
|
||||
from neutron.extensions import portbindings
|
||||
from neutron import manager
|
||||
from neutron.plugins.ml2 import driver_api as api
|
||||
from neutron.plugins.ml2 import models
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
|
@ -34,96 +34,18 @@ LOG = log.getLogger(__name__)
|
|||
# limit the number of port OR LIKE statements in one query
|
||||
MAX_PORTS_PER_QUERY = 500
|
||||
|
||||
# The API methods from segments_db
|
||||
add_network_segment = segments_db.add_network_segment
|
||||
|
||||
def _make_segment_dict(record):
|
||||
"""Make a segment dictionary out of a DB record."""
|
||||
return {api.ID: record.id,
|
||||
api.NETWORK_TYPE: record.network_type,
|
||||
api.PHYSICAL_NETWORK: record.physical_network,
|
||||
api.SEGMENTATION_ID: record.segmentation_id}
|
||||
get_network_segments = segments_db.get_network_segments
|
||||
|
||||
get_networks_segments = segments_db.get_networks_segments
|
||||
|
||||
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(),
|
||||
network_id=network_id,
|
||||
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)
|
||||
segment[api.ID] = record.id
|
||||
LOG.info(_LI("Added segment %(id)s of type %(network_type)s for network"
|
||||
" %(network_id)s"),
|
||||
{'id': record.id,
|
||||
'network_type': record.network_type,
|
||||
'network_id': record.network_id})
|
||||
get_segment_by_id = segments_db.get_segment_by_id
|
||||
|
||||
get_dynamic_segment = segments_db.get_dynamic_segment
|
||||
|
||||
def get_network_segments(session, network_id, filter_dynamic=False):
|
||||
return get_networks_segments(
|
||||
session, [network_id], filter_dynamic)[network_id]
|
||||
|
||||
|
||||
def get_networks_segments(session, network_ids, filter_dynamic=False):
|
||||
with session.begin(subtransactions=True):
|
||||
query = (session.query(models.NetworkSegment).
|
||||
filter(models.NetworkSegment.network_id.in_(network_ids)).
|
||||
order_by(models.NetworkSegment.segment_index))
|
||||
if filter_dynamic is not None:
|
||||
query = query.filter_by(is_dynamic=filter_dynamic)
|
||||
records = query.all()
|
||||
result = {net_id: [] for net_id in network_ids}
|
||||
for record in records:
|
||||
result[record.network_id].append(_make_segment_dict(record))
|
||||
return result
|
||||
|
||||
|
||||
def get_segment_by_id(session, segment_id):
|
||||
with session.begin(subtransactions=True):
|
||||
try:
|
||||
record = (session.query(models.NetworkSegment).
|
||||
filter_by(id=segment_id).
|
||||
one())
|
||||
return _make_segment_dict(record)
|
||||
except exc.NoResultFound:
|
||||
return
|
||||
|
||||
|
||||
def get_dynamic_segment(session, network_id, physical_network=None,
|
||||
segmentation_id=None):
|
||||
"""Return a dynamic segment for the filters provided if one exists."""
|
||||
with session.begin(subtransactions=True):
|
||||
query = (session.query(models.NetworkSegment).
|
||||
filter_by(network_id=network_id, is_dynamic=True))
|
||||
if physical_network:
|
||||
query = query.filter_by(physical_network=physical_network)
|
||||
if segmentation_id:
|
||||
query = query.filter_by(segmentation_id=segmentation_id)
|
||||
record = query.first()
|
||||
|
||||
if record:
|
||||
return _make_segment_dict(record)
|
||||
else:
|
||||
LOG.debug("No dynamic segment found for "
|
||||
"Network:%(network_id)s, "
|
||||
"Physical network:%(physnet)s, "
|
||||
"segmentation_id:%(segmentation_id)s",
|
||||
{'network_id': network_id,
|
||||
'physnet': physical_network,
|
||||
'segmentation_id': segmentation_id})
|
||||
return None
|
||||
|
||||
|
||||
def delete_network_segment(session, segment_id):
|
||||
"""Release a dynamic segment for the params provided if one exists."""
|
||||
with session.begin(subtransactions=True):
|
||||
(session.query(models.NetworkSegment).
|
||||
filter_by(id=segment_id).delete())
|
||||
delete_network_segment = segments_db.delete_network_segment
|
||||
|
||||
|
||||
def add_port_binding(session, port_id):
|
||||
|
|
|
@ -23,27 +23,6 @@ from neutron.extensions import portbindings
|
|||
BINDING_PROFILE_LEN = 4095
|
||||
|
||||
|
||||
class NetworkSegment(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
|
||||
specific physical realization. A neutron network can consist of
|
||||
one or more segments.
|
||||
"""
|
||||
|
||||
__tablename__ = 'ml2_network_segments'
|
||||
|
||||
network_id = sa.Column(sa.String(36),
|
||||
sa.ForeignKey('networks.id', ondelete="CASCADE"),
|
||||
nullable=False)
|
||||
network_type = sa.Column(sa.String(32), nullable=False)
|
||||
physical_network = sa.Column(sa.String(64))
|
||||
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):
|
||||
"""Represent binding-related state of a port.
|
||||
|
||||
|
@ -95,7 +74,7 @@ class PortBindingLevel(model_base.BASEV2):
|
|||
level = sa.Column(sa.Integer, primary_key=True, autoincrement=False)
|
||||
driver = sa.Column(sa.String(64))
|
||||
segment_id = sa.Column(sa.String(36),
|
||||
sa.ForeignKey('ml2_network_segments.id',
|
||||
sa.ForeignKey('networksegments.id',
|
||||
ondelete="SET NULL"))
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue