File 0001-dhcp-serializing-port-delete-and-network-rpc-calls.patch of Package openstack-neutron
diff -crB --new-file neutron-9.4.2.dev21-backup/neutron/agent/dhcp/agent.py neutron-9.4.2.dev21/neutron/agent/dhcp/agent.py
*** neutron-9.4.2.dev21-backup/neutron/agent/dhcp/agent.py 2019-08-16 12:59:46.283957521 -0700
--- neutron-9.4.2.dev21/neutron/agent/dhcp/agent.py 2019-08-16 13:01:36.268768984 -0700
***************
*** 388,401 ****
# Use the update handler for the subnet create event.
subnet_create_end = subnet_update_end
@_wait_if_syncing
def subnet_delete_end(self, context, payload):
"""Handle the subnet.delete.end notification event."""
! subnet_id = payload['subnet_id']
! network = self.cache.get_network_by_subnet_id(subnet_id)
! if not network:
return
! with _net_lock(network.id):
network = self.cache.get_network_by_subnet_id(subnet_id)
if not network:
return
--- 388,419 ----
# Use the update handler for the subnet create event.
subnet_create_end = subnet_update_end
+ def _get_network_lock_id(self, payload):
+ """Determine which lock to hold when servicing an RPC event"""
+ # TODO(alegacy): in a future release this function can be removed and
+ # uses of it can be replaced with payload['network_id']. It exists
+ # only to satisfy backwards compatibility between older servers and
+ # newer agents. Once the 'network_id' attribute is guaranteed to be
+ # sent by the server on all *_delete_end events then it can be removed.
+ if 'network_id' in payload:
+ return payload['network_id']
+ elif 'subnet_id' in payload:
+ subnet_id = payload['subnet_id']
+ network = self.cache.get_network_by_subnet_id(subnet_id)
+ return network.id if network else None
+ elif 'port_id' in payload:
+ port_id = payload['port_id']
+ port = self.cache.get_port_by_id(port_id)
+ return port.network_id if port else None
+
@_wait_if_syncing
def subnet_delete_end(self, context, payload):
"""Handle the subnet.delete.end notification event."""
! network_id = self._get_network_lock_id(payload)
! if not network_id:
return
! with _net_lock(network_id):
! subnet_id = payload['subnet_id']
network = self.cache.get_network_by_subnet_id(subnet_id)
if not network:
return
***************
*** 471,482 ****
@_wait_if_syncing
def port_delete_end(self, context, payload):
"""Handle the port.delete.end notification event."""
! port = self.cache.get_port_by_id(payload['port_id'])
! self.cache.deleted_ports.add(payload['port_id'])
! if not port:
return
! with _net_lock(port.network_id):
! port = self.cache.get_port_by_id(payload['port_id'])
if not port:
return
network = self.cache.get_network_by_id(port.network_id)
--- 489,501 ----
@_wait_if_syncing
def port_delete_end(self, context, payload):
"""Handle the port.delete.end notification event."""
! network_id = self._get_network_lock_id(payload)
! if not network_id:
return
! with _net_lock(network_id):
! port_id = payload['port_id']
! port = self.cache.get_port_by_id(port_id)
! self.cache.deleted_ports.add(port_id)
if not port:
return
network = self.cache.get_network_by_id(port.network_id)
diff -crB --new-file neutron-9.4.2.dev21-backup/neutron/api/rpc/agentnotifiers/dhcp_rpc_agent_api.py neutron-9.4.2.dev21/neutron/api/rpc/agentnotifiers/dhcp_rpc_agent_api.py
*** neutron-9.4.2.dev21-backup/neutron/api/rpc/agentnotifiers/dhcp_rpc_agent_api.py 2019-08-16 12:59:46.283957521 -0700
--- neutron-9.4.2.dev21/neutron/api/rpc/agentnotifiers/dhcp_rpc_agent_api.py 2019-08-16 13:00:24.308238062 -0700
***************
*** 296,303 ****
method_name = method_name.replace(".", "_")
if method_name.endswith("_delete_end"):
if 'id' in obj_value:
! self._notify_agents(context, method_name,
! {obj_type + '_id': obj_value['id']},
! network_id)
else:
self._notify_agents(context, method_name, data, network_id)
--- 296,304 ----
method_name = method_name.replace(".", "_")
if method_name.endswith("_delete_end"):
if 'id' in obj_value:
! payload = {obj_type + '_id': obj_value['id']}
! if obj_type != 'network':
! payload['network_id'] = network_id
! self._notify_agents(context, method_name, payload, network_id)
else:
self._notify_agents(context, method_name, data, network_id)
diff -crB --new-file neutron-9.4.2.dev21-backup/neutron/tests/unit/agent/dhcp/test_agent.py neutron-9.4.2.dev21/neutron/tests/unit/agent/dhcp/test_agent.py
*** neutron-9.4.2.dev21-backup/neutron/tests/unit/agent/dhcp/test_agent.py 2019-08-16 12:59:46.287957551 -0700
--- neutron-9.4.2.dev21/neutron/tests/unit/agent/dhcp/test_agent.py 2019-08-16 13:00:24.312238092 -0700
***************
*** 1000,1006 ****
self.call_driver.assert_called_once_with('restart',
new_state)
! def test_subnet_update_end_delete_payload(self):
prev_state = dhcp.NetModel(dict(id=fake_network.id,
tenant_id=fake_network.tenant_id,
admin_state_up=True,
--- 1000,1006 ----
self.call_driver.assert_called_once_with('restart',
new_state)
! def test_subnet_delete_end_no_network_id(self):
prev_state = dhcp.NetModel(dict(id=fake_network.id,
tenant_id=fake_network.tenant_id,
admin_state_up=True,
***************
*** 1021,1026 ****
--- 1021,1047 ----
mock.call.put(fake_network)])
self.call_driver.assert_called_once_with('restart',
fake_network)
+ def test_subnet_update_end_delete_payload(self):
+ prev_state = dhcp.NetModel(dict(id=fake_network.id,
+ tenant_id=fake_network.tenant_id,
+ admin_state_up=True,
+ subnets=[fake_subnet1, fake_subnet3],
+ ports=[fake_port1]))
+
+ payload = dict(subnet_id=fake_subnet1.id, network_id=fake_network.id)
+ self.cache.get_network_by_subnet_id.return_value = prev_state
+ self.cache.get_network_by_id.return_value = prev_state
+ self.plugin.get_network_info.return_value = fake_network
+
+ self.dhcp.subnet_delete_end(None, payload)
+
+ self.cache.assert_has_calls([
+ mock.call.get_network_by_subnet_id(
+ 'bbbbbbbb-bbbb-bbbb-bbbbbbbbbbbb'),
+ mock.call.get_network_by_id(FAKE_NETWORK_UUID),
+ mock.call.put(fake_network)])
+ self.call_driver.assert_called_once_with('restart',
+ fake_network)
def test_port_update_end(self):
self.reload_allocations_p = mock.patch.object(self.dhcp,
***************
*** 1125,1131 ****
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
self.cache.get_port_by_id.return_value = fake_port2
--- 1146,1152 ----
self.call_driver.assert_has_calls(
[mock.call.call_driver('reload_allocations', fake_network)])
! def test_port_delete_end_no_network_id(self):
payload = dict(port_id=fake_port2.id)
self.cache.get_network_by_id.return_value = fake_network
self.cache.get_port_by_id.return_value = fake_port2
***************
*** 1133,1147 ****
self.dhcp.port_delete_end(None, payload)
self.cache.assert_has_calls(
[mock.call.get_port_by_id(fake_port2.id),
- mock.call.deleted_ports.add(fake_port2.id),
mock.call.get_port_by_id(fake_port2.id),
mock.call.get_network_by_id(fake_network.id),
mock.call.remove_port(fake_port2)])
self.call_driver.assert_has_calls(
[mock.call.call_driver('reload_allocations', fake_network)])
def test_port_delete_end_unknown_port(self):
! payload = dict(port_id='unknown')
self.cache.get_port_by_id.return_value = None
self.dhcp.port_delete_end(None, payload)
--- 1154,1182 ----
self.dhcp.port_delete_end(None, payload)
self.cache.assert_has_calls(
[mock.call.get_port_by_id(fake_port2.id),
mock.call.get_port_by_id(fake_port2.id),
+ mock.call.deleted_ports.add(fake_port2.id),
+ mock.call.get_network_by_id(fake_network.id),
+ mock.call.remove_port(fake_port2)])
+ 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, network_id=fake_network.id)
+ self.cache.get_network_by_id.return_value = fake_network
+ self.cache.get_port_by_id.return_value = fake_port2
+
+ self.dhcp.port_delete_end(None, payload)
+ self.cache.assert_has_calls(
+ [mock.call.get_port_by_id(fake_port2.id),
+ mock.call.deleted_ports.add(fake_port2.id),
mock.call.get_network_by_id(fake_network.id),
mock.call.remove_port(fake_port2)])
self.call_driver.assert_has_calls(
[mock.call.call_driver('reload_allocations', fake_network)])
def test_port_delete_end_unknown_port(self):
! payload = dict(port_id='unknown', network_id='unknown')
self.cache.get_port_by_id.return_value = None
self.dhcp.port_delete_end(None, payload)
***************
*** 1156,1162 ****
port['device_id'] = device_id
self.cache.get_network_by_id.return_value = fake_network
self.cache.get_port_by_id.return_value = port
! self.dhcp.port_delete_end(None, {'port_id': port.id})
self.call_driver.assert_has_calls(
[mock.call.call_driver('disable', fake_network)])
--- 1191,1198 ----
port['device_id'] = device_id
self.cache.get_network_by_id.return_value = fake_network
self.cache.get_port_by_id.return_value = port
! self.dhcp.port_delete_end(None, {'port_id': port.id,
! 'network_id': fake_network.id})
self.call_driver.assert_has_calls(
[mock.call.call_driver('disable', fake_network)])