Skip to content

Instantly share code, notes, and snippets.

@nZac
Created May 27, 2020 17:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nZac/88c11168d1dd49a3b785bca2bf9d7069 to your computer and use it in GitHub Desktop.
Save nZac/88c11168d1dd49a3b785bca2bf9d7069 to your computer and use it in GitHub Desktop.
Convert R53 to TF
#!/usr/bin/env python3
import argparse
from typing import List, Optional
import dataclasses
import enum
INDENT = ' '
class DNSRecordType(enum.Enum):
# https://en.wikipedia.org/wiki/List_of_DNS_record_types
A = "A"
AAAA = "AAAA"
CNAME = "CNAME"
MX = "MX"
NS = "NS"
PTR = "PTR"
SOA = "SOA"
SRV = "SRV"
TXT = "TXT"
@dataclasses.dataclass
class DNSRecord:
type: DNSRecordType
name: str
domain: str
ttl: int
value: List[str]
priority: Optional[int] = None
@property
def domain_resource_name(self):
return self.domain.rstrip('.').replace('.', '_')
@property
def aws_zone_reference_name(self):
return f"aws_route53_zone.{self.domain_resource_name}.id"
@property
def values_to_list(self):
values = '['
for v in self.value:
values = values + f"\n{INDENT * 2}\"" + v.replace("\"", "") + "\","
values = values + f'\n{INDENT}]'
return values
@property
def tf_aws_rendered_zone(self) -> List[str]:
lines: List[str] = []
lines.append(f'resource "aws_route53_zone" "{self.domain_resource_name}" {{')
lines.append(f" name = \"{self.domain}\"")
lines.append("}")
return lines
@property
def terraform_aws_rendered_record(self) -> List[str]:
lines: List[str] = []
lines.append(f'resource "aws_route53_record" "{self.resource_name}" {{')
lines.append(f'{INDENT}zone_id = {self.aws_zone_reference_name}')
lines.append(f'{INDENT}name = "{self.name_without_domain}"')
lines.append(f'{INDENT}type = "{self.type.value}"')
lines.append(f'{INDENT}ttl = "{self.ttl}"')
lines.append(f'{INDENT}records = {self.values_to_list}')
lines.append('}')
return lines
@property
def resource_name(self):
rec = self.name.rstrip('.')
name = rec.replace(self.domain, "").rstrip('.').replace(".", "_").lower() or "naked"
full = f'{self.domain_resource_name}_{self.type.value.lower()}_{name}'
final = full.replace('__', '_')[0:60]
return final
@property
def name_without_domain(self) -> str:
name = self.name.replace(self.domain, "").rstrip(".")
return name if name else "@"
def get_r53_records(hosted_zone_id: str) -> List[DNSRecordType]:
import boto3
r53_client = boto3.client("route53")
domain = r53_client.get_hosted_zone(Id=hosted_zone_id)['HostedZone']['Name'].rstrip('.')
is_truncated = True
next_record_name = ""
next_record_type = ""
records = []
while is_truncated:
extras = dict(
StartRecordName=next_record_name,
StartRecordType=next_record_type,
) if next_record_name or next_record_type else dict()
resp = r53_client.list_resource_record_sets(
HostedZoneId=hosted_zone_id,
**extras,
)
records = records + resp['ResourceRecordSets']
is_truncated = resp['IsTruncated']
if is_truncated:
next_record_name = resp.get('NextRecordName')
next_record_type = resp.get('NextRecordType')
return [
DNSRecord(
type=DNSRecordType[r["Type"]],
name=r["Name"],
domain=domain,
ttl=r["TTL"],
value=[
x["Value"] for x in r["ResourceRecords"]
]
)
for r in records
]
def create_file_for_r53_zone(args: argparse.Namespace) -> None:
records: List[DNSRecord] = get_r53_records(args.hosted_zone_id)
if not records:
return
lines: List[str] = []
if args.create_zone:
lines = lines + records[0].tf_aws_rendered_zone + [""]
for rec in records:
if rec.type == DNSRecordType.SOA:
continue
lines = lines + rec.terraform_aws_rendered_record + [""]
for l in lines:
print(l)
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Import DNS records from Name.com")
parser.add_argument("--create-zone", action="store_true")
parser.set_defaults(handler=lambda args: print("Missing subcommand"))
subs = parser.add_subparsers(title="create dns from different sources")
r53 = subs.add_parser(name="r53", help="create dns records from R53 hosted zone")
r53.add_argument("hosted_zone_id", action="store")
r53.set_defaults(handler=create_file_for_r53_zone)
args = parser.parse_args()
# Call the subcommand handler
args.handler(args)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment