Merge "Fix dvr ha router gateway goes wrong host"
This commit is contained in:
commit
a35bbeea52
|
@ -606,29 +606,31 @@ class _DVRAgentInterfaceMixin(object):
|
||||||
LOG.debug("Return the SNAT ports: %s", interfaces)
|
LOG.debug("Return the SNAT ports: %s", interfaces)
|
||||||
return interfaces
|
return interfaces
|
||||||
|
|
||||||
|
def _get_gateway_port_host(self, context, router, gw_ports):
|
||||||
|
binding_objs = rb_obj.RouterL3AgentBinding.get_objects(
|
||||||
|
context, router_id=[router['id']])
|
||||||
|
if not binding_objs:
|
||||||
|
return
|
||||||
|
|
||||||
|
gw_port_id = router['gw_port_id']
|
||||||
|
# Collect gw ports only if available
|
||||||
|
if gw_port_id and gw_ports.get(gw_port_id):
|
||||||
|
l3_agent = ag_obj.Agent.get_object(context,
|
||||||
|
id=binding_objs[0].l3_agent_id)
|
||||||
|
return l3_agent.host
|
||||||
|
|
||||||
def _build_routers_list(self, context, routers, gw_ports):
|
def _build_routers_list(self, context, routers, gw_ports):
|
||||||
# Perform a single query up front for all routers
|
# Perform a single query up front for all routers
|
||||||
routers = super(_DVRAgentInterfaceMixin, self)._build_routers_list(
|
routers = super(_DVRAgentInterfaceMixin, self)._build_routers_list(
|
||||||
context, routers, gw_ports)
|
context, routers, gw_ports)
|
||||||
if not routers:
|
if not routers:
|
||||||
return []
|
return []
|
||||||
router_ids = [r['id'] for r in routers]
|
for router in routers:
|
||||||
binding_objs = rb_obj.RouterL3AgentBinding.get_objects(
|
gw_port_host = self._get_gateway_port_host(
|
||||||
context, router_id=router_ids)
|
context, router, gw_ports)
|
||||||
bindings = dict((b.router_id, b) for b in binding_objs)
|
LOG.debug("Set router %s gateway port host: %s",
|
||||||
for rtr in routers:
|
router['id'], gw_port_host)
|
||||||
gw_port_id = rtr['gw_port_id']
|
router['gw_port_host'] = gw_port_host
|
||||||
# Collect gw ports only if available
|
|
||||||
if gw_port_id and gw_ports.get(gw_port_id):
|
|
||||||
binding = bindings.get(rtr['id'])
|
|
||||||
if not binding:
|
|
||||||
rtr['gw_port_host'] = None
|
|
||||||
LOG.debug('No snat is bound to router %s', rtr['id'])
|
|
||||||
continue
|
|
||||||
|
|
||||||
l3_agent = ag_obj.Agent.get_object(context,
|
|
||||||
id=binding.l3_agent_id)
|
|
||||||
rtr['gw_port_host'] = l3_agent.host
|
|
||||||
|
|
||||||
return routers
|
return routers
|
||||||
|
|
||||||
|
|
|
@ -716,6 +716,41 @@ class L3_HA_NAT_db_mixin(l3_dvr_db.L3_NAT_with_dvr_db_mixin,
|
||||||
# Take concurrently deleted interfaces in to account
|
# Take concurrently deleted interfaces in to account
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def _get_gateway_port_host(self, context, router, gw_ports):
|
||||||
|
if not router.get('ha'):
|
||||||
|
return super(L3_HA_NAT_db_mixin, self)._get_gateway_port_host(
|
||||||
|
context, router, gw_ports)
|
||||||
|
|
||||||
|
gw_port_id = router['gw_port_id']
|
||||||
|
gateway_port = gw_ports.get(gw_port_id)
|
||||||
|
if not gw_port_id or not gateway_port:
|
||||||
|
return
|
||||||
|
gateway_port_status = gateway_port['status']
|
||||||
|
gateway_port_binding_host = gateway_port[portbindings.HOST_ID]
|
||||||
|
|
||||||
|
admin_ctx = context.elevated()
|
||||||
|
router_id = router['id']
|
||||||
|
ha_bindings = self.get_l3_bindings_hosting_router_with_ha_states(
|
||||||
|
admin_ctx, router_id)
|
||||||
|
LOG.debug("HA router %(router_id)s gateway port %(gw_port_id)s "
|
||||||
|
"binding host: %(host)s, status: %(status)s",
|
||||||
|
{"router_id": router_id,
|
||||||
|
"gw_port_id": gateway_port['id'],
|
||||||
|
"host": gateway_port_binding_host,
|
||||||
|
"status": gateway_port_status})
|
||||||
|
for ha_binding_agent, ha_binding_state in ha_bindings:
|
||||||
|
if ha_binding_state != n_const.HA_ROUTER_STATE_ACTIVE:
|
||||||
|
continue
|
||||||
|
# For create router gateway, the gateway port may not be ACTIVE
|
||||||
|
# yet, so we return 'master' host directly.
|
||||||
|
if gateway_port_status != constants.PORT_STATUS_ACTIVE:
|
||||||
|
return ha_binding_agent.host
|
||||||
|
# Do not let the original 'master' (current is backup) host,
|
||||||
|
# override the gateway port binding host.
|
||||||
|
if (gateway_port_status == constants.PORT_STATUS_ACTIVE and
|
||||||
|
ha_binding_agent.host == gateway_port_binding_host):
|
||||||
|
return ha_binding_agent.host
|
||||||
|
|
||||||
|
|
||||||
def is_ha_router(router):
|
def is_ha_router(router):
|
||||||
"""Return True if router to be handled is ha."""
|
"""Return True if router to be handled is ha."""
|
||||||
|
|
|
@ -33,6 +33,7 @@ from neutron.db import l3_dvrscheduler_db
|
||||||
from neutron.db.models import l3 as l3_models
|
from neutron.db.models import l3 as l3_models
|
||||||
from neutron.db import models_v2
|
from neutron.db import models_v2
|
||||||
from neutron.objects import agent as agent_obj
|
from neutron.objects import agent as agent_obj
|
||||||
|
from neutron.objects import l3agent as rb_obj
|
||||||
from neutron.objects import router as router_obj
|
from neutron.objects import router as router_obj
|
||||||
from neutron.tests.unit.db import test_db_base_plugin_v2
|
from neutron.tests.unit.db import test_db_base_plugin_v2
|
||||||
|
|
||||||
|
@ -1007,3 +1008,36 @@ class L3DvrTestCase(test_db_base_plugin_v2.NeutronDbPluginV2TestCase):
|
||||||
self.assertEqual(port_dict['device_id'], port_info['device_id'])
|
self.assertEqual(port_dict['device_id'], port_info['device_id'])
|
||||||
self.assertEqual(port_dict['device_owner'],
|
self.assertEqual(port_dict['device_owner'],
|
||||||
port_info['device_owner'])
|
port_info['device_owner'])
|
||||||
|
|
||||||
|
def test__get_sync_routers_check_gw_port_host(self):
|
||||||
|
router_dict = {'name': 'test_router', 'admin_state_up': True,
|
||||||
|
'distributed': True}
|
||||||
|
router = self._create_router(router_dict)
|
||||||
|
with self.network() as public,\
|
||||||
|
self.subnet() as subnet:
|
||||||
|
ext_net_1_id = public['network']['id']
|
||||||
|
self.core_plugin.update_network(
|
||||||
|
self.ctx, ext_net_1_id,
|
||||||
|
{'network': {'router:external': True}})
|
||||||
|
self.mixin.update_router(
|
||||||
|
self.ctx, router['id'],
|
||||||
|
{'router': {'external_gateway_info':
|
||||||
|
{'network_id': ext_net_1_id}}})
|
||||||
|
self.mixin.add_router_interface(self.ctx, router['id'],
|
||||||
|
{'subnet_id': subnet['subnet']['id']})
|
||||||
|
routers = self.mixin._get_sync_routers(self.ctx,
|
||||||
|
router_ids=[router['id']])
|
||||||
|
self.assertIsNone(routers[0]['gw_port_host'])
|
||||||
|
|
||||||
|
agent = mock.Mock()
|
||||||
|
agent.host = "fake-host"
|
||||||
|
bind = mock.Mock()
|
||||||
|
bind.l3_agent_id = "fake-id"
|
||||||
|
with mock.patch.object(
|
||||||
|
rb_obj.RouterL3AgentBinding, 'get_objects',
|
||||||
|
return_value=[bind]), mock.patch.object(
|
||||||
|
agent_obj.Agent, 'get_object',
|
||||||
|
return_value=agent):
|
||||||
|
routers = self.mixin._get_sync_routers(
|
||||||
|
self.ctx, router_ids=[router['id']])
|
||||||
|
self.assertEqual("fake-host", routers[0]['gw_port_host'])
|
||||||
|
|
|
@ -1324,6 +1324,42 @@ class L3HAModeDbTestCase(L3HATestFramework):
|
||||||
self.assertEqual(constants.DEVICE_OWNER_ROUTER_INTF,
|
self.assertEqual(constants.DEVICE_OWNER_ROUTER_INTF,
|
||||||
routerport.port.device_owner)
|
routerport.port.device_owner)
|
||||||
|
|
||||||
|
def test__get_sync_routers_with_state_change_and_check_gw_port_host(self):
|
||||||
|
ext_net = self._create_network(self.core_plugin, self.admin_ctx,
|
||||||
|
external=True)
|
||||||
|
network_id = self._create_network(self.core_plugin, self.admin_ctx)
|
||||||
|
subnet = self._create_subnet(self.core_plugin, self.admin_ctx,
|
||||||
|
network_id)
|
||||||
|
interface_info = {'subnet_id': subnet['id']}
|
||||||
|
|
||||||
|
router = self._create_router()
|
||||||
|
self.plugin._update_router_gw_info(self.admin_ctx, router['id'],
|
||||||
|
{'network_id': ext_net})
|
||||||
|
self.plugin.add_router_interface(self.admin_ctx,
|
||||||
|
router['id'],
|
||||||
|
interface_info)
|
||||||
|
|
||||||
|
self.plugin.update_routers_states(
|
||||||
|
self.admin_ctx, {router['id']: n_const.HA_ROUTER_STATE_ACTIVE},
|
||||||
|
self.agent1['host'])
|
||||||
|
self.plugin.update_routers_states(
|
||||||
|
self.admin_ctx, {router['id']: n_const.HA_ROUTER_STATE_STANDBY},
|
||||||
|
self.agent2['host'])
|
||||||
|
|
||||||
|
routers = self.plugin._get_sync_routers(self.admin_ctx,
|
||||||
|
router_ids=[router['id']])
|
||||||
|
self.assertEqual(self.agent1['host'], routers[0]['gw_port_host'])
|
||||||
|
|
||||||
|
self.plugin.update_routers_states(
|
||||||
|
self.admin_ctx, {router['id']: n_const.HA_ROUTER_STATE_STANDBY},
|
||||||
|
self.agent1['host'])
|
||||||
|
self.plugin.update_routers_states(
|
||||||
|
self.admin_ctx, {router['id']: n_const.HA_ROUTER_STATE_ACTIVE},
|
||||||
|
self.agent2['host'])
|
||||||
|
routers = self.plugin._get_sync_routers(self.admin_ctx,
|
||||||
|
router_ids=[router['id']])
|
||||||
|
self.assertEqual(self.agent2['host'], routers[0]['gw_port_host'])
|
||||||
|
|
||||||
|
|
||||||
class L3HAUserTestCase(L3HATestFramework):
|
class L3HAUserTestCase(L3HATestFramework):
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue