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
179 lines
6.9 KiB
Python
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
|