Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions zoneforge/api/zones.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from zoneforge.core import (
get_zones,
create_zone,
create_zone_from_text,
delete_zone,
create_record,
update_record,
Expand Down Expand Up @@ -126,6 +127,25 @@
},
)

zone_import_parser = reqparse.RequestParser()
zone_import_parser.add_argument(
"content", type=str, help="Content of the DNS Zone file", required=True
)

zone_export_model = api.model(
"DnsZoneExport",
{
"name": fields.String(example="example.com."),
"content": fields.String(
example="""
$ORIGIN example.com.
@ 36000 IN SOA ns1 hostmaster 20250116 28800 1800 2592000 86400 ; minimum (1 day)
@ 86400 IN NS ns1
"""
),
},
)

zone_transfer_parser = reqparse.RequestParser()
zone_transfer_parser.add_argument(
"zone_name",
Expand Down Expand Up @@ -327,6 +347,39 @@ def delete(self, zone_name: str):
raise NotFound("A zone with that name does not exist.")


@api.route("/<string:zone_name>/import")
class DnsZoneImport(Resource):
@api.marshal_with(zone_model)
def post(self, zone_name: str):
args = zone_import_parser.parse_args()
dns_name = dns.name.from_text(zone_name)
new_zone = create_zone_from_text(
zone_name=dns_name,
zone_text=args["content"],
zonefile_folder=current_app.config["ZONE_FILE_FOLDER"],
)
return new_zone.to_response()


@api.route("/<string:zone_name>/export")
class DnsZoneExport(Resource):
@api.marshal_with(zone_export_model)
def get(self, zone_name: str):
dns_name = dns.name.from_text(zone_name)
export_zone = get_zones(
zonefile_folder=current_app.config["ZONE_FILE_FOLDER"],
zone_name=dns_name,
)[0]
if not export_zone:
raise NotFound("A zone with that name does not exist.")

export_data = {
"zone_name": zone_name,
"content": export_zone.to_text(),
}
return export_data


@api.route("/transfer")
class DnsZoneInboundTransfer(Resource):
@api.expect(zone_transfer_parser)
Expand Down
18 changes: 17 additions & 1 deletion zoneforge/core/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ def __setattr__(self, name, value):
else:
setattr(self._zone, name, value)

def to_response(self):
def to_response(self) -> dict:
res = {}
res["name"] = self.origin.to_text()
res["record_count"] = self.record_count
Expand Down Expand Up @@ -150,6 +150,22 @@ def create_zone(
return new_zfzone


def create_zone_from_text(
zone_name: dns.name.Name, zone_text: str, zonefile_folder: str
) -> ZFZone:
try:
new_zone = dns.zone.from_text(
text=zone_text,
origin=zone_name,
relativize=True,
)
except dns.exception.SyntaxError as e:
raise BadRequest("Invalid zone file content was provided") from e
new_zfzone = ZFZone(zone=new_zone, zonefile_folder=zonefile_folder)
new_zfzone.write_to_file()
return new_zfzone


def delete_zone(zone_name: dns.name.Name, zonefile_folder: str) -> bool:
zone_file_name = join(zonefile_folder, f"{zone_name}zone")
if exists(zone_file_name):
Expand Down