]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
LBaaS: remove orphan haproxy instances on agent start
authorOleg Bondarev <obondarev@mirantis.com>
Tue, 18 Mar 2014 08:22:05 +0000 (12:22 +0400)
committerOleg Bondarev <obondarev@mirantis.com>
Fri, 25 Apr 2014 08:06:33 +0000 (12:06 +0400)
This change adds remove_orphans() handling to the haproxy
namespace driver. remove_orphans() is already called by
lbaas agent on start for all drivers

Closes-Bug: #1262885
Change-Id: I5deae8e56c2cd2deb1667e9646633fd59a94b34e

neutron/services/loadbalancer/drivers/haproxy/namespace_driver.py
neutron/tests/unit/services/loadbalancer/drivers/haproxy/test_namespace_driver.py

index 7307bca1e1dc78e4f074d70f735f3cae473ec05e..6bbe4f6b873e65a55ba745df54ad68b499be8a10 100644 (file)
@@ -113,7 +113,7 @@ class HaproxyNSDriver(agent_device_driver.AgentDeviceDriver):
         self.pool_to_port_id[pool_id] = logical_config['vip']['port']['id']
 
     @n_utils.synchronized('haproxy-driver')
-    def undeploy_instance(self, pool_id):
+    def undeploy_instance(self, pool_id, cleanup_namespace=False):
         namespace = get_ns_name(pool_id)
         ns = ip_lib.IPWrapper(self.root_helper, namespace)
         pid_path = self._get_state_file_path(pool_id, 'pid')
@@ -125,6 +125,12 @@ class HaproxyNSDriver(agent_device_driver.AgentDeviceDriver):
         if pool_id in self.pool_to_port_id:
             self._unplug(namespace, self.pool_to_port_id[pool_id])
 
+        # delete all devices from namespace;
+        # used when deleting orphans and port_id is not known for pool_id
+        if cleanup_namespace:
+            for device in ns.get_devices(exclude_loopback=True):
+                self.vif_driver.unplug(device.name, namespace=namespace)
+
         # remove the configuration directory
         conf_dir = os.path.dirname(self._get_state_file_path(pool_id, ''))
         if os.path.isdir(conf_dir):
@@ -326,6 +332,16 @@ class HaproxyNSDriver(agent_device_driver.AgentDeviceDriver):
     def delete_pool_health_monitor(self, health_monitor, pool_id):
         self._refresh_device(pool_id)
 
+    def remove_orphans(self, known_pool_ids):
+        if not os.path.exists(self.state_path):
+            return
+
+        orphans = (pool_id for pool_id in os.listdir(self.state_path)
+                   if pool_id not in known_pool_ids)
+        for pool_id in orphans:
+            if self.exists(pool_id):
+                self.undeploy_instance(pool_id, cleanup_namespace=True)
+
 
 # NOTE (markmcclain) For compliance with interface.py which expects objects
 class Wrap(object):
index 504c592e997023ff8c6dc60483635d3579ce7ba2..6d96bd550b6ce33cfe1264cba3af06372445b283 100644 (file)
@@ -123,6 +123,41 @@ class TestHaproxyNSDriver(base.BaseTestCase):
                 mock.call().garbage_collect_namespace()
             ])
 
+    def test_undeploy_instance_with_ns_cleanup(self):
+        with contextlib.nested(
+            mock.patch.object(self.driver, '_get_state_file_path'),
+            mock.patch.object(self.driver, 'vif_driver'),
+            mock.patch.object(namespace_driver, 'kill_pids_in_file'),
+            mock.patch('neutron.agent.linux.ip_lib.IPWrapper'),
+            mock.patch('os.path.isdir'),
+            mock.patch('shutil.rmtree')
+        ) as (gsp, vif, kill, ip_wrap, isdir, rmtree):
+            device = mock.Mock()
+            device_name = 'port_device'
+            device.name = device_name
+            ip_wrap.return_value.get_devices.return_value = [device]
+
+            self.driver.undeploy_instance('pool_id', cleanup_namespace=True)
+            vif.unplug.assert_called_once_with(device_name,
+                                               namespace='qlbaas-pool_id')
+
+    def test_remove_orphans(self):
+        with contextlib.nested(
+            mock.patch.object(self.driver, 'exists'),
+            mock.patch.object(self.driver, 'undeploy_instance'),
+            mock.patch('os.listdir'),
+            mock.patch('os.path.exists')
+        ) as (exists, undeploy, listdir, path_exists):
+            known = ['known1', 'known2']
+            unknown = ['unknown1', 'unknown2']
+            listdir.return_value = known + unknown
+            exists.side_effect = lambda x: x == 'unknown2'
+
+            self.driver.remove_orphans(known)
+
+            undeploy.assert_called_once_with('unknown2',
+                                             cleanup_namespace=True)
+
     def test_exists(self):
         with contextlib.nested(
             mock.patch.object(self.driver, '_get_state_file_path'),