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)])
  
openSUSE Build Service is sponsored by