Project

General

Profile

Download (4.56 KB) Statistics
| Branch: | Tag: | Revision:
#--
# CyborgHood, a distributed system management software.
# Copyright (c) 2009-2010 Marc Dequènes (Duck) <Duck@DuckCorp.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#++

require 'fileutils'

module CyborgHood
module Services
class DNS
attr_reader :zone
attr_accessor :content

def initialize(zone)
@zone = zone

@config = Config.instance
@content = nil

@filename = @config.dns.master_zone_pattern.gsub("#ZONE#", @zone)
# TODO: should be checked at startup time
raise CyberError.new(:unrecoverable, "services/dns", "erroneous configuration: pattern is constant") if @filename == @config.dns.master_zone_pattern

# ensure we can find the needed programs (should be handled somewhere else)
ENV['PATH'] = (ENV['PATH'].split(":") + ["/sbin", "/usr/sbin", "/usr/local/sbin"]).uniq.join(":")
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)")
end
end

def serial
case @config.dns.nameserver || :bind
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")
end

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
else
nil
end
else
# TODO: should be checked at startup time
raise CyberError.new(:unrecoverable, "services/dns", "erroneous configuration: unknown nameserver")
end
end

def check_zone_file(filename)
case @config.dns.nameserver || :bind
when :bind
output = []
begin
IO.popen("named-checkzone '#{@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")
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

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
else
# TODO: should be checked at startup time
raise CyberError.new(:unrecoverable, "services/dns", "erroneous configuration: unknown nameserver")
end
end

def write_zone_from_file(new_zone_filename)
# create backup
FileUtils.cp(@filename, backup_zone_filename())

FileUtils.cp(new_zone_filename, @filename)
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")
end
end

def reload_zone
system "sudo rndc reload '#{@zone}' >/dev/null"
end

private

def backup_zone_filename
@filename + ".ch-backup"
end
end
end
end
    (1-1/1)