Using Python to migrate DigitalOcean domains to Terraform managed
·2 mins
I was thinking about migrating some cloud services into Terraform, but we seemed to have too many domains. So I wrote a small python script that takes a domain, then using doctl (the DigitalOcean command line) it extracts all current records. After that it outputs the file into tf and also gives a import command to import the current state in Terraform state. This assumes you already installed and configured both doctl and Terraform with the Digitalocean cloud provider.
The usage is simple:
$ python3 doctl-domain-to-terraform.py techwolf12.nl
This would then give an output similar to:
tf file:
resource "digitalocean_domain" "techwolf12_nl" {
name = "techwolf12.nl"
}
resource "digitalocean_record" "techwolf12_nl_NS_" {
domain = digitalocean_domain.techwolf12_nl.id
type = "NS"
name = "@"
value = "ns1.digitalocean.com."
}
resource "digitalocean_record" "techwolf12_nl_NS__" {
domain = digitalocean_domain.techwolf12_nl.id
type = "NS"
name = "@"
value = "ns2.digitalocean.com."
}
Import commands:
terraform import digitalocean_domain.techwolf12_nl techwolf12.nl
terraform import digitalocean_record.techwolf12_nl_NS_ techwolf12.nl,1234567
terraform import digitalocean_record.techwolf12_nl_NS__ techwolf12.nl,7654321
You can import this as TF file and then use the import commands to import the current state.
The code is available here, save it as a file and run it as instructed above:
"""Doctl Domain to Terraform
Made by Techwolf12, more info: https://techwolf12.nl/blog/using-python-migrate-digitalocean-domains-terraform-managed
"""
import subprocess
import sys
import json
def get_unique_resource(resource_string):
if resource_string in list_of_record_resource_strings:
return get_unique_resource(f'{resource_string}_')
else:
list_of_record_resource_strings.append(resource_string)
return resource_string
if len(sys.argv) < 2:
print("Need domain as argument")
quit(1)
domain = sys.argv[1]
output = subprocess.run(['doctl', 'compute', 'domain', 'records', 'list', '-o', 'json', domain.encode('utf-8')], stdout=subprocess.PIPE).stdout.decode('utf-8')
records = json.loads(output)
domain_resource = str(domain).replace('.', '_')
import_commands = ""
list_of_record_resource_strings = list()
print("tf file:\n\n")
print(f'''
resource "digitalocean_domain" "{domain_resource:s}" {{
name = "{domain:s}"
}}
''')
import_commands += f'terraform import digitalocean_domain.{domain_resource:s} {domain:s}\n'
supported_records = ['A', 'AAAA', 'CAA', 'CNAME', 'MX', 'NS', 'TXT', 'SRV']
for record in records:
if record.get('type') in supported_records:
record_name = record.get("name").replace(".", "_") if record.get("name") != "@" else ""
resource = get_unique_resource(f'{domain_resource:s}_{record.get("type")}_{record_name}')
record_value = record.get("data").replace("\"","\\\"")
if record.get('type') in ['CNAME', 'MX', 'NS']:
record_value += "."
print(f'resource "digitalocean_record" "{resource}" {{')
print(f' domain = digitalocean_domain.{domain_resource:s}.id')
print(f' type = "{record.get("type")}"')
if record.get('type') == 'MX':
print(f' priority = "{record.get("priority")}"')
print(f' name = "{record.get("name")}"')
print(f' value = "{record_value}"')
print("}\n")
import_commands += f'terraform import digitalocean_record.{resource} {domain},{record.get("id")}\n'
print("\n\nImport commands:\n\n")
print(import_commands)
Onto next time! :)