{'network': binding.network_id,
'agent': binding.dhcp_agent_id,
'dead_time': agent_dead_limit})
+ # save binding object to avoid ObjectDeletedError
+ # in case binding is concurrently deleted from the DB
+ saved_binding = {'net': binding.network_id,
+ 'agent': binding.dhcp_agent_id}
try:
self.remove_network_from_dhcp_agent(context,
binding.dhcp_agent_id,
# measures against concurrent operation
LOG.debug("Network %(net)s already removed from DHCP agent "
"%(agent)s",
- {'net': binding.network_id,
- 'agent': binding.dhcp_agent_id})
+ saved_binding)
# still continue and allow concurrent scheduling attempt
except Exception:
LOG.exception(_LE("Unexpected exception occured while "
"removing network %(net)s from agent "
"%(agent)s"),
- {'net': binding.network_id,
- 'agent': binding.dhcp_agent_id})
+ saved_binding)
if cfg.CONF.network_auto_schedule:
self._schedule_network(
- context, binding.network_id, dhcp_notifier)
+ context, saved_binding['net'], dhcp_notifier)
def get_dhcp_agents_hosting_networks(
self, context, network_ids, active=None):
from neutron.db import agents_db
from neutron.db import agentschedulers_db as sched_db
from neutron.db import models_v2
+from neutron.extensions import dhcpagentscheduler
from neutron.scheduler import dhcp_agent_scheduler
from neutron.tests.unit import testlib_api
notifier.network_added_to_agent.assert_called_with(
mock.ANY, self.network_id, agents[1].host)
- def test_reschedule_network_from_down_agent_failed(self):
+ def _test_failed_rescheduling(self, rn_side_effect=None):
agents = self._create_and_set_agents_down(['host-a'], 1)
self._test_schedule_bind_network([agents[0]], self.network_id)
with contextlib.nested(
- mock.patch.object(self, 'remove_network_from_dhcp_agent'),
+ mock.patch.object(
+ self, 'remove_network_from_dhcp_agent',
+ side_effect=rn_side_effect),
mock.patch.object(self, 'schedule_network',
return_value=None),
mock.patch.object(self, 'get_network', create=True,
sch.assert_called_with(mock.ANY, {'id': self.network_id})
self.assertFalse(notifier.network_added_to_agent.called)
+ def test_reschedule_network_from_down_agent_failed(self):
+ self._test_failed_rescheduling()
+
+ def test_reschedule_network_from_down_agent_concurrent_removal(self):
+ self._test_failed_rescheduling(
+ rn_side_effect=dhcpagentscheduler.NetworkNotHostedByDhcpAgent(
+ network_id='foo', agent_id='bar'))
+
def test_filter_bindings(self):
bindings = [
sched_db.NetworkDhcpAgentBinding(network_id='foo1',