Created
May 27, 2020 17:17
-
-
Save nZac/88c11168d1dd49a3b785bca2bf9d7069 to your computer and use it in GitHub Desktop.
Convert R53 to TF
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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