def test_tftp_service_does_not_bind_to_link_local_addresses(self): # Initial set of interfaces to bind to. ipv4_test_net_3 = IPNetwork("203.0.113.0/24") # RFC 5737 normal_addresses = { factory.pick_ip_in_network(ipv4_test_net_3), factory.make_ipv6_address(), } link_local_addresses = { factory.pick_ip_in_network(IPV4_LINK_LOCAL), factory.pick_ip_in_network(IPV6_LINK_LOCAL), } self.patch( tftp_module, "get_all_interface_addresses", lambda: normal_addresses | link_local_addresses, ) tftp_service = TFTPService( resource_root=self.make_dir(), client_service=Mock(), port=factory.pick_port(), ) tftp_service.updateServers() # Only the "normal" addresses have been used. self.assertEqual( normal_addresses, {server.name for server in tftp_service.getServers()}, )
def test_get_ptr_mapping_drops_IPs_not_in_network(self): name = factory.make_string() network = IPNetwork("192.12.0.1/30") in_network_mapping = { factory.make_string(): factory.pick_ip_in_network(network), factory.make_string(): factory.pick_ip_in_network(network), } expected = [ ( IPAddress(ip).reverse_dns.split(".")[0], 30, "%s.%s." % (hostname, name), ) for hostname, ip in in_network_mapping.items() ] mapping = { "%s.%s" % (hostname, name): HostnameIPMapping(None, 30, [ip]) for hostname, ip in in_network_mapping.items() } extra_mapping = { factory.make_string(): HostnameIPMapping(None, 30, ["192.50.0.2"]), factory.make_string(): HostnameIPMapping(None, 30, ["192.70.0.2"]), } mapping.update(extra_mapping) self.assertItemsEqual( expected, DNSReverseZoneConfig.get_PTR_mapping(mapping, network) )
def test_bind_write_zones_writes_file(self): domain = factory.make_string() network = IPNetwork("192.168.0.3/24") dns_ip_list = [factory.pick_ip_in_network(network)] ip = factory.pick_ip_in_network(network) ttl = random.randint(10, 1000) forward_zone = DNSForwardZoneConfig( domain, serial=random.randint(1, 100), mapping={ factory.make_string(): HostnameIPMapping(None, ttl, {ip}) }, dns_ip_list=dns_ip_list, ) reverse_zone = DNSReverseZoneConfig( domain, serial=random.randint(1, 100), network=network ) actions.bind_write_zones(zones=[forward_zone, reverse_zone]) forward_file_name = "zone.%s" % domain reverse_file_name = "zone.0.168.192.in-addr.arpa" expected_files = [ join(self.dns_conf_dir, forward_file_name), join(self.dns_conf_dir, reverse_file_name), ] self.assertThat(expected_files, AllMatch(FileExists()))
def make_subnet_config( network=None, pools=None, ipv6=False, dhcp_snippets=None, disabled_boot_architectures=None, ): """Return complete DHCP configuration dict for a subnet.""" if network is None: if ipv6 is True: network = factory.make_ipv6_network( # The dynamic range must be at least 256 hosts in size. slash=random.randint(112, 120)) else: network = factory.make_ipv4_network() if pools is None: pools = [make_subnet_pool(network)] if dhcp_snippets is None: dhcp_snippets = make_subnet_dhcp_snippets() domain_name = "%s.example.com" % factory.make_name("domain") return { "subnet": str(IPAddress(network.first)), "subnet_mask": str(network.netmask), "subnet_cidr": str(network.cidr), "broadcast_ip": str(network.broadcast), "dns_servers": [ IPAddress(factory.pick_ip_in_network(network)), IPAddress(factory.pick_ip_in_network(network)), ], "ntp_servers": [ factory.make_ipv4_address(), factory.make_ipv6_address(), factory.make_name("ntp-server"), ], "domain_name": domain_name, "search_list": [domain_name], "router_ip": factory.pick_ip_in_network(network), "pools": pools, "dhcp_snippets": dhcp_snippets, "disabled_boot_architectures": disabled_boot_architectures if disabled_boot_architectures else [], }
def test_handles_slash_32_dynamic_range(self): target_dir = patch_dns_config_path(self) domain = factory.make_string() network = factory.make_ipv4_network() ipv4_hostname = factory.make_name("host") ipv4_ip = factory.pick_ip_in_network(network) range_ip = factory.pick_ip_in_network(network, but_not={ipv4_ip}) ipv6_hostname = factory.make_name("host") ipv6_ip = factory.make_ipv6_address() ttl = random.randint(10, 300) mapping = { ipv4_hostname: HostnameIPMapping(None, ttl, {ipv4_ip}), ipv6_hostname: HostnameIPMapping(None, ttl, {ipv6_ip}), } dynamic_range = IPRange(IPAddress(range_ip), IPAddress(range_ip)) expected_generate_directives = ( DNSForwardZoneConfig.get_GENERATE_directives(dynamic_range) ) other_mapping = { ipv4_hostname: HostnameRRsetMapping(None, {(ttl, "MX", "10 bar")}) } dns_zone_config = DNSForwardZoneConfig( domain, serial=random.randint(1, 100), other_mapping=other_mapping, default_ttl=ttl, mapping=mapping, dynamic_ranges=[dynamic_range], ) dns_zone_config.write_config() self.assertThat( os.path.join(target_dir, "zone.%s" % domain), FileContains( matcher=ContainsAll( [ "$TTL %d" % ttl, "%s %d IN A %s" % (ipv4_hostname, ttl, ipv4_ip), "%s %d IN AAAA %s" % (ipv6_hostname, ttl, ipv6_ip), "%s %d IN MX 10 bar" % (ipv4_hostname, ttl), ] + [ "$GENERATE %s %s IN A %s" % (iterator_values, reverse_dns, hostname) for iterator_values, reverse_dns, hostname in expected_generate_directives ] ) ), )
def test_ignores_generate_directives_for_v6_dynamic_ranges(self): patch_dns_config_path(self) domain = factory.make_string() network = factory.make_ipv4_network() ipv4_hostname = factory.make_name("host") ipv4_ip = factory.pick_ip_in_network(network) ipv6_hostname = factory.make_name("host") ipv6_ip = factory.make_ipv6_address() ipv6_network = factory.make_ipv6_network() dynamic_range = IPRange(ipv6_network.first, ipv6_network.last) ttl = random.randint(10, 300) mapping = { ipv4_hostname: HostnameIPMapping(None, ttl, {ipv4_ip}), ipv6_hostname: HostnameIPMapping(None, ttl, {ipv6_ip}), } dns_zone_config = DNSForwardZoneConfig( domain, serial=random.randint(1, 100), mapping=mapping, default_ttl=ttl, dynamic_ranges=[dynamic_range], ) get_generate_directives = self.patch(dns_zone_config, "get_GENERATE_directives") dns_zone_config.write_config() self.assertThat(get_generate_directives, MockNotCalled())
def test_parse_route_with_proto_and_metric(self): network = factory.make_ipv4_network() subnet = str(network.cidr) gateway = factory.pick_ip_in_network(network) interface = factory.make_name("nic") proto = factory.make_name("proto") metric = random.randint(50, 100) route_line = "%s via %s dev %s proto %s metric %d" % ( subnet, gateway, interface, proto, metric, ) self.assertEquals( ( subnet, { "via": gateway, "dev": interface, "proto": proto, "metric": metric, }, ), _parse_route_definition(route_line), )
def test_get_ptr_mapping(self): name = factory.make_string() network = IPNetwork('192.12.0.1/30') hosts = { factory.make_string(): factory.pick_ip_in_network(network), factory.make_string(): factory.pick_ip_in_network(network), } expected = [(IPAddress(ip).reverse_dns.split('.')[0], 30, '%s.%s.' % (hostname, name)) for hostname, ip in hosts.items()] mapping = { "%s.%s" % (hostname, name): HostnameIPMapping(None, 30, {ip}) for hostname, ip in hosts.items() } self.assertItemsEqual( expected, DNSReverseZoneConfig.get_PTR_mapping(mapping, network))
def make_route_line(self, subnet=None): network = factory.make_ipv4_network() gateway = factory.pick_ip_in_network(network) if subnet is None: subnet = str(network.cidr) interface = factory.make_name("nic") route_line = "%s via %s dev %s" % (subnet, gateway, interface) return route_line, {subnet: {"via": gateway, "dev": interface}}
def make_subnet_config(network=None, pools=None, ipv6=False, dhcp_snippets=None): """Return complete DHCP configuration dict for a subnet.""" if network is None: if ipv6 is True: network = factory.make_ipv6_network( # The dynamic range must be at least 256 hosts in size. slash=random.randint(112, 120)) else: network = factory.make_ipv4_network() if pools is None: pools = [make_subnet_pool(network)] if dhcp_snippets is None: dhcp_snippets = make_subnet_dhcp_snippets() domain_name = '%s.example.com' % factory.make_name('domain') return { 'subnet': str(IPAddress(network.first)), 'subnet_mask': str(network.netmask), 'subnet_cidr': str(network.cidr), 'broadcast_ip': str(network.broadcast), 'dns_servers': [ IPAddress(factory.pick_ip_in_network(network)), IPAddress(factory.pick_ip_in_network(network)), ], 'ntp_servers': [ factory.make_ipv4_address(), factory.make_ipv6_address(), factory.make_name("ntp-server"), ], 'domain_name': domain_name, 'search_list': [domain_name], 'router_ip': factory.pick_ip_in_network(network), 'pools': pools, 'dhcp_snippets': dhcp_snippets, }
def test_parse_route_without_proto_or_metric(self): network = factory.make_ipv4_network() subnet = str(network.cidr) gateway = factory.pick_ip_in_network(network) interface = factory.make_name("nic") route_line = "%s via %s dev %s" % (subnet, gateway, interface) self.assertEquals( (subnet, {"via": gateway, "dev": interface}), _parse_route_definition(route_line), )
def test__includes_next_server_in_config_from_all_addresses(self): params = make_sample_params(self, ipv6=False) subnet = params['shared_networks'][0]['subnets'][0] next_server_ip = factory.pick_ip_in_network( netaddr.IPNetwork(subnet['subnet_cidr'])) self.patch(net_utils, 'get_all_interface_addresses').return_value = [ next_server_ip ] config_output = config.get_config('dhcpd.conf.template', **params) validate_dhcpd_configuration(self, config_output, False) self.assertThat( config_output, Contains('next-server %s;' % next_server_ip))
def test_includes_next_server_in_config_from_interface_addresses(self): params = make_sample_params(self, ipv6=False, with_interface=True) subnet = params["shared_networks"][0]["subnets"][0] next_server_ip = factory.pick_ip_in_network( netaddr.IPNetwork(subnet["subnet_cidr"])) self.patch( net_utils, "get_all_addresses_for_interface").return_value = [next_server_ip] config_output = config.get_config("dhcpd.conf.template", **params) validate_dhcpd_configuration(self, config_output, False) self.assertThat(config_output, Contains("next-server %s;" % next_server_ip))
def test_write_config_writes_config(self): target_dir = patch_dns_config_path(self) domain = factory.make_string() network = IPNetwork('192.168.0.3/24') ip = factory.pick_ip_in_network(network) forward_zone = DNSForwardZoneConfig( domain, mapping={factory.make_string(): ip}) reverse_zone = DNSReverseZoneConfig(domain, network=network) dnsconfig = DNSConfig((forward_zone, reverse_zone)) dnsconfig.write_config() self.assertThat( os.path.join(target_dir, MAAS_NAMED_CONF_NAME), FileContains(matcher=ContainsAll([ 'zone.%s' % domain, 'zone.0.168.192.in-addr.arpa', MAAS_NAMED_RNDC_CONF_NAME, ])))
def test_fields(self): domain = factory.make_string() serial = random.randint(1, 200) hostname = factory.make_string() network = factory.make_ipv4_network() ip = factory.pick_ip_in_network(network) default_ttl = random.randint(10, 300) mapping = {hostname: [ip]} dns_zone_config = DNSForwardZoneConfig( domain, serial=serial, default_ttl=default_ttl, mapping=mapping ) self.assertThat( dns_zone_config, MatchesStructure.byEquality( domain=domain, serial=serial, _mapping=mapping, default_ttl=default_ttl, ), )
def test_writes_dns_zone_config(self): target_dir = patch_dns_config_path(self) domain = factory.make_string() network = factory.make_ipv4_network() ipv4_hostname = factory.make_name('host') ipv4_ip = factory.pick_ip_in_network(network) ipv6_hostname = factory.make_name('host') ipv6_ip = factory.make_ipv6_address() ttl = random.randint(10, 300) mapping = { ipv4_hostname: HostnameIPMapping(None, ttl, {ipv4_ip}), ipv6_hostname: HostnameIPMapping(None, ttl, {ipv6_ip}), } expected_generate_directives = ( DNSForwardZoneConfig.get_GENERATE_directives(network)) other_mapping = { ipv4_hostname: HostnameRRsetMapping(None, {(ttl, 'MX', '10 bar')}) } dns_zone_config = DNSForwardZoneConfig( domain, serial=random.randint(1, 100), other_mapping=other_mapping, default_ttl=ttl, mapping=mapping, dynamic_ranges=[IPRange(network.first, network.last)]) dns_zone_config.write_config() self.assertThat( os.path.join(target_dir, 'zone.%s' % domain), FileContains(matcher=ContainsAll([ '$TTL %d' % ttl, '%s %d IN A %s' % (ipv4_hostname, ttl, ipv4_ip), '%s %d IN AAAA %s' % (ipv6_hostname, ttl, ipv6_ip), '%s %d IN MX 10 bar' % (ipv4_hostname, ttl), ] + [ '$GENERATE %s %s IN A %s' % (iterator_values, reverse_dns, hostname) for iterator_values, reverse_dns, hostname in expected_generate_directives ])))
def test_pick_ip_in_network_for_ipv6(self): # For IPv6, pick_ip_in_network will not consider the very first # address in a network because this is reserved for routers. network = factory.make_ipv6_network(slash=126) ip = factory.pick_ip_in_network(network) self.assertTrue(network.first < IPAddress(ip).value <= network.last)
def test_pick_ip_in_network_for_ipv4_slash_30(self): network = factory.make_ipv4_network(slash=30) ip = factory.pick_ip_in_network(network) self.assertTrue(network.first < IPAddress(ip).value < network.last)