def test_canonical_records_ipv6(self, zones): n = NodeAddr('vm00', 'fe', 'whq', ip.IPAddress('2a02:248:101:63::5b')) n.inject_records(zones) zones.add_addr.assert_any_call('vm00.fe.whq', ip.IPAddress('2a02:248:101:63::5b')) zones.add_addr.assert_any_call('vm00.fe.whq.ipv6', ip.IPAddress('2a02:248:101:63::5b'))
def test_render_forward(self): config = configobj.ConfigObj( pkg_resources.resource_stream(__name__, 'fixtures/configure-zones.cfg')) z = ForwardZone('gocept.net', parent_zones=Zones(config)) z.add_a('vm00', ip.IPAddress('212.122.41.136')) z.add_a('vm00', ip.IPAddress('2a02:248:101:63::5b')) z.add_cname('vm00.srv.whq', 'vm00') self.maxDiff = 1024 self.assertEqual( z.render(2014021900), """\ ; generated by configure-zones $TTL 86400 $ORIGIN gocept.net. @ 86400 IN SOA ns1.gocept.net. hostmaster.fcio.net. ( 2014021900 ; serial 10800 ; refresh 900 ; retry 2419200 ; expire 1800 ; neg ttl ) NS ns1.gocept.net. NS ns2.gocept.net. $TTL 7200 vm00 A 212.122.41.136 vm00 AAAA 2a02:248:101:63::5b vm00.srv.whq CNAME vm00 """)
def test_canonical_records_ipv4(self, zones): n = NodeAddr('vm00', 'fe', 'whq', ip.IPAddress('195.62.120.10')) n.inject_records(zones) zones.add_addr.assert_any_call('vm00.fe.whq', ip.IPAddress('195.62.120.10')) zones.add_addr.assert_any_call('vm00.fe.whq.ipv4', ip.IPAddress('195.62.120.10'))
def test_default_reverse(self, zones): n = NodeAddr('vm00', 'srv', 'whq', ip.IPAddress('212.122.42.136'), canonical=True) n.inject_records(zones) zones.add_reverse.assert_called_with(ip.IPAddress('212.122.42.136'), 'vm00')
def test_custom_reverse(self, zones): n = NodeAddr('vm00', 'fe', 'whq', ip.IPAddress('195.62.125.10'), reverse='www.example.com.') n.inject_records(zones) zones.add_reverse.assert_called_with(ip.IPAddress('195.62.125.10'), 'www.example.com.')
def test_add_addr_creates_public_records(self): self.z.add_addr('vm00', ip.IPAddress('195.62.125.33'), ['vm00.ipv4']) self.assertIn(RR.A('vm00', ip.IPAddress('195.62.125.33')), self.z.external_forward.records) self.assertIn(RR.A('vm00', ip.IPAddress('195.62.125.33')), self.z.internal_forward.records) self.assertIn(RR.CNAME('vm00.ipv4', 'vm00'), self.z.external_forward.records) self.assertIn(RR.CNAME('vm00.ipv4', 'vm00'), self.z.internal_forward.records)
def test_short_and_canonical_for_srv_ipv4(self, zones): n = NodeAddr('vm00', 'srv', 'whq', ip.IPAddress('212.122.41.136'), canonical=True) n.inject_records(zones) zones.add_addr.assert_any_call('vm00', ip.IPAddress('212.122.41.136'), ['vm00.srv.whq']) zones.add_addr.assert_any_call('vm00.ipv4', ip.IPAddress('212.122.41.136'), ['vm00.srv.whq.ipv4'])
def test_short_and_canonical_for_srv_ipv6(self, zones): n = NodeAddr('vm00', 'srv', 'whq', ip.IPAddress('2a02:248:101:63::5b'), canonical=True) n.inject_records(zones) zones.add_addr.assert_any_call('vm00', ip.IPAddress('2a02:248:101:63::5b'), ['vm00.srv.whq']) zones.add_addr.assert_any_call('vm00.ipv6', ip.IPAddress('2a02:248:101:63::5b'), ['vm00.srv.whq.ipv6'])
def walk(directory): for node in sorted(directory.list_nodes()): shortname = node['name'] location = node['parameters']['location'] production = node['parameters']['production'] # Choose the VLAN for the canonical name: SRV is preferable, but some # devices only have MGMT and then we use that. canonical_vlan = None vlans = set(node['parameters']['interfaces']) for v in ['srv', 'mgm']: if v in vlans: canonical_vlan = v break # sort everything to keep stable ordering for vlan, params in sorted(node['parameters']['interfaces'].items()): for addresses in sorted(params['networks'].values()): for addr in sorted(addresses): reverse = node['parameters']['reverses'].get(addr) yield NodeAddr(shortname, vlan, location, ip.IPAddress(addr), production, reverse, canonical=(vlan == canonical_vlan))
def test_add_ptr_strips_prefix(self): z = ReverseZone('1.0.1.0.8.4.2.0.2.0.a.2.ip6.arpa', ip.IPNetwork('2a02:238:101::/48')) z.add_ptr(ip.IPAddress('2a02:248:101:63::5b'), 'vm00') self.assertEqual( RR.PTR('b.5.0.0.0.0.0.0.0.0.0.0.0.0.0.0.3.6.0.0', 'vm00'), z.records[0])
def validate(self, value): """ ensure valid ip address """ super(IPAddressField, self).validate(value) try: ip.IPAddress(value) except (ip.AddrFormatError, ValueError): raise ValidationError(_('Invalid ip address'))
def test_save_returns_true_if_changed(self, now): now.return_value = datetime.datetime(2014, 2, 17, tzinfo=pytz.utc) with open(self.filename, 'w') as f: f.write(self.z.render(2014021703)) self.z.records.append(RR.A('vm01', ip.IPAddress('192.168.1.1'))) self.assertTrue(self.z.save()) with open(self.filename) as f: self.assertEqual(f.read(), self.z.render(2014021704))
def inject_records(self, zones): """Implement naming policy.""" for index, variant in enumerate(self.variants): if self.canonical: # e.g., vm00.{ipv4.,ipv6.,}gocept.net # with alias vm00.srv.whq.{ipv4.,ipv6.,}gocept.net default_name = join_dn(self.name, variant) zones.add_addr( default_name, self.addr, [join_dn(self.name, self.vlan, self.loc, variant)]) else: # e.g., vm00.fe.whq.{ipv4.,ipv6.,}gocept.net default_name = join_dn(self.name, self.vlan, self.loc, variant) zones.add_addr(default_name, ip.IPAddress(self.addr)) if index == 0: # the first variant determines the reverse address zones.add_reverse(self.addr, self.reverse or default_name)
def test_forward_ipv6(self): z = ForwardZone('gocept.net') z.add_a('vm00.srv.whq', ip.IPAddress('2a02:248:101:63::5b')) self.assertIn( RR.AAAA('vm00.srv.whq', ip.IPAddress('2a02:248:101:63::5b')), z.records)
def test_add_pre_strips_correct_prefix_for_cidr_zones(self): z = ReverseZone('128-25.41.122.212.in-addr.arpa', prefix=ip.IPNetwork('212.122.41.128/25'), strip_suffix='41.122.212.in-addr.arpa') z.add_ptr(ip.IPAddress('212.122.41.152'), 'rt.gocept.com.') self.assertEqual(RR.PTR('152', 'rt.gocept.com.'), z.records[0])
def import_interfaces(self): self.verbose('retrieving interfaces from old mysql DB...') self.old_interfaces = list(OldInterface.objects.all()) self.message('retrieved %d interfaces' % len(self.old_interfaces)) saved_interfaces = [] saved_vaps = [] saved_ipv4 = [] saved_ipv6 = [] for old_interface in self.old_interfaces: interface_dict = { "id": old_interface.id, "device_id": int(old_interface.device_id), "mac": old_interface.mac_address, "name": old_interface.cname[0:10], "added": old_interface.added, "updated": old_interface.updated, "data": {} } vap = None ipv4 = None ipv6 = None # determine interface type and specific fields if old_interface.type == 'eth': interface_dict['standard'] = 'fast' interface_dict['duplex'] = 'full' InterfaceModel = Ethernet elif old_interface.type == 'wifi': interface_dict['mode'] = old_interface.wireless_mode interface_dict['channel'] = old_interface.wireless_channel InterfaceModel = Wireless # determine ssid if old_interface.essid or old_interface.bssid: vap = Vap(**{ "interface_id": old_interface.id, "essid": old_interface.essid, "bssid": old_interface.essid }) if old_interface.essid: interface_dict['data']['essid'] = old_interface.essid if old_interface.bssid: interface_dict['data']['bssid'] = old_interface.bssid elif old_interface.type == 'bridge': InterfaceModel = Bridge elif old_interface.type == 'vpn': InterfaceModel = Tunnel else: interface_dict['type'] = INTERFACE_TYPES.get('virtual') interface_dict['data']['old_nodeshot_interface_type'] = old_interface.get_type_display() InterfaceModel = Interface interface = InterfaceModel(**interface_dict) if old_interface.ipv4_address: old_interface.ipv4_address = old_interface.ipv4_address.strip() # stupid django bug ipv4 = Ip(**{ "interface_id": old_interface.id, "address": old_interface.ipv4_address }) # ensure ipv4 is valid try: ip.IPAddress(old_interface.ipv4_address) except (ip.AddrFormatError, ValueError): self.message('Invalid IPv4 address %s' % (old_interface.ipv4_address)) ipv4 = None if old_interface.ipv6_address: old_interface.ipv6_address = old_interface.ipv6_address.strip() # stupid django bug ipv6 = Ip(**{ "interface_id": old_interface.id, "address": old_interface.ipv6_address }) # ensure ipv6 is valid try: ip.IPAddress(old_interface.ipv6_address) except (ip.AddrFormatError, ValueError): self.message('Invalid IPv6 address %s' % (old_interface.ipv6_address)) ipv6 = None try: interface.full_clean() interface.save(auto_update=False) saved_interfaces.append(interface) self.verbose('Saved interface %s' % interface.name) except Exception as e: self.message('Could not save interface %s, got exception: %s' % (interface.mac, e)) continue if vap: try: vap.full_clean() vap.save() saved_vaps.append(vap) self.verbose('Saved vap %s' % vap.essid or vap.bssid) except Exception as e: self.message('Could not save vap %s, got exception: %s' % (vap.essid or vap.bssid, e)) if ipv4: try: ipv4.full_clean() ipv4.save() saved_ipv4.append(ipv4) self.verbose('Saved ipv4 %s' % ipv4.address) except Exception as e: self.message('Could not save ipv4 %s, got exception: %s' % (ipv4.address, e)) if ipv6: try: ipv6.full_clean() ipv6.save() saved_ipv6.append(ipv6) self.verbose('Saved ipv6 %s' % ipv6.address) except Exception as e: self.message('Could not save ipv6 %s, got exception: %s' % (ipv6.address, e)) self.message('saved %d interfaces into local DB' % len(saved_interfaces)) self.message('saved %d vaps into local DB' % len(saved_vaps)) self.message('saved %d ipv4 addresses into local DB' % len(saved_ipv4)) self.message('saved %d ipv6 addresses into local DB' % len(saved_ipv6)) self.saved_interfaces = saved_interfaces self.saved_vaps = saved_vaps self.saved_ipv4 = saved_ipv4 self.saved_ipv6 = saved_ipv6
def test_add_addr_creates_no_public_records(self): self.z.add_addr('vm00', ip.IPAddress('172.22.48.20'), ['vm00.ipv4']) self.assertNotIn(RR.A('vm00', ip.IPAddress('172.22.48.20')), self.z.external_forward.records) self.assertNotIn(RR.CNAME('vm00.ipv4', 'vm00'), self.z.external_forward.records)
def test_add_reverse_to_correct_zone(self): self.z.add_reverse(ip.IPAddress('2a02:248:101:63::5b'), 'vm00.ipv6') self.assertEqual( 'vm00.ipv6.gocept.net.', self.z.reverse_zones[ip.IPNetwork( '2a02:248:101::/48')].records[0].value)
def test_cannot_mix_a_and_cname(self): z = ForwardZone('gocept.net') z.add_a('vm00', ip.IPAddress('2a02:248:101:63::5b')) with self.assertRaises(MixedRecordTypesException): z.add_cname('vm00', 'other')
def test_add_reverse_does_not_fail_when_address_does_not_fit_any_zone( self): # We used to fail here but decided to not fail as that will # (kinda silently) block DNS updates that people expect to see quickly. self.z.add_reverse(ip.IPAddress('192.0.1.2'), 'vm00')
def test_forward_ipv4(self): z = ForwardZone('gocept.net') z.add_a('vm00.fe.whq', ip.IPAddress('195.62.125.10')) self.assertIn(RR.A('vm00.fe.whq', ip.IPAddress('195.62.125.10')), z.records)
def import_interfaces(self): self.verbose('retrieving interfaces from old mysql DB...') self.old_interfaces = list(OldInterface.objects.all()) self.message('retrieved %d interfaces' % len(self.old_interfaces)) saved_interfaces = [] saved_vaps = [] saved_ipv4 = [] saved_ipv6 = [] for old_interface in self.old_interfaces: interface_dict = { "id": old_interface.id, "device_id": int(old_interface.device_id), "mac": old_interface.mac_address, "name": old_interface.cname[0:10], "added": old_interface.added, "updated": old_interface.updated, "data": {} } vap = None ipv4 = None ipv6 = None # determine interface type and specific fields if old_interface.type == 'eth': interface_dict['standard'] = 'fast' interface_dict['duplex'] = 'full' InterfaceModel = Ethernet elif old_interface.type == 'wifi': interface_dict['mode'] = old_interface.wireless_mode interface_dict['channel'] = old_interface.wireless_channel InterfaceModel = Wireless # determine ssid if old_interface.essid or old_interface.bssid: vap = Vap( **{ "interface_id": old_interface.id, "essid": old_interface.essid, "bssid": old_interface.bssid }) # if vap already exists flag it for UPDATE instead of INSERT try: v = Vap.objects.get( Q(interface_id=old_interface.id) & (Q(essid=old_interface.essid) | Q(bssid=old_interface.bssid))) # trick to make django do an update query instead of an insert # working on django 1.6 vap.id = v.id vap._state.adding = False except Vap.DoesNotExist: pass if old_interface.essid: interface_dict['data']['essid'] = old_interface.essid if old_interface.bssid: interface_dict['data']['bssid'] = old_interface.bssid elif old_interface.type == 'bridge': InterfaceModel = Bridge elif old_interface.type == 'vpn': InterfaceModel = Tunnel else: interface_dict['type'] = INTERFACE_TYPES.get('virtual') interface_dict['data'][ 'old_nodeshot_interface_type'] = old_interface.get_type_display( ) InterfaceModel = Interface interface = InterfaceModel(**interface_dict) # if interface already exists flag it for UPDATE instead of INSERT try: InterfaceModel.objects.get(pk=old_interface.id) interface._state.adding = False except InterfaceModel.DoesNotExist: pass if old_interface.ipv4_address: old_interface.ipv4_address = old_interface.ipv4_address.strip( ) # stupid django bug ipv4 = Ip( **{ "interface_id": old_interface.id, "address": old_interface.ipv4_address }) # if ip already exists flag it for UPDATE instead of INSERT try: ipv4.id = Ip.objects.get( address=old_interface.ipv4_address).id ipv4._state.adding = False except Ip.DoesNotExist: pass # ensure ipv4 is valid try: ip.IPAddress(old_interface.ipv4_address) except (ip.AddrFormatError, ValueError): self.message('Invalid IPv4 address %s' % (old_interface.ipv4_address)) ipv4 = None if old_interface.ipv6_address: old_interface.ipv6_address = old_interface.ipv6_address.strip( ) # stupid django bug ipv6 = Ip( **{ "interface_id": old_interface.id, "address": old_interface.ipv6_address }) # if ip already exists flag it for UPDATE instead of INSERT try: ipv6.id = Ip.objects.get( address=old_interface.ipv6_address).id ipv6._state.adding = False except Ip.DoesNotExist: pass # ensure ipv6 is valid try: ip.IPAddress(old_interface.ipv6_address) except (ip.AddrFormatError, ValueError): self.message('Invalid IPv6 address %s' % (old_interface.ipv6_address)) ipv6 = None try: interface.full_clean() interface.save(auto_update=False) saved_interfaces.append(interface) self.verbose('Saved interface %s' % interface.name) except Exception: tb = traceback.format_exc() self.message( 'Could not save interface %s, got exception:\n\n%s' % (interface.mac, tb)) continue if vap: try: vap.full_clean() vap.save() saved_vaps.append(vap) self.verbose('Saved vap %s' % vap.essid or vap.bssid) except Exception: tb = traceback.format_exc() self.message( 'Could not save vap %s, got exception:\n\n%s' % (vap.essid or vap.bssid, tb)) if ipv4: try: ipv4.full_clean() ipv4.save() saved_ipv4.append(ipv4) self.verbose('Saved ipv4 %s' % ipv4.address) except Exception: tb = traceback.format_exc() self.message( 'Could not save ipv4 %s, got exception:\n\n%s' % (ipv4.address, tb)) if ipv6: try: ipv6.full_clean() ipv6.save() saved_ipv6.append(ipv6) self.verbose('Saved ipv6 %s' % ipv6.address) except Exception: tb = traceback.format_exc() self.message( 'Could not save ipv6 %s, got exception:\n\n%s' % (ipv6.address, tb)) self.message('saved %d interfaces into local DB' % len(saved_interfaces)) self.message('saved %d vaps into local DB' % len(saved_vaps)) self.message('saved %d ipv4 addresses into local DB' % len(saved_ipv4)) self.message('saved %d ipv6 addresses into local DB' % len(saved_ipv6)) self.saved_interfaces = saved_interfaces self.saved_vaps = saved_vaps self.saved_ipv4 = saved_ipv4 self.saved_ipv6 = saved_ipv6
def to_internal_value(self, value): try: return ip.IPAddress(value) except (ip.AddrFormatError, ValueError): raise ValidationError(_('Invalid ip address'))