From: Tan Lin Date: Thu, 23 Oct 2014 11:00:22 +0000 (+0800) Subject: Enable adding new tag with options X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=434665eb785a3abec654b6dd0b57ac2c78b0ced8;p=openstack-build%2Fneutron-build.git Enable adding new tag with options It is useful to add a new tag when update the options with dnsmasq. We have a use case in Ironic to support ipxe with dnsmasq. It looks like this: dhcp_opts.append({'opt_name': 'tag:!ipxe,bootfile-name', 'opt_value': CONF.pxe.pxe_bootfile_name}) Change-Id: Idfaae9e8f8b7582f988e9da8707ef7d4823c6ff4 Closes-Bug: #1384577 --- diff --git a/neutron/agent/linux/dhcp.py b/neutron/agent/linux/dhcp.py index 534d27969..2dba7fa77 100644 --- a/neutron/agent/linux/dhcp.py +++ b/neutron/agent/linux/dhcp.py @@ -719,6 +719,10 @@ class Dnsmasq(DhcpLocalProcess): def _format_option(self, ip_version, tag, option, *args): """Format DHCP option by option name or code.""" option = str(option) + pattern = "(tag:(.*),)?(.*)$" + matches = re.match(pattern, option) + extra_tag = matches.groups()[0] + option = matches.groups()[2] if isinstance(tag, int): tag = self._TAG_PREFIX % tag @@ -728,8 +732,11 @@ class Dnsmasq(DhcpLocalProcess): option = 'option:%s' % option else: option = 'option6:%s' % option - - return ','.join(('tag:' + tag, '%s' % option) + args) + if extra_tag: + tags = ('tag:' + tag, extra_tag[:-1], '%s' % option) + else: + tags = ('tag:' + tag, '%s' % option) + return ','.join(tags + args) @staticmethod def _convert_to_literal_addrs(ip_version, ips): diff --git a/neutron/tests/unit/test_linux_dhcp.py b/neutron/tests/unit/test_linux_dhcp.py index 98b5beaab..991aabb4a 100644 --- a/neutron/tests/unit/test_linux_dhcp.py +++ b/neutron/tests/unit/test_linux_dhcp.py @@ -472,6 +472,17 @@ class FakeDualStackNetworkSingleDHCP(object): ports = [FakePort1(), FakePort4(), FakeRouterPort()] +class FakeV4NetworkMultipleTags(object): + id = 'dddddddd-dddd-dddd-dddd-dddddddddddd' + subnets = [FakeV4Subnet()] + ports = [FakePort1(), FakeRouterPort()] + namespace = 'qdhcp-ns' + + def __init__(self): + self.ports[0].extra_dhcp_opts = [ + DhcpOpt(opt_name='tag:ipxe,bootfile-name', opt_value='pxelinux.0')] + + class LocalChild(dhcp.DhcpLocalProcess): PORTS = {4: [4], 6: [6]} @@ -1054,6 +1065,25 @@ class TestDnsmasq(TestBase): self._test_output_opts_file(expected, FakeDualV4Pxe3Ports()) + def test_output_opts_file_multiple_tags(self): + expected = ( + 'tag:tag0,option:dns-server,8.8.8.8\n' + 'tag:tag0,option:classless-static-route,20.0.0.1/24,20.0.0.1,' + '0.0.0.0/0,192.168.0.1\n' + 'tag:tag0,249,20.0.0.1/24,20.0.0.1,0.0.0.0/0,192.168.0.1\n' + 'tag:tag0,option:router,192.168.0.1\n' + 'tag:eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee,' + 'tag:ipxe,option:bootfile-name,pxelinux.0') + expected = expected.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, FakeV4NetworkMultipleTags(), + version=dhcp.Dnsmasq.MINIMUM_VERSION) + dm._output_opts_file() + + self.safe.assert_called_once_with('/foo/opts', expected) + @property def _test_no_dhcp_domain_alloc_data(self): exp_host_name = '/dhcp/cccccccc-cccc-cccc-cccc-cccccccccccc/host'