Moving DNS from Rackspace to Amazon Route53 Using Fog
Had to move a few domains and knocked up this script. It mostly just glosses over some differences in the formatting of the records, A and CNAME records translate pretty well but TXT and MX are combined in R53 and have separate attributes in Rackspace. We didn’t have any other record types.
I opened an issue on Fog for strange behaviour if you have 100+ domains in Rackspace.
require 'fog'
require 'pp'
RACKSPACE = {
:provider => 'Rackspace',
:rackspace_api_key => 'EDIT' ,
:rackspace_username => 'EDIT'
}
R53 = {
:provider => 'AWS',
:aws_access_key_id => 'EDIT',
:aws_secret_access_key => 'EDIT'
}
class Provider
def initialize(connection_spec)
@connection = Fog::DNS.new(connection_spec)
end
def get_records(domain,types=nil)
types = %w[CNAME A] unless types
get_domain(domain).records.select{|r| types.include? r.type}
end
def get_domain(domain)
@connection.zones.select{|z| z.domain == domain or z.domain == add_dot(domain)}[0]
end
def create_zone(domain)
unless get_domain(domain)
@connection.zones.create(:domain => domain)
end
end
def new_record(domain,name,value,ttl,type)
name = name.downcase
# some of the rackspace entries had uppercase but when added to R53 it went to downcase.
existing = get_records(domain,[type]).select{|r| add_dot(name) == r.name}
unless existing.empty?
puts "#{name} => #{value} (#{type}) EXISTS"
return
end
puts "#{name} => #{value} (#{type})"
get_domain(domain).records.create({
:name => name,
:value => value,
:ttl => ttl,
:type => type
})
end
def add_dot(s)
return s if s[-1] == '.'
"#{s}."
end
end
def migrate(domain)
puts "MIGRATING #{domain}"
r53 = Provider.new(R53)
rs = Provider.new(RACKSPACE)
r53.create_zone domain
rs.get_records(domain).each do |record|
r53.new_record(domain, record.name, record.value, record.ttl, record.type)
end
rs.get_records(domain,["TXT"]).group_by{|r| r.name}.each_pair do |name,records|
texts = records.map(&:value)
texts.map!{|t| "\"#{t}\""}
r53.new_record(domain, name, texts , records[0].ttl, "TXT")
end
rs.get_records(domain,["MX"]).group_by{|r| r.name}.each_pair do |name,records|
entries = records.map{|r| "#{r.priority} #{r.value}."}
r53.new_record(domain, name, entries , records[0].ttl, "MX")
end
end
DOMAINS = %w[something.com somethingelse.net]
DOMAINS.each do |d|
migrate d
end