#!/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