From d218a8abb2ebf22dae8a9297e054b83a84f5f673 Mon Sep 17 00:00:00 2001 From: Slawek Kaplonski Date: Fri, 1 Feb 2019 11:04:56 +0100 Subject: [PATCH] Ensure dnsmasq is down before enabling it in restart method Dnsmasq driver used by dhcp agent has restart() method which is calling disable() and then enable() dnsmasq process again. What can be observed in functional tests from time to time it may happen that start dnsmasq process will be called before old process is really down. That leads to error that IP address to which dnsmasq wants to bind is already in use and it fails to start. This patch adds possibility to call disable() method with block flag set to True. In such case driver will ensure in disable() method that process is really not active. This blocking disable() is used in restart() method now. Change-Id: I419a451633badbc3d32edcee1945fca3e3d9f6be Closes-Bug: #1811126 (cherry picked from commit d471a85931d6f6495efdb8ff43bf903e3e1d639d) --- neutron/agent/linux/dhcp.py | 11 +++++++---- neutron/tests/unit/agent/linux/test_dhcp.py | 6 +++--- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/neutron/agent/linux/dhcp.py b/neutron/agent/linux/dhcp.py index 88e99d89645..f79e317ed4e 100644 --- a/neutron/agent/linux/dhcp.py +++ b/neutron/agent/linux/dhcp.py @@ -138,12 +138,12 @@ class DhcpBase(object): """Enables DHCP for this network.""" @abc.abstractmethod - def disable(self, retain_port=False): + def disable(self, retain_port=False, block=False): """Disable dhcp for this network.""" def restart(self): """Restart the dhcp service for the network.""" - self.disable(retain_port=True) + self.disable(retain_port=True, block=True) self.enable() @abc.abstractproperty @@ -231,10 +231,13 @@ class DhcpLocalProcess(DhcpBase): pid_file=self.get_conf_file_name('pid'), run_as_root=True) - def disable(self, retain_port=False): + def disable(self, retain_port=False, block=False): """Disable DHCP for this network by killing the local process.""" self.process_monitor.unregister(self.network.id, DNSMASQ_SERVICE_NAME) - self._get_process_manager().disable() + pm = self._get_process_manager() + pm.disable() + if block: + common_utils.wait_until_true(lambda: not pm.active) if not retain_port: self._destroy_namespace_and_port() self._remove_config_files() diff --git a/neutron/tests/unit/agent/linux/test_dhcp.py b/neutron/tests/unit/agent/linux/test_dhcp.py index e616be6eee5..c4140e2855b 100644 --- a/neutron/tests/unit/agent/linux/test_dhcp.py +++ b/neutron/tests/unit/agent/linux/test_dhcp.py @@ -1012,8 +1012,8 @@ class TestDhcpBase(TestBase): def enable(self): self.called.append('enable') - def disable(self, retain_port=False): - self.called.append('disable %s' % retain_port) + def disable(self, retain_port=False, block=False): + self.called.append('disable %s %s' % (retain_port, block)) def reload_allocations(self): pass @@ -1024,7 +1024,7 @@ class TestDhcpBase(TestBase): c = SubClass() c.restart() - self.assertEqual(c.called, ['disable True', 'enable']) + self.assertEqual(c.called, ['disable True True', 'enable']) class TestDhcpLocalProcess(TestBase):