Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
barnybug committed Oct 13, 2015
0 parents commit 6c82a0f
Show file tree
Hide file tree
Showing 28 changed files with 2,809 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
cli53
vendor/
.stfolder
cli53.sublime-project
release/
28 changes: 28 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
language: go
go:
- 1.5
sudo: required
before_script:
- sudo apt-get -y install upx-ucl
script:
- make test
after_success:
- make release
deploy:
provider: releases
api_key:
secure: nmqbnVuj7XpuUMs5YmB2X+/Dkq5I2hoWaIUSO5Okse7D8iYW0fWPeqR5xMy3ctSlHJgNarMx3qPJZmr+lJAuwT7xZhvW2kFOJE7Ra/nJgLtuWOMu4zrJ2cLNYTgE4fN3jag5VkgnuB4Ax57QZESssWKLvyBVA7ePaV/HXe1hX7k=
file:
- release/cli53-linux-386
- release/cli53-linux-amd64
- release/cli53-linux-arm
- release/cli53-mac-amd64
- release/cli53-windows-386.exe
- release/cli53-windows-amd64.exe
on:
repo: barnybug/cli53
tags: true
env:
global:
- secure: "M6bUhLlefRqTAfbVfQd2/j4/4CsifJqKQ6Szz2G5RTI0ADrbdNnS0m3SqTdk\nsbp/4cgwaQM+sgnISW2alDaGP+1PmkyXGyftZdLHM1NuGca8/yKVWy/vLW3e\nv++AiYPFLTRxoiZJ9j0bdHjGOffCMvotZhtc9xv0VXVijGdHiIM="
- secure: "lnku5GaQtu8MLapFboAAsUzm2kYm+lVoshaJPmtod0gERoxiwaOUMMkY9Muq\nrezBxXy7dvHdDEEMoU0zelpJYfpxV6ql1vPjxgusVA6KouTTl1rTV3GfP0z7\nqUylHf1RqwYWNL0DkBURG44npnfkTT+F97qcq0kCCUAlLjAoyJg="
32 changes: 32 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
export GO15VENDOREXPERIMENT=1

exe = ./cmd/cli53
buildargs = -ldflags '-X github.com/barnybug/cli53.version=${TRAVIS_BRANCH}'

.PHONY: all build install test coverage deps release

all: install

build:
go build $(exe)

install:
go install $(exe)

release:
GOOS=linux GOARCH=386 go build $(buildargs) -o release/cli53-linux-386 $(exe)
GOOS=linux GOARCH=amd64 go build $(buildargs) -o release/cli53-linux-amd64 $(exe)
GOOS=linux GOARCH=arm go build $(buildargs) -o release/cli53-linux-arm $(exe)
GOOS=darwin GOARCH=amd64 go build $(buildargs) -o release/cli53-mac-amd64 $(exe)
GOOS=windows GOARCH=386 go build $(buildargs) -o release/cli53-windows-386.exe $(exe)
GOOS=windows GOARCH=amd64 go build $(buildargs) -o release/cli53-windows-amd64.exe $(exe)
goupx release/cli53-linux-amd64
upx release/cli53-linux-386 release/cli53-linux-arm release/cli53-windows-386.exe release/cli53-windows-amd64.exe

test-unit:
go test .

test-integration: build
gucumber

test: test-unit test-integration
134 changes: 134 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
[![Build status](https://secure.travis-ci.org/barnybug/cli53.png?branch=master)](https://secure.travis-ci.org/barnybug/cli53)

# cli53 - Command line tool to administer the Amazon Route 53 DNS service

## Introduction

cli53 provides import and export from BIND format and simple command line management of
Route 53 domains.

Features:

- create hosted zones

- delete hosted zones

- list hosted zones

- import from BIND format

- export to BIND format

- create resource records

- delete resource records

- works with BIND format zone files we all know and love

- create AWS extensions: failover, geolocation, latency and weighted records

- create AWS Alias records

## Installation

Installation is easy, just download the binary from the github releases page (builds are available for Linux, Mac and Windows):
https://github.com/barnybug/cli53/releases/latest

$ sudo cp cli53-my-platform /usr/local/bin
$ sudo chmod +x /usr/local/bin/cli53

To configure your Amazon credentials, either place them in a file `~/.aws/credentials`:

[default]
aws_access_key_id = AKID1234567890
aws_secret_access_key = MY-SECRET-KEY

Or set the environment variables: `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY`.

For more information, see:

http://blogs.aws.amazon.com/security/post/Tx3D6U6WSFGOK2H/A-New-and-Standardized-Way-to-Manage-Credentials-in-the-AWS-SDKs

## Building from source

To build yourself from source you will need golang 1.5 installed and 'GO15VENDOREXPERIMENT=1' set in your environment, then:

$ go get github.com/barnybug/cli53
$ cd $GOPATH/src/github.com/barnybug/cli53
$ make install

This will produce a binary `cli53` in `~/go/bin`, after this follow the steps as above.

## Getting Started

Create a hosted zone:

$ cli53 create example.com --comment 'my first zone'

Check what we've done:

$ cli53 list

Import a BIND zone file:

$ cli53 import --file zonefile.txt example.com

Replace with an imported zone, waiting for completion:

$ cli53 import --file zonefile.txt --replace --wait example.com

Manually create some records:

$ cli53 rrcreate example.com 'www 3600 A 192.168.0.1'
$ cli53 rrcreate --replace example.com 'www 3600 A 192.168.0.2'
$ cli53 rrcreate example.com '@ MX "10 192.168.0.1" "20 192.168.0.2"'

Export as a BIND zone file (for backup!):

$ cli53 export example.com

Create some weighted records:

$ cli53 rrcreate --identifier server1 --weight 10 example.com 'www A 192.168.0.1'
$ cli53 rrcreate --identifier server2 --weight 20 example.com 'www A 192.168.0.2'

Create an alias to ELB:

$ cli53 rrcreate example.com 'www ALIAS ABCDEFABCDE dns-name.elb.amazonaws.com.'

Further documentation is available, e.g.:

$ cli53 --help
$ cli53 rrcreate --help

## Broken CNAME exports (GoDaddy)

Some DNS providers export broken bind files, without the trailing '.'
on CNAME records. This is a requirement for absolute records
(i.e. ones outside of the qualifying domain).

If you see CNAME records being imported to route53 with an extra
mydomain.com on the end (e.g. ghs.google.com.mydomain.com), then you
need to fix your zone file before importing:

$ perl -pe 's/(CNAME\s+[-a-zA-Z0-9.-_]+)(?!.)$/$1./i' broken.txt > fixed.txt

## Private/public zones

To manage zones that have both a private and a public zone, you must specify the
zone ID instead the domain name, which is ambiguous. This is the 13 character ID
after '/hostedzone/' you can see in the output to 'cli53 list'. eg:

$ cli53 rrcreate ZZZZZZZZZZZZZ 'name A 127.0.0.1'

Caveats
-------
As Amazon limits operations to a maximum of 100 changes, if you
perform a large operation that changes over 100 resource records it
will be split. An operation that involves deletes, followed by updates
such as an import with --replace will very briefly leave the domain
inconsistent. You have been warned!

Changelog
---------
0.6.0 New go version released!
161 changes: 161 additions & 0 deletions awsrr.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
package cli53

import (
"errors"
"fmt"

"github.com/miekg/dns"
)

const ClassAWS = 253
const TypeALIAS = 0x0F99

type ALIAS struct {
Type string
Target string
ZoneId string
EvaluateTargetHealth bool
}

func (rd *ALIAS) Copy(dest dns.PrivateRdata) error {
d := dest.(*ALIAS)
d.Type = rd.Type
d.Target = rd.Target
d.ZoneId = rd.ZoneId
d.EvaluateTargetHealth = rd.EvaluateTargetHealth
return nil
}

func (rd *ALIAS) Len() int {
return 0
}

func (rd *ALIAS) Parse(txt []string) error {
if len(txt) != 4 {
return errors.New("4 parts required for ALIAS: type target zoneid evaluateTargetHealth")
}
rd.Type = txt[0]
rd.Target = txt[1]
rd.ZoneId = txt[2]
rd.EvaluateTargetHealth = (txt[3] == "true")
return nil
}

func (rd *ALIAS) Pack(buf []byte) (int, error) {
return 0, nil
}

func (rd *ALIAS) Unpack(buf []byte) (int, error) {
return 0, nil
}

func (rr *ALIAS) String() string {
return fmt.Sprintf("%s %s %s %v",
rr.Type,
rr.Target,
rr.ZoneId,
rr.EvaluateTargetHealth,
)
}

func NewALIAS() dns.PrivateRdata { return new(ALIAS) }

func init() {
dns.StringToClass["AWS"] = ClassAWS
dns.ClassToString[ClassAWS] = "AWS"
dns.PrivateHandle("ALIAS", TypeALIAS, NewALIAS)
}

type AWSRoute interface {
String() string
Parse(KeyValues)
}

type AWSRR struct {
dns.RR
Route AWSRoute
HealthCheckId *string
Identifier string
}

func (rr *AWSRR) String() string {
var kvs KeyValues
if rr.HealthCheckId != nil {
kvs = append(kvs, "healthCheckId", *rr.HealthCheckId)
}
kvs = append(kvs, "identifier", rr.Identifier)
return fmt.Sprintf("%s ; AWS %s %s",
rr.RR,
rr.Route,
kvs,
)
}

type FailoverRoute struct {
Failover string
}

func (f *FailoverRoute) String() string {
return KeyValues{"routing", "FAILOVER", "failover", f.Failover}.String()
}

func (f *FailoverRoute) Parse(kvs KeyValues) {
f.Failover = kvs.GetString("failover")
}

type GeoLocationRoute struct {
CountryCode *string
ContinentCode *string
SubdivisionCode *string
}

func (f *GeoLocationRoute) String() string {
args := KeyValues{"routing", "GEOLOCATION"}
if f.CountryCode != nil {
args = append(args, "countryCode", *f.CountryCode)
}
if f.ContinentCode != nil {
args = append(args, "continentCode", *f.ContinentCode)
}
if f.SubdivisionCode != nil {
args = append(args, "subdivisionCode", *f.SubdivisionCode)
}
return args.String()
}

func (f *GeoLocationRoute) Parse(kvs KeyValues) {
f.CountryCode = kvs.GetOptString("countryCode")
f.ContinentCode = kvs.GetOptString("continentCode")
f.SubdivisionCode = kvs.GetOptString("subdivisonCode")
}

type LatencyRoute struct {
Region string
}

func (f *LatencyRoute) String() string {
return KeyValues{"routing", "LATENCY", "region", f.Region}.String()
}

func (f *LatencyRoute) Parse(kvs KeyValues) {
f.Region = kvs.GetString("region")
}

type WeightedRoute struct {
Weight int64
}

func (f *WeightedRoute) String() string {
return KeyValues{"routing", "WEIGHTED", "weight", f.Weight}.String()
}

func (f *WeightedRoute) Parse(kvs KeyValues) {
f.Weight = int64(kvs.GetInt("weight"))
}

var RoutingTypes = map[string]func() AWSRoute{
"FAILOVER": func() AWSRoute { return &FailoverRoute{} },
"GEOLOCATION": func() AWSRoute { return &GeoLocationRoute{} },
"LATENCY": func() AWSRoute { return &LatencyRoute{} },
"WEIGHTED": func() AWSRoute { return &WeightedRoute{} },
}
Loading

0 comments on commit 6c82a0f

Please sign in to comment.