#!/usr/bin/env python3 import pynetbox import argparse from dns import rdatatype from dns import rdataclass from dns.rdtypes.ANY.SOA import SOA from dns.rdtypes.ANY.NS import NS from dns.rdtypes.ANY.CNAME import CNAME from dns.rdtypes.IN.A import A from dns.zone import Zone from pathlib import Path from pprint import pprint def build_auth_dns_zones(nb: pynetbox.api, nox_dir: Path): zones_dir = nox_dir / "data" / "zones" zones_dir.mkdir(parents=True,exist_ok=True) print(f"Fetching IPAM data to build authorative zonefiles in {zones_dir}") print(f"Building zone eh22.intern") zonefile_path = zones_dir / "eh22.intern.zone" # build zone management stuff (SOA record, NS record) zone = Zone(origin="eh22.intern") zone.get_rdataset("@", rdtype=rdatatype.SOA, create=True)\ .add(SOA(rdclass=rdataclass.IN, rdtype=rdatatype.SOA, mname="auth-dns.noc.eh22.intern.", rname="noc.eh22.easterhegg.eu.", serial=1, refresh=7200, retry=3600, expire=3600000, minimum=60)) zone.get_rdataset("@", rdtype=rdatatype.NS, create=True)\ .add(NS(rdclass=rdataclass.IN, rdtype=rdatatype.NS, target="10.20.25.3")) # iterate over all ip addresses with dns names ending in noc.eh22.intern for i_addr in nb.ipam.ip_addresses.filter("eh22.intern"): raw_addr = i_addr.address.rsplit("/", maxsplit=1)[0] relative_name = i_addr.dns_name.removesuffix(".eh22.intern") # add A/AAAA record for the name itself if i_addr.family.value == 4: zone.get_rdataset(relative_name, rdtype=rdatatype.A, create=True)\ .add(A(rdclass=rdataclass.IN, rdtype=rdatatype.A, address=raw_addr)) else: raise RuntimeError(f"Got unknown IP family {i_addr.family} ({i_addr.family.value})") # add CNAME records for all registered alternative names if i_addr.custom_fields["altnames"]: for i_altname in i_addr.custom_fields["altnames"].split(","): i_altname = i_altname.strip().removesuffix(".eh22.intern") zone.get_rdataset(i_altname, rdtype=rdatatype.CNAME, create=True)\ .add(CNAME(rdclass=rdataclass.IN, rdtype=rdatatype.CNAME, target=relative_name + ".eh22.intern.")) with open(zonefile_path, mode="w") as f: zone.to_file(f, want_comments=True, want_origin=True) def main(): argp = argparse.ArgumentParser(prog="fetch-netbox-data", description="Fetch current IPAM data from netbox") argp.add_argument("--base-url", default="https://netbox.eh22.easterhegg.eu", help="URL of the netbox installation") argp.add_argument("--token", required=True, help="Netbox API Token") argp.add_argument("--nox-dir", required=True, type=Path, help="Path to the nox repository") args = argp.parse_args() nb = pynetbox.api(args.base_url, token=args.token) build_auth_dns_zones(nb, args.nox_dir) if __name__ == "__main__": main()