]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
Dnsmasq uses all agent IPs as nameservers
authorSylvain Afchain <sylvain.afchain@enovance.com>
Wed, 4 Dec 2013 20:01:06 +0000 (21:01 +0100)
committerSylvain Afchain <sylvain.afchain@enovance.com>
Mon, 23 Dec 2013 09:14:49 +0000 (10:14 +0100)
Add dhcp option which provides all agent IPs
which will be used as nameserver entries when
neutron uses multiple dhcp agent per network and
when there is no dns nameserver provided by the
neutron server.

Change-Id: I639a844bba212a731616851ff479a5e735612cf8
Closes-bug: #1259482

neutron/agent/linux/dhcp.py
neutron/tests/unit/test_linux_dhcp.py

index 137f7a9272e9cb90bd72a14c9325e0ea658e828a..1cf1a8e1e777cbbd52a10237c2d08005d1e84b75 100644 (file)
@@ -16,6 +16,7 @@
 #    under the License.
 
 import abc
+import collections
 import os
 import re
 import shutil
@@ -442,6 +443,9 @@ class Dnsmasq(DhcpLocalProcess):
             subnet_to_interface_ip = self._make_subnet_interface_ip_map()
 
         options = []
+
+        dhcp_ips = collections.defaultdict(list)
+        subnet_idx_map = {}
         for i, subnet in enumerate(self.network.subnets):
             if not subnet.enable_dhcp:
                 continue
@@ -449,6 +453,10 @@ class Dnsmasq(DhcpLocalProcess):
                 options.append(
                     self._format_option(i, 'dns-server',
                                         ','.join(subnet.dns_nameservers)))
+            else:
+                # use the dnsmasq ip as nameservers only if there is no
+                # dns-server submitted by the server
+                subnet_idx_map[subnet.id] = i
 
             gateway = subnet.gateway_ip
             host_routes = []
@@ -486,6 +494,22 @@ class Dnsmasq(DhcpLocalProcess):
                     self._format_option(port.id, opt.opt_name, opt.opt_value)
                     for opt in port.extra_dhcp_opts)
 
+            # provides all dnsmasq ip as dns-server if there is more than
+            # one dnsmasq for a subnet and there is no dns-server submitted
+            # by the server
+            if port.device_owner == 'network:dhcp':
+                for ip in port.fixed_ips:
+                    i = subnet_idx_map.get(ip.subnet_id)
+                    if i is None:
+                        continue
+                    dhcp_ips[i].append(ip.ip_address)
+
+        for i, ips in dhcp_ips.items():
+            if len(ips) > 1:
+                options.append(self._format_option(i,
+                                                   'dns-server',
+                                                   ','.join(ips)))
+
         name = self.get_conf_file_name('opts')
         utils.replace_file(name, '\n'.join(options))
         return name
index 3ab90b84a407227d07d854989635f8f005eea1f6..9dec635ded0a5ac807b900dde447e49e42d5e4d4 100644 (file)
@@ -89,6 +89,30 @@ class FakeRouterPort:
         self.extra_dhcp_opts = []
 
 
+class FakePortMultipleAgents1:
+    id = 'rrrrrrrr-rrrr-rrrr-rrrr-rrrrrrrrrrrr'
+    admin_state_up = True
+    device_owner = 'network:dhcp'
+    fixed_ips = [FakeIPAllocation('192.168.0.5',
+                                  'dddddddd-dddd-dddd-dddd-dddddddddddd')]
+    mac_address = '00:00:0f:dd:dd:dd'
+
+    def __init__(self):
+        self.extra_dhcp_opts = []
+
+
+class FakePortMultipleAgents2:
+    id = 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa'
+    admin_state_up = True
+    device_owner = 'network:dhcp'
+    fixed_ips = [FakeIPAllocation('192.168.0.6',
+                                  'dddddddd-dddd-dddd-dddd-dddddddddddd')]
+    mac_address = '00:00:0f:ee:ee:ee'
+
+    def __init__(self):
+        self.extra_dhcp_opts = []
+
+
 class FakeV4HostRoute:
     destination = '20.0.0.1/24'
     nexthop = '20.0.0.1'
@@ -124,6 +148,42 @@ class FakeV4SubnetGatewayRoute:
     dns_nameservers = ['8.8.8.8']
 
 
+class FakeV4SubnetMultipleAgentsWithoutDnsProvided:
+    id = 'dddddddd-dddd-dddd-dddd-dddddddddddd'
+    ip_version = 4
+    cidr = '192.168.0.0/24'
+    gateway_ip = '192.168.0.1'
+    enable_dhcp = True
+    dns_nameservers = []
+    host_routes = []
+
+
+class FakeV4MultipleAgentsWithoutDnsProvided:
+    id = 'ffffffff-ffff-ffff-ffff-ffffffffffff'
+    subnets = [FakeV4SubnetMultipleAgentsWithoutDnsProvided()]
+    ports = [FakePort1(), FakePort2(), FakePort3(), FakeRouterPort(),
+             FakePortMultipleAgents1(), FakePortMultipleAgents2()]
+    namespace = 'qdhcp-ns'
+
+
+class FakeV4SubnetMultipleAgentsWithDnsProvided:
+    id = 'dddddddd-dddd-dddd-dddd-dddddddddddd'
+    ip_version = 4
+    cidr = '192.168.0.0/24'
+    gateway_ip = '192.168.0.1'
+    enable_dhcp = True
+    dns_nameservers = ['8.8.8.8']
+    host_routes = []
+
+
+class FakeV4MultipleAgentsWithDnsProvided:
+    id = 'ffffffff-ffff-ffff-ffff-ffffffffffff'
+    subnets = [FakeV4SubnetMultipleAgentsWithDnsProvided()]
+    ports = [FakePort1(), FakePort2(), FakePort3(), FakeRouterPort(),
+             FakePortMultipleAgents1(), FakePortMultipleAgents2()]
+    namespace = 'qdhcp-ns'
+
+
 class FakeV6Subnet:
     id = 'ffffffff-ffff-ffff-ffff-ffffffffffff'
     ip_version = 6
@@ -716,6 +776,30 @@ tag:tag1,249,%s,%s""".lstrip() % (fake_v6,
 
         self.safe.assert_called_once_with('/foo/opts', expected)
 
+    def test_output_opts_file_multiple_agents_without_dns_provided(self):
+        expected = """
+tag:tag0,option:router,192.168.0.1
+tag:tag0,option:dns-server,192.168.0.5,192.168.0.6""".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,
+                              FakeV4MultipleAgentsWithoutDnsProvided(),
+                              version=float(2.59))
+            dm._output_opts_file()
+        self.safe.assert_called_once_with('/foo/opts', expected)
+
+    def test_output_opts_file_multiple_agents_with_dns_provided(self):
+        expected = """
+tag:tag0,option:dns-server,8.8.8.8
+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,
+                              FakeV4MultipleAgentsWithDnsProvided(),
+                              version=float(2.59))
+            dm._output_opts_file()
+        self.safe.assert_called_once_with('/foo/opts', expected)
+
     def test_output_opts_file_single_dhcp(self):
         expected = """
 tag:tag0,option:dns-server,8.8.8.8