DEV Community

Ken Moini
Ken Moini

Posted on

Automated DigitalOcean DNS ABCs: APIs, Bash, & cURL

This script is an extraction of another larger single-node Kubernetes on DigitalOcean deployer that can be read here:

So while doing the whole DevOps thing you usually have to build automation to deploy infrastructure and platforms. It's often not just Virtual Machines that you need to create and automate, but also DNS, networking, and more. When using Ansible and Terraform with the larger public cloud providers this is no problem, but sometimes the more niche providers such as DigitalOcean and Linode don't have mature modules and providers in those automation platforms.

Thankfully though, pretty much everyone has mature APIs available for use, including DigitalOcean and Linode! Yay, my friends are still cool! So in deploying a system to DigitalOcean with Ansible or Terraform we can create and use a Bash script wrapper that has some functions that call to the DigitalOcean API and process things for us.

So let's build out a Bash script that will:

  • Check to see if a DNS Zone exists for a supplied domain
  • Check to see if a specific record exists in that Zone
  • Create a record with a specific type and value
  • Add addition or delete and overwrite records when directed/forced

What-what-whaaaaat?

Beefy bits eh? I like providing the whole source upfront in case you wanna skip the small-talk, then stepping through the functionality to add detail. Let's review:

  • The commented set -x makes Bash print the invocation of each line as well, useful for debugging variables as they're expanded and passed around.
  • Set a few variables, the DO_PAT variable is imported when previously exported and set in the shell, otherwise is defined as blank. This is your DigitalOcean Personal Access Token, get one here.
  • Bash does not hoist functions like JavaScript does so functions needed earlier need to be defined before earlier. The print_help function is an example of that.
  • The if/while/switch-case defines and switches through arguments passed into the script, defines needed variables where supplied
  • Some arguments are required, so we check for $domain, $ip_addr, and $record_name
  • There are some programs that are required on the system this script is run, namely curl and jq - the Bash script has a checkForProgram function that will check for the existence of those programs
  • First up, the checkDomain function - this one is a pretty simple idea, before we do anything we want to make sure the domain in question has a Zone in DigitalOcean's DNS servers. We attempt to retrieve an existing domain from the DigitalOcean API and use jq to check to see if the returned JSON value is null or not
  • Next, we define the checkRecord function which takes in a supplied domain and record name+type. So say you wanted to check to see if the domain example.com has an A type record that is named k8s, or otherwise, that's to check if the A record for k8s.example.com exists or not.
  • Since you can store multiple records with the same name+type, we need to have a way to delete extra records that are stale. The deleteRecord function makes the API call to do exactly that with whatever DigitalOcean DNS Record ID it is passed.
  • Finally, the writeDNS function writes a DNS Record of the specified name, type, and value to a specific domain.

The rest of the script basically just goes through some logic to check if the domain exists, if so then check if the record exists - if not, create the specified record. There is also a forced override that will delete previous matched records and create the intended one.

Examples

Make sure to pass the executable bit to the script with chmod +x ./config_dns.sh

Before starting, take that DigitalOcean Personal Access Token and export it to a variable:

$ export DO_PAT="your-token-here"

1) Say we just used Ansible or Terraform to create a new Droplet. This new Droplet has an IP address of 12.34.56.78 and will be hosting our new blog at wombat-adventures.com and www.wombat-adventures.com. We can use this script like so:

$ ./config_dns.sh -d wombat-adventures.com \
                  -t "A" \
                  -r "@" \
                  -i "12.34.56.78"

$ ./config_dns.sh --domain wombat-adventures.com \
                  --type "A" \
                  --record "www" \
                  --ip "12.34.56.78"

2) You have a new Load Balancer with an IP Address of 98.76.54.43 and want to set a CNAME record at lb.internal.shootersbar.com, deleting any other records that match and ensuring only one exists with the new Load Balancer IP.

$ ./config_dns.sh -d shootersbar.com \
                  -t "CNAME" \
                  -r "lb.internal" \
                  -i "98.76.54.43" \
                  --force

3) You need to configure GMail/GSuite MX records for mail at hyperloop-sandwiches.net

$ ./config_dns.sh -d hyperloop-sandwiches.net \
                  -t "MX" \
                  -r "@" \
                  -i "ASPMX.L.GOOGLE.COM" \
                  -p "1" \
                  --force-add

$ ./config_dns.sh -d hyperloop-sandwiches.net \
                  -t "MX" \
                  -r "@" \
                  -i "ALT1.ASPMX.L.GOOGLE.COM" \
                  --priority "5" \
                  --force-add

$ ./config_dns.sh -d hyperloop-sandwiches.net \
                  -t "MX" \
                  -r "@" \
                  -i "ALT2.ASPMX.L.GOOGLE.COM" \
                  --priority "5" \
                  --force-add

$ ./config_dns.sh -d hyperloop-sandwiches.net \
                  -t "MX" \
                  -r "@" \
                  -i "ALT3.ASPMX.L.GOOGLE.COM" \
                  --priority "10" \
                  --force-add

$ ./config_dns.sh -d hyperloop-sandwiches.net \
                  -t "MX" \
                  -r "@" \
                  -i "ALT4.ASPMX.L.GOOGLE.COM" \
                  --priority "10" \
                  --force-add

That's that right there, pretty simple wrapper for the DigitalOcean API to set DNS records. It's fairly extensible, supports a wide range of records and use cases, and is pretty simple to plug into most pipelines and workflows so get to automatin'!

Top comments (0)