# under the License.
import abc
+import collections
import os
import re
import shutil
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
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 = []
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
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'
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
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