Update network object in DHCP agent with router interface changes
In Dnsmasq, the function get_isolated_subnets() returns a list of subnets in a network if the subnet is not connected to a router. The implementation of this function checks all the router interface ports in a cached network object passed from DHCP agent. But the cached network object is not updated when a subnet is attached to or detached from a router. This patch fixes that by adding callback functions in DHCP RPC client to notify DHCP agent when changes happen on router interfaces. Closes-Bug: #1554825 Change-Id: Ifaab163f49e0d1c5cb3eba6efa96214104647e4e
This commit is contained in:
parent
f36fe29556
commit
aa00310eef
|
@ -18,6 +18,9 @@ from oslo_log import log as logging
|
|||
import oslo_messaging
|
||||
|
||||
from neutron._i18n import _LE, _LW
|
||||
from neutron.callbacks import events
|
||||
from neutron.callbacks import registry
|
||||
from neutron.callbacks import resources
|
||||
from neutron.common import constants
|
||||
from neutron.common import rpc as n_rpc
|
||||
from neutron.common import topics
|
||||
|
@ -51,6 +54,11 @@ class DhcpAgentNotifyAPI(object):
|
|||
self._plugin = plugin
|
||||
target = oslo_messaging.Target(topic=topic, version='1.0')
|
||||
self.client = n_rpc.get_client(target)
|
||||
# register callbacks for router interface changes
|
||||
registry.subscribe(self._after_router_interface_created,
|
||||
resources.ROUTER_INTERFACE, events.AFTER_CREATE)
|
||||
registry.subscribe(self._after_router_interface_deleted,
|
||||
resources.ROUTER_INTERFACE, events.AFTER_DELETE)
|
||||
|
||||
@property
|
||||
def plugin(self):
|
||||
|
@ -171,6 +179,18 @@ class DhcpAgentNotifyAPI(object):
|
|||
self._cast_message(context, 'agent_updated',
|
||||
{'admin_state_up': admin_state_up}, host)
|
||||
|
||||
def _after_router_interface_created(self, resource, event, trigger,
|
||||
**kwargs):
|
||||
self._notify_agents(kwargs['context'], 'port_create_end',
|
||||
{'port': kwargs['port']},
|
||||
kwargs['port']['network_id'])
|
||||
|
||||
def _after_router_interface_deleted(self, resource, event, trigger,
|
||||
**kwargs):
|
||||
self._notify_agents(kwargs['context'], 'port_delete_end',
|
||||
{'port_id': kwargs['port']['id']},
|
||||
kwargs['port']['network_id'])
|
||||
|
||||
def notify(self, context, data, method_name):
|
||||
# data is {'key' : 'value'} with only one key
|
||||
if method_name not in self.VALID_METHOD_NAMES:
|
||||
|
|
|
@ -712,11 +712,13 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase,
|
|||
registry.notify(resources.ROUTER_INTERFACE,
|
||||
events.AFTER_CREATE,
|
||||
self,
|
||||
context=context,
|
||||
network_id=gw_network_id,
|
||||
gateway_ips=gw_ips,
|
||||
cidrs=[x['cidr'] for x in subnets],
|
||||
port_id=port['id'],
|
||||
router_id=router_id,
|
||||
port=port,
|
||||
interface_info=interface_info)
|
||||
|
||||
return self._make_router_interface_info(
|
||||
|
@ -833,9 +835,11 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase,
|
|||
registry.notify(resources.ROUTER_INTERFACE,
|
||||
events.AFTER_DELETE,
|
||||
self,
|
||||
context=context,
|
||||
cidrs=[x['cidr'] for x in subnets],
|
||||
network_id=gw_network_id,
|
||||
gateway_ips=gw_ips)
|
||||
gateway_ips=gw_ips,
|
||||
port=port)
|
||||
return self._make_router_interface_info(router_id, port['tenant_id'],
|
||||
port['id'], port['network_id'],
|
||||
subnets[0]['id'],
|
||||
|
|
|
@ -309,11 +309,13 @@ class L3_NAT_with_dvr_db_mixin(l3_db.L3_NAT_db_mixin,
|
|||
registry.notify(resources.ROUTER_INTERFACE,
|
||||
events.AFTER_CREATE,
|
||||
self,
|
||||
context=context,
|
||||
network_id=gw_network_id,
|
||||
gateway_ips=gw_ips,
|
||||
cidrs=[x['cidr'] for x in subnets],
|
||||
port_id=port['id'],
|
||||
router_id=router_id,
|
||||
port=port,
|
||||
interface_info=interface_info)
|
||||
return router_interface_info
|
||||
|
||||
|
|
|
@ -138,20 +138,25 @@ class TestDhcpAgentNotifyAPI(base.BaseTestCase):
|
|||
mock.ANY, 'foo_network_id')
|
||||
self.assertEqual(1, self.mock_fanout.call_count)
|
||||
|
||||
def _test__notify_agents(self, method,
|
||||
expected_scheduling=0, expected_casts=0):
|
||||
def _test__notify_agents_with_function(
|
||||
self, function, expected_scheduling=0, expected_casts=0):
|
||||
with mock.patch.object(self.notifier, '_schedule_network') as f:
|
||||
with mock.patch.object(self.notifier, '_get_enabled_agents') as g:
|
||||
agent = agents_db.Agent()
|
||||
agent.admin_state_up = True
|
||||
agent.heartbeat_timestamp = timeutils.utcnow()
|
||||
g.return_value = [agent]
|
||||
dummy_payload = {'port': {}}
|
||||
self.notifier._notify_agents(mock.Mock(), method,
|
||||
dummy_payload, 'foo_network_id')
|
||||
function()
|
||||
self.assertEqual(expected_scheduling, f.call_count)
|
||||
self.assertEqual(expected_casts, self.mock_cast.call_count)
|
||||
|
||||
def _test__notify_agents(self, method,
|
||||
expected_scheduling=0, expected_casts=0):
|
||||
self._test__notify_agents_with_function(
|
||||
lambda: self.notifier._notify_agents(
|
||||
mock.Mock(), method, {'port': {}}, 'foo_network_id'),
|
||||
expected_scheduling, expected_casts)
|
||||
|
||||
def test__notify_agents_cast_required_with_scheduling(self):
|
||||
self._test__notify_agents('port_create_end',
|
||||
expected_scheduling=1, expected_casts=1)
|
||||
|
@ -168,6 +173,20 @@ class TestDhcpAgentNotifyAPI(base.BaseTestCase):
|
|||
self._test__notify_agents('network_create_end',
|
||||
expected_scheduling=0, expected_casts=0)
|
||||
|
||||
def test__notify_agents_with_router_interface_add(self):
|
||||
self._test__notify_agents_with_function(
|
||||
lambda: self.notifier._after_router_interface_created(
|
||||
mock.ANY, mock.ANY, mock.ANY, context=mock.Mock(),
|
||||
port={'id': 'foo_port_id', 'network_id': 'foo_network_id'}),
|
||||
expected_scheduling=1, expected_casts=1)
|
||||
|
||||
def test__notify_agents_with_router_interface_delete(self):
|
||||
self._test__notify_agents_with_function(
|
||||
lambda: self.notifier._after_router_interface_deleted(
|
||||
mock.ANY, mock.ANY, mock.ANY, context=mock.Mock(),
|
||||
port={'id': 'foo_port_id', 'network_id': 'foo_network_id'}),
|
||||
expected_scheduling=0, expected_casts=1)
|
||||
|
||||
def test__fanout_message(self):
|
||||
self.notifier._fanout_message(mock.ANY, mock.ANY, mock.ANY)
|
||||
self.assertEqual(1, self.mock_fanout.call_count)
|
||||
|
|
Loading…
Reference in New Issue