r53.py is a simple commandline tool to help you manage your AWS Route 53 DNS records. It interfaces with AWS via boto: http://code.google.com/p/boto/ . It supports a workflow where a canonical zone file is managed via version control and pushed to AWS. This is different, but complementary to, https://github.com/barnybug/cli53 . We recommend these tools be used in concert. This tool was developed at foursquare.com, where we use it to manage our DNS. It is offered under the MIT license.

Features:
- Maintains your own canonical version of your DNS configs under source control.
- Calculates the minimal changeset required to accomplish a DNS change.
- Enforces Route 53 API constraints (see http://docs.amazonwebservices.com/Route53/latest/APIReference/)

Requirements:
boto: http://code.google.com/p/boto/
lxml: http://lxml.de/

Installation:
Super easy!
$ pip install r53

Sample usage:
$ r53.py --help
usage: r53.py [-h] [--push file_to_push.xml] [--pull] [--confirm] [--verbose]
              --zone foursquare.com

Push/pull Amazon Route 53 configs.

optional arguments:
  -h, --help            show this help message and exit
  --push file_to_push.xml
                        Push the config in this file to R53.
  --pull                Dump current R53 config to stdout.
  --confirm             Do not prompt before push.
  --verbose
  --zone foursquare.com
                        Zone to push/pull.
$ cli53 create test.domain
HostedZone:
  CallerReference: d35c4ced-c89b-474d-8703-08430eb92a8f
  Config:
    Comment:
  Id: /hostedzone/Z32RY3SDPIRMZ0
  Name: test.domain.
ChangeInfo:
  Status: PENDING
  SubmittedAt: 2011-08-31T00:34:18.518Z
  Id: /change/C2H851FU66F9RY
DelegationSet:
  NameServers:
    - ns-929.awsdns-52.net
    - ns-1276.awsdns-31.org
    - ns-314.awsdns-39.com
    - ns-1608.awsdns-09.co.uk
$ r53.py --pull --zone=test.domain | tee test.domain.xml
looking up zone for test.domain
fetching live config for zone Z32RY3SDPIRMZ0
<ResourceRecordSets xmlns="https://route53.amazonaws.com/doc/2011-05-05/">
  <ResourceRecordSet>
    <Name>test.domain.</Name>
    <Type>NS</Type>
    <TTL>172800</TTL>
    <ResourceRecords>
      <ResourceRecord>
        <Value>ns-929.awsdns-52.net.</Value>
      </ResourceRecord>
      <ResourceRecord>
        <Value>ns-1276.awsdns-31.org.</Value>
      </ResourceRecord>
      <ResourceRecord>
        <Value>ns-314.awsdns-39.com.</Value>
      </ResourceRecord>
      <ResourceRecord>
        <Value>ns-1608.awsdns-09.co.uk.</Value>
      </ResourceRecord>
    </ResourceRecords>
  </ResourceRecordSet>
  <ResourceRecordSet>
    <Name>test.domain.</Name>
    <Type>SOA</Type>
    <TTL>900</TTL>
    <ResourceRecords>
      <ResourceRecord>
        <Value>ns-929.awsdns-52.net. awsdns-hostmaster.amazon.com. 1 7200 900 1209600 86400</Value>
      </ResourceRecord>
    </ResourceRecords>
  </ResourceRecordSet>
</ResourceRecordSets>

# MAD EDITS HAPPEN

$ r53.py --push=test.domain.xml --zone=test.domain
looking up zone for test.domain
fetching live config for zone Z32RY3SDPIRMZ0
==CHANGESET==
<ChangeResourceRecordSetsRequest xmlns="https://route53.amazonaws.com/doc/2011-05-05/">
  <ChangeBatch>
    <Comment>Generated by r53.py for coops@lol at 2011-08-31 00:41:07.</Comment>
    <Changes>
      <Change>
        <Action>CREATE</Action>
        <ResourceRecordSet>
          <Name>www.test.domain.</Name>
          <Type>CNAME</Type>
          <TTL>900</TTL>
          <ResourceRecords>
            <ResourceRecord>
              <Value>test.domain.</Value>
            </ResourceRecord>
          </ResourceRecords>
        </ResourceRecordSet>
      </Change>
    </Changes>
  </ChangeBatch>
</ChangeResourceRecordSetsRequest>

Push y/N? y
$

# MO' EDITS HAPPEN

$ r53.py --push=test.domain.xml --zone=test.domain
looking up zone for test.domain
fetching live config for zone Z32RY3SDPIRMZ0
==CHANGESET==
<ChangeResourceRecordSetsRequest xmlns="https://route53.amazonaws.com/doc/2011-05-05/">
  <ChangeBatch>
    <Comment>Generated by r53.py for coops@staging at 2011-08-31 00:43:05.</Comment>
    <Changes>
      <Change>
        <Action>DELETE</Action>
        <ResourceRecordSet>
          <Name>www.test.domain.</Name>
          <Type>CNAME</Type>
          <TTL>900</TTL>
          <ResourceRecords>
            <ResourceRecord>
              <Value>test.domain.</Value>
            </ResourceRecord>
          </ResourceRecords>
        </ResourceRecordSet>
      </Change>
      <Change>
        <Action>CREATE</Action>
        <ResourceRecordSet>
          <Name>different-www.test.domain.</Name>
          <Type>CNAME</Type>
          <TTL>900</TTL>
          <ResourceRecords>
            <ResourceRecord>
              <Value>test.domain.</Value>
            </ResourceRecord>
          </ResourceRecords>
        </ResourceRecordSet>
      </Change>
    </Changes>
  </ChangeBatch>
</ChangeResourceRecordSetsRequest>

Push y/N? y
$