summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorvenkata anil <anilvenkata@redhat.com>2017-06-05 09:56:18 +0000
committervenkata anil <anilvenkata@redhat.com>2017-06-13 12:51:10 +0000
commit633b452e28b7a95ced1917257ca0e200cbffa4ba (patch)
tree7df3702b36a532c1edea1e75dbaa7cc4db4e1cbc
parenta08aa3bf2f567d4d0a5678d470cc3a3aec382d74 (diff)
Set HA network port to DOWN when l3 agent starts
When l3 agent node is rebooted, if HA network port status is already ACTIVE in DB, agent will get this status from server and then spawn the keepalived (though l2 agent might not have wired the port), resulting in multiple HA masters active at the same time. To fix this, when the L3 agent starts up we can have it explicitly set the port status to DOWN for all of the HA ports on that node. Then we are guaranteed that when they go to ACTIVE it will be because the L2 agent has wired the ports. Closes-bug: #1597461 Change-Id: Ib0c8a71b6ff97e43a414f3db4882914b12170d53 (cherry picked from commit d730b1010277138136512eb6efb12ab893ca6793)
Notes
Notes (review): Code-Review+2: Ihar Hrachyshka <ihrachys@redhat.com> Code-Review+2: Brian Haley <haleyb.dev@gmail.com> Workflow+1: Brian Haley <haleyb.dev@gmail.com> Verified+2: Jenkins Submitted-by: Jenkins Submitted-at: Tue, 13 Jun 2017 20:02:47 +0000 Reviewed-on: https://review.openstack.org/473819 Project: openstack/neutron Branch: refs/heads/stable/ocata
-rw-r--r--neutron/api/rpc/handlers/l3_rpc.py29
-rw-r--r--neutron/tests/unit/db/test_l3_hamode_db.py31
2 files changed, 60 insertions, 0 deletions
diff --git a/neutron/api/rpc/handlers/l3_rpc.py b/neutron/api/rpc/handlers/l3_rpc.py
index c75389f..db4b6d6 100644
--- a/neutron/api/rpc/handlers/l3_rpc.py
+++ b/neutron/api/rpc/handlers/l3_rpc.py
@@ -60,13 +60,42 @@ class L3RpcCallback(object):
60 self._l3plugin = directory.get_plugin(constants.L3) 60 self._l3plugin = directory.get_plugin(constants.L3)
61 return self._l3plugin 61 return self._l3plugin
62 62
63 def _update_ha_network_port_status(self, context, host_id):
64 # set HA network port status to DOWN.
65 device_filter = {
66 'device_owner': [constants.DEVICE_OWNER_ROUTER_HA_INTF],
67 'status': [constants.PORT_STATUS_ACTIVE]}
68 ports = self.plugin.get_ports(context, filters=device_filter)
69 ha_ports = [p['id'] for p in ports
70 if p.get(portbindings.HOST_ID) == host_id]
71 if not ha_ports:
72 return
73 LOG.debug("L3 agent on host %(host)s requested for fullsync, so "
74 "setting HA network ports %(ha_ports)s status to DOWN.",
75 {"host": host_id, "ha_ports": ha_ports})
76 for p in ha_ports:
77 self.plugin.update_port(
78 context, p, {'port': {'status': constants.PORT_STATUS_DOWN}})
79
63 def get_router_ids(self, context, host): 80 def get_router_ids(self, context, host):
64 """Returns IDs of routers scheduled to l3 agent on <host> 81 """Returns IDs of routers scheduled to l3 agent on <host>
65 82
66 This will autoschedule unhosted routers to l3 agent on <host> and then 83 This will autoschedule unhosted routers to l3 agent on <host> and then
67 return all ids of routers scheduled to it. 84 return all ids of routers scheduled to it.
85 This will also update HA network port status to down for all HA routers
86 hosted on <host>. This is needed to avoid l3 agent spawning keepalived
87 when l2 agent not yet wired the port. This can happen after a system
88 reboot that has wiped out flows, etc and the L2 agent hasn't started up
89 yet. The port will still be ACTIVE in the data model and the L3 agent
90 will use that info to mistakenly think that L2 network is ready.
91 By forcing into DOWN, we will require the L2 agent to essentially ack
92 that the port is indeed ACTIVE by reacting to the port update and
93 calling update_device_up.
68 """ 94 """
69 if utils.is_extension_supported( 95 if utils.is_extension_supported(
96 self.plugin, constants.PORT_BINDING_EXT_ALIAS):
97 self._update_ha_network_port_status(context, host)
98 if utils.is_extension_supported(
70 self.l3plugin, constants.L3_AGENT_SCHEDULER_EXT_ALIAS): 99 self.l3plugin, constants.L3_AGENT_SCHEDULER_EXT_ALIAS):
71 if cfg.CONF.router_auto_schedule: 100 if cfg.CONF.router_auto_schedule:
72 self.l3plugin.auto_schedule_routers(context, host, 101 self.l3plugin.auto_schedule_routers(context, host,
diff --git a/neutron/tests/unit/db/test_l3_hamode_db.py b/neutron/tests/unit/db/test_l3_hamode_db.py
index 21b830d..dc3b141 100644
--- a/neutron/tests/unit/db/test_l3_hamode_db.py
+++ b/neutron/tests/unit/db/test_l3_hamode_db.py
@@ -1042,6 +1042,37 @@ class L3HAModeDbTestCase(L3HATestFramework):
1042 for port in self._get_router_port_bindings(router['id']): 1042 for port in self._get_router_port_bindings(router['id']):
1043 self.assertEqual(self.agent2['host'], port[portbindings.HOST_ID]) 1043 self.assertEqual(self.agent2['host'], port[portbindings.HOST_ID])
1044 1044
1045 def test_get_router_ids_updates_ha_network_port_status(self):
1046 router = self._create_router(ha=True)
1047 callback = l3_rpc.L3RpcCallback()
1048 callback._l3plugin = self.plugin
1049 host = self.agent1['host']
1050 ctx = self.admin_ctx
1051 bindings = self.plugin.get_ha_router_port_bindings(
1052 ctx, [router['id']])
1053 binding = [binding for binding in bindings
1054 if binding.l3_agent_id == self.agent1['id']][0]
1055 port = self.core_plugin.get_port(ctx, binding.port_id)
1056
1057 # As network segments are not available, mock bind_port
1058 # to avoid binding failures
1059 def bind_port(context):
1060 binding = context._binding
1061 binding.vif_type = portbindings.VIF_TYPE_OVS
1062 with mock.patch.object(self.core_plugin.mechanism_manager,
1063 'bind_port', side_effect=bind_port):
1064 callback._ensure_host_set_on_port(
1065 ctx, host, port, router_id=router['id'])
1066 # Port status will be DOWN by default as we are not having
1067 # l2 agent in test, so update it to ACTIVE.
1068 self.core_plugin.update_port_status(
1069 ctx, port['id'], constants.PORT_STATUS_ACTIVE, host=host)
1070 port = self.core_plugin.get_port(ctx, port['id'])
1071 self.assertEqual(constants.PORT_STATUS_ACTIVE, port['status'])
1072 callback.get_router_ids(ctx, host)
1073 port = self.core_plugin.get_port(ctx, port['id'])
1074 self.assertEqual(constants.PORT_STATUS_DOWN, port['status'])
1075
1045 def test_ensure_host_set_on_ports_dvr_ha_binds_to_active(self): 1076 def test_ensure_host_set_on_ports_dvr_ha_binds_to_active(self):
1046 agent3 = helpers.register_l3_agent('host_3', 1077 agent3 = helpers.register_l3_agent('host_3',
1047 constants.L3_AGENT_MODE_DVR_SNAT) 1078 constants.L3_AGENT_MODE_DVR_SNAT)