diff --git a/neutron/db/l3_dvr_db.py b/neutron/db/l3_dvr_db.py index 69561719263..9093c42ce66 100644 --- a/neutron/db/l3_dvr_db.py +++ b/neutron/db/l3_dvr_db.py @@ -294,6 +294,9 @@ class L3_NAT_with_dvr_db_mixin(l3_db.L3_NAT_db_mixin, floating_ip['host'] = self.get_vm_port_hostid( context, floating_ip['port_id']) LOG.debug("Floating IP host: %s", floating_ip['host']) + # if no VM there won't be an agent assigned + if not floating_ip['host']: + continue fip_agent = self._get_agent_by_type_and_host( context, l3_const.AGENT_TYPE_L3, floating_ip['host']) diff --git a/neutron/tests/unit/db/test_l3_dvr_db.py b/neutron/tests/unit/db/test_l3_dvr_db.py index be27ce9ca40..44da11c29c4 100644 --- a/neutron/tests/unit/db/test_l3_dvr_db.py +++ b/neutron/tests/unit/db/test_l3_dvr_db.py @@ -231,3 +231,52 @@ class L3DvrTestCase(testlib_api.SqlTestCase): } mock_fip_clear = self._delete_floatingip_test_setup(floatingip) self.assertTrue(mock_fip_clear.called) + + def _floatingip_on_port_test_setup(self, hostid): + router = {'id': 'foo_router_id', 'distributed': True} + floatingip = { + 'id': _uuid(), + 'port_id': _uuid(), + 'router_id': 'foo_router_id' + } + routers = { + 'foo_router_id': router + } + fipagent = { + 'id': _uuid() + } + + # NOTE: mock.patch is not needed here since self.mixin is created fresh + # for each test. It doesn't work with some methods since the mixin is + # tested in isolation (e.g. _get_agent_by_type_and_host). + self.mixin.get_vm_port_hostid = mock.Mock(return_value=hostid) + self.mixin._get_agent_by_type_and_host = mock.Mock( + return_value=fipagent) + self.mixin.get_fip_sync_interfaces = mock.Mock( + return_value='fip_interface') + + self.mixin._process_floating_ips(self.ctx, routers, [floatingip]) + return (router, floatingip) + + def test_floatingip_on_port_no_host(self): + router, fip = self._floatingip_on_port_test_setup(None) + + self.assertTrue(self.mixin.get_vm_port_hostid.called) + self.assertFalse(self.mixin._get_agent_by_type_and_host.called) + self.assertFalse(self.mixin.get_fip_sync_interfaces.called) + + self.assertNotIn(l3_const.FLOATINGIP_KEY, router) + self.assertNotIn(l3_const.FLOATINGIP_AGENT_INTF_KEY, router) + + def test_floatingip_on_port_with_host(self): + router, fip = self._floatingip_on_port_test_setup(_uuid()) + + self.assertTrue(self.mixin.get_vm_port_hostid.called) + self.assertTrue(self.mixin._get_agent_by_type_and_host.called) + self.assertTrue(self.mixin.get_fip_sync_interfaces.called) + + self.assertIn(l3_const.FLOATINGIP_KEY, router) + self.assertIn(l3_const.FLOATINGIP_AGENT_INTF_KEY, router) + self.assertIn(fip, router[l3_const.FLOATINGIP_KEY]) + self.assertIn('fip_interface', + router[l3_const.FLOATINGIP_AGENT_INTF_KEY])