Merge "Inherit segmentation details for trunk subports if requested"
This commit is contained in:
commit
90567b3bc0
|
@ -79,3 +79,4 @@ TRUNK_SUBPORT_OWNER = 'trunk:subport'
|
|||
|
||||
# String literals for segmentation types
|
||||
VLAN = 'vlan'
|
||||
INHERIT = 'inherit'
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
from neutron_lib.api import converters
|
||||
from neutron_lib.api.definitions import portbindings
|
||||
from neutron_lib.api.definitions import provider_net as provider
|
||||
from neutron_lib.api import validators
|
||||
from neutron_lib import exceptions as n_exc
|
||||
from neutron_lib.plugins import directory
|
||||
|
@ -22,6 +23,7 @@ from neutron._i18n import _
|
|||
from neutron.common import utils as n_utils
|
||||
from neutron.objects import trunk as trunk_objects
|
||||
from neutron.plugins.ml2 import driver_api as api
|
||||
from neutron.services.trunk import constants
|
||||
from neutron.services.trunk import exceptions as trunk_exc
|
||||
from neutron.services.trunk import utils
|
||||
|
||||
|
@ -165,11 +167,41 @@ class SubPortsValidator(object):
|
|||
|
||||
if trunk_validation:
|
||||
trunk_port_mtu = self._get_port_mtu(context, self.trunk_port_id)
|
||||
self._prepare_subports(context)
|
||||
return [self._validate(context, s, trunk_port_mtu)
|
||||
for s in self.subports]
|
||||
else:
|
||||
return self.subports
|
||||
|
||||
def _prepare_subports(self, context):
|
||||
"""Update subports segmentation details if INHERIT is requested."""
|
||||
port_ids = {
|
||||
s['port_id']: i
|
||||
for i, s in enumerate(self.subports)
|
||||
if s.get('segmentation_type') == constants.INHERIT
|
||||
}
|
||||
core_plugin = directory.get_plugin()
|
||||
if not port_ids:
|
||||
return
|
||||
elif not n_utils.is_extension_supported(core_plugin, provider.ALIAS):
|
||||
msg = _("Cannot accept segmentation type %s") % constants.INHERIT
|
||||
raise n_exc.InvalidInput(error_message=msg)
|
||||
|
||||
ports = core_plugin.get_ports(context, filters={'id': port_ids})
|
||||
# this assumes a user does not try to trunk the same network
|
||||
# more than once.
|
||||
network_port_map = {
|
||||
x['network_id']: {'port_id': x['id']}
|
||||
for x in ports
|
||||
}
|
||||
networks = core_plugin.get_networks(
|
||||
context.elevated(), filters={'id': network_port_map})
|
||||
for net in networks:
|
||||
port = network_port_map[net['id']]
|
||||
port.update({'segmentation_id': net[provider.SEGMENTATION_ID],
|
||||
'segmentation_type': net[provider.NETWORK_TYPE]})
|
||||
self.subports[port_ids[port['port_id']]] = port
|
||||
|
||||
def _get_port_mtu(self, context, port_id):
|
||||
"""
|
||||
Return MTU for the network where the given port belongs to.
|
||||
|
|
|
@ -91,6 +91,7 @@ case $VENV in
|
|||
load_rc_hook qos
|
||||
load_rc_hook trunk
|
||||
load_conf_hook mtu
|
||||
load_conf_hook vlan_provider
|
||||
load_conf_hook osprofiler
|
||||
if [[ "$VENV" =~ "dsvm-scenario" ]]; then
|
||||
load_rc_hook ubuntu_image
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
[[test-config|$TEMPEST_CONFIG]]
|
||||
|
||||
[neutron_plugin_options]
|
||||
provider_vlans=foo,
|
||||
|
||||
[[post-config|/$Q_PLUGIN_CONF_FILE]]
|
||||
|
||||
[ml2_type_vlan]
|
||||
network_vlan_ranges = foo:1:10
|
|
@ -220,6 +220,53 @@ class TrunkTestJSON(TrunkTestJSONBase):
|
|||
self.assertEqual(1, len(observed_subports))
|
||||
|
||||
|
||||
class TrunkTestInheritJSONBase(TrunkTestJSONBase):
|
||||
|
||||
required_extensions = ['provider', 'trunk']
|
||||
|
||||
@classmethod
|
||||
def skip_checks(cls):
|
||||
super(TrunkTestInheritJSONBase, cls).skip_checks()
|
||||
for ext in cls.required_extensions:
|
||||
if not test.is_extension_enabled(ext, 'network'):
|
||||
msg = "%s extension not enabled." % ext
|
||||
raise cls.skipException(msg)
|
||||
if not config.CONF.neutron_plugin_options.provider_vlans:
|
||||
raise cls.skipException("No provider VLAN networks available")
|
||||
|
||||
def create_provider_network(self):
|
||||
foo_net = config.CONF.neutron_plugin_options.provider_vlans[0]
|
||||
post_body = {'network_name': data_utils.rand_name('vlan-net-'),
|
||||
'provider:network_type': 'vlan',
|
||||
'provider:physical_network': foo_net}
|
||||
return self.create_shared_network(**post_body)
|
||||
|
||||
@decorators.idempotent_id('0f05d98e-41f5-4629-dada-9aee269c9602')
|
||||
def test_add_subport(self):
|
||||
trunk_network = self.create_provider_network()
|
||||
trunk_port = self.create_port(trunk_network)
|
||||
subport_networks = [
|
||||
self.create_provider_network(),
|
||||
self.create_provider_network(),
|
||||
]
|
||||
subport1 = self.create_port(subport_networks[0])
|
||||
subport2 = self.create_port(subport_networks[1])
|
||||
subports = [{'port_id': subport1['id'],
|
||||
'segmentation_type': 'inherit',
|
||||
'segmentation_id': subport1['id']},
|
||||
{'port_id': subport2['id'],
|
||||
'segmentation_type': 'inherit',
|
||||
'segmentation_id': subport2['id']}]
|
||||
trunk = self.client.create_trunk(trunk_port['id'], subports)['trunk']
|
||||
self.trunks.append(trunk)
|
||||
# Validate that subport got segmentation details from the network
|
||||
for i in range(2):
|
||||
self.assertEqual(subport_networks[i]['provider:network_type'],
|
||||
trunk['sub_ports'][i]['segmentation_type'])
|
||||
self.assertEqual(subport_networks[i]['provider:segmentation_id'],
|
||||
trunk['sub_ports'][i]['segmentation_id'])
|
||||
|
||||
|
||||
class TrunkTestMtusJSONBase(TrunkTestJSONBase):
|
||||
|
||||
required_extensions = ['provider', 'trunk']
|
||||
|
|
|
@ -102,6 +102,18 @@ class TrunkTestJSON(test_trunk.TrunkTestJSONBase):
|
|||
[{'segmentation_type': 'vlan',
|
||||
'segmentation_id': 3}])
|
||||
|
||||
@test.attr(type='negative')
|
||||
@decorators.idempotent_id('40aed9be-e976-47d0-dada-bde2c7e74e57')
|
||||
def test_create_subport_invalid_inherit_network_segmentation_type(self):
|
||||
trunk = self._create_trunk_with_network_and_parent([])
|
||||
subport_network = self.create_network()
|
||||
parent_port = self.create_port(subport_network)
|
||||
self.assertRaises(lib_exc.BadRequest, self.client.add_subports,
|
||||
trunk['trunk']['id'],
|
||||
[{'port_id': parent_port['id'],
|
||||
'segmentation_type': 'inherit',
|
||||
'segmentation_id': -1}])
|
||||
|
||||
@test.attr(type='negative')
|
||||
@decorators.idempotent_id('40aed9be-e976-47d0-a555-bde2c7e74e57')
|
||||
def test_create_trunk_duplicate_subport_segmentation_ids(self):
|
||||
|
|
|
@ -19,6 +19,9 @@ CONF = config.CONF
|
|||
|
||||
|
||||
NeutronPluginOptions = [
|
||||
cfg.ListOpt('provider_vlans',
|
||||
default=[],
|
||||
help='List of provider networks available in the deployment.'),
|
||||
cfg.BoolOpt('specify_floating_ip_address_available',
|
||||
default=True,
|
||||
help='Allow passing an IP Address of the floating ip when '
|
||||
|
|
|
@ -44,6 +44,8 @@ class SubPortsValidatorTestCase(base.BaseTestCase):
|
|||
|
||||
mock.patch.object(rules.SubPortsValidator, '_get_port_mtu',
|
||||
return_value=None).start()
|
||||
mock.patch.object(rules.SubPortsValidator, '_prepare_subports',
|
||||
return_value=None).start()
|
||||
|
||||
def test_validate_subport_subport_and_trunk_shared_port_id(self):
|
||||
shared_id = uuidutils.generate_uuid()
|
||||
|
@ -124,6 +126,26 @@ class SubPortsValidatorTestCase(base.BaseTestCase):
|
|||
self.context, basic_validation=True)
|
||||
|
||||
|
||||
class SubPortsValidatorPrepareTestCase(base.BaseTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(SubPortsValidatorPrepareTestCase, self).setUp()
|
||||
self.segmentation_types = {constants.VLAN: utils.is_valid_vlan_tag}
|
||||
self.context = mock.ANY
|
||||
|
||||
mock.patch.object(rules.SubPortsValidator, '_get_port_mtu',
|
||||
return_value=None).start()
|
||||
|
||||
def test__prepare_subports_raise_no_provider_ext(self):
|
||||
validator = rules.SubPortsValidator(
|
||||
self.segmentation_types,
|
||||
[{'port_id': uuidutils.generate_uuid(),
|
||||
'segmentation_type': 'inherit'}])
|
||||
self.assertRaises(n_exc.InvalidInput,
|
||||
validator._prepare_subports,
|
||||
self.context)
|
||||
|
||||
|
||||
class SubPortsValidatorMtuSanityTestCase(test_plugin.Ml2PluginV2TestCase):
|
||||
|
||||
def setUp(self):
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
---
|
||||
features:
|
||||
- Subport segmentation details can now accept ``inherit`` as segmentation
|
||||
type during a trunk creation/update request. The trunk plugin will
|
||||
determine the segmentation type and ID and replace them with those of
|
||||
the network to which the port is connected. Only single-segment VLAN
|
||||
networks are set to have expected and correct results at this point.
|
Loading…
Reference in New Issue