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:26 +0000
commit90c24e9d263eaef66369210f06c158b1425996aa (patch)
treed15b81ff23c743cdee6540620c13e93b82e6f8c9
parent96fbfe743af4c975a3dbddeafdeb454af6e85ba9 (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: Wed, 14 Jun 2017 16:59:20 +0000 Reviewed-on: https://review.openstack.org/473820 Project: openstack/neutron Branch: refs/heads/stable/newton
-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 19833e3..da99dc4 100644
--- a/neutron/api/rpc/handlers/l3_rpc.py
+++ b/neutron/api/rpc/handlers/l3_rpc.py
@@ -62,13 +62,42 @@ class L3RpcCallback(object):
62 plugin_constants.L3_ROUTER_NAT] 62 plugin_constants.L3_ROUTER_NAT]
63 return self._l3plugin 63 return self._l3plugin
64 64
65 def _update_ha_network_port_status(self, context, host_id):
66 # set HA network port status to DOWN.
67 device_filter = {
68 'device_owner': [constants.DEVICE_OWNER_ROUTER_HA_INTF],
69 'status': [constants.PORT_STATUS_ACTIVE]}
70 ports = self.plugin.get_ports(context, filters=device_filter)
71 ha_ports = [p['id'] for p in ports
72 if p.get(portbindings.HOST_ID) == host_id]
73 if not ha_ports:
74 return
75 LOG.debug("L3 agent on host %(host)s requested for fullsync, so "
76 "setting HA network ports %(ha_ports)s status to DOWN.",
77 {"host": host_id, "ha_ports": ha_ports})
78 for p in ha_ports:
79 self.plugin.update_port(
80 context, p, {'port': {'status': constants.PORT_STATUS_DOWN}})
81
65 def get_router_ids(self, context, host): 82 def get_router_ids(self, context, host):
66 """Returns IDs of routers scheduled to l3 agent on <host> 83 """Returns IDs of routers scheduled to l3 agent on <host>
67 84
68 This will autoschedule unhosted routers to l3 agent on <host> and then 85 This will autoschedule unhosted routers to l3 agent on <host> and then
69 return all ids of routers scheduled to it. 86 return all ids of routers scheduled to it.
87 This will also update HA network port status to down for all HA routers
88 hosted on <host>. This is needed to avoid l3 agent spawning keepalived
89 when l2 agent not yet wired the port. This can happen after a system
90 reboot that has wiped out flows, etc and the L2 agent hasn't started up
91 yet. The port will still be ACTIVE in the data model and the L3 agent
92 will use that info to mistakenly think that L2 network is ready.
93 By forcing into DOWN, we will require the L2 agent to essentially ack
94 that the port is indeed ACTIVE by reacting to the port update and
95 calling update_device_up.
70 """ 96 """
71 if utils.is_extension_supported( 97 if utils.is_extension_supported(
98 self.plugin, constants.PORT_BINDING_EXT_ALIAS):
99 self._update_ha_network_port_status(context, host)
100 if utils.is_extension_supported(
72 self.l3plugin, constants.L3_AGENT_SCHEDULER_EXT_ALIAS): 101 self.l3plugin, constants.L3_AGENT_SCHEDULER_EXT_ALIAS):
73 if cfg.CONF.router_auto_schedule: 102 if cfg.CONF.router_auto_schedule:
74 self.l3plugin.auto_schedule_routers(context, host, 103 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 b0dc8a4..4a9a5c1 100644
--- a/neutron/tests/unit/db/test_l3_hamode_db.py
+++ b/neutron/tests/unit/db/test_l3_hamode_db.py
@@ -1098,6 +1098,37 @@ class L3HAModeDbTestCase(L3HATestFramework):
1098 for port in self._get_router_port_bindings(router['id']): 1098 for port in self._get_router_port_bindings(router['id']):
1099 self.assertEqual(self.agent2['host'], port[portbindings.HOST_ID]) 1099 self.assertEqual(self.agent2['host'], port[portbindings.HOST_ID])
1100 1100
1101 def test_get_router_ids_updates_ha_network_port_status(self):
1102 router = self._create_router(ha=True)
1103 callback = l3_rpc.L3RpcCallback()
1104 callback._l3plugin = self.plugin
1105 host = self.agent1['host']
1106 ctx = self.admin_ctx
1107 bindings = self.plugin.get_ha_router_port_bindings(
1108 ctx, [router['id']])
1109 binding = [binding for binding in bindings
1110 if binding.l3_agent_id == self.agent1['id']][0]
1111 port = self.core_plugin.get_port(ctx, binding.port_id)
1112
1113 # As network segments are not available, mock bind_port
1114 # to avoid binding failures
1115 def bind_port(context):
1116 binding = context._binding
1117 binding.vif_type = portbindings.VIF_TYPE_OVS
1118 with mock.patch.object(self.core_plugin.mechanism_manager,
1119 'bind_port', side_effect=bind_port):
1120 callback._ensure_host_set_on_port(
1121 ctx, host, port, router_id=router['id'])
1122 # Port status will be DOWN by default as we are not having
1123 # l2 agent in test, so update it to ACTIVE.
1124 self.core_plugin.update_port_status(
1125 ctx, port['id'], constants.PORT_STATUS_ACTIVE, host=host)
1126 port = self.core_plugin.get_port(ctx, port['id'])
1127 self.assertEqual(constants.PORT_STATUS_ACTIVE, port['status'])
1128 callback.get_router_ids(ctx, host)
1129 port = self.core_plugin.get_port(ctx, port['id'])
1130 self.assertEqual(constants.PORT_STATUS_DOWN, port['status'])
1131
1101 def test_ensure_host_set_on_ports_dvr_ha_binds_to_active(self): 1132 def test_ensure_host_set_on_ports_dvr_ha_binds_to_active(self):
1102 agent3 = helpers.register_l3_agent('host_3', 1133 agent3 = helpers.register_l3_agent('host_3',
1103 constants.L3_AGENT_MODE_DVR_SNAT) 1134 constants.L3_AGENT_MODE_DVR_SNAT)