Skip to content

Commit 9608f86

Browse files
authored
Merge pull request #162 from cirrax/add_autoprimaries
add type/provider for autoprimary
2 parents d020471 + 8df34bc commit 9608f86

File tree

8 files changed

+200
-0
lines changed

8 files changed

+200
-0
lines changed

README.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,21 @@ Remark: if the target\_zone is not managed with powerdns\_zone resource, powerdn
167167

168168
Passwords can be passed either as plain-text strings or as [Puppet's Sensitive type](https://www.puppet.com/docs/puppet/7/lang_data_sensitive.html) when appropriate encrypted backend is configured on Puppet server.
169169

170+
### Manage autoprimaries (automatic provisioning of secondaries)
171+
It's possible to manage the the 'autoprimaries' with puppet (For a decription of the autoprimary functionality in
172+
powerdns see [powerdns manual](https://doc.powerdns.com/authoritative/modes-of-operation.html#autoprimary-automatic-provisioning-of-secondaries).
173+
The autoprimaries are set with the powerdns\_autoprimary resource. As an example we add the primary 1.2.3.4 named ns1.example.org whith the account 'test'
174+
``` yaml
175+
powerdns_autoprimary{'1.2.3.4@ns1.example.org':
176+
ensure => 'present',
177+
account => 'test',
178+
}
179+
```
180+
As an alternative, you can set the autoprimaries parameter of the powerdns class to achive the same (eg. if you use hiera).
181+
182+
For removal of an autoprimary set ensure to 'absent' or set the parameter purge\_autoprimaries of the powerdns class to true which willa
183+
remove all autoprimaries that are not present in the puppet manifest.
184+
170185
## Reference
171186

172187
### Parameters
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
# frozen_string_literal: true
2+
3+
Puppet::Type.type(:powerdns_autoprimary).provide(:pdnsutil) do
4+
desc "@summary provider which provides autprimary,
5+
using the pdnsutil command."
6+
7+
commands pdnsutil: 'pdnsutil'
8+
9+
def initialize(value = {})
10+
super(value)
11+
@property_flush = {}
12+
end
13+
14+
def self.instances
15+
pdnsutil('list-autoprimaries').split("\n").map do |line|
16+
raise Puppet::Error, "Cannot parse invalid autoprimary line: #{line}" unless line =~ %r{^IP=(\S+),\s+NS=(\S+),\s+account=(\S*)$}
17+
new(
18+
ensure: :present,
19+
name: Regexp.last_match(1) + '@' + Regexp.last_match(2),
20+
account: Regexp.last_match(3),
21+
)
22+
end
23+
end
24+
25+
def self.prefetch(resources)
26+
autoprimaries = instances
27+
resources.each_key do |name|
28+
if (provider = autoprimaries.find { |aprim| aprim.name == name })
29+
resources[name].provider = provider
30+
end
31+
end
32+
end
33+
34+
def create
35+
pdnsutil('add-autoprimary', resource[:name].split('@'), resource[:account])
36+
@property_hash[:ensure] = :present
37+
end
38+
39+
def destroy
40+
pdnsutil('remove-autoprimary', resource[:name].split('@'))
41+
@property_hash[:ensure] = :absent
42+
end
43+
44+
def account
45+
@property_hash[:account]
46+
end
47+
48+
def account=(account)
49+
pdnsutil('remove-autoprimary', resource[:name].split('@'))
50+
pdnsutil('add-autoprimary', resource[:name].split('@'), account)
51+
@property_hash[:ensure] = account
52+
end
53+
54+
def exists?
55+
@property_hash[:ensure] == :present
56+
end
57+
58+
def flush
59+
return if @property_flush.empty?
60+
content = @property_flush[:content] || @resource[:content]
61+
virsh_define(content)
62+
@property_flush.clear
63+
end
64+
end
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# frozen_string_literal: true
2+
3+
require 'puppet/parameter/boolean'
4+
5+
Puppet::Type.newtype(:powerdns_autoprimary) do
6+
@doc = 'ensures autoprimary servers (for automatic provisioning of secondaries)
7+
'
8+
9+
ensurable do
10+
desc 'Manage the state of this type.'
11+
defaultvalues
12+
defaultto :present
13+
end
14+
15+
newparam(:name, namevar: true) do
16+
desc 'name of the autoprimary in the format IP@NAMESERVER'
17+
18+
newvalues(%r{^\S+@\S+$})
19+
end
20+
21+
newproperty(:account) do
22+
desc 'account to ensure (default to no account)'
23+
defaultto ''
24+
25+
validate do |value|
26+
raise ArgumentError, 'ip needs to be a string' unless value.is_a?(String)
27+
end
28+
end
29+
30+
autorequire(:service) do
31+
['pdns']
32+
end
33+
end

manifests/init.pp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
11
# powerdns
2+
#
3+
# @param autoprimaries
4+
# Hash of autoprimaries the ensurce (with resource powerdns_autoprimary)
5+
# @param purge_autoprimaries
6+
# Set this to true if you like to purge all autoprimaries not managed with puppet
7+
#
28
class powerdns (
39
Boolean $authoritative = true,
410
Boolean $recursor = false,
@@ -25,6 +31,8 @@
2531
String[1] $mysql_schema_file = $powerdns::params::mysql_schema_file,
2632
String[1] $pgsql_schema_file = $powerdns::params::pgsql_schema_file,
2733
Hash $forward_zones = {},
34+
Powerdns::Autoprimaries $autoprimaries = {},
35+
Boolean $purge_autoprimaries = false,
2836
) inherits powerdns::params {
2937
# Do some additional checks. In certain cases, some parameters are no longer optional.
3038
if $authoritative {
@@ -68,4 +76,11 @@
6876
$powerdns_recursor_defaults = { 'type' => 'recursor' }
6977
create_resources(powerdns::config, $powerdns_recursor_config, $powerdns_recursor_defaults)
7078
}
79+
80+
if $purge_autoprimaries {
81+
resources { 'powerdns_autoprimary':
82+
purge => true,
83+
}
84+
}
85+
create_resources('powerdns_autoprimary', $autoprimaries)
7186
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
require 'spec_helper'
2+
3+
describe 'Powerdns::Autoprimaries' do
4+
describe 'valid types' do
5+
context 'with valid types' do
6+
[
7+
{},
8+
{ '1.2.3.4@ns1.example.org' => {} },
9+
{ '2001:db8::1@ns1.example.org' => { 'account' => 'test' } },
10+
].each do |value|
11+
describe value.inspect do
12+
it { is_expected.to allow_value(value) }
13+
end
14+
end
15+
end
16+
end
17+
18+
describe 'invalid types' do
19+
context 'with garbage inputs' do
20+
[
21+
true,
22+
nil,
23+
{ 'foo' => 'bar' },
24+
'55555',
25+
{ '@ns1.example.org' => {} },
26+
{ '1.2.3.4@' => {} },
27+
].each do |value|
28+
describe value.inspect do
29+
it { is_expected.not_to allow_value(value) }
30+
end
31+
end
32+
end
33+
end
34+
end
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# frozen_string_literal: true
2+
3+
require 'spec_helper'
4+
5+
provider_class = Puppet::Type.type(:powerdns_autoprimary).provider(:pdnsutil)
6+
7+
describe provider_class do
8+
let(:resource) do
9+
Puppet::Type::Powerdns_autoprimary.new(
10+
name: '1.2.3.4@ns1.example.com',
11+
provider: described_class.name,
12+
)
13+
end
14+
15+
let(:provider) { provider_class.new(resource) }
16+
17+
it 'has its name set' do
18+
expect(resource[:name]).to eq('1.2.3.4@ns1.example.com')
19+
end
20+
end
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
require 'puppet'
2+
require 'puppet/type/powerdns_autoprimary'
3+
4+
describe Puppet::Type.type(:powerdns_autoprimary) do
5+
let!(:autoprimary) { Puppet::Type.type(:powerdns_autoprimary).new(name: '1.2.3.4@ns1.example.com') }
6+
7+
it 'has its name set' do
8+
expect(autoprimary[:name]).to eq('1.2.3.4@ns1.example.com')
9+
end
10+
it 'has set account to empty string' do
11+
expect(autoprimary[:account]).to eq('')
12+
end
13+
end

types/autoprimaries.pp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
type Powerdns::Autoprimaries=Hash[
2+
Pattern[/.+@.+/],
3+
Struct[{
4+
account => Optional[String],
5+
}]
6+
]

0 commit comments

Comments
 (0)