Merge "Inherit segmentation details for trunk subports if requested"

This commit is contained in:
Jenkins 2017-04-05 09:36:56 +00:00 committed by Gerrit Code Review
commit 90567b3bc0
9 changed files with 134 additions and 0 deletions

View File

@ -79,3 +79,4 @@ TRUNK_SUBPORT_OWNER = 'trunk:subport'
# String literals for segmentation types
VLAN = 'vlan'
INHERIT = 'inherit'

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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']

View File

@ -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):

View File

@ -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 '

View File

@ -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):

View File

@ -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.