diff --git a/neutron/agent/dhcp/agent.py b/neutron/agent/dhcp/agent.py index 613d7fcbc76..214bfdff14d 100644 --- a/neutron/agent/dhcp/agent.py +++ b/neutron/agent/dhcp/agent.py @@ -316,8 +316,21 @@ class DhcpAgent(manager.Manager): updated_port = dhcp.DictModel(payload['port']) network = self.cache.get_network_by_id(updated_port.network_id) if network: + driver_action = 'reload_allocations' + if self._is_port_on_this_agent(updated_port): + orig = self.cache.get_port_by_id(updated_port['id']) + # assume IP change if not in cache + old_ips = {i['ip_address'] for i in orig['fixed_ips'] or []} + new_ips = {i['ip_address'] for i in updated_port['fixed_ips']} + if old_ips != new_ips: + driver_action = 'restart' self.cache.put_port(updated_port) - self.call_driver('reload_allocations', network) + self.call_driver(driver_action, network) + + def _is_port_on_this_agent(self, port): + thishost = utils.get_dhcp_agent_device_id( + port['network_id'], self.conf.host) + return port['device_id'] == thishost # Use the update handler for the port create event. port_create_end = port_update_end diff --git a/neutron/tests/unit/test_dhcp_agent.py b/neutron/tests/unit/test_dhcp_agent.py index d6669adf57a..b574f931224 100644 --- a/neutron/tests/unit/test_dhcp_agent.py +++ b/neutron/tests/unit/test_dhcp_agent.py @@ -33,6 +33,7 @@ from neutron.agent.linux import interface from neutron.common import config as common_config from neutron.common import constants as const from neutron.common import exceptions +from neutron.common import utils from neutron import context from neutron.tests import base @@ -102,6 +103,7 @@ fake_port1 = dhcp.DictModel(dict(id='12345678-1234-aaaa-1234567890ab', fixed_ips=[fake_fixed_ip1])) fake_port2 = dhcp.DictModel(dict(id='12345678-1234-aaaa-123456789000', + device_id='dhcp-12345678-1234-aaaa-123456789000', device_owner='', mac_address='aa:bb:cc:dd:ee:99', network_id='12345678-1234-5678-1234567890ab', @@ -529,6 +531,7 @@ class TestDhcpAgentEventHandler(base.BaseTestCase): cfg.CONF.set_override('interface_driver', 'neutron.agent.linux.interface.NullDriver') cfg.CONF.register_opts(dhcp_config.DHCP_AGENT_OPTS) + cfg.CONF.register_opts(dhcp_config.DHCP_OPTS) self.plugin_p = mock.patch(DHCP_PLUGIN) plugin_cls = self.plugin_p.start() @@ -914,6 +917,26 @@ class TestDhcpAgentEventHandler(base.BaseTestCase): self.call_driver.assert_has_calls( [mock.call.call_driver('reload_allocations', fake_network)]) + def test_port_update_change_ip_on_dhcp_agents_port(self): + self.cache.get_network_by_id.return_value = fake_network + self.cache.get_port_by_id.return_value = fake_port1 + payload = dict(port=copy.deepcopy(fake_port1)) + device_id = utils.get_dhcp_agent_device_id( + payload['port']['network_id'], self.dhcp.conf.host) + payload['port']['fixed_ips'][0]['ip_address'] = '172.9.9.99' + payload['port']['device_id'] = device_id + self.dhcp.port_update_end(None, payload) + self.call_driver.assert_has_calls( + [mock.call.call_driver('restart', fake_network)]) + + def test_port_update_on_dhcp_agents_port_no_ip_change(self): + payload = dict(port=fake_port1) + self.cache.get_network_by_id.return_value = fake_network + self.cache.get_port_by_id.return_value = fake_port1 + self.dhcp.port_update_end(None, payload) + self.call_driver.assert_has_calls( + [mock.call.call_driver('reload_allocations', fake_network)]) + def test_port_delete_end(self): payload = dict(port_id=fake_port2.id) self.cache.get_network_by_id.return_value = fake_network