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 path53Trusted 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 MediumSecurityUsing bundler, the process is similar:
bundle --trust-policy MediumSecurityWhy 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.pemYou 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 zoneWith 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'
endThere’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')
endIf 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.