Merge "Add filter for provider network attributes in ML2"

This commit is contained in:
Jenkins 2015-02-28 00:41:22 +00:00 committed by Gerrit Code Review
commit c411910cb1
3 changed files with 125 additions and 4 deletions

View File

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

View File

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

View File

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