Merge pull request #9 from inkblot/resource-record-type

Create resource_record type
This commit is contained in:
Nate Riffe 2014-09-10 13:17:14 -05:00
commit 7bb07a4d10
5 changed files with 252 additions and 97 deletions

View File

@ -1,6 +1,9 @@
require 'tempfile' require 'puppet_bind/provider/nsupdate'
Puppet::Type.type(:dns_rr).provide(:nsupdate) do Puppet::Type.type(:dns_rr).provide(:nsupdate) do
include PuppetBind::Provider::NsUpdate
commands :dig => 'dig', :nsupdate => 'nsupdate' commands :dig => 'dig', :nsupdate => 'nsupdate'
def initialize(value={}) def initialize(value={})
@ -8,38 +11,6 @@ Puppet::Type.type(:dns_rr).provide(:nsupdate) do
@properties = {} @properties = {}
end end
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|
destructo(file)
accio(file)
end
end
def ttl
query.first[:ttl]
end
def ttl=(ttl)
@properties[:ttl] = ttl
end
def rrdata def rrdata
query.map { |record| record[:rrdata] }.sort query.map { |record| record[:rrdata] }.sort
end end
@ -50,43 +21,8 @@ Puppet::Type.type(:dns_rr).provide(:nsupdate) do
private private
def update(&block) def newdata
file = Tempfile.new('dns_rr-nsupdate-') resource[:rrdata]
file.write "server #{server}\n"
file.write "zone #{resource[:zone]}\n" unless resource[:zone].nil?
yield file
file.write "send\n"
file.close
if keyed?
nsupdate('-y', tsig_param, file.path)
else
nsupdate(file.path)
end
file.unlink
end
def accio(file)
resource[:rrdata].each do |datum|
file.write "update add #{name}. #{resource[:ttl]} #{rrclass} #{type} #{datum}\n"
end
end
def destructo(file)
rrdata.each do |datum|
file.write "update delete #{name}. #{ttl} #{rrclass} #{type} #{datum}\n"
end
end
def keyed?
!(resource[:secret].nil?)
end
def tsig_param
"#{resource[:hmac]}:#{resource[:keyname]}:#{resource[:secret]}"
end
def server
resource[:server]
end end
def specarray def specarray
@ -105,27 +41,4 @@ private
specarray[2] specarray[2]
end end
def query
unless @query
if keyed?
dig_text = dig("@#{server}", '+noall', '+answer', name, type, '-c', rrclass, '-y', tsig_param)
else
dig_text = dig("@#{server}", '+noall', '+answer', name, type, '-c', rrclass)
end
@query = dig_text.lines.map do |line|
linearray = line.chomp.split(/\s+/, 5)
{
: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

View File

@ -0,0 +1,44 @@
require 'puppet_bind/provider/nsupdate'
Puppet::Type.type(:resource_record).provide(:nsupdate) do
include PuppetBind::Provider::NsUpdate
commands :dig => 'dig', :nsupdate => 'nsupdate'
def initialize(value={})
super(value)
@properties = {}
end
def data
query.map { |record| record[:rrdata] }.sort
end
def data=(data)
@properties[:rrdata] = data
end
private
def rrdata
data
end
def newdata
resource[:data]
end
def rrclass
resource[:rrclass]
end
def type
resource[:type]
end
def name
resource[:record]
end
end

View File

@ -10,14 +10,14 @@ Puppet::Type.newtype(:dns_rr) do
if (value =~ /^([A-Z]+)\/([A-Z]+)\/[a-zA-Z0-9._-]+$/) if (value =~ /^([A-Z]+)\/([A-Z]+)\/[a-zA-Z0-9._-]+$/)
rrclass = $1 rrclass = $1
if ( !%w(IN CH HS).include? rrclass ) if ( !%w(IN CH HS).include? rrclass )
raise ArgumentError, "Invalid resource record class: %s" % rrdata Util::Errors.fail "Invalid resource record class: %s" % rrdata
end end
type = $2 type = $2
if ( !%w(A AAAA CNAME NS MX SRV NAPTR PTR).include? type) if ( !%w(A AAAA CNAME NS MX SPF SRV NAPTR PTR TXT).include? type)
raise ArgumentError, "Invalid resource record type: %s" % type Util::Errors.fail "Invalid resource record type: %s" % type
end end
else else
raise ArgumentError, "%s must be of the form Class/Type/Name" % value Util::Errors.fail "%s must be of the form Class/Type/Name" % value
end end
end end
end end
@ -33,6 +33,7 @@ Puppet::Type.newtype(:dns_rr) do
newproperty(:rrdata, :array_matching => :all) do newproperty(:rrdata, :array_matching => :all) do
desc 'The resource record\'s data' desc 'The resource record\'s data'
isrequired
def insync?(is) def insync?(is)
Array(is).sort == Array(@should).sort Array(is).sort == Array(@should).sort

View File

@ -0,0 +1,72 @@
Puppet::Type.newtype(:resource_record) do
@doc = 'A Resource Record in the Domain Name System'
ensurable
newparam(:title, :namevar => true) do
desc 'A unique name for the puppet resource'
end
newparam(:rrclass) do
desc 'The record class'
defaultto 'IN'
newvalues 'IN', 'CH', 'HS'
end
newparam(:type) do
desc 'The record type'
isrequired
newvalues 'A', 'AAAA', 'CNAME', 'NS', 'MX', 'SPF', 'SRV', 'NAPTR', 'PTR', 'TXT'
end
newparam(:record) do
desc 'The fully-qualified record name'
isrequired
validate do |value|
Util::Errors.fail "Invalid value for record: #{value}" unless value =~ /^([a-zA-Z0-9_-]+\.)*[a-zA-Z0-9_-]+$/
end
end
newparam(:zone) do
desc 'The zone to update'
end
newparam(:server) do
desc 'The master server for the resource record'
defaultto 'localhost'
end
newparam(:keyname) do
desc 'Keyname for the TSIG key used to update the record'
defaultto 'update'
end
newparam(:hmac) do
desc 'The HMAC type of the update key'
defaultto 'HMAC-SHA1'
end
newparam(:secret) do
desc 'The secret of the update key'
end
newproperty(:ttl) do
desc 'Time to live of the resource record'
defaultto 43200
munge do |value|
Integer(value)
end
end
newproperty(:data, :array_matching => :all) do
desc 'The resource record\'s data'
isrequired
def insync?(is)
Array(is).sort == Array(@should).sort
end
end
end

View File

@ -0,0 +1,125 @@
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|
destructo(file)
accio(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)
else
nsupdate(file.path)
end
file.unlink
end
def accio(file)
newdata.each do |datum|
file.write "update add #{name}. #{resource[:ttl]} #{rrclass} #{type} #{datum}\n"
end
end
def destructo(file)
rrdata.each do |datum|
file.write "update delete #{name}. #{ttl} #{rrclass} #{type} #{datum}\n"
end
end
def server
resource[:server]
end
def zone
resource[:zone]
end
def keyname
resource[:keyname]
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', '+answer', name, type, '-c', rrclass, '-y', tsig_param)
else
dig_text = dig("@#{server}", '+noall', '+answer', name, type, '-c', rrclass)
end
@query = dig_text.lines.map do |line|
linearray = line.chomp.split(/\s+/, 5)
{
: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