Browse Source

neutron-lbaas haproxy agent prevent vif unplug when failover occurs

When lbaas fails over after an agent is unresponsive, the dead
agent on coming up should not unplug the vif port, if the lbaas
is active on other agent and when failover is configured.

This patch fixes the problem.

Story: #2003672
Change-Id: I76c38b20eb72c1dba0a0a2a140bbe77053aa3ed0
Swaminathan Vasudevan 9 months ago
parent
commit
72399374b2

+ 8
- 6
neutron_lbaas/agent/agent_manager.py View File

@@ -159,7 +159,7 @@ class LbaasAgentManager(periodic_task.PeriodicTasks):
159 159
             ready_instances = set(self.plugin_rpc.get_ready_devices())
160 160
 
161 161
             for deleted_id in known_instances - ready_instances:
162
-                self._destroy_loadbalancer(deleted_id)
162
+                self._destroy_loadbalancer(deleted_id, resync=True)
163 163
 
164 164
             for loadbalancer_id in ready_instances:
165 165
                 self._reload_loadbalancer(loadbalancer_id)
@@ -168,7 +168,7 @@ class LbaasAgentManager(periodic_task.PeriodicTasks):
168 168
             LOG.exception('Unable to retrieve ready devices')
169 169
             self.needs_resync = True
170 170
 
171
-        self.remove_orphans()
171
+        self.remove_orphans(resync=True)
172 172
 
173 173
     def _get_driver(self, loadbalancer_id):
174 174
         if loadbalancer_id not in self.instance_mapping:
@@ -198,10 +198,11 @@ class LbaasAgentManager(periodic_task.PeriodicTasks):
198 198
                           loadbalancer_id)
199 199
             self.needs_resync = True
200 200
 
201
-    def _destroy_loadbalancer(self, lb_id):
201
+    def _destroy_loadbalancer(self, lb_id, resync=False):
202 202
         driver = self._get_driver(lb_id)
203 203
         try:
204
-            driver.undeploy_instance(lb_id, delete_namespace=True)
204
+            driver.undeploy_instance(lb_id, delete_namespace=True,
205
+                                     resync=resync)
205 206
             del self.instance_mapping[lb_id]
206 207
             self.plugin_rpc.loadbalancer_destroyed(lb_id)
207 208
         except Exception:
@@ -209,12 +210,13 @@ class LbaasAgentManager(periodic_task.PeriodicTasks):
209 210
                           lb_id)
210 211
             self.needs_resync = True
211 212
 
212
-    def remove_orphans(self):
213
+    def remove_orphans(self, resync=False):
213 214
         for driver_name in self.device_drivers:
214 215
             lb_ids = [lb_id for lb_id in self.instance_mapping
215 216
                       if self.instance_mapping[lb_id] == driver_name]
216 217
             try:
217
-                self.device_drivers[driver_name].remove_orphans(lb_ids)
218
+                self.device_drivers[driver_name].remove_orphans(lb_ids,
219
+                                                                resync=resync)
218 220
             except NotImplementedError:
219 221
                 pass  # Not all drivers will support this
220 222
 

+ 10
- 4
neutron_lbaas/drivers/haproxy/namespace_driver.py View File

@@ -156,8 +156,13 @@ class HaproxyNSDriver(agent_device_driver.AgentDeviceDriver):
156 156
                                              pids_path=pid_path,
157 157
                                              pid_file=pid_data)
158 158
         pm.disable()
159
-        # unplug the ports
160
-        if loadbalancer_id in self.deployed_loadbalancers:
159
+        # Before unplugging the port check if the LBaas
160
+        # is being active and see if it is a resync
161
+        # or failover is configured
162
+        resync = kwargs.get('resync', False)
163
+        failover_state = cfg.CONF.allow_automatic_lbaas_agent_failover
164
+        if (loadbalancer_id in self.deployed_loadbalancers and
165
+            not (resync and failover_state)):
161 166
             self._unplug(namespace,
162 167
                          self.deployed_loadbalancers[loadbalancer_id].vip_port)
163 168
 
@@ -181,7 +186,7 @@ class HaproxyNSDriver(agent_device_driver.AgentDeviceDriver):
181 186
         if loadbalancer_id in self.deployed_loadbalancers:
182 187
             del self.deployed_loadbalancers[loadbalancer_id]
183 188
 
184
-    def remove_orphans(self, known_loadbalancer_ids):
189
+    def remove_orphans(self, known_loadbalancer_ids, resync=False):
185 190
         if not os.path.exists(self.state_path):
186 191
             return
187 192
 
@@ -189,7 +194,8 @@ class HaproxyNSDriver(agent_device_driver.AgentDeviceDriver):
189 194
                    if lb_id not in known_loadbalancer_ids)
190 195
         for lb_id in orphans:
191 196
             if self.exists(lb_id):
192
-                self.undeploy_instance(lb_id, cleanup_namespace=True)
197
+                self.undeploy_instance(lb_id, cleanup_namespace=True,
198
+                                       resync=resync)
193 199
 
194 200
     def get_stats(self, loadbalancer_id):
195 201
         socket_path = self._get_state_file_path(loadbalancer_id,

+ 10
- 8
neutron_lbaas/tests/unit/agent/test_agent_manager.py View File

@@ -98,8 +98,9 @@ class TestManager(base.BaseTestCase):
98 98
 
99 99
             reload.assert_has_calls([mock.call(i) for i in reloaded],
100 100
                                     any_order=True)
101
-            destroy.assert_has_calls([mock.call(i) for i in destroyed],
102
-                                     any_order=True)
101
+            destroy.assert_has_calls(
102
+                [mock.call(i, resync=True) for i in destroyed],
103
+                any_order=True)
103 104
             self.assertFalse(self.mgr.needs_resync)
104 105
 
105 106
     def test_sync_state_all_known(self):
@@ -180,7 +181,7 @@ class TestManager(base.BaseTestCase):
180 181
         self.mgr._destroy_loadbalancer(lb_id)
181 182
 
182 183
         self.driver_mock.undeploy_instance.assert_called_once_with(
183
-            lb_id, delete_namespace=True)
184
+            lb_id, delete_namespace=True, resync=False)
184 185
         self.assertNotIn(lb_id, self.mgr.instance_mapping)
185 186
         self.rpc_mock.loadbalancer_destroyed.assert_called_once_with(lb_id)
186 187
         self.assertFalse(self.mgr.needs_resync)
@@ -193,7 +194,7 @@ class TestManager(base.BaseTestCase):
193 194
         self.mgr._destroy_loadbalancer(lb_id)
194 195
 
195 196
         self.driver_mock.undeploy_instance.assert_called_once_with(
196
-            lb_id, delete_namespace=True)
197
+            lb_id, delete_namespace=True, resync=False)
197 198
         self.assertIn(lb_id, self.mgr.instance_mapping)
198 199
         self.assertFalse(self.rpc_mock.loadbalancer_destroyed.called)
199 200
         self.assertTrue(self.log.exception.called)
@@ -204,15 +205,16 @@ class TestManager(base.BaseTestCase):
204 205
                           self.mgr._get_driver, 'unknown')
205 206
 
206 207
     def test_remove_orphans(self):
207
-        self.mgr.remove_orphans()
208
-        self.driver_mock.remove_orphans.assert_called_once_with(['1', '2'])
208
+        self.mgr.remove_orphans(resync=False)
209
+        self.driver_mock.remove_orphans.assert_called_once_with(
210
+            ['1', '2'], resync=False)
209 211
 
210 212
     def test_agent_disabled(self):
211 213
         payload = {'admin_state_up': False}
212 214
         self.mgr.agent_updated(mock.Mock(), payload)
213 215
         self.driver_mock.undeploy_instance.assert_has_calls(
214
-            [mock.call('1', delete_namespace=True),
215
-             mock.call('2', delete_namespace=True)],
216
+            [mock.call('1', delete_namespace=True, resync=False),
217
+             mock.call('2', delete_namespace=True, resync=False)],
216 218
             any_order=True
217 219
         )
218 220
 

+ 1
- 1
neutron_lbaas/tests/unit/drivers/haproxy/test_namespace_driver.py View File

@@ -142,7 +142,7 @@ class TestHaproxyNSDriver(base.BaseTestCase):
142 142
         list_dir.assert_called_once_with(self.driver.state_path)
143 143
         self.driver.exists.assert_called_once_with('lb2')
144 144
         self.driver.undeploy_instance.assert_called_once_with(
145
-            'lb2', cleanup_namespace=True)
145
+            'lb2', cleanup_namespace=True, resync=False)
146 146
 
147 147
     def test_get_stats(self):
148 148
         # Shamelessly stolen from v1 namespace driver tests.

Loading…
Cancel
Save