Merge "[apic] on demand synchronization This patch changes the synchronizator behavior:"
This commit is contained in:
commit
ab1b96611d
|
@ -37,18 +37,14 @@ class SynchronizerBase(object):
|
|||
def sync(self, f, *args, **kwargs):
|
||||
"""Fire synchronization based on interval.
|
||||
|
||||
Interval can be 0 for 'sync once' >0 for 'sync periodically' and
|
||||
<0 for 'no sync'
|
||||
Interval can be >0 for 'sync periodically' and
|
||||
<=0 for 'no sync'
|
||||
"""
|
||||
if self.interval:
|
||||
if self.interval > 0:
|
||||
loop_call = loopingcall.FixedIntervalLoopingCall(f, *args,
|
||||
**kwargs)
|
||||
loop_call.start(interval=self.interval)
|
||||
return loop_call
|
||||
else:
|
||||
# Fire once
|
||||
f(*args, **kwargs)
|
||||
if self.interval and self.interval > 0:
|
||||
loop_call = loopingcall.FixedIntervalLoopingCall(f, *args,
|
||||
**kwargs)
|
||||
loop_call.start(interval=self.interval)
|
||||
return loop_call
|
||||
|
||||
|
||||
class ApicBaseSynchronizer(SynchronizerBase):
|
||||
|
|
|
@ -17,8 +17,10 @@ from apicapi import apic_manager
|
|||
from keystoneclient.v2_0 import client as keyclient
|
||||
import netaddr
|
||||
from neutron.common import constants as n_constants
|
||||
from neutron.common import exceptions as n_exc
|
||||
from neutron.plugins.common import constants
|
||||
from neutron.plugins.ml2 import driver_api as api
|
||||
from neutron.plugins.ml2 import driver_context
|
||||
from neutron.plugins.ml2 import models
|
||||
from oslo_concurrency import lockutils
|
||||
from oslo_config import cfg
|
||||
|
@ -30,6 +32,12 @@ from networking_cisco.plugins.ml2.drivers.cisco.apic import config
|
|||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
APIC_SYNC_NETWORK = 'apic-sync-network'
|
||||
|
||||
|
||||
class ReservedSynchronizationName(n_exc.BadRequest):
|
||||
message = _("The name used for this network is reserved for on demand "
|
||||
"synchronization.")
|
||||
|
||||
|
||||
class APICMechanismDriver(api.MechanismDriver):
|
||||
|
@ -64,6 +72,10 @@ class APICMechanismDriver(api.MechanismDriver):
|
|||
return apic_sync.ApicRouterSynchronizer(inst,
|
||||
apic_config.apic_sync_interval)
|
||||
|
||||
@staticmethod
|
||||
def _is_network_context(ctx):
|
||||
return isinstance(ctx, driver_context.NetworkContext)
|
||||
|
||||
def initialize(self):
|
||||
# initialize apic
|
||||
self.apic_manager = APICMechanismDriver.get_apic_manager()
|
||||
|
@ -78,7 +90,10 @@ class APICMechanismDriver(api.MechanismDriver):
|
|||
inst.synchronizer = (
|
||||
APICMechanismDriver.get_base_synchronizer(inst))
|
||||
inst.synchronizer.sync_base()
|
||||
# pylint: disable=not-callable
|
||||
if args and APICMechanismDriver._is_network_context(args[0]):
|
||||
if (args[0]._plugin_context.is_admin and
|
||||
args[0].current['name'] == APIC_SYNC_NETWORK):
|
||||
inst.synchronizer._sync_base()
|
||||
return f(inst, *args, **kwargs)
|
||||
return inner
|
||||
|
||||
|
@ -211,6 +226,10 @@ class APICMechanismDriver(api.MechanismDriver):
|
|||
|
||||
@sync_init
|
||||
def create_network_postcommit(self, context):
|
||||
# The following validation is not happening in the precommit to avoid
|
||||
# database lock timeout
|
||||
if context.current['name'] == APIC_SYNC_NETWORK:
|
||||
raise ReservedSynchronizationName()
|
||||
if not context.current.get('router:external'):
|
||||
tenant_id = context.current['tenant_id']
|
||||
network_id = context.current['id']
|
||||
|
|
|
@ -68,6 +68,9 @@ class TestCiscoApicMechDriver(base.BaseTestCase,
|
|||
name_mapper=mock.Mock(), ext_net_dict=self.external_network_dict)
|
||||
|
||||
self.driver.apic_manager.apic.transaction = self.fake_transaction
|
||||
self.synchronizer = mock.Mock()
|
||||
md.APICMechanismDriver.get_base_synchronizer = mock.Mock(
|
||||
return_value=self.synchronizer)
|
||||
|
||||
def test_initialize(self):
|
||||
self.driver.initialize()
|
||||
|
@ -165,12 +168,30 @@ class TestCiscoApicMechDriver(base.BaseTestCase,
|
|||
ctx = self._get_network_context(mocked.APIC_TENANT,
|
||||
mocked.APIC_NETWORK,
|
||||
TEST_SEGMENT1)
|
||||
ctx._plugin_context.is_admin = True
|
||||
md.APICMechanismDriver._is_network_context = mock.Mock(
|
||||
return_value=True)
|
||||
mgr = self.driver.apic_manager
|
||||
self.driver.create_network_postcommit(ctx)
|
||||
mgr.ensure_bd_created_on_apic.assert_called_once_with(
|
||||
mocked.APIC_TENANT, mocked.APIC_NETWORK, transaction='transaction')
|
||||
mgr.ensure_epg_created.assert_called_once_with(
|
||||
mocked.APIC_TENANT, mocked.APIC_NETWORK, transaction='transaction')
|
||||
# Sync not called
|
||||
self.assertEqual(0, self.synchronizer._sync_base.call_count)
|
||||
|
||||
def test_create_sync_network(self):
|
||||
ctx = self._get_network_context(mocked.APIC_TENANT,
|
||||
mocked.APIC_NETWORK,
|
||||
TEST_SEGMENT1,
|
||||
name=md.APIC_SYNC_NETWORK)
|
||||
ctx._plugin_context.is_admin = True
|
||||
md.APICMechanismDriver._is_network_context = mock.Mock(
|
||||
return_value=True)
|
||||
self.assertRaises(
|
||||
md.ReservedSynchronizationName,
|
||||
self.driver.create_network_postcommit, ctx)
|
||||
self.assertEqual(1, self.synchronizer._sync_base.call_count)
|
||||
|
||||
def test_create_external_network_postcommit(self):
|
||||
ctx = self._get_network_context(mocked.APIC_TENANT,
|
||||
|
@ -226,9 +247,9 @@ class TestCiscoApicMechDriver(base.BaseTestCase,
|
|||
self.assertFalse(mgr.ensure_subnet_created_on_apic.called)
|
||||
|
||||
def _get_network_context(self, tenant_id, net_id, seg_id=None,
|
||||
seg_type='vlan', external=False):
|
||||
seg_type='vlan', external=False, name=None):
|
||||
network = {'id': net_id,
|
||||
'name': net_id + '-name',
|
||||
'name': name or (net_id + '-name'),
|
||||
'tenant_id': tenant_id,
|
||||
'provider:segmentation_id': seg_id}
|
||||
if external:
|
||||
|
@ -271,6 +292,7 @@ class FakeNetworkContext(object):
|
|||
def __init__(self, network, segments):
|
||||
self._network = network
|
||||
self._segments = segments
|
||||
self._plugin_context = mock.Mock()
|
||||
|
||||
@property
|
||||
def current(self):
|
||||
|
|
|
@ -63,7 +63,7 @@ class TestCiscoApicSync(base.BaseTestCase):
|
|||
sync.core_plugin.get_subnets.return_value = [{'id': 'sub'}]
|
||||
sync.core_plugin.get_ports.return_value = [{'id': 'port',
|
||||
'network_id': 'net'}]
|
||||
sync.sync_base()
|
||||
sync._sync_base()
|
||||
self.assertEqual(1, self.driver.create_network_postcommit.call_count)
|
||||
self.assertEqual(1, self.driver.create_subnet_postcommit.call_count)
|
||||
self.assertEqual(1, self.get_locked_port_and_binding.call_count)
|
||||
|
@ -75,6 +75,6 @@ class TestCiscoApicSync(base.BaseTestCase):
|
|||
sync.core_plugin.get_ports.return_value = [{'id': 'port',
|
||||
'network_id': 'net',
|
||||
'device_id': 'dev'}]
|
||||
sync.sync_router()
|
||||
sync._sync_router()
|
||||
self.assertEqual(
|
||||
1, self.driver.add_router_interface_postcommit.call_count)
|
||||
|
|
Loading…
Reference in New Issue