Re-structure for packaging

This commit is contained in:
2026-01-18 16:22:29 +01:00
parent 758d7effdc
commit ac0d54814a
13 changed files with 166 additions and 98 deletions

View File

@@ -7,3 +7,4 @@ Manage DNS zones and dynamic records.
* [Bind-Tools](https://www.isc.org/bind/) (if not bundled with Bind)
* [dnspython](https://www.dnspython.org)
* [prettytable](https://zetcode.com/python/prettytable/)
* [pyyaml](https://pyyaml.org)

42
pyproject.toml Normal file
View File

@@ -0,0 +1,42 @@
[build-system]
requires = ["setuptools >= 77.0.3"]
build-backend = "setuptools.build_meta"
[tool.setuptools.dynamic]
version = {attr = "dnsmgr.__version__"}
[project]
name = "dnsmgr"
dynamic = ["version"]
dependencies = [
"dnspython>=2.8.0",
"prettytable>=3.17.0",
"pyyaml>=6.0.3"
]
requires-python = ">=3.11"
authors = [
{name = "Thomas Oettli", email = "spacefreak@noop.ch"}
]
maintainers = [
{name = "Thomas Oettli", email = "spacefreak@noop.ch"}
]
description = "Manage DNS zones and dynamic records."
readme = "README.md"
license = "GPL-3.0-only"
keywords = ["dns"]
classifiers = [
"Development Status :: 4 - Beta",
"Topic :: Internet :: Name Service (DNS)",
"Intended Audience :: System Administrators",
"Programming Language :: Python :: 3"
]
[project.scripts]
dns-confgen = "dnsmgr.confgen:main"
dns-list-zones = "dnsmgr.list-zones:main"
dns-record-add = "dnsmgr.record-add:main"
dns-record-delete = "dnsmgr.record-delete:main"
dns-zone-add = "dnsmgr.zone-add:main"
dns-zone-delete = "dnsmgr.zone-delete:main"
dns-zone-list = "dnsmgr.zone-list:main"

View File

@@ -1,5 +1,3 @@
#!/usr/bin/env python3
import dns.name
import dns.tsig
import dns.rcode
@@ -20,6 +18,8 @@ from hashlib import sha1
from prettytable import PrettyTable
from shutil import chown
__version__ = "1.0.0"
__author__ = "Thomas Oettli <spacefreak@noop.ch>"
DEFAULT_CFGFILE = '/etc/dns-manager/config.yml'

15
dns-confgen → src/dnsmgr/confgen.py Executable file → Normal file
View File

@@ -1,19 +1,18 @@
#!/usr/bin/env python3
import argparse
import dnsmgr
import sys
from . import DEFAULT_CFGFILE, DNSManager, printe
def main():
parser = argparse.ArgumentParser(description='Generate Bind config files.')
parser.add_argument('-c', '--config', help='path to config file', default=dnsmgr.DEFAULT_CFGFILE)
parser.add_argument('-c', '--config', help='path to config file', default=DEFAULT_CFGFILE)
args = parser.parse_args()
try:
manager = dnsmgr.DNSManager(cfgfile=args.config)
manager = DNSManager(cfgfile=args.config)
except RuntimeError as e:
dnsmgr.printe(f'config: {e}')
printe(f'config: {e}')
sys.exit(100)
try:
@@ -25,7 +24,7 @@ def main():
print('OK')
except RuntimeError as e:
dnsmgr.printe(e)
printe(e)
sys.exit(150)
print('Reloading named... ', end='')
@@ -34,7 +33,7 @@ def main():
manager.named_reload()
print('OK')
except RuntimeError as e:
dnsmgr.printe(e)
printe(e)
sys.exit(170)

14
dns-list-zones → src/dnsmgr/list-zones.py Executable file → Normal file
View File

@@ -1,9 +1,7 @@
#!/usr/bin/env python3
import argparse
import dnsmgr
import sys
from . import DEFAULT_CFGFILE, DNSManager, printe, prettytable
from json import dumps
@@ -13,7 +11,7 @@ def main():
formatter_class=lambda prog: argparse.HelpFormatter(
prog, max_help_position=45, width=140))
parser.add_argument('-a', '--all-zones', help='do not ignore zones that are not managed', action='store_true')
parser.add_argument('-c', '--config', help='path to config file', default=dnsmgr.DEFAULT_CFGFILE)
parser.add_argument('-c', '--config', help='path to config file', default=DEFAULT_CFGFILE)
parser.add_argument('-d', '--decode', help='decode internationalized domain names (IDN)', action='store_true')
output = parser.add_mutually_exclusive_group()
output.add_argument('-j', '--json', help='print json format', action='store_true')
@@ -22,15 +20,15 @@ def main():
args = parser.parse_args()
try:
manager = dnsmgr.DNSManager(cfgfile=args.config)
manager = DNSManager(cfgfile=args.config)
except RuntimeError as e:
dnsmgr.printe(f'config: {e}')
printe(f'config: {e}')
sys.exit(100)
try:
zones = manager.all_zones if args.all_zones else manager.zones
except RuntimeError as e:
dnsmgr.printe(e)
printe(e)
sys.exit(150)
zones.sort(key=lambda zone: zone.origin.to_unicode() if args.decode else zone.origin.to_text())
@@ -63,7 +61,7 @@ def main():
if args.all_zones:
row.append(zone.cfgfile is not None)
rows.append(row)
print(dnsmgr.prettytable(field_names, rows))
print(prettytable(field_names, rows))
print(f'\nTotal: {len(rows)}\n')

49
dns-record-add → src/dnsmgr/record-add.py Executable file → Normal file
View File

@@ -1,11 +1,24 @@
#!/usr/bin/env python3
import argparse
import dns.rdataclass
import dns.rdataset
import dnsmgr
import sys
from . import (
DEFAULT_CFGFILE,
NAMED_DEFAULT_VIEW,
DNSManager,
input_name,
input_rdata,
input_ttl,
input_yes_no,
name_from_text,
printe,
rdata_from_text,
select_type,
ttl_from_text,
type_from_text
)
def main():
preparser = argparse.ArgumentParser(add_help=False)
@@ -18,7 +31,7 @@ def main():
parser.add_argument('-a', '--all-zones', help='allow zones that are not managed', action='store_true')
parser.add_argument('-A', '--all-types', help='allow unsupported record types', action='store_true')
parser.add_argument('-b', '--batch', help='run in batch mode (no user input)', action='store_true')
parser.add_argument('-c', '--config', help='path to config file', default=dnsmgr.DEFAULT_CFGFILE)
parser.add_argument('-c', '--config', help='path to config file', default=DEFAULT_CFGFILE)
parser.add_argument('zone', metavar='ZONE[@VIEWS]', nargs=nargs, help='DNS zone name and optional list of views (comma separated or asterisk to select all views)', default=None)
parser.add_argument('name', metavar='NAME', nargs=nargs, help='DNS record name', default=None)
parser.add_argument('ttl', metavar='TTL', nargs=nargs, help='DNS record TTL in seconds', type=int, default=None)
@@ -27,9 +40,9 @@ def main():
args = parser.parse_args()
try:
manager = dnsmgr.DNSManager(cfgfile=args.config)
manager = DNSManager(cfgfile=args.config)
except RuntimeError as e:
dnsmgr.printe(f'config: {e}')
printe(f'config: {e}')
sys.exit(100)
try:
@@ -41,27 +54,27 @@ def main():
origin = zones[0].origin
if args.name is None:
name = dnsmgr.input_name(origin, prompt='Record name')
name = input_name(origin, prompt='Record name')
else:
name = dnsmgr.name_from_text(args.name, origin)
name = name_from_text(args.name, origin)
if args.ttl is None:
ttl = dnsmgr.input_ttl()
ttl = input_ttl()
else:
ttl = dnsmgr.ttl_from_text(args.ttl)
ttl = ttl_from_text(args.ttl)
if args.type is None:
rdtype = dnsmgr.select_type(args.all_types)
rdtype = select_type(args.all_types)
else:
rdtype = dnsmgr.type_from_text(args.type, args.all_types)
rdtype = type_from_text(args.type, args.all_types)
if not args.value:
rdata = dnsmgr.input_rdata(rdtype, origin)
rdata = input_rdata(rdtype, origin)
else:
rdata = dnsmgr.rdata_from_text(rdtype, ' '.join(args.value), origin)
rdata = rdata_from_text(rdtype, ' '.join(args.value), origin)
except RuntimeError as e:
dnsmgr.printe(e)
printe(e)
sys.exit(150)
except KeyboardInterrupt:
sys.exit(0)
@@ -75,12 +88,12 @@ def main():
print(f'View: {zone.view}')
print(f'\033[32m+ {name} {text}\033[0m\n')
if not dnsmgr.input_yes_no():
if not input_yes_no():
sys.exit(0)
for zone in zones:
origin = zone.origin.to_text(omit_final_dot=True)
if len(zones) > 1 or zone.view != dnsmgr.NAMED_DEFAULT_VIEW:
if len(zones) > 1 or zone.view != NAMED_DEFAULT_VIEW:
origin = f'{origin}@{zone.view}'
print(f"Sending DDNS updates for '{origin}'... ", end='')
@@ -88,7 +101,7 @@ def main():
manager.add_zone_record(zone, name, rdataset)
print('OK')
except RuntimeError as e:
dnsmgr.printe(e)
printe(e)
sys.exit(160)

46
dns-record-delete → src/dnsmgr/record-delete.py Executable file → Normal file
View File

@@ -1,10 +1,20 @@
#!/usr/bin/env python3
import argparse
import dns.rdataclass
import dnsmgr
import sys
from . import (
DEFAULT_CFGFILE,
NAMED_DEFAULT_VIEW,
RECORD_TYPES,
DNSManager,
input_yes_no,
name_from_text,
prettyselect,
printe,
rdata_from_text,
type_from_text,
)
def main():
preparser = argparse.ArgumentParser(add_help=False)
@@ -16,7 +26,7 @@ def main():
parser.add_argument('-a', '--all-zones', help='allow zones that are not managed', action='store_true')
parser.add_argument('-A', '--all-types', help='allow unsupported record types', action='store_true')
parser.add_argument('-b', '--batch', help='run in batch mode (no user input)', action='store_true')
parser.add_argument('-c', '--config', help='path to config file', default=dnsmgr.DEFAULT_CFGFILE)
parser.add_argument('-c', '--config', help='path to config file', default=DEFAULT_CFGFILE)
parser.add_argument('zone', metavar='ZONE[@VIEWS]', nargs=nargs, help='DNS zone name and optional list of views (comma separated or asterisk to select all views)', default=None)
parser.add_argument('name', metavar='NAME', nargs=nargs, help='DNS record name', default=None)
parser.add_argument('type', metavar='TYPE', nargs=nargs, help='DNS record type', default=None)
@@ -24,9 +34,9 @@ def main():
args = parser.parse_args()
try:
manager = dnsmgr.DNSManager(cfgfile=args.config)
manager = DNSManager(cfgfile=args.config)
except RuntimeError as e:
dnsmgr.printe(f'config: {e}')
printe(f'config: {e}')
sys.exit(100)
try:
@@ -43,10 +53,10 @@ def main():
if args.name is None:
names = sorted(set([name.to_unicode() for name in zone for zone in zones]))
rows = [[name] for name in names]
index = dnsmgr.prettyselect(['Record name'], rows, prompt='Select record name')
index = prettyselect(['Record name'], rows, prompt='Select record name')
args.name = names[index]
name = dnsmgr.name_from_text(args.name, origin)
name = name_from_text(args.name, origin)
for zone in zones:
zone.filter_by_name(name, origin)
@@ -58,13 +68,13 @@ def main():
if args.type is None:
rdtypes = sorted(set([rdataset.rdtype for rdataset in zone.get_node(name) for zone in zones]))
if not args.all_types:
rdtypes = list(filter(lambda rdtype: rdtype in dnsmgr.RECORD_TYPES, rdtypes))
rdtypes = list(filter(lambda rdtype: rdtype in RECORD_TYPES, rdtypes))
rdtypes = [rdtype.to_text(rdtype) for rdtype in rdtypes]
rows = [[rdtype] for rdtype in rdtypes]
index = dnsmgr.prettyselect(['Record type'], rows, prompt='Select record type')
index = prettyselect(['Record type'], rows, prompt='Select record type')
args.type = rdtypes[index]
rdtype = dnsmgr.type_from_text(args.type, args.all_types)
rdtype = type_from_text(args.type, args.all_types)
for zone in zones:
zone.filter_by_rdtype(rdtype)
@@ -74,7 +84,7 @@ def main():
raise RuntimeError(f"No such {rdtype.to_text(rdtype)} record -- '{name.to_text(True)}'")
rdata = None
if not args.value and not args.batch and not dnsmgr.input_yes_no(f'Delete all {rdtype.to_text(rdtype)}-records?'):
if not args.value and not args.batch and not input_yes_no(f'Delete all {rdtype.to_text(rdtype)}-records?'):
values = []
for zone in zones:
for rdataset in zone.get_node(name):
@@ -82,12 +92,12 @@ def main():
values.append(rdata.to_text(origin=zone.origin, relativize=False))
values = sorted(set(values))
rows = [[value] for value in values]
index = dnsmgr.prettyselect(['Record value'], rows, prompt='Select record value', truncate=True)
index = prettyselect(['Record value'], rows, prompt='Select record value', truncate=True)
args.value = [values[index]]
if args.value:
value = ' '.join(args.value)
rdata = dnsmgr.rdata_from_text(rdtype, value, origin)
rdata = rdata_from_text(rdtype, value, origin)
for zone in zones:
zone.filter_by_rdata(rdata)
@@ -96,7 +106,7 @@ def main():
raise RuntimeError(f"No such DNS record found -- {name.to_text(True)} IN {rdtype.to_text(rdtype)} {value}")
except RuntimeError as e:
dnsmgr.printe(e)
printe(e)
sys.exit(150)
except KeyboardInterrupt:
sys.exit(0)
@@ -115,12 +125,12 @@ def main():
print(f'\033[31m- {name} {rdataset.ttl} {rdclassstr} {rdtypestr} {text}\033[0m')
print()
if not dnsmgr.input_yes_no():
if not input_yes_no():
sys.exit(0)
for zone in zones:
origin = zone.origin.to_text(omit_final_dot=True)
if len(zones) > 1 or zone.view != dnsmgr.NAMED_DEFAULT_VIEW:
if len(zones) > 1 or zone.view != NAMED_DEFAULT_VIEW:
origin = f'{origin}@{zone.view}'
print(f"Sending DDNS updates for '{origin}'... ", end='')
@@ -131,7 +141,7 @@ def main():
manager.delete_zone_record(zone, name, rdataset)
print('OK')
except RuntimeError as e:
dnsmgr.printe(e)
printe(e)
sys.exit(160)

46
dns-zone-add → src/dnsmgr/zone-add.py Executable file → Normal file
View File

@@ -1,12 +1,20 @@
#!/usr/bin/env python3
import argparse
import dns.rdataclass
import dns.rdataset
import dns.rdatatype
import dnsmgr
import sys
from . import (
DEFAULT_CFGFILE,
NAMED_DEFAULT_VIEW,
DNSManager,
input_name,
input_yes_no,
name_views_from_text,
prettyselect,
printe,
rdata_from_text,
)
from time import sleep
@@ -18,32 +26,32 @@ def main():
parser = argparse.ArgumentParser(description='Add DNS zones.')
parser.add_argument('-b', '--batch', help='run in batch mode (no user input)', action='store_true')
parser.add_argument('-c', '--config', help='path to config file', default=dnsmgr.DEFAULT_CFGFILE)
parser.add_argument('-c', '--config', help='path to config file', default=DEFAULT_CFGFILE)
parser.add_argument('-t', '--config-template', help='config file/template (overrides value set in ZONE_TEMPLATES config option)', default=None)
parser.add_argument('-z', '--zone-template', help='zone file/template (overrides value set in ZONE_TEMPLATES config option)', default=None)
parser.add_argument('zone', metavar='ZONE[@VIEWS]', nargs=nargs, help='DNS zone name and optional list of views (comma separated or asterisk to select all views)', default=None)
args = parser.parse_args()
try:
manager = dnsmgr.DNSManager(cfgfile=args.config)
manager = DNSManager(cfgfile=args.config)
except RuntimeError as e:
dnsmgr.printe(f'config: {e}')
printe(f'config: {e}')
sys.exit(100)
managed_views = sorted(manager.config.zones_config.keys())
try:
if args.zone is None:
name = dnsmgr.input_name()
name = input_name()
rows = [[view] for view in managed_views]
index = dnsmgr.prettyselect(['View'], rows, prompt='Select view', also_valid=['*'])
index = prettyselect(['View'], rows, prompt='Select view', also_valid=['*'])
views = managed_views if index == '*' else [managed_views[index]]
else:
(name, views) = dnsmgr.name_views_from_text(args.zone)
(name, views) = name_views_from_text(args.zone)
if views is None:
if len(managed_views) > 1:
raise RuntimeError('multiple managed views configured but none specified')
elif managed_views[0] != dnsmgr.NAMED_DEFAULT_VIEW:
elif managed_views[0] != NAMED_DEFAULT_VIEW:
raise RuntimeError('the default view is not managed')
views = managed_views
elif views == '*':
@@ -59,7 +67,7 @@ def main():
raise RuntimeError(f'zone already exists in view {views}')
except RuntimeError as e:
dnsmgr.printe(e)
printe(e)
sys.exit(150)
except KeyboardInterrupt:
sys.exit(0)
@@ -70,13 +78,13 @@ def main():
print(f'View: {view}')
print(f'\033[32m+ {origin}\033[0m\n')
if not dnsmgr.input_yes_no():
if not input_yes_no():
sys.exit(0)
zones = []
for view in views:
origin = name.to_text(omit_final_dot=True)
if len(views) > 1 or view != dnsmgr.NAMED_DEFAULT_VIEW:
if len(views) > 1 or view != NAMED_DEFAULT_VIEW:
origin = f'{origin}@{view}'
print(f"Adding zone '{origin}'... ", end='')
@@ -87,7 +95,7 @@ def main():
if manager.config.zones_config[view].catalog_zone:
zones.append(zone)
except RuntimeError as e:
dnsmgr.printe(e)
printe(e)
sys.exit(160)
try:
@@ -95,7 +103,7 @@ def main():
manager.named_reload()
print('OK')
except RuntimeError as e:
dnsmgr.printe(e)
printe(e)
sys.exit(170)
if zones:
@@ -109,16 +117,16 @@ def main():
raise RuntimeError(f'catalog zone of view \'{zone.view}\': {e}')
origin = zone.origin.to_text(omit_final_dot=True)
if len(zones) > 1 or zone.view != dnsmgr.NAMED_DEFAULT_VIEW:
if len(zones) > 1 or zone.view != NAMED_DEFAULT_VIEW:
origin = f'{origin}@{zone.view}'
for catalog_zone in catalog_zones:
rdata = dnsmgr.rdata_from_text(dns.rdatatype.PTR, zone.origin.to_text(), catalog_zone.origin)
rdata = rdata_from_text(dns.rdatatype.PTR, zone.origin.to_text(), catalog_zone.origin)
rdataset = dns.rdataset.Rdataset(dns.rdataclass.IN, dns.rdatatype.PTR, ttl=3600)
rdataset.add(rdata)
rdname = dns.name.from_text(zone.nfz() + '.zones', catalog_zone.origin)
catalog_zone_origin = catalog_zone.origin.to_text(omit_final_dot=True)
if catalog_zone.view != dnsmgr.NAMED_DEFAULT_VIEW:
if catalog_zone.view != NAMED_DEFAULT_VIEW:
catalog_zone_origin += f'@{catalog_zone.view}'
try:
@@ -126,7 +134,7 @@ def main():
manager.add_zone_record(catalog_zone, rdname, rdataset)
print('OK')
except RuntimeError as e:
dnsmgr.printe(e)
printe(e)
if __name__ == '__main__':

27
dns-zone-delete → src/dnsmgr/zone-delete.py Executable file → Normal file
View File

@@ -1,12 +1,11 @@
#!/usr/bin/env python3
import argparse
import dns.rdataclass
import dns.rdataset
import dns.rdatatype
import dnsmgr
import sys
from . import DEFAULT_CFGFILE, NAMED_DEFAULT_VIEW, DNSManager, printe, input_yes_no
def main():
preparser = argparse.ArgumentParser(add_help=False)
@@ -16,14 +15,14 @@ def main():
parser = argparse.ArgumentParser(description='Delete DNS zones.')
parser.add_argument('-b', '--batch', help='run in batch mode (no user input)', action='store_true')
parser.add_argument('-c', '--config', help='path to config file', default=dnsmgr.DEFAULT_CFGFILE)
parser.add_argument('-c', '--config', help='path to config file', default=DEFAULT_CFGFILE)
parser.add_argument('zone', metavar='ZONE[@VIEWS]', nargs=nargs, help='DNS zone name and optional list of views (comma separated or asterisk to select all views)', default=None)
args = parser.parse_args()
try:
manager = dnsmgr.DNSManager(cfgfile=args.config)
manager = DNSManager(cfgfile=args.config)
except RuntimeError as e:
dnsmgr.printe(f'config: {e}')
printe(f'config: {e}')
sys.exit(100)
try:
@@ -32,7 +31,7 @@ def main():
else:
zones = manager.get_zones(args.zone)
except RuntimeError as e:
dnsmgr.printe(e)
printe(e)
sys.exit(150)
except KeyboardInterrupt:
sys.exit(0)
@@ -43,12 +42,12 @@ def main():
print(f'View: {zone.view}')
print(f'\033[31m- {origin}\033[0m\n')
if not dnsmgr.input_yes_no():
if not input_yes_no():
sys.exit(0)
for zone in zones:
origin = zone.origin.to_text(omit_final_dot=True)
if len(zones) > 1 or zone.view != dnsmgr.NAMED_DEFAULT_VIEW:
if len(zones) > 1 or zone.view != NAMED_DEFAULT_VIEW:
origin = f'{origin}@{zone.view}'
try:
@@ -72,7 +71,7 @@ def main():
continue
catalog_zone_origin = catalog_zone.origin.to_text(omit_final_dot=True)
if catalog_zone.view != dnsmgr.NAMED_DEFAULT_VIEW:
if catalog_zone.view != NAMED_DEFAULT_VIEW:
catalog_zone_origin += f'@{catalog_zone.view}'
print(f'Removing zone \'{origin}\' from catalog zone \'{catalog_zone_origin}\'... ', end='')
manager.delete_zone_record(catalog_zone, rdname, rdataset)
@@ -82,7 +81,7 @@ def main():
manager.delete_zone(zone)
print('OK')
except RuntimeError as e:
dnsmgr.printe(e)
printe(e)
sys.exit(160)
try:
@@ -90,12 +89,12 @@ def main():
manager.named_reload()
print('OK')
except RuntimeError as e:
dnsmgr.printe(e)
printe(e)
sys.exit(170)
for zone in zones:
origin = zone.origin.to_text(omit_final_dot=True)
if len(zones) > 1 or zone.view != dnsmgr.NAMED_DEFAULT_VIEW:
if len(zones) > 1 or zone.view != NAMED_DEFAULT_VIEW:
origin = f'{origin}@{zone.view}'
print(f"Cleanup zone files of zone '{origin}'... ", end='')
@@ -103,7 +102,7 @@ def main():
manager.cleanup_zone(zone)
print('OK')
except Exception as e:
dnsmgr.printe(e)
printe(e)
sys.exit(180)

20
dns-zone-list → src/dnsmgr/zone-list.py Executable file → Normal file
View File

@@ -1,10 +1,8 @@
#!/usr/bin/env python3
import argparse
import dnsmgr
import re
import sys
from . import NAMED_DEFAULT_VIEW, RECORD_TYPES, DEFAULT_CFGFILE, DNSManager, printe, prettytable
from dns.reversename import ipv4_reverse_domain, ipv6_reverse_domain
from json import dumps
@@ -19,7 +17,7 @@ def main():
parser.add_argument('-a', '--all-zones', help='do not ignore zones that are not managed', action='store_true')
parser.add_argument('-A', '--all-records', help='do not ignore unsupported record types', action='store_true')
parser.add_argument('-b', '--batch', help='run in batch mode (no user input)', action='store_true')
parser.add_argument('-c', '--config', help='path to config file', default=dnsmgr.DEFAULT_CFGFILE)
parser.add_argument('-c', '--config', help='path to config file', default=DEFAULT_CFGFILE)
parser.add_argument('-d', '--decode', help='decode internationalized domain names (IDN)', action='store_true')
parser.add_argument('zone', metavar='ZONE[@VIEWS]', nargs=nargs, help='DNS zone name and optional list of views (comma separated or asterisk to select all views)', default=None)
output = parser.add_mutually_exclusive_group()
@@ -29,9 +27,9 @@ def main():
args = parser.parse_args()
try:
manager = dnsmgr.DNSManager(cfgfile=args.config)
manager = DNSManager(cfgfile=args.config)
except RuntimeError as e:
dnsmgr.printe(f'config: {e}')
printe(f'config: {e}')
sys.exit(100)
try:
@@ -41,7 +39,7 @@ def main():
zones = manager.get_zones(args.zone, args.all_zones)
except RuntimeError as e:
dnsmgr.printe(e)
printe(e)
sys.exit(150)
except KeyboardInterrupt:
sys.exit(0)
@@ -53,13 +51,13 @@ def main():
try:
manager.get_zone_content(zone)
except RuntimeError as e:
dnsmgr.printe(f"zone transfer of '{zone.origin.to_text(True)}@{zone.view}': {e}")
printe(f"zone transfer of '{zone.origin.to_text(True)}@{zone.view}': {e}")
sys.exit(160)
records = []
for name, node in zone.items():
for rdataset in node:
if not args.all_records and rdataset.rdtype not in dnsmgr.RECORD_TYPES:
if not args.all_records and rdataset.rdtype not in RECORD_TYPES:
continue
for value in rdataset:
records.append({
@@ -101,9 +99,9 @@ def main():
row = [record['name'], record['ttl'], record['type'], record['value']]
rows.append(row)
if len(views) > 1 or view != dnsmgr.NAMED_DEFAULT_VIEW:
if len(views) > 1 or view != NAMED_DEFAULT_VIEW:
print(f'View: {view}')
print(dnsmgr.prettytable(field_names, rows, truncate=True))
print(prettytable(field_names, rows, truncate=True))
print()