Create segment_host mapping after new network

This adds logic to add segment to host mappings for agents after a
network with one or more segments is created. The previous logic was
doing this only after an agent initially reported after the server
started.  This meant that any segmented networks created after the
agent was running would not get mappings to the agent's host.

Change-Id: Ie265500639b1119f0448ed272d235fb709db36f6
Partially-Implements: blueprint routed-networks
This commit is contained in:
Carl Baldwin 2016-06-27 13:30:44 -06:00
parent 4ed9a3e56c
commit 040d740d20
6 changed files with 49 additions and 21 deletions

View File

@ -16,6 +16,9 @@ import sqlalchemy as sa
from sqlalchemy.orm import exc
from neutron._i18n import _LI
from neutron.callbacks import events
from neutron.callbacks import registry
from neutron.callbacks import resources
from neutron.db import model_base
LOG = logging.getLogger(__name__)
@ -60,9 +63,9 @@ def _make_segment_dict(record):
SEGMENTATION_ID: record.segmentation_id}
def add_network_segment(session, network_id, segment, segment_index=0,
def add_network_segment(context, network_id, segment, segment_index=0,
is_dynamic=False):
with session.begin(subtransactions=True):
with context.session.begin(subtransactions=True):
record = NetworkSegment(
id=uuidutils.generate_uuid(),
network_id=network_id,
@ -72,7 +75,12 @@ def add_network_segment(session, network_id, segment, segment_index=0,
segment_index=segment_index,
is_dynamic=is_dynamic
)
session.add(record)
context.session.add(record)
registry.notify(resources.SEGMENT,
events.PRECOMMIT_CREATE,
trigger=add_network_segment,
context=context,
segment=record)
segment['id'] = record.id
LOG.info(_LI("Added segment %(id)s of type %(network_type)s for network "
"%(network_id)s"),

View File

@ -259,7 +259,7 @@ class PortContext(MechanismDriverContext, api.PortContext):
network_id = self._network_context.current['id']
return self._plugin.type_manager.allocate_dynamic_segment(
self._plugin_context.session, network_id, segment)
self._plugin_context, network_id, segment)
def release_dynamic_segment(self, segment_id):
return self._plugin.type_manager.release_dynamic_segment(

View File

@ -182,10 +182,10 @@ class TypeManager(stevedore.named.NamedExtensionManager):
LOG.info(_LI("Initializing driver for type '%s'"), network_type)
driver.obj.initialize()
def _add_network_segment(self, session, network_id, segment, mtu,
def _add_network_segment(self, context, network_id, segment, mtu,
segment_index=0):
segments_db.add_network_segment(
session, network_id, segment, segment_index)
context, network_id, segment, segment_index)
if segment.get(api.MTU, 0) > 0:
mtu.append(segment[api.MTU])
@ -200,15 +200,15 @@ class TypeManager(stevedore.named.NamedExtensionManager):
for segment_index, segment in enumerate(segments):
segment = self.reserve_provider_segment(
session, segment)
self._add_network_segment(session, network_id, segment,
self._add_network_segment(context, network_id, segment,
mtu, segment_index)
elif (cfg.CONF.ml2.external_network_type and
self._get_attribute(network, external_net.EXTERNAL)):
segment = self._allocate_ext_net_segment(session)
self._add_network_segment(session, network_id, segment, mtu)
self._add_network_segment(context, network_id, segment, mtu)
else:
segment = self._allocate_tenant_net_segment(session)
self._add_network_segment(session, network_id, segment, mtu)
self._add_network_segment(context, network_id, segment, mtu)
network[api.MTU] = min(mtu) if mtu else 0
def is_partial_segment(self, segment):
@ -265,18 +265,19 @@ class TypeManager(stevedore.named.NamedExtensionManager):
LOG.error(_LE("Failed to release segment '%s' because "
"network type is not supported."), segment)
def allocate_dynamic_segment(self, session, network_id, segment):
def allocate_dynamic_segment(self, context, network_id, segment):
"""Allocate a dynamic segment using a partial or full segment dict."""
dynamic_segment = segments_db.get_dynamic_segment(
session, network_id, segment.get(api.PHYSICAL_NETWORK),
context.session, network_id, segment.get(api.PHYSICAL_NETWORK),
segment.get(api.SEGMENTATION_ID))
if dynamic_segment:
return dynamic_segment
driver = self.drivers.get(segment.get(api.NETWORK_TYPE))
dynamic_segment = driver.obj.reserve_provider_segment(session, segment)
segments_db.add_network_segment(session, network_id, dynamic_segment,
dynamic_segment = driver.obj.reserve_provider_segment(context.session,
segment)
segments_db.add_network_segment(context, network_id, dynamic_segment,
is_dynamic=True)
return dynamic_segment

View File

@ -19,6 +19,9 @@ from oslo_utils import uuidutils
import webob.exc
from neutron.api.v2 import attributes
from neutron.callbacks import events
from neutron.callbacks import registry
from neutron.callbacks import resources
from neutron import context
from neutron.db import agents_db
from neutron.db import db_base_plugin_v2
@ -189,6 +192,22 @@ class TestSegment(SegmentTestCase):
self.assertEqual(2, len(res['segments']))
class TestSegmentML2(SegmentTestCase):
def setUp(self):
super(TestSegmentML2, self).setUp(
plugin='neutron.plugins.ml2.plugin.Ml2Plugin')
def test_segment_notification_on_create_network(self):
with mock.patch.object(registry, 'notify') as notify:
with self.network():
pass
notify.assert_any_call(resources.SEGMENT,
events.PRECOMMIT_CREATE,
context=mock.ANY,
segment=mock.ANY,
trigger=mock.ANY)
class TestSegmentSubnetAssociation(SegmentTestCase):
def test_basic_association(self):
with self.network() as network:
@ -259,7 +278,7 @@ class TestSegmentSubnetAssociation(SegmentTestCase):
segment = {segments_db.NETWORK_TYPE: 'phys_net',
segments_db.PHYSICAL_NETWORK: 'net_type',
segments_db.SEGMENTATION_ID: 200}
segments_db.add_network_segment(cxt.session,
segments_db.add_network_segment(cxt,
network_id=net['id'],
segment=segment,
is_dynamic=True)

View File

@ -66,7 +66,7 @@ class Ml2DBTestCase(testlib_api.SqlTestCase):
self._setup_neutron_network(network_id)
for segment in segments:
segments_db.add_network_segment(
self.ctx.session, network_id, segment,
self.ctx, network_id, segment,
is_dynamic=is_seg_dynamic)
net_segments = segments_db.get_network_segments(

View File

@ -1367,7 +1367,7 @@ class TestMultiSegmentNetworks(Ml2PluginV2TestCase):
driver_api.PHYSICAL_NETWORK: 'physnet1'}
network_id = network['network']['id']
self.driver.type_manager.allocate_dynamic_segment(
self.context.session, network_id, segment)
self.context, network_id, segment)
dynamic_segment = segments_db.get_dynamic_segment(
self.context.session, network_id, 'physnet1')
self.assertEqual('vlan', dynamic_segment[driver_api.NETWORK_TYPE])
@ -1378,7 +1378,7 @@ class TestMultiSegmentNetworks(Ml2PluginV2TestCase):
driver_api.SEGMENTATION_ID: 1234,
driver_api.PHYSICAL_NETWORK: 'physnet3'}
self.driver.type_manager.allocate_dynamic_segment(
self.context.session, network_id, segment2)
self.context, network_id, segment2)
dynamic_segment = segments_db.get_dynamic_segment(
self.context.session, network_id, segmentation_id='1234')
self.assertEqual('vlan', dynamic_segment[driver_api.NETWORK_TYPE])
@ -1396,7 +1396,7 @@ class TestMultiSegmentNetworks(Ml2PluginV2TestCase):
driver_api.PHYSICAL_NETWORK: 'physnet1'}
network_id = network['network']['id']
self.driver.type_manager.allocate_dynamic_segment(
self.context.session, network_id, segment)
self.context, network_id, segment)
dynamic_segment = segments_db.get_dynamic_segment(
self.context.session, network_id, 'physnet1')
self.assertEqual('vlan', dynamic_segment[driver_api.NETWORK_TYPE])
@ -1411,7 +1411,7 @@ class TestMultiSegmentNetworks(Ml2PluginV2TestCase):
segment2 = {driver_api.NETWORK_TYPE: 'vlan',
driver_api.PHYSICAL_NETWORK: 'physnet2'}
self.driver.type_manager.allocate_dynamic_segment(
self.context.session, network_id, segment2)
self.context, network_id, segment2)
dynamic_segment2 = segments_db.get_dynamic_segment(
self.context.session, network_id, 'physnet2')
dynamic_segmentation2_id = dynamic_segment2[driver_api.SEGMENTATION_ID]
@ -1427,7 +1427,7 @@ class TestMultiSegmentNetworks(Ml2PluginV2TestCase):
driver_api.PHYSICAL_NETWORK: 'physnet1'}
network_id = network['network']['id']
self.driver.type_manager.allocate_dynamic_segment(
self.context.session, network_id, segment)
self.context, network_id, segment)
dynamic_segment = segments_db.get_dynamic_segment(
self.context.session, network_id, 'physnet1')
self.assertEqual('vlan', dynamic_segment[driver_api.NETWORK_TYPE])
@ -1564,7 +1564,7 @@ class TestMultiSegmentNetworks(Ml2PluginV2TestCase):
segment = {driver_api.NETWORK_TYPE: 'vlan',
driver_api.PHYSICAL_NETWORK: 'physnet2'}
self.driver.type_manager.allocate_dynamic_segment(
self.context.session, network_id, segment)
self.context, network_id, segment)
dynamic_segment = segments_db.get_dynamic_segment(
self.context.session, network_id, 'physnet2')
self.assertEqual('vlan', dynamic_segment[driver_api.NETWORK_TYPE])