Files
neutron/neutron/db/segments_db.py
Kailun Qin 563a536d02 Support Network Segment Range CRUD as extensions
This patch adds the support for network segment range CRUD. Subsequent
patches will be added to use this network segment range on segment
allocation if this extension is loaded.

Changes include:
- an API extension which exposes the segment range to be administered;
- standard attributes with tagging support for the new resource;
- a new service plugin "network_segment_range" for the feature
  enabling/disabling;
- a new network segment range DB table model along with operation
  logic;
- Oslo Versioned Objects for network segment range data model;
- policy-in-code support for network segment range.

Co-authored-by: Allain Legacy <Allain.legacy@windriver.com>

Partially-implements: blueprint network-segment-range-management
Change-Id: I75814e50b2c9402fe6776229d469745d7a72290b
2019-03-07 08:20:30 +00:00

179 lines
6.9 KiB
Python

# 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_lib.api.definitions import segment as segment_def
from neutron_lib.callbacks import events
from neutron_lib.callbacks import registry
from neutron_lib.callbacks import resources
from neutron_lib.db import api as db_api
from oslo_log import log as logging
from oslo_utils import uuidutils
from neutron.objects import base as base_obj
from neutron.objects import network as network_obj
LOG = logging.getLogger(__name__)
NETWORK_TYPE = segment_def.NETWORK_TYPE
PHYSICAL_NETWORK = segment_def.PHYSICAL_NETWORK
SEGMENTATION_ID = segment_def.SEGMENTATION_ID
NETWORK_ID = 'network_id'
def _make_segment_dict(obj):
"""Make a segment dictionary out of an object."""
return {'id': obj.id,
NETWORK_TYPE: obj.network_type,
PHYSICAL_NETWORK: obj.physical_network,
SEGMENTATION_ID: obj.segmentation_id,
NETWORK_ID: obj.network_id}
def add_network_segment(context, network_id, segment, segment_index=0,
is_dynamic=False):
with db_api.CONTEXT_WRITER.using(context):
netseg_obj = network_obj.NetworkSegment(
context, 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)
netseg_obj.create()
registry.notify(resources.SEGMENT,
events.PRECOMMIT_CREATE,
trigger=add_network_segment,
context=context,
segment=netseg_obj)
segment['id'] = netseg_obj.id
LOG.info("Added segment %(id)s of type %(network_type)s for network "
"%(network_id)s",
{'id': netseg_obj.id,
'network_type': netseg_obj.network_type,
'network_id': netseg_obj.network_id})
def get_network_segments(context, network_id, filter_dynamic=False):
return get_networks_segments(
context, [network_id], filter_dynamic)[network_id]
def get_networks_segments(context, network_ids, filter_dynamic=False):
if not network_ids:
return {}
with db_api.CONTEXT_READER.using(context):
filters = {
'network_id': network_ids,
}
if filter_dynamic is not None:
filters['is_dynamic'] = filter_dynamic
objs = network_obj.NetworkSegment.get_objects(context, **filters)
result = {net_id: [] for net_id in network_ids}
for record in objs:
result[record.network_id].append(_make_segment_dict(record))
return result
def get_segment_by_id(context, segment_id):
with db_api.CONTEXT_READER.using(context):
net_obj = network_obj.NetworkSegment.get_object(context, id=segment_id)
if net_obj:
return _make_segment_dict(net_obj)
def get_dynamic_segment(context, network_id, physical_network=None,
segmentation_id=None):
"""Return a dynamic segment for the filters provided if one exists."""
with db_api.CONTEXT_READER.using(context):
filters = {
'network_id': network_id,
'is_dynamic': True,
}
if physical_network:
filters['physical_network'] = physical_network
if segmentation_id:
filters['segmentation_id'] = segmentation_id
pager = base_obj.Pager(limit=1)
objs = network_obj.NetworkSegment.get_objects(
context, _pager=pager, **filters)
if objs:
return _make_segment_dict(objs[0])
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})
def delete_network_segment(context, segment_id):
"""Release a dynamic segment for the params provided if one exists."""
with db_api.CONTEXT_WRITER.using(context):
network_obj.NetworkSegment.delete_objects(context, id=segment_id)
def network_segments_exist_in_range(context, network_type, physical_network,
segment_range=None):
"""Check whether one or more network segments exist in a range."""
with db_api.CONTEXT_READER.using(context):
filters = {
'network_type': network_type,
'physical_network': physical_network,
}
segment_objs = network_obj.NetworkSegment.get_objects(
context, **filters)
if segment_range:
minimum_id = segment_range['minimum']
maximum_id = segment_range['maximum']
segment_objs = [
segment for segment in segment_objs if
minimum_id <= segment.segmentation_id <= maximum_id]
return len(segment_objs) > 0
def min_max_actual_segments_in_range(context, network_type, physical_network,
segment_range=None):
"""Return the minimum and maximum segmentation IDs used in a network
segment range
"""
with db_api.CONTEXT_READER.using(context):
filters = {
'network_type': network_type,
'physical_network': physical_network,
}
pager = base_obj.Pager()
# (NOTE) True means ASC, False is DESC
pager.sorts = [('segmentation_id', True)]
segment_objs = network_obj.NetworkSegment.get_objects(
context, _pager=pager, **filters)
if segment_range:
minimum_id = segment_range['minimum']
maximum_id = segment_range['maximum']
segment_objs = [
segment for segment in segment_objs if
minimum_id <= segment.segmentation_id <= maximum_id]
if segment_objs:
return (segment_objs[0].segmentation_id,
segment_objs[-1].segmentation_id)
else:
LOG.debug("No existing segment found for "
"Network type:%(network_type)s, "
"Physical network:%(physical_network)s",
{'network_type': network_type,
'physical_network': physical_network})
return None, None