From 3339f96afefb569dde450888493aaa0307f0406e Mon Sep 17 00:00:00 2001 From: Gary Kotton Date: Tue, 14 May 2013 13:20:44 +0000 Subject: [PATCH] Add support for dnsmasq version 2.48 Following the bug fix for bug 1170793 we are able to add in support for dnsmasq versions that do not support tags. 2.48 is the version shipped in RHEL 6.4 Change-Id: Ia7d2b1c0adb477159ce146bcd4323d4b2795bff5 (cherry picked from commit 6012b7e97c361a90d88a573d3c6a9f33e03f4281) --- quantum/agent/dhcp_agent.py | 5 ++-- quantum/agent/linux/dhcp.py | 21 ++++++++++---- quantum/tests/unit/test_dhcp_agent.py | 6 ++-- quantum/tests/unit/test_linux_dhcp.py | 41 ++++++++++++++++++++------- 4 files changed, 53 insertions(+), 20 deletions(-) diff --git a/quantum/agent/dhcp_agent.py b/quantum/agent/dhcp_agent.py index 5d8de731dd..41ce571f2b 100644 --- a/quantum/agent/dhcp_agent.py +++ b/quantum/agent/dhcp_agent.py @@ -80,7 +80,7 @@ class DhcpAgent(manager.Manager): self.device_manager = DeviceManager(self.conf, self.plugin_rpc) self.lease_relay = DhcpLeaseRelay(self.update_lease) - self.dhcp_driver_cls.check_version() + self.dhcp_version = self.dhcp_driver_cls.check_version() self._populate_networks_cache() def _populate_networks_cache(self): @@ -126,7 +126,8 @@ class DhcpAgent(manager.Manager): network, self.root_helper, self.device_manager, - self._ns_name(network)) + self._ns_name(network), + self.dhcp_version) getattr(driver, action)() return True diff --git a/quantum/agent/linux/dhcp.py b/quantum/agent/linux/dhcp.py index ff5e843a95..2844b1a627 100644 --- a/quantum/agent/linux/dhcp.py +++ b/quantum/agent/linux/dhcp.py @@ -66,12 +66,13 @@ class DhcpBase(object): __metaclass__ = abc.ABCMeta def __init__(self, conf, network, root_helper='sudo', - device_delegate=None, namespace=None): + device_delegate=None, namespace=None, version=None): self.conf = conf self.network = network self.root_helper = root_helper self.device_delegate = device_delegate self.namespace = namespace + self.version = version @abc.abstractmethod def enable(self): @@ -230,7 +231,7 @@ class Dnsmasq(DhcpLocalProcess): @classmethod def check_version(cls): - is_valid_version = None + ver = 0 try: cmd = ['dnsmasq', '--version'] out = utils.execute(cmd) @@ -245,7 +246,7 @@ class Dnsmasq(DhcpLocalProcess): LOG.warning(_('Unable to determine dnsmasq version. ' 'Please ensure that its version is %s ' 'or above!'), cls.MINIMUM_VERSION) - return is_valid_version + return float(ver) @classmethod def existing_dhcp_networks(cls, conf, root_helper): @@ -299,8 +300,12 @@ class Dnsmasq(DhcpLocalProcess): # TODO (mark): how do we indicate other options # ra-only, slaac, ra-nameservers, and ra-stateless. mode = 'static' - cmd.append('--dhcp-range=set:%s,%s,%s,%ss' % - (self._TAG_PREFIX % i, + if self.version >= self.MINIMUM_VERSION: + set_tag = 'set:' + else: + set_tag = '' + cmd.append('--dhcp-range=%s%s,%s,%s,%ss' % + (set_tag, self._TAG_PREFIX % i, netaddr.IPNetwork(subnet.cidr).network, mode, self.conf.dhcp_lease_time)) @@ -434,7 +439,11 @@ class Dnsmasq(DhcpLocalProcess): 'quantum-dhcp-agent-dnsmasq-lease-update') def _format_option(self, index, option_name, *args): - return ','.join(('tag:' + self._TAG_PREFIX % index, + if self.version >= self.MINIMUM_VERSION: + set_tag = 'tag:' + else: + set_tag = '' + return ','.join((set_tag + self._TAG_PREFIX % index, 'option:%s' % option_name) + args) @classmethod diff --git a/quantum/tests/unit/test_dhcp_agent.py b/quantum/tests/unit/test_dhcp_agent.py index 519dc23146..25e0cc1934 100644 --- a/quantum/tests/unit/test_dhcp_agent.py +++ b/quantum/tests/unit/test_dhcp_agent.py @@ -218,7 +218,8 @@ class TestDhcpAgent(base.BaseTestCase): mock.ANY, 'sudo', mock.ANY, - 'qdhcp-1') + 'qdhcp-1', + mock.ANY) def test_call_driver_failure(self): network = mock.Mock() @@ -233,7 +234,8 @@ class TestDhcpAgent(base.BaseTestCase): mock.ANY, 'sudo', mock.ANY, - 'qdhcp-1') + 'qdhcp-1', + mock.ANY) self.assertEqual(log.call_count, 1) self.assertTrue(dhcp.needs_resync) diff --git a/quantum/tests/unit/test_linux_dhcp.py b/quantum/tests/unit/test_linux_dhcp.py index 7f317b7a49..f29a364bfa 100644 --- a/quantum/tests/unit/test_linux_dhcp.py +++ b/quantum/tests/unit/test_linux_dhcp.py @@ -450,7 +450,8 @@ class TestDnsmasq(TestBase): argv.__getitem__.side_effect = fake_argv dm = dhcp.Dnsmasq(self.conf, FakeDualNetwork(), device_delegate=delegate, - namespace='qdhcp-ns') + namespace='qdhcp-ns', + version=float(2.59)) dm.spawn_process() self.assertTrue(mocks['_output_opts_file'].called) self.execute.assert_called_once_with(expected, @@ -488,7 +489,8 @@ tag:tag1,option:classless-static-route,%s,%s""".lstrip() % (fake_v6, with mock.patch.object(dhcp.Dnsmasq, 'get_conf_file_name') as conf_fn: conf_fn.return_value = '/foo/opts' - dm = dhcp.Dnsmasq(self.conf, FakeDualNetwork()) + dm = dhcp.Dnsmasq(self.conf, FakeDualNetwork(), + version=float(2.59)) dm._output_opts_file() self.safe.assert_called_once_with('/foo/opts', expected) @@ -500,7 +502,21 @@ tag:tag0,option:classless-static-route,20.0.0.1/24,20.0.0.1 tag:tag0,option:router,192.168.0.1""".lstrip() with mock.patch.object(dhcp.Dnsmasq, 'get_conf_file_name') as conf_fn: conf_fn.return_value = '/foo/opts' - dm = dhcp.Dnsmasq(self.conf, FakeDualNetworkSingleDHCP()) + dm = dhcp.Dnsmasq(self.conf, FakeDualNetworkSingleDHCP(), + version=float(2.59)) + dm._output_opts_file() + + self.safe.assert_called_once_with('/foo/opts', expected) + + def test_output_opts_file_single_dhcp_ver2_48(self): + expected = """ +tag0,option:dns-server,8.8.8.8 +tag0,option:classless-static-route,20.0.0.1/24,20.0.0.1 +tag0,option:router,192.168.0.1""".lstrip() + with mock.patch.object(dhcp.Dnsmasq, 'get_conf_file_name') as conf_fn: + conf_fn.return_value = '/foo/opts' + dm = dhcp.Dnsmasq(self.conf, FakeDualNetworkSingleDHCP(), + version=float(2.48)) dm._output_opts_file() self.safe.assert_called_once_with('/foo/opts', expected) @@ -512,7 +528,8 @@ tag:tag0,option:router""".lstrip() with mock.patch.object(dhcp.Dnsmasq, 'get_conf_file_name') as conf_fn: conf_fn.return_value = '/foo/opts' - dm = dhcp.Dnsmasq(self.conf, FakeV4NoGatewayNetwork()) + dm = dhcp.Dnsmasq(self.conf, FakeV4NoGatewayNetwork(), + version=float(2.59)) with mock.patch.object(dm, '_make_subnet_interface_ip_map') as ipm: ipm.return_value = {FakeV4SubnetNoGateway.id: '192.168.1.1'} @@ -551,7 +568,8 @@ tag:tag1,option:classless-static-route,%s,%s""".lstrip() % (fake_v6, with mock.patch.object(dhcp.Dnsmasq, 'pid') as pid: pid.__get__ = mock.Mock(return_value=5) dm = dhcp.Dnsmasq(self.conf, FakeDualNetwork(), - namespace='qdhcp-ns') + namespace='qdhcp-ns', + version=float(2.59)) method_name = '_make_subnet_interface_ip_map' with mock.patch.object(dhcp.Dnsmasq, @@ -593,7 +611,7 @@ tag:tag1,option:classless-static-route,%s,%s""".lstrip() % (fake_v6, with mock.patch.object(dhcp.Dnsmasq, 'pid') as pid: pid.__get__ = mock.Mock(return_value=5) dm = dhcp.Dnsmasq(self.conf, FakeDualNetwork(), - namespace='qdhcp-ns') + namespace='qdhcp-ns', version=float(2.59)) method_name = '_make_subnet_interface_ip_map' with mock.patch.object(dhcp.Dnsmasq, method_name) as ip_map: @@ -727,13 +745,16 @@ tag:tag1,option:classless-static-route,%s,%s""".lstrip() % (fake_v6, self.assertEqual(result, expected_value) def test_check_minimum_version(self): - self._check_version('Dnsmasq version 2.59 Copyright (c)...', True) + self._check_version('Dnsmasq version 2.59 Copyright (c)...', + float(2.59)) def test_check_future_version(self): - self._check_version('Dnsmasq version 2.65 Copyright (c)...', True) + self._check_version('Dnsmasq version 2.65 Copyright (c)...', + float(2.65)) def test_check_fail_version(self): - self._check_version('Dnsmasq version 2.48 Copyright (c)...', False) + self._check_version('Dnsmasq version 2.48 Copyright (c)...', + float(2.48)) def test_check_version_failed_cmd_execution(self): - self._check_version('Error while executing command', None) + self._check_version('Error while executing command', 0)