Basic Extension and CRUD for Segments
This patch enables CRUD on Segments by defining a new entity called 'Segment' with an extension definition and some DB code to read the existing segments DB. A basic framework for create, update, and delete are provided. For now, this is just the basic boiler-plate but I've got to start somewhere. It is implemented as a service plugin that is disabled by default because it has not been fully tested with any plugin. Follow-on patches will implement support for this new extension in ML2 and OVN at least. Change-Id: Ifc370fdd38f9a5b296334635fa85bd93d270b910 Partially-Implements: blueprint routed-networks
This commit is contained in:
parent
f18db6f754
commit
a34c3543d0
@ -61,6 +61,11 @@
|
||||
"update_network:router:external": "rule:admin_only",
|
||||
"delete_network": "rule:admin_or_owner",
|
||||
|
||||
"create_segment": "rule:admin_only",
|
||||
"get_segment": "rule:admin_only",
|
||||
"update_segment": "rule:admin_only",
|
||||
"delete_segment": "rule:admin_only",
|
||||
|
||||
"network_device": "field:port:device_owner=~^network:",
|
||||
"create_port": "",
|
||||
"create_port:device_owner": "not rule:network_device or rule:context_is_advsvc or rule:admin_or_network_owner",
|
||||
|
202
neutron/extensions/segment.py
Normal file
202
neutron/extensions/segment.py
Normal file
@ -0,0 +1,202 @@
|
||||
# Copyright (c) 2016 Hewlett Packard Enterprise Development Company, L.P.
|
||||
#
|
||||
# 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.
|
||||
|
||||
import abc
|
||||
import six
|
||||
|
||||
from neutron.api import extensions
|
||||
from neutron.api.v2 import attributes
|
||||
from neutron.api.v2 import base
|
||||
from neutron.extensions import providernet
|
||||
from neutron.services.segments import plugin
|
||||
|
||||
SEGMENT = 'segment'
|
||||
SEGMENTS = '%ss' % SEGMENT
|
||||
SEGMENT_ID = 'segment_id'
|
||||
|
||||
NETWORK_TYPE = 'network_type'
|
||||
PHYSICAL_NETWORK = 'physical_network'
|
||||
SEGMENTATION_ID = 'segmentation_id'
|
||||
|
||||
# Attribute Map
|
||||
RESOURCE_ATTRIBUTE_MAP = {
|
||||
SEGMENTS: {
|
||||
'id': {'allow_post': False,
|
||||
'allow_put': False,
|
||||
'validate': {'type:uuid': None},
|
||||
'is_visible': True,
|
||||
'primary_key': True},
|
||||
'tenant_id': {'allow_post': True,
|
||||
'allow_put': False,
|
||||
'validate': {'type:string':
|
||||
attributes.TENANT_ID_MAX_LEN},
|
||||
'is_visible': False},
|
||||
'network_id': {'allow_post': True,
|
||||
'allow_put': False,
|
||||
'validate': {'type:uuid': None},
|
||||
'is_visible': True},
|
||||
PHYSICAL_NETWORK: {'allow_post': True,
|
||||
'allow_put': False,
|
||||
'default': attributes.ATTR_NOT_SPECIFIED,
|
||||
'validate': {'type:string':
|
||||
providernet.PHYSICAL_NETWORK_MAX_LEN},
|
||||
'is_visible': True},
|
||||
NETWORK_TYPE: {'allow_post': True,
|
||||
'allow_put': False,
|
||||
'validate': {'type:string':
|
||||
providernet.PHYSICAL_NETWORK_MAX_LEN},
|
||||
'is_visible': True},
|
||||
SEGMENTATION_ID: {'allow_post': True,
|
||||
'allow_put': False,
|
||||
'default': attributes.ATTR_NOT_SPECIFIED,
|
||||
'convert_to': attributes.convert_to_int,
|
||||
'is_visible': True},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
class Segment(extensions.ExtensionDescriptor):
|
||||
"""Extension class supporting Segments."""
|
||||
|
||||
@classmethod
|
||||
def get_name(cls):
|
||||
return "Segment"
|
||||
|
||||
@classmethod
|
||||
def get_alias(cls):
|
||||
return "segment"
|
||||
|
||||
@classmethod
|
||||
def get_description(cls):
|
||||
return "Segments extension."
|
||||
|
||||
@classmethod
|
||||
def get_updated(cls):
|
||||
return "2016-02-24T17:00:00-00:00"
|
||||
|
||||
@classmethod
|
||||
def get_resources(cls):
|
||||
"""Returns Extended Resource for service type management."""
|
||||
attributes.PLURALS[SEGMENTS] = SEGMENT
|
||||
resource_attributes = RESOURCE_ATTRIBUTE_MAP[SEGMENTS]
|
||||
controller = base.create_resource(
|
||||
SEGMENTS,
|
||||
SEGMENT,
|
||||
plugin.Plugin.get_instance(),
|
||||
resource_attributes)
|
||||
return [extensions.ResourceExtension(SEGMENTS,
|
||||
controller,
|
||||
attr_map=resource_attributes)]
|
||||
|
||||
def get_extended_resources(self, version):
|
||||
if version == "2.0":
|
||||
return RESOURCE_ATTRIBUTE_MAP
|
||||
else:
|
||||
return {}
|
||||
|
||||
|
||||
@six.add_metaclass(abc.ABCMeta)
|
||||
class SegmentPluginBase(object):
|
||||
|
||||
@abc.abstractmethod
|
||||
def create_segment(self, context, segment):
|
||||
"""Create a segment.
|
||||
|
||||
Create a segment, which represents an L2 segment of a network.
|
||||
|
||||
:param context: neutron api request context
|
||||
:param segment: dictionary describing the segment, with keys
|
||||
as listed in the :obj:`RESOURCE_ATTRIBUTE_MAP` object
|
||||
in :file:`neutron/extensions/segment.py`. All keys
|
||||
will be populated.
|
||||
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def update_segment(self, context, uuid, segment):
|
||||
"""Update values of a segment.
|
||||
|
||||
:param context: neutron api request context
|
||||
:param uuid: UUID representing the segment to update.
|
||||
:param segment: dictionary with keys indicating fields to update.
|
||||
valid keys are those that have a value of True for
|
||||
'allow_put' as listed in the
|
||||
:obj:`RESOURCE_ATTRIBUTE_MAP` object in
|
||||
:file:`neutron/extensions/segment.py`.
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_segment(self, context, uuid, fields=None):
|
||||
"""Retrieve a segment.
|
||||
|
||||
:param context: neutron api request context
|
||||
:param uuid: UUID representing the segment to fetch.
|
||||
:param fields: a list of strings that are valid keys in a
|
||||
segment dictionary as listed in the
|
||||
:obj:`RESOURCE_ATTRIBUTE_MAP` object in
|
||||
:file:`neutron/extensions/segment.py`. Only these fields
|
||||
will be returned.
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_segments(self, context, filters=None, fields=None,
|
||||
sorts=None, limit=None, marker=None,
|
||||
page_reverse=False):
|
||||
"""Retrieve a list of segments.
|
||||
|
||||
The contents of the list depends on the identity of the user making the
|
||||
request (as indicated by the context) as well as any filters.
|
||||
|
||||
:param context: neutron api request context
|
||||
:param filters: a dictionary with keys that are valid keys for
|
||||
a segment as listed in the
|
||||
:obj:`RESOURCE_ATTRIBUTE_MAP` object in
|
||||
:file:`neutron/extensions/segment.py`. Values in this
|
||||
dictionary are an iterable containing values that will
|
||||
be used for an exact match comparison for that value.
|
||||
Each result returned by this function will have matched
|
||||
one of the values for each key in filters.
|
||||
:param fields: a list of strings that are valid keys in a
|
||||
segment dictionary as listed in the
|
||||
:obj:`RESOURCE_ATTRIBUTE_MAP` object in
|
||||
:file:`neutron/extensions/segment.py`. Only these fields
|
||||
will be returned.
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def delete_segment(self, context, uuid):
|
||||
"""Delete a segment.
|
||||
|
||||
:param context: neutron api request context
|
||||
:param uuid: UUID representing the segment to delete.
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_segments_count(self, context, filters=None):
|
||||
"""Return the number of segments.
|
||||
|
||||
The result depends on the identity
|
||||
of the user making the request (as indicated by the context) as well
|
||||
as any filters.
|
||||
|
||||
:param context: neutron api request context
|
||||
:param filters: a dictionary with keys that are valid keys for
|
||||
a segment as listed in the
|
||||
:obj:`RESOURCE_ATTRIBUTE_MAP` object
|
||||
in :file:`neutron/extensions/segment.py`. Values in
|
||||
this dictionary are an iterable containing values that
|
||||
will be used for an exact match comparison for that
|
||||
value. Each result returned by this function will have
|
||||
matched one of the values for each key in filters.
|
||||
"""
|
0
neutron/services/segments/__init__.py
Normal file
0
neutron/services/segments/__init__.py
Normal file
116
neutron/services/segments/db.py
Normal file
116
neutron/services/segments/db.py
Normal file
@ -0,0 +1,116 @@
|
||||
# Copyright 2016 Hewlett Packard Enterprise Development, LP
|
||||
#
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# 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.
|
||||
|
||||
|
||||
import functools
|
||||
|
||||
from oslo_log import helpers as log_helpers
|
||||
from oslo_utils import uuidutils
|
||||
from sqlalchemy.orm import exc
|
||||
|
||||
from neutron.api.v2 import attributes
|
||||
from neutron.db import common_db_mixin
|
||||
from neutron.db import segments_db as db
|
||||
from neutron.services.segments import exceptions
|
||||
|
||||
|
||||
class SegmentDbMixin(common_db_mixin.CommonDbMixin):
|
||||
"""Mixin class to add segment."""
|
||||
|
||||
def _make_segment_dict(self, segment_db, fields=None):
|
||||
res = {'id': segment_db['id'],
|
||||
'network_id': segment_db['network_id'],
|
||||
db.PHYSICAL_NETWORK: segment_db[db.PHYSICAL_NETWORK],
|
||||
db.NETWORK_TYPE: segment_db[db.NETWORK_TYPE],
|
||||
db.SEGMENTATION_ID: segment_db[db.SEGMENTATION_ID]}
|
||||
return self._fields(res, fields)
|
||||
|
||||
def _get_segment(self, context, segment_id):
|
||||
try:
|
||||
return self._get_by_id(
|
||||
context, db.NetworkSegment, segment_id)
|
||||
except exc.NoResultFound:
|
||||
raise exceptions.SegmentNotFound(segment_id=segment_id)
|
||||
|
||||
@log_helpers.log_method_call
|
||||
def create_segment(self, context, segment):
|
||||
"""Create a segment."""
|
||||
segment = segment['segment']
|
||||
segment_id = segment.get('id') or uuidutils.generate_uuid()
|
||||
with context.session.begin(subtransactions=True):
|
||||
network_id = segment['network_id']
|
||||
# FIXME couldn't use constants because of a circular import problem
|
||||
physical_network = segment['physical_network']
|
||||
if physical_network == attributes.ATTR_NOT_SPECIFIED:
|
||||
physical_network = None
|
||||
network_type = segment['network_type']
|
||||
segmentation_id = segment['segmentation_id']
|
||||
if segmentation_id == attributes.ATTR_NOT_SPECIFIED:
|
||||
segmentation_id = None
|
||||
args = {'id': segment_id,
|
||||
'network_id': network_id,
|
||||
db.PHYSICAL_NETWORK: physical_network,
|
||||
db.NETWORK_TYPE: network_type,
|
||||
db.SEGMENTATION_ID: segmentation_id}
|
||||
new_segment = db.NetworkSegment(**args)
|
||||
context.session.add(new_segment)
|
||||
|
||||
return self._make_segment_dict(new_segment)
|
||||
|
||||
@log_helpers.log_method_call
|
||||
def update_segment(self, context, uuid, segment):
|
||||
"""Update an existing segment."""
|
||||
segment = segment['segment']
|
||||
with context.session.begin(subtransactions=True):
|
||||
curr_segment = self._get_segment(context, uuid)
|
||||
curr_segment.update(segment)
|
||||
return self._make_segment_dict(curr_segment)
|
||||
|
||||
@log_helpers.log_method_call
|
||||
def get_segment(self, context, uuid, fields=None):
|
||||
segment_db = self._get_segment(context, uuid)
|
||||
return self._make_segment_dict(segment_db, fields)
|
||||
|
||||
@log_helpers.log_method_call
|
||||
def get_segments(self, context, filters=None, fields=None,
|
||||
sorts=None, limit=None, marker=None,
|
||||
page_reverse=False):
|
||||
marker_obj = self._get_marker_obj(context, 'segment', limit, marker)
|
||||
make_segment_dict = functools.partial(self._make_segment_dict)
|
||||
return self._get_collection(context,
|
||||
db.NetworkSegment,
|
||||
make_segment_dict,
|
||||
filters=filters,
|
||||
fields=fields,
|
||||
sorts=sorts,
|
||||
limit=limit,
|
||||
marker_obj=marker_obj,
|
||||
page_reverse=page_reverse)
|
||||
|
||||
@log_helpers.log_method_call
|
||||
def get_segments_count(self, context, filters=None):
|
||||
return self._get_collection_count(context,
|
||||
db.NetworkSegment,
|
||||
filters=filters)
|
||||
|
||||
@log_helpers.log_method_call
|
||||
def delete_segment(self, context, uuid):
|
||||
"""Delete an existing segment."""
|
||||
with context.session.begin(subtransactions=True):
|
||||
query = self._model_query(context, db.NetworkSegment)
|
||||
query = query.filter(db.NetworkSegment.id == uuid)
|
||||
if 0 == query.delete():
|
||||
raise exceptions.SegmentNotFound(segment_id=uuid)
|
23
neutron/services/segments/exceptions.py
Normal file
23
neutron/services/segments/exceptions.py
Normal file
@ -0,0 +1,23 @@
|
||||
# Copyright 2016 Hewlett Packard Enterprise Development, LP
|
||||
#
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# 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._i18n import _
|
||||
from neutron_lib import exceptions
|
||||
|
||||
|
||||
class SegmentNotFound(exceptions.NotFound):
|
||||
message = _("Segment %(segment_id)s could not be found.")
|
37
neutron/services/segments/plugin.py
Normal file
37
neutron/services/segments/plugin.py
Normal file
@ -0,0 +1,37 @@
|
||||
# Copyright 2016 Hewlett Packard Enterprise Development, LP
|
||||
#
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# 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.services.segments import db
|
||||
|
||||
|
||||
class Plugin(db.SegmentDbMixin):
|
||||
|
||||
_instance = None
|
||||
|
||||
supported_extension_aliases = ["segment"]
|
||||
|
||||
@classmethod
|
||||
def get_instance(cls):
|
||||
if cls._instance is None:
|
||||
cls._instance = cls()
|
||||
return cls._instance
|
||||
|
||||
def get_plugin_description(self):
|
||||
return "Network Segments"
|
||||
|
||||
def get_plugin_type(self):
|
||||
return "segments"
|
@ -61,6 +61,11 @@
|
||||
"update_network:router:external": "rule:admin_only",
|
||||
"delete_network": "rule:admin_or_owner",
|
||||
|
||||
"create_segment": "rule:admin_only",
|
||||
"get_segment": "rule:admin_only",
|
||||
"update_segment": "rule:admin_only",
|
||||
"delete_segment": "rule:admin_only",
|
||||
|
||||
"network_device": "field:port:device_owner=~^network:",
|
||||
"create_port": "",
|
||||
"create_port:device_owner": "not rule:network_device or rule:context_is_advsvc or rule:admin_or_network_owner",
|
||||
|
158
neutron/tests/unit/extensions/test_segment.py
Normal file
158
neutron/tests/unit/extensions/test_segment.py
Normal file
@ -0,0 +1,158 @@
|
||||
# Copyright (c) 2016 Hewlett Packard Enterprise Development Company, L.P.
|
||||
#
|
||||
# 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.
|
||||
|
||||
import webob.exc
|
||||
|
||||
from neutron.api.v2 import attributes
|
||||
from neutron.db import db_base_plugin_v2
|
||||
from neutron.extensions import segment as ext_segment
|
||||
from neutron.services.segments import db
|
||||
from neutron.tests.unit.db import test_db_base_plugin_v2
|
||||
|
||||
DB_PLUGIN_KLASS = ('neutron.tests.unit.extensions.test_segment.'
|
||||
'SegmentTestPlugin')
|
||||
|
||||
|
||||
class SegmentTestExtensionManager(object):
|
||||
|
||||
def get_resources(self):
|
||||
# Add the resources to the global attribute map
|
||||
# This is done here as the setup process won't
|
||||
# initialize the main API router which extends
|
||||
# the global attribute map
|
||||
attributes.RESOURCE_ATTRIBUTE_MAP.update(
|
||||
ext_segment.RESOURCE_ATTRIBUTE_MAP)
|
||||
return ext_segment.Segment.get_resources()
|
||||
|
||||
def get_actions(self):
|
||||
return []
|
||||
|
||||
def get_request_extensions(self):
|
||||
return []
|
||||
|
||||
|
||||
class SegmentTestCase(test_db_base_plugin_v2.NeutronDbPluginV2TestCase):
|
||||
|
||||
def setUp(self):
|
||||
plugin = DB_PLUGIN_KLASS
|
||||
ext_mgr = SegmentTestExtensionManager()
|
||||
super(SegmentTestCase, self).setUp(plugin=plugin, ext_mgr=ext_mgr)
|
||||
|
||||
def _create_segment(self, fmt, expected_res_status=None, **kwargs):
|
||||
segment = {'segment': {}}
|
||||
for k, v in kwargs.items():
|
||||
segment['segment'][k] = str(v)
|
||||
|
||||
segment_req = self.new_create_request(
|
||||
'segments', segment, fmt)
|
||||
|
||||
segment_res = segment_req.get_response(self.ext_api)
|
||||
if expected_res_status:
|
||||
self.assertEqual(segment_res.status_int, expected_res_status)
|
||||
return segment_res
|
||||
|
||||
def _make_segment(self, fmt, **kwargs):
|
||||
res = self._create_segment(fmt, **kwargs)
|
||||
if res.status_int >= webob.exc.HTTPClientError.code:
|
||||
raise webob.exc.HTTPClientError(
|
||||
code=res.status_int, explanation=str(res))
|
||||
return self.deserialize(fmt, res)
|
||||
|
||||
def segment(self, **kwargs):
|
||||
kwargs.setdefault('network_type', 'net_type')
|
||||
return self._make_segment(
|
||||
self.fmt, tenant_id=self._tenant_id, **kwargs)
|
||||
|
||||
def _test_create_segment(self, expected=None, **kwargs):
|
||||
keys = kwargs.copy()
|
||||
segment = self.segment(**keys)
|
||||
self._validate_resource(segment, keys, 'segment')
|
||||
if expected:
|
||||
self._compare_resource(segment, expected, 'segment')
|
||||
return segment
|
||||
|
||||
|
||||
class SegmentTestPlugin(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
db.SegmentDbMixin):
|
||||
__native_pagination_support = True
|
||||
__native_sorting_support = True
|
||||
|
||||
supported_extension_aliases = ["segment"]
|
||||
|
||||
|
||||
class TestSegment(SegmentTestCase):
|
||||
|
||||
def test_create_segment(self):
|
||||
with self.network() as network:
|
||||
network = network['network']
|
||||
expected_segment = {'network_id': network['id'],
|
||||
'physical_network': 'phys_net',
|
||||
'network_type': 'net_type',
|
||||
'segmentation_id': 200}
|
||||
self._test_create_segment(network_id=network['id'],
|
||||
physical_network='phys_net',
|
||||
segmentation_id=200,
|
||||
expected=expected_segment)
|
||||
|
||||
def test_create_segment_no_phys_net(self):
|
||||
with self.network() as network:
|
||||
network = network['network']
|
||||
expected_segment = {'network_id': network['id'],
|
||||
'physical_network': None,
|
||||
'network_type': 'net_type',
|
||||
'segmentation_id': 200}
|
||||
self._test_create_segment(network_id=network['id'],
|
||||
segmentation_id=200,
|
||||
expected=expected_segment)
|
||||
|
||||
def test_create_segment_no_segmentation_id(self):
|
||||
with self.network() as network:
|
||||
network = network['network']
|
||||
expected_segment = {'network_id': network['id'],
|
||||
'physical_network': 'phys_net',
|
||||
'network_type': 'net_type',
|
||||
'segmentation_id': None}
|
||||
self._test_create_segment(network_id=network['id'],
|
||||
physical_network='phys_net',
|
||||
expected=expected_segment)
|
||||
|
||||
def test_delete_segment(self):
|
||||
with self.network() as network:
|
||||
network = network['network']
|
||||
segment = self.segment(network_id=network['id'])
|
||||
self._delete('segments', segment['segment']['id'])
|
||||
self._show('segments', segment['segment']['id'],
|
||||
expected_code=webob.exc.HTTPNotFound.code)
|
||||
|
||||
def test_get_segment(self):
|
||||
with self.network() as network:
|
||||
network = network['network']
|
||||
segment = self._test_create_segment(network_id=network['id'],
|
||||
physical_network='phys_net',
|
||||
segmentation_id=200)
|
||||
req = self.new_show_request('segments', segment['segment']['id'])
|
||||
res = self.deserialize(self.fmt, req.get_response(self.ext_api))
|
||||
self.assertEqual(segment['segment']['id'], res['segment']['id'])
|
||||
|
||||
def test_list_segments(self):
|
||||
with self.network() as network:
|
||||
network = network['network']
|
||||
self._test_create_segment(network_id=network['id'],
|
||||
physical_network='phys_net1',
|
||||
segmentation_id=200)
|
||||
self._test_create_segment(network_id=network['id'],
|
||||
physical_network='phys_net2',
|
||||
segmentation_id=200)
|
||||
res = self._list('segments')
|
||||
self.assertEqual(2, len(res['segments']))
|
@ -79,6 +79,7 @@ neutron.service_plugins =
|
||||
tag = neutron.services.tag.tag_plugin:TagPlugin
|
||||
flavors = neutron.services.flavors.flavors_plugin:FlavorsPlugin
|
||||
auto_allocate = neutron.services.auto_allocate.plugin:Plugin
|
||||
segments = neutron.services.segments.plugin:Plugin
|
||||
network_ip_availability = neutron.services.network_ip_availability.plugin:NetworkIPAvailabilityPlugin
|
||||
timestamp_core = neutron.services.timestamp.timestamp_plugin:TimeStampPlugin
|
||||
neutron.qos.notification_drivers =
|
||||
|
Loading…
Reference in New Issue
Block a user