Don't immediately restart in DHCP agent on port change

Now that the agent will receive port update events for
all port changes[1], we need to avoid immediately restarting
when the subnets on the agent's port changes. Otherwise
the restart may request ports on a subnet which is in the
process of being deleted. While the server is equipped to
handle this, it makes subnet deletion much more contentious
than it needs to be.

This alters the logic to schedule a resync for later if the
agent's port has had its subnets changed rather than restarting
right away. Then by the time the agent eventually syncs the
server should have finished deleting the subnet. Even if it hasn't,
it spaces out the request from the agent for the network far enough
that the operation will be much less frequent to avoid racing
with the server.

1. I607635601caff0322fd0c80c9023f5c4f663ca25

Partial-Bug: #1622616
Change-Id: I98761a7e3f4bce8d5485c885f03c6bfdde246802
This commit is contained in:
Kevin Benton 2016-09-18 22:50:16 -07:00
parent 70907b3e55
commit 673abd56c9
2 changed files with 27 additions and 3 deletions

View File

@ -387,7 +387,20 @@ class DhcpAgent(manager.Manager):
orig = orig or {'fixed_ips': []}
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:
old_subs = {i['subnet_id'] for i in orig['fixed_ips'] or []}
new_subs = {i['subnet_id'] for i in updated_port['fixed_ips']}
if new_subs != old_subs:
# subnets being serviced by port have changed, this could
# indicate a subnet_delete is in progress. schedule a
# resync rather than an immediate restart so we don't
# attempt to re-allocate IPs at the same time the server
# is deleting them.
self.schedule_resync("Agent port was modified",
updated_port.network_id)
return
elif old_ips != new_ips:
LOG.debug("Agent IPs on network %s changed from %s to %s",
network.id, old_ips, new_ips)
driver_action = 'restart'
self.cache.put_port(updated_port)
self.call_driver(driver_action, network)

View File

@ -1040,6 +1040,17 @@ class TestDhcpAgentEventHandler(base.BaseTestCase):
self.call_driver.assert_has_calls(
[mock.call.call_driver('reload_allocations', fake_network)])
def test_port_update_change_subnet_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]['subnet_id'] = '77777-7777'
payload['port']['device_id'] = device_id
self.dhcp.port_update_end(None, payload)
self.assertFalse(self.call_driver.called)
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
@ -1061,8 +1072,8 @@ class TestDhcpAgentEventHandler(base.BaseTestCase):
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)])
self.schedule_resync.assert_called_once_with(mock.ANY,
fake_port1.network_id)
def test_port_update_on_dhcp_agents_port_no_ip_change(self):
self.cache.get_network_by_id.return_value = fake_network