Notify mech drivers with original and modified network.
Include original and modified network when notifying mechanism drivers in PRECOMMIT event. PRECOMMIT_CREATE modified network includes new segment, while original does not. Exact opposite for PRECOMMIT_DELETE Closes-Bug: #1967742 Change-Id: I364fc7981458374ed25eb8837d1ed3afff046b95
This commit is contained in:
parent
42ce0ea42c
commit
d1fe14d366
neutron
@ -162,9 +162,9 @@ class TypeManager(stevedore.named.NamedExtensionManager):
|
||||
net_segments = segments_db.get_networks_segments(context, ids)
|
||||
for network in networks:
|
||||
segments = net_segments[network['id']]
|
||||
self._extend_network_dict_provider(network, segments)
|
||||
self.extend_network_with_provider_segments(network, segments)
|
||||
|
||||
def _extend_network_dict_provider(self, network, segments):
|
||||
def extend_network_with_provider_segments(self, network, segments):
|
||||
if not segments:
|
||||
LOG.debug("Network %s has no segments", network['id'])
|
||||
for attr in provider.ATTRIBUTES:
|
||||
@ -183,6 +183,22 @@ class TypeManager(stevedore.named.NamedExtensionManager):
|
||||
network[provider.SEGMENTATION_ID] = segment[
|
||||
api.SEGMENTATION_ID]
|
||||
|
||||
@staticmethod
|
||||
def pop_segments_from_network(network):
|
||||
multiple_segments = network.pop(mpnet_apidef.SEGMENTS, [])
|
||||
if multiple_segments:
|
||||
network_segments = multiple_segments
|
||||
else:
|
||||
network_segments = [
|
||||
{provider_key: network.pop(provider_key)
|
||||
for provider_key in provider.ATTRIBUTES}]
|
||||
|
||||
return (
|
||||
[{api.NETWORK_TYPE: network_segment[provider.NETWORK_TYPE],
|
||||
api.PHYSICAL_NETWORK: network_segment[provider.PHYSICAL_NETWORK],
|
||||
api.SEGMENTATION_ID: network_segment[provider.SEGMENTATION_ID]}
|
||||
for network_segment in network_segments])
|
||||
|
||||
def initialize(self):
|
||||
for network_type, driver in self.drivers.items():
|
||||
LOG.info("Initializing driver for type '%s'", network_type)
|
||||
|
@ -13,6 +13,8 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import copy
|
||||
|
||||
from eventlet import greenthread
|
||||
import netaddr
|
||||
from netaddr.strategy import eui48
|
||||
@ -2511,7 +2513,7 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
|
||||
try:
|
||||
self._notify_mechanism_driver_for_segment_change(
|
||||
event, context, network_id)
|
||||
event, context, segment)
|
||||
except ml2_exc.MechanismDriverError:
|
||||
with excutils.save_and_reraise_exception():
|
||||
LOG.error("mechanism_manager error occurred when "
|
||||
@ -2519,15 +2521,53 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
"'%(segment)s'",
|
||||
{'event': event, 'segment': segment['id']})
|
||||
|
||||
def _build_original_network(self, event, network, changed_segment):
|
||||
"""Constructs a copy of the given network where the given
|
||||
segment will be either removed(precommit_create) or added
|
||||
(precommit_delete) to the copied network
|
||||
"""
|
||||
|
||||
network_copy = copy.deepcopy(network)
|
||||
network_segments = managers.TypeManager()\
|
||||
.pop_segments_from_network(network_copy)
|
||||
|
||||
if event == events.PRECOMMIT_CREATE:
|
||||
network_segments = [network_segment
|
||||
for network_segment in network_segments
|
||||
# A segment popped from a network could have its
|
||||
# segmentation_id set to None if the segment
|
||||
# beeing created is partial.
|
||||
if not ((network_segment[api.SEGMENTATION_ID] ==
|
||||
changed_segment[api.SEGMENTATION_ID] or
|
||||
network_segment[api.SEGMENTATION_ID] is None) and
|
||||
network_segment[api.NETWORK_TYPE] ==
|
||||
changed_segment[api.NETWORK_TYPE] and
|
||||
network_segment[api.PHYSICAL_NETWORK] ==
|
||||
changed_segment[api.PHYSICAL_NETWORK])]
|
||||
elif event == events.PRECOMMIT_DELETE:
|
||||
network_segments.append(changed_segment)
|
||||
|
||||
self.type_manager.extend_network_with_provider_segments(
|
||||
network_copy, network_segments)
|
||||
|
||||
return network_copy
|
||||
|
||||
def _notify_mechanism_driver_for_segment_change(self, event,
|
||||
context, network_id):
|
||||
network_with_segments = self.get_network(context, network_id)
|
||||
mech_context = driver_context.NetworkContext(
|
||||
self, context, network_with_segments,
|
||||
original_network=network_with_segments)
|
||||
context, segment):
|
||||
network = self.get_network(context, segment['network_id'])
|
||||
|
||||
if event in [events.PRECOMMIT_CREATE, events.PRECOMMIT_DELETE]:
|
||||
original_network = self._build_original_network(
|
||||
event, network, segment)
|
||||
mech_context = driver_context.NetworkContext(
|
||||
self, context, network,
|
||||
original_network=original_network)
|
||||
self.mechanism_manager.update_network_precommit(mech_context)
|
||||
elif event in [events.AFTER_CREATE, events.AFTER_DELETE]:
|
||||
|
||||
if event in [events.AFTER_CREATE, events.AFTER_DELETE]:
|
||||
mech_context = driver_context.NetworkContext(
|
||||
self, context, network,
|
||||
original_network=network)
|
||||
self.mechanism_manager.update_network_postcommit(mech_context)
|
||||
|
||||
@staticmethod
|
||||
|
@ -3647,3 +3647,90 @@ class TestML2Segments(Ml2PluginV2TestCase):
|
||||
resource_id=segment['id']))
|
||||
exist_port = self._show('ports', port['port']['id'])
|
||||
self.assertEqual(port['port']['id'], exist_port['port']['id'])
|
||||
|
||||
def test_precommit_create_builds_single_segment_original_network(self):
|
||||
event = events.PRECOMMIT_CREATE
|
||||
network_type = 'vlan'
|
||||
physical_network = self.physnet
|
||||
segmentation_id = 2
|
||||
|
||||
network_segments = [{pnet.NETWORK_TYPE: 'vlan',
|
||||
pnet.PHYSICAL_NETWORK: self.physnet2,
|
||||
pnet.SEGMENTATION_ID: 1},
|
||||
{pnet.NETWORK_TYPE: network_type,
|
||||
pnet.PHYSICAL_NETWORK: physical_network,
|
||||
pnet.SEGMENTATION_ID: segmentation_id}]
|
||||
|
||||
new_segment = {driver_api.NETWORK_TYPE: network_type,
|
||||
driver_api.PHYSICAL_NETWORK: physical_network,
|
||||
driver_api.SEGMENTATION_ID: segmentation_id}
|
||||
|
||||
with self.network(**{'arg_list': (mpnet_apidef.SEGMENTS, ),
|
||||
mpnet_apidef.SEGMENTS: network_segments})\
|
||||
as test_network:
|
||||
multisegment_network = test_network['network']
|
||||
observed_network = self.driver._build_original_network(
|
||||
event, multisegment_network, new_segment)
|
||||
# Should become a single segment network
|
||||
self.assertNotIn(mpnet_apidef.SEGMENTS, observed_network)
|
||||
# Where new segment in not part of the network
|
||||
self.assertNotEqual(segmentation_id,
|
||||
observed_network[pnet.SEGMENTATION_ID])
|
||||
|
||||
def test_precommit_create_builds_multisegment_original_network(self):
|
||||
event = events.PRECOMMIT_CREATE
|
||||
network_type = 'vlan'
|
||||
physical_network = self.physnet
|
||||
segmentation_id = 3
|
||||
|
||||
network_segments = [{pnet.NETWORK_TYPE: 'vlan',
|
||||
pnet.PHYSICAL_NETWORK: self.physnet2,
|
||||
pnet.SEGMENTATION_ID: 1},
|
||||
{pnet.NETWORK_TYPE: 'vlan',
|
||||
pnet.PHYSICAL_NETWORK: self.physnet3,
|
||||
pnet.SEGMENTATION_ID: 2},
|
||||
{pnet.NETWORK_TYPE: network_type,
|
||||
pnet.PHYSICAL_NETWORK: physical_network,
|
||||
pnet.SEGMENTATION_ID: segmentation_id}]
|
||||
|
||||
new_segment = {driver_api.NETWORK_TYPE: network_type,
|
||||
driver_api.PHYSICAL_NETWORK: physical_network,
|
||||
driver_api.SEGMENTATION_ID: segmentation_id}
|
||||
|
||||
with self.network(**{'arg_list': (mpnet_apidef.SEGMENTS, ),
|
||||
mpnet_apidef.SEGMENTS: network_segments})\
|
||||
as test_network:
|
||||
multisegment_network = test_network['network']
|
||||
observed_network = self.driver._build_original_network(
|
||||
event, multisegment_network, new_segment)
|
||||
# Should remain a multisegment network
|
||||
self.assertIn(mpnet_apidef.SEGMENTS, observed_network)
|
||||
# Where new segment in not part of the multisegment
|
||||
self.assertNotIn(network_segments[2],
|
||||
observed_network[mpnet_apidef.SEGMENTS])
|
||||
|
||||
def test_precommit_delete_builds_multisegment_original_network(self):
|
||||
event = events.PRECOMMIT_DELETE
|
||||
network_type = 'vlan'
|
||||
physical_network = self.physnet
|
||||
segmentation_id = 2
|
||||
|
||||
deleted_segment = {driver_api.NETWORK_TYPE: network_type,
|
||||
driver_api.PHYSICAL_NETWORK: physical_network,
|
||||
driver_api.SEGMENTATION_ID: segmentation_id}
|
||||
|
||||
expected_segment = {pnet.NETWORK_TYPE: network_type,
|
||||
pnet.PHYSICAL_NETWORK: physical_network,
|
||||
pnet.SEGMENTATION_ID: segmentation_id}
|
||||
|
||||
with self.network() as test_network:
|
||||
# network() implicitaly creates a single segment
|
||||
single_segment_network = test_network['network']
|
||||
observed_network = self.driver._build_original_network(
|
||||
event, single_segment_network, deleted_segment)
|
||||
# Should become a multisegment network
|
||||
self.assertIn(mpnet_apidef.SEGMENTS, observed_network)
|
||||
self.assertEqual(2, len(observed_network[mpnet_apidef.SEGMENTS]))
|
||||
# Where new segment is part of segments
|
||||
self.assertIn(expected_segment,
|
||||
observed_network[mpnet_apidef.SEGMENTS])
|
||||
|
Loading…
x
Reference in New Issue
Block a user