Merge "Add filter for provider network attributes in ML2"
This commit is contained in:
commit
c411910cb1
@ -96,7 +96,8 @@ class TypeManager(stevedore.named.NamedExtensionManager):
|
||||
# at the same time.
|
||||
if attributes.is_attr_set(network.get(mpnet.SEGMENTS)):
|
||||
raise mpnet.SegmentsSetInConjunctionWithProviders()
|
||||
return [self._process_provider_segment(network)]
|
||||
segment = self._get_provider_segment(network)
|
||||
return [self._process_provider_segment(segment)]
|
||||
elif attributes.is_attr_set(network.get(mpnet.SEGMENTS)):
|
||||
segments = [self._process_provider_segment(s)
|
||||
for s in network[mpnet.SEGMENTS]]
|
||||
@ -105,6 +106,31 @@ class TypeManager(stevedore.named.NamedExtensionManager):
|
||||
self.is_partial_segment)
|
||||
return segments
|
||||
|
||||
def _match_segment(self, segment, filters):
|
||||
return all(not filters.get(attr) or segment.get(attr) in filters[attr]
|
||||
for attr in provider.ATTRIBUTES)
|
||||
|
||||
def _get_provider_segment(self, network):
|
||||
# TODO(manishg): Placeholder method
|
||||
# Code intended for operating on a provider segment should use
|
||||
# this method to extract the segment, even though currently the
|
||||
# segment attributes are part of the network dictionary. In the
|
||||
# future, network and segment information will be decoupled and
|
||||
# here we will do the job of extracting the segment information.
|
||||
return network
|
||||
|
||||
def network_matches_filters(self, network, filters):
|
||||
if not filters:
|
||||
return True
|
||||
if any(attributes.is_attr_set(network.get(attr))
|
||||
for attr in provider.ATTRIBUTES):
|
||||
segments = [self._get_provider_segment(network)]
|
||||
elif attributes.is_attr_set(network.get(mpnet.SEGMENTS)):
|
||||
segments = self._get_attribute(network, mpnet.SEGMENTS)
|
||||
else:
|
||||
return True
|
||||
return any(self._match_segment(s, filters) for s in segments)
|
||||
|
||||
def _get_attribute(self, attrs, key):
|
||||
value = attrs.get(key)
|
||||
if value is attributes.ATTR_NOT_SPECIFIED:
|
||||
|
@ -156,9 +156,11 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
fanout=False)
|
||||
return self.conn.consume_in_threads()
|
||||
|
||||
def _filter_nets_provider(self, context, nets, filters):
|
||||
# TODO(rkukura): Implement filtering.
|
||||
return nets
|
||||
def _filter_nets_provider(self, context, networks, filters):
|
||||
return [network
|
||||
for network in networks
|
||||
if self.type_manager.network_matches_filters(network, filters)
|
||||
]
|
||||
|
||||
def _notify_l3_agent_new_port(self, context, port):
|
||||
if not port:
|
||||
|
@ -16,6 +16,7 @@
|
||||
import contextlib
|
||||
import functools
|
||||
import mock
|
||||
import six
|
||||
import testtools
|
||||
import uuid
|
||||
import webob
|
||||
@ -137,6 +138,38 @@ class TestMl2V2HTTPResponse(test_plugin.TestV2HTTPResponse,
|
||||
|
||||
class TestMl2NetworksV2(test_plugin.TestNetworksV2,
|
||||
Ml2PluginV2TestCase):
|
||||
def setUp(self, plugin=None):
|
||||
super(TestMl2NetworksV2, self).setUp()
|
||||
# provider networks
|
||||
self.pnets = [{'name': 'net1',
|
||||
pnet.NETWORK_TYPE: 'vlan',
|
||||
pnet.PHYSICAL_NETWORK: 'physnet1',
|
||||
pnet.SEGMENTATION_ID: 1,
|
||||
'tenant_id': 'tenant_one'},
|
||||
{'name': 'net2',
|
||||
pnet.NETWORK_TYPE: 'vlan',
|
||||
pnet.PHYSICAL_NETWORK: 'physnet2',
|
||||
pnet.SEGMENTATION_ID: 210,
|
||||
'tenant_id': 'tenant_one'},
|
||||
{'name': 'net3',
|
||||
pnet.NETWORK_TYPE: 'vlan',
|
||||
pnet.PHYSICAL_NETWORK: 'physnet2',
|
||||
pnet.SEGMENTATION_ID: 220,
|
||||
'tenant_id': 'tenant_one'}
|
||||
]
|
||||
# multiprovider networks
|
||||
self.mp_nets = [{'name': 'net4',
|
||||
mpnet.SEGMENTS:
|
||||
[{pnet.NETWORK_TYPE: 'vlan',
|
||||
pnet.PHYSICAL_NETWORK: 'physnet2',
|
||||
pnet.SEGMENTATION_ID: 1},
|
||||
{pnet.NETWORK_TYPE: 'vlan',
|
||||
pnet.PHYSICAL_NETWORK: 'physnet2',
|
||||
pnet.SEGMENTATION_ID: 202}],
|
||||
'tenant_id': 'tenant_one'}
|
||||
]
|
||||
self.nets = self.mp_nets + self.pnets
|
||||
|
||||
def test_port_delete_helper_tolerates_failure(self):
|
||||
plugin = manager.NeutronManager.get_plugin()
|
||||
with mock.patch.object(plugin, "delete_port",
|
||||
@ -149,6 +182,66 @@ class TestMl2NetworksV2(test_plugin.TestNetworksV2,
|
||||
side_effect=exc.SubnetNotFound(subnet_id="1")):
|
||||
plugin._delete_subnets(None, [mock.MagicMock()])
|
||||
|
||||
def _create_and_verify_networks(self, networks):
|
||||
for net_idx, net in enumerate(networks):
|
||||
# create
|
||||
req = self.new_create_request('networks',
|
||||
{'network': net})
|
||||
# verify
|
||||
network = self.deserialize(self.fmt,
|
||||
req.get_response(self.api))['network']
|
||||
if mpnet.SEGMENTS not in net:
|
||||
for k, v in six.iteritems(net):
|
||||
self.assertEqual(net[k], network[k])
|
||||
self.assertNotIn(mpnet.SEGMENTS, network)
|
||||
else:
|
||||
segments = network[mpnet.SEGMENTS]
|
||||
expected_segments = net[mpnet.SEGMENTS]
|
||||
self.assertEqual(len(expected_segments), len(segments))
|
||||
for expected, actual in zip(expected_segments, segments):
|
||||
self.assertEqual(expected, actual)
|
||||
|
||||
def _lookup_network_by_segmentation_id(self, seg_id, num_expected_nets):
|
||||
params_str = "%s=%s" % (pnet.SEGMENTATION_ID, seg_id)
|
||||
net_req = self.new_list_request('networks', None,
|
||||
params=params_str)
|
||||
networks = self.deserialize(self.fmt, net_req.get_response(self.api))
|
||||
if num_expected_nets:
|
||||
self.assertIsNotNone(networks)
|
||||
self.assertEqual(num_expected_nets, len(networks['networks']))
|
||||
else:
|
||||
self.assertIsNone(networks)
|
||||
return networks
|
||||
|
||||
def test_list_networks_with_segmentation_id(self):
|
||||
self._create_and_verify_networks(self.pnets)
|
||||
# verify we can find the network that we expect
|
||||
lookup_vlan_id = 1
|
||||
expected_net = [n for n in self.pnets
|
||||
if n[pnet.SEGMENTATION_ID] == lookup_vlan_id].pop()
|
||||
networks = self._lookup_network_by_segmentation_id(lookup_vlan_id, 1)
|
||||
# verify all provider attributes
|
||||
network = networks['networks'][0]
|
||||
for attr in pnet.ATTRIBUTES:
|
||||
self.assertEqual(expected_net[attr], network[attr])
|
||||
|
||||
def test_list_mpnetworks_with_segmentation_id(self):
|
||||
self._create_and_verify_networks(self.nets)
|
||||
|
||||
# get all networks with seg_id=1 (including multisegment networks)
|
||||
lookup_vlan_id = 1
|
||||
networks = self._lookup_network_by_segmentation_id(lookup_vlan_id, 2)
|
||||
|
||||
# get the mpnet
|
||||
networks = [n for n in networks['networks'] if mpnet.SEGMENTS in n]
|
||||
network = networks.pop()
|
||||
# verify attributes of the looked up item
|
||||
segments = network[mpnet.SEGMENTS]
|
||||
expected_segments = self.mp_nets[0][mpnet.SEGMENTS]
|
||||
self.assertEqual(len(expected_segments), len(segments))
|
||||
for expected, actual in zip(expected_segments, segments):
|
||||
self.assertEqual(expected, actual)
|
||||
|
||||
|
||||
class TestMl2SubnetsV2(test_plugin.TestSubnetsV2,
|
||||
Ml2PluginV2TestCase):
|
||||
|
Loading…
Reference in New Issue
Block a user