189 lines
4.1 KiB
Ruby
189 lines
4.1 KiB
Ruby
# ex: syntax=ruby si sw=2 ts=2 et
|
|
require 'tempfile'
|
|
|
|
module PuppetBind
|
|
module Provider
|
|
|
|
def self.nsupdate_provider(type)
|
|
end
|
|
|
|
module NsUpdate
|
|
|
|
def exists?
|
|
!(query.empty?)
|
|
end
|
|
|
|
def create
|
|
update do |file|
|
|
accio(file)
|
|
end
|
|
end
|
|
|
|
def destroy
|
|
update do |file|
|
|
destructo(file)
|
|
end
|
|
end
|
|
|
|
def flush
|
|
return if @properties.empty?
|
|
update do |file|
|
|
accio(file)
|
|
destructo(file)
|
|
end
|
|
end
|
|
|
|
def ttl
|
|
query.first[:ttl]
|
|
end
|
|
|
|
def ttl=(ttl)
|
|
@properties[:ttl] = ttl
|
|
end
|
|
|
|
private
|
|
|
|
def update(&block)
|
|
file = Tempfile.new('dns_rr-nsupdate-')
|
|
file.write "server #{server}\n"
|
|
file.write "zone #{zone}\n" unless zone.nil?
|
|
yield file
|
|
file.write "send\n"
|
|
file.close
|
|
if keyed?
|
|
nsupdate('-y', tsig_param, file.path)
|
|
elsif keyfile?
|
|
nsupdate('-k', kfile, file.path)
|
|
else
|
|
nsupdate(file.path)
|
|
end
|
|
file.unlink
|
|
end
|
|
|
|
def accio(file)
|
|
rrdata_adds.each do |datum|
|
|
file.write "update add #{name}. #{resource[:ttl]} #{rrclass} #{type} #{maybe_quote(type, datum)}\n"
|
|
end
|
|
end
|
|
|
|
def destructo(file)
|
|
rrdata_deletes.each do |datum|
|
|
file.write "update delete #{name}. #{ttl} #{rrclass} #{type} #{maybe_quote(type, datum)}\n"
|
|
end
|
|
end
|
|
|
|
def quoted_type?(type)
|
|
%w(TXT SPF).include?(type)
|
|
end
|
|
|
|
def escaped_type?(type)
|
|
%w(TXT).include?(type)
|
|
end
|
|
|
|
def spaced_type?(type)
|
|
%w(DS TLSA SSHFP).include?(type)
|
|
end
|
|
|
|
def maybe_quote(type, datum)
|
|
quoted_type?(type) ? "\"#{datum}\"" : datum
|
|
end
|
|
|
|
def maybe_unquote(type, datum)
|
|
quoted_type?(type) ? datum.gsub(/^\"(.*)\"$/, '\1') : datum
|
|
end
|
|
|
|
def maybe_unescape(type, datum)
|
|
escaped_type?(type) ? datum.gsub(/\\;/, ';') : datum
|
|
end
|
|
|
|
def maybe_unspace(type, datum)
|
|
if spaced_type?(type)
|
|
case type
|
|
when 'DS', 'TLSA'
|
|
datum.gsub(/^(\d+)\s+(\d+)\s+(\d+)\s+(\w+)\s+(\w+)$/, '\1 \2 \3 \4\5')
|
|
when 'SSHFP'
|
|
datum.gsub(/^(\d+)\s+(\d+)\s+(\w+)\s+(\w+)$/, '\1 \2 \3\4')
|
|
end
|
|
else
|
|
datum
|
|
end
|
|
end
|
|
|
|
def rrdata_adds
|
|
resource[:ensure] === :absent ? [] : newdata - rrdata
|
|
end
|
|
|
|
def rrdata_deletes
|
|
resource[:ensure] === :absent ? rrdata : (type === 'SOA' ? [] : rrdata - newdata)
|
|
end
|
|
|
|
def server
|
|
resource[:server]
|
|
end
|
|
|
|
def zone
|
|
resource[:zone]
|
|
end
|
|
|
|
def query_section
|
|
resource[:query_section]
|
|
end
|
|
|
|
def keyname
|
|
resource[:keyname]
|
|
end
|
|
|
|
def kfile
|
|
resource[:keyfile]
|
|
end
|
|
|
|
def keyfile?
|
|
!kfile.nil?
|
|
end
|
|
|
|
def hmac
|
|
resource[:hmac]
|
|
end
|
|
|
|
def secret
|
|
resource[:secret]
|
|
end
|
|
|
|
def keyed?
|
|
!secret.nil?
|
|
end
|
|
|
|
def tsig_param
|
|
"#{hmac}:#{keyname}:#{secret}"
|
|
end
|
|
|
|
def query
|
|
unless @query
|
|
if keyed?
|
|
dig_text = dig("@#{server}", '+noall', '+nosearch', '+norecurse', "+#{query_section}", name, type, '-c', rrclass, '-y', tsig_param)
|
|
else
|
|
dig_text = dig("@#{server}", '+noall', '+nosearch', '+norecurse', "+#{query_section}", name, type, '-c', rrclass)
|
|
end
|
|
@query = dig_text.lines.map do |line|
|
|
linearray = line.chomp.split(/\s+/, 5)
|
|
linearray[4] = maybe_unquote(linearray[3], linearray[4])
|
|
linearray[4] = maybe_unescape(linearray[3], linearray[4])
|
|
linearray[4] = maybe_unspace(linearray[3], linearray[4])
|
|
{
|
|
:name => linearray[0],
|
|
:ttl => linearray[1],
|
|
:rrclass => linearray[2],
|
|
:type => linearray[3],
|
|
:rrdata => linearray[4]
|
|
}
|
|
end.select do |record|
|
|
record[:name] == "#{name}."
|
|
end
|
|
end
|
|
@query
|
|
end
|
|
|
|
end
|
|
end
|
|
end
|