Project

General

Profile

« Previous | Next » 

Revision ca79e27e

Added by Marc Dequènes over 13 years ago

  • ID ca79e27e4f538a8ddfbfccb3342ea3c1fe0167c6

[evol] reworked DNS classes (refs #31)

View differences:

bin/mapmaker
include CyborgServerInterface
include CyborgServerDefaultInterface
class DNS < Services::DNS
class DNS < Services::DNS::System
include CyborgServerInterface
export_parent_methods
......
include CyborgServerInterface
def initialize
@dns = Services::DNS.new
@dns = Services::DNS::System.new
end
def api_methods
......
end
end
class Zone < Services::Zone
class Zone < Services::DNS::Zone
include CyborgServerEmbededInterface
end
end
lib/cyborghood/cyborg/interface.rb
# preliminary outgoing message handling
action.call(*formated_data).to_yaml
rescue
logger.debug "node action error message: " + $!
logger.debug "node action error backtrace: " + $!.backtrace.join("\n")
return "550 method call failed: " + $!
end
end
lib/cyborghood/cyborg/server.rb
end
cmd = $1
flags = $2 || ""
pp "GROK"
pp cmd
pp flags
if flags.index '?'
send_line "250+ ok"
send_line({'exists?' => @interface.has_node?(cmd)}.to_yaml)
send_line({'exists' => @interface.has_node?(cmd)}.to_yaml)
return
end
lib/cyborghood/services/dns.rb
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#++
require 'digest/md5'
require 'tempfile'
require 'fileutils'
# ensure we can find the needed programs (should be handled somewhere else)
......
module CyborgHood
module Services
class DNS
def initialize
@config = Config.instance
module DNS
class System
def initialize
@config = Config.instance
@zone_files_pattern = @config.dns.master_zone_pattern.gsub("#ZONE#", "*")
@zone_files_regex = Regexp.new("^" + @config.dns.master_zone_pattern.gsub("#ZONE#", "(.*)") + "$")
end
@zone_files_pattern = @config.dns.master_zone_pattern.gsub("#ZONE#", "*")
@zone_files_regex = Regexp.new("^" + @config.dns.master_zone_pattern.gsub("#ZONE#", "(.*)") + "$")
end
def zones(zone = nil)
if zone.nil?
def zones
Dir.glob(@zone_files_pattern).collect do |file|
$1 if file =~ @zone_files_regex
end
else
end
def [](zone)
return unless zones.include?(zone)
Zone.new(zone)
end
def check_zone_file(check_type)
case @config.dns.software
when 'bind'
output = []
begin
IO.popen("named-checkconf '#{@zone}' #{filename}") do |fp|
output << fp.gets.chomp! until fp.eof?
end
rescue
raise CyberError.new(:unrecoverable, "services/dns", "global configuration could not be checked (I/O error)")
end
if $?.success?
return {:ok => true, :warnings => output}.to_ostruct
else
return {:ok => false, :errors => output}.to_ostruct
end
end
end
end
end
class Zone
attr_reader :zone
attr_accessor :content
class Zone
def initialize(zone)
@zone = zone
def initialize(zone)
@zone = zone
@config = Config.instance
@content = nil
@temp_file = nil
@config = Config.instance
@content = nil
@filename = @config.dns.master_zone_pattern.gsub("#ZONE#", @zone)
@filename = @config.dns.master_zone_pattern.gsub("#ZONE#", @zone)
end
at_exit {cleanup_temp}
end
def read_zone
begin
@content = File.read(@filename)
rescue
raise CyberError.new(:unrecoverable, "services/dns", "zone '#{@zone}' cannot be read (nonexistent or lack of permission)")
def content
read_zone(@filename) if @content.nil?
@content
end
end
def serial
case @config.dns.software
when 'bind'
output = []
begin
IO.popen("named-checkzone -i none '#{@zone}' #{@filename}") do |fp|
output << fp.gets.chomp! until fp.eof?
end
rescue
raise CyberError.new(:unrecoverable, "services/dns", "zone serial for '#{@zone}' could not be found (I/O error)")
def content=(txt)
@content = txt
end
def changed?
return false if @content.nil?
# if original hash is missing, save zone content, reload
# original file, compute hash, and restore previous content
if @content_hash.nil?
content_backup = @content
@content = nil
content
@content = content_backup
end
raise CyberError.new(:unrecoverable, "services/dns", "zone serial for '#{@zone}' could not be found (#{output.first})") unless $?.success?
if $? == 0
serial = nil
output.each do |l|
if l =~ /: loaded serial (\d+)$/
serial = $1
break
end
end
if serial
serial
else
raise CyberError.new(:unrecoverable, "services/dns", "no serial returned")
end
Digest::MD5.hexdigest(@content) != @content_hash
end
def cancel_changes
@content = nil
cleanup_temp
end
def check(force_real = false)
check_zone_file('full', force_real = false)
end
def serial(force_real = false)
r = check_zone_file('none', force_real = false)
if r.ok
r.serial
else
nil
raise CyberError.new(:unrecoverable, "services/dns", "zone serial for '#{@zone}' could not be found (#{r.errors.first})")
end
end
end
def check_zone_file(filename)
case @config.dns.software
when 'bind'
output = []
def import_from_file(new_zone_filename)
read_zone(new_zone_filename)
end
def import_from_backup
read_zone(self.backup_filename)
end
def create_backup
FileUtils.cp(@filename, backup_filename())
end
def save
raise CyberError.new(:unrecoverable, "services/dns", "won't save an empty zone file") if @content.nil?
write_zone(@filename)
update_hash
cleanup_temp
end
def activate
system "sudo rndc reload '#{@zone}' >/dev/null"
raise CyberError.new(:unrecoverable, "services/dns", "zone activation failed") unless $?.success?
end
protected
def backup_filename
@filename + ".ch-backup"
end
def save_to_temp
return unless temp_file.nil?
begin
IO.popen("named-checkzone '#{@zone}' #{filename}") do |fp|
output << fp.gets.chomp! until fp.eof?
end
@temp_file = Tempfile.new(@zone)
@temp_file.write(@content)
@temp_file.close
rescue
raise CyberError.new(:unrecoverable, "services/dns", "zone '#{@zone}' could not be checked")
raise CyberError.new(:unrecoverable, "services/dns", "could not save temporary zone")
end
end
if $? == 0
serial = nil
messages = []
output.each do |l|
next if l == "OK"
if l =~ /: loaded serial (\d+)$/
serial = $1
next
end
messages << l
end
def cleanup_temp
return if @temp_file.nil?
if serial
return {:ok => true, :serial => serial, :warnings => messages}.to_ostruct
else
raise CyberError.new(:unrecoverable, "services/dns", "zone validated but no serial returned")
end
else
return {:ok => false, :errors => messages}.to_ostruct
@temp_file.close!
@temp_file = nil
end
def temp_filename
@temp_file.path
end
def current_filename
if changed?
save_to_temp
return temp_filename
end
@filename
end
end
def write_zone_from_file(new_zone_filename)
# create backup
FileUtils.cp(@filename, backup_zone_filename())
def update_hash
@content_hash = Digest::MD5.hexdigest(@content)
end
FileUtils.cp(new_zone_filename, @filename)
end
def read_zone(filename)
begin
@content = File.read(filename)
update_hash if filename == @filename
rescue
raise CyberError.new(:unrecoverable, "services/dns", "zone '#{@zone}' cannot be read from '#{filename}' (I/O error, nonexistent or lack of permission)")
end
end
def replace_zone_with_backup
if File.exists?(backup_zone_filename())
FileUtils.cp(backup_zone_filename(), @filename)
else
raise CyberError.new(:unrecoverable, "services/dns", "no zone backup file found")
def write_zone(filename)
begin
File.open(filename, "w") do |fp|
fp.print @content
end
rescue
raise CyberError.new(:unrecoverable, "services/dns", "zone '#{@zone}' cannot be written from '#{filename}' (I/O error or lack of permission)")
end
end
end
def reload_zone
system "sudo rndc reload '#{@zone}' >/dev/null"
end
def check_zone_file(check_type, force_real = false)
filename = force_real ? @filename : current_filename
private
case @config.dns.software
when 'bind'
output = []
begin
IO.popen("named-checkzone -i #{check_type} '#{@zone}' #{filename}") do |fp|
output << fp.gets.chomp! until fp.eof?
end
rescue
raise CyberError.new(:unrecoverable, "services/dns", "zone '#{@zone}' could not be checked (I/O error)")
end
if $?.success?
serial = nil
messages = []
output.each do |l|
next if l == "OK"
if l =~ /: loaded serial (\d+)$/
serial = $1
next
end
messages << l
end
def backup_zone_filename
@filename + ".ch-backup"
if serial
return {:ok => true, :serial => serial, :warnings => messages}.to_ostruct
else
raise CyberError.new(:unrecoverable, "services/dns", "zone validated but no serial returned")
end
else
return {:ok => false, :errors => messages}.to_ostruct
end
end
end
end
end
end

Also available in: Unified diff