#!/usr/ruby
#
# loosely based on (Tangerine ALPHA ) by Isam M (r0cketjump YAHOO COM) [his code was useful :-)]
#
# ZoneParser was created by Ben Congleton from Hab.la (http://www.hab.la) and Nethernet Consulting (http://www.nethernet.com)
#
#
# I recommend using Zone Parser to import your zones from your normal DNS server,
# and then Isam's Tangerine to deal with them once their in slicehost.


require 'rubygems'
require 'activeresource'

API_PASSWORD = 'API_KEY_HERE'
API_ADDRESS = "https://#{API_PASSWORD}@api.slicehost.com/"
NAMESERVERS = ["ns1.slicehost.com", "ns2.slicehost.com", "ns3.slicehost.com"]
VERBOSE = true
DEBUG = false

class Zone < ActiveResource::Base
self.site = API_ADDRESS
end

class Record < ActiveResource::Base
self.site = API_ADDRESS
end



class ZoneParser
attr_accessor :records
attr_accessor :domain
def initialize(filename, domain)
@records = Array.new
@domain = domain

File.open(filename, 'r').each_line do |line|
next if (line =~ /SOA/)
next if (line =~ /^\s*\;/)
parts = line.split(/\s\s*/)
next if (parts.size == 0)
next if ( (parts.first == "" or parts.first == "@") && !parts[1].match(/^\D\D*$/) )
next if (parts[1] == "NS") # no need for NS records
p line if (DEBUG)

if(parts.first == "" or parts.first == "@" )
parts[0] = domain + "."
end

if(parts[1] == "IN")
parts = [parts[0], parts[2], parts[3], parts[4..parts.size].join(" ")]
end

ap = {
:record_type => parts[1],
:name => parts[0],
:data => parts.last,
:ttl => 8000,
:active => 'Y',
:aux => 0
}
if(parts.size == 4)
ap[:aux] = parts[2]
end
p ap if(DEBUG)

#p parts
#p ap
#p line
@records << ap
end
end

def sync(clear = true)
# syncronizes the web-based zone from the file-based zone.
z = Zone.find(:first, :params => {'origin' => @domain + "."})
p z if(DEBUG)

if( not z):
z = Zone.new({
:origin => @domain,
:ttl => 8000,
:active => 'Y'
})
z.save unless z.nil?
end

if(not z)
raise Exception.new("Error finding/creating zone for #{@domain}")
elsif(VERBOSE)
print "Syncing Zone: #{@domain}\n"
end

p z if(DEBUG)

# ok at this point we have a zone.
# wipe it
if(clear)
print "\nRemoving all records for zone: #{@domain}\n" if(VERBOSE)
Record.find(:all, :params => {:zone_id => z.id}).each do |r|
r.destroy unless r.nil?
p r if (DEBUG)
print "\t- #{r.name} #{r.record_type} #{r.data}\n" if(VERBOSE)
end
end
print "\nAdding records to zone: #{@domain}\n" if(VERBOSE)

# add the Nameservers:
base = {
:record_type => "NS",
:name => @domain + ".",
:ttl => 8000,
:active => 'Y',
:aux => 0
}
NAMESERVERS.each do |ns|
base[:data] = ns
@records << base.dup
end

# add the zones
@records.each do |r|
r[:zone_id] = z.id
rec = Record.new(r)
rec.save unless rec.nil?

if(not rec or rec.errors.size > 0)
print "\t* ERROR ADDING #{r[:name]} #{r[:record_type]} #{r[:data]}\n"
p rec
elsif(rec && VERBOSE)
p rec if(DEBUG)
print "\t+ #{r[:name]} #{r[:record_type]} #{r[:data]}\n"
end



end

end

end #end class



z = ZoneParser.new("test_zone.txt", "hab.la")

z.sync



=begin
;
;This is an example test zone
;
@ IN SOA ns1.netherweb.com. ben.nethernet.com. (
2008102701
3600 ; refresh [1h]
3600 ; retry [1h]
6H ; expire [2h]
3H) ; minimum [1d]

NS ns1.netherweb.com.
NS ns2.netherweb.com.

@ A 216.9.83.199
MX 1 ASPMX.L.GOOGLE.COM.
MX 5 ALT1.ASPMX.L.GOOGLE.COM.
MX 5 ALT2.ASPMX.L.GOOGLE.COM.
MX 10 ASPMX2.GOOGLEMAIL.COM.
MX 10 ASPMX3.GOOGLEMAIL.COM.
MX 10 ASPMX4.GOOGLEMAIL.COM.
MX 10 ASPMX5.GOOGLEMAIL.COM.
www A 216.9.83.199
*.async A 216.9.83.197
*.aync A 216.9.83.197

_jabber._tcp.staging IN SRV 0 0 18269 staging.hab.la.
_xmpp-server._tcp.staging IN SRV 0 0 18269 staging.hab.la.
_xmpp-client._tcp.staging IN SRV 0 0 18222 staging.hab.la.


=end