Path53
Overview
path53
provides a cleaner, simpler interface to Route53 change requests.
Why does this exist?
Because making simple changes is unreasonably complicated. Route53’s errors are
generic, the request structure is a nested mess of complexity, and the
validation rules are often surprising. path53
aims to tame this complexity.
Installation
gem install path53
Trusted Installation
path53
is cryptographically signed. You can verify that it hasn’t been
tampered with (and really should, since calling apply!
acts on your AWS
account with your credentials).
Assuming you have trusted the certificate, you can perform a trusted installation like so:
gem install path53 --trust-policy MediumSecurity
Using bundler
, the process is similar:
bundle --trust-policy MediumSecurity
Why MediumSecurity?
MediumSecurity
requires valid signatures on signed gems, but allows unsigned
dependencies. While path53
has few dependencies, not all of them are signed.
Using HighSecurity
will fail unless all dependencies are signed.
Trusting the signing certificate
A copy of the public key is included in the repository for verification.
Assuming you’ve cloned the repository to ./path53
, you can add it to your list
of trusted keys like so:
gem cert --add ./path53/trust/certificates/colstrom.cert.pem
You can also fetch the key directly from GitHub.
For modern shells like fish
, use the following:
gem cert --add (curl -s https://raw.githubusercontent.com/colstrom/path53/master/trust/certificates/colstrom.cert.pem | psub)
For vintage shells like bash
, use the following:
gem cert add <(curl -s https://raw.githubusercontent.com/colstrom/path53/master/trust/certificates/colstrom.cert.pem)
Usage
First, we need to require it.
require 'path53'
We need a HostedZone to change. This can come from the Route53 API, but for the purposes of this example, we’ll use a simple fixture.
Zone = Struct.new :id, :name
zone = Zone.new 'abc123', 'example.com.'
The primary feature of path53
is changesets. Let’s create one now:
changes = Path53::ChangeSet.new zone
With a changeset, we now create a batch of changes, using a block.
changes.batch do
add upsert a 'example.com', '127.0.0.1'
add upsert cname 'www.example.com.', 'example.com'
end
There’s a fair bit going on in there, so let’s have a look.
add
says we want to add a change to this batch. remove
would do the
opposite.
upsert
is what this change should do. create
, delete
, and upsert
are all
valid here.
a
and cname
describe the type of record we want to change. Any standard DNS
record type would valid here.
In the context of the a
record, example.com
refers to the name of the
record, and 127.0.0.1
refers to the target of that record.
Now that we have a batch of changes, simply call apply!
to apply them.
changes.apply!
Want more?
As a convenient shorthand, you can do the following:
Path53.change(zone).batch { add upsert a 'www.example.com', '127.0.0.1' }.apply!
If you leave out an action, path53
will assume you meant to upsert
.
Therefore, this is equivalent to the previous example:
Path53.change(zone).batch { add a 'www.example.com', '127.0.0.1' }.apply!
path53
plays nicely with aws-sdk
. If you’re working with ELBs for instance,
you can pass a LoadBalancerDescription as a target, and path53
will do the
right thing. Therefore, the following is valid:
Path53.change(zone).batch { add a 'www.example.com', MyLoadBalancer }.apply!
Alias Targets are supported as well:
Path53.change(zone).batch { add a 'www.example.com', alias_target('zone_id', 'name') }.apply!
You may be wondering what’s up with the remove
method for changesets. Well, it
turns out path53
makes it really easy to cache things.
require 'yaml'
changes = Path53.change(zone).batch { add a 'www.example.com', '127.0.0.1' }
File.write 'saved-changes', YAML.dump(changes)
restored = YAML.load File.read 'saved-changes'
restored.apply!
This is useful when you have a changeset that is expensive to calculate, or you want to hold state for some reason.
Even more?
Most methods in path53
support partial evaluation. The following is valid:
Path53.change(zone).batch do
www = a 'www.example.com'
add www.('127.0.0.1')
end
If for some reason you wanted to do that. It’s pretty handy in an
each_with_object
block, as an example.
License
path53
is available under the MIT License. See LICENSE.txt
for the full text.