Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add systemd timer to update root.hints file #332

Merged
merged 1 commit into from
Feb 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .fixtures.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ fixtures:
repositories:
concat: "https://github.com/puppetlabs/puppetlabs-concat.git"
stdlib: "https://github.com/puppetlabs/puppetlabs-stdlib.git"
systemd: "https://github.com/voxpupuli/puppet-systemd.git"
13 changes: 10 additions & 3 deletions REFERENCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

### Classes

* [`unbound`](#unbound): Class: unbound Installs and configures Unbound, the caching DNS resolver from NLnet Labs
* [`unbound`](#unbound): Installs and configures Unbound, the caching DNS resolver from NLnet Labs
* [`unbound::remote`](#unbound--remote): Class: unbound::remote Configure remote control of the unbound daemon process === Parameters: [*enable*] (optional) The option is used t

### Defined types
Expand Down Expand Up @@ -36,8 +36,6 @@

### <a name="unbound"></a>`unbound`

Class: unbound

Installs and configures Unbound, the caching DNS resolver from NLnet Labs

#### Parameters
Expand All @@ -47,6 +45,7 @@ The following parameters are available in the `unbound` class:
* [`hints_file`](#-unbound--hints_file)
* [`hints_file_content`](#-unbound--hints_file_content)
* [`unbound_version`](#-unbound--unbound_version)
* [`update_root_hints`](#-unbound--update_root_hints)
* [`manage_service`](#-unbound--manage_service)
* [`verbosity`](#-unbound--verbosity)
* [`statistics_interval`](#-unbound--statistics_interval)
Expand Down Expand Up @@ -274,6 +273,14 @@ the version of the installed unbound instance. defaults to the fact, but you can

Default value: `$facts['unbound_version']`

##### <a name="-unbound--update_root_hints"></a>`update_root_hints`

Data type: `Enum['absent','present','unmanaged']`

If set to true (and hints_file isn't set to 'builtin') a systemd timer will be configured to update the root hints file every month

Default value: `fact('systemd') ? { true => 'present', default => 'unmanaged'`

##### <a name="-unbound--manage_service"></a>`manage_service`

Data type: `Boolean`
Expand Down
11 changes: 11 additions & 0 deletions files/roothints.timer
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# THIS FILE IS MANAGED BY PUPPET
# BASED ON https://wiki.archlinux.org/title/Unbound#Roothints_systemd_timer
[Unit]
Description=Run root.hints monthly

[Timer]
OnCalendar=monthly
Persistent=true

[Install]
WantedBy=timers.target
22 changes: 19 additions & 3 deletions manifests/init.pp
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
# Class: unbound
#
# Installs and configures Unbound, the caching DNS resolver from NLnet Labs
# @summary Installs and configures Unbound, the caching DNS resolver from NLnet Labs
#
# @param hints_file
# File path to the root-hints. Set to 'builtin' to remove root-hint option from unbound.conf and use built-in hints.
# @param hints_file_content
# Contents of the root hints file, if it's not remotely fetched.
# @param unbound_version
# the version of the installed unbound instance. defaults to the fact, but you can overwrite it. this reduces the initial puppet runs from two to one
# @param update_root_hints
# If set to true (and hints_file isn't set to 'builtin') a systemd timer will be configured to update the root hints file every month
#
class unbound (
Boolean $manage_service = true,
Integer[0,5] $verbosity = 1,
Expand Down Expand Up @@ -135,7 +137,7 @@
Optional[Integer] $key_cache_slabs = undef,
Optional[Unbound::Size] $neg_cache_size = undef,
Boolean $unblock_lan_zones = false,
Boolean $insecure_lan_zones = false, # version 1.5.8
Boolean $insecure_lan_zones = false, # version 1.5.8
Unbound::Local_zone $local_zone = {},
Array[String[1]] $local_data = [],
Array[String[1]] $local_data_ptr = [],
Expand Down Expand Up @@ -212,6 +214,7 @@
Integer[1] $redis_timeout = 100,
Stdlib::Absolutepath $unbound_conf_d = "${confdir}/unbound.conf.d",
Unbound::Hints_file $hints_file = "${confdir}/root.hints",
Enum['absent','present','unmanaged'] $update_root_hints = fact('systemd') ? { true => 'present', default => 'unmanaged' },
Optional[String[1]] $hints_file_content = undef,
Hash[String[1], Unbound::Rpz] $rpzs = {},
Optional[String[1]] $unbound_version = $facts['unbound_version'],
Expand Down Expand Up @@ -316,6 +319,19 @@
mode => '0444',
content => $hints_file_content,
}
if $update_root_hints == 'present' {
systemd::timer { 'roothints.timer':
timer_content => file("${module_name}/roothints.timer"),
service_content => epp("${module_name}/roothints.service.epp", { 'hints_file' => $hints_file, 'root_hints_url' => $root_hints_url, 'fetch_client' => $fetch_client }),
active => true,
enable => true,
}
}
}
if $update_root_hints == 'absent' {
systemd::timer { 'roothints.timer':
ensure => 'absent',
}
}

# purge unmanaged files in configuration directory
Expand Down
4 changes: 4 additions & 0 deletions metadata.json
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,10 @@
{
"name": "puppetlabs/stdlib",
"version_requirement": ">= 4.25.0 < 10.0.0"
},
{
"name": "puppet/systemd",
"version_requirement": ">= 6.3.0 < 7.0.0"
}
]
}
113 changes: 78 additions & 35 deletions spec/classes/init_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,6 @@

pidfile = nil

if facts.dig(:os, 'family').nil?
if facts[:osfamily]
puts "Skipping tests on on platform #{facts[:osfamily]} due to missing facts[:os][:family]"
else
puts "Skipping tests on on platform #{facts[:kernel]} due to missing facts[:os][:family]"
end
next
end

case facts[:os]['family']
when 'Debian'
pidfile = '/run/unbound.pid'
Expand Down Expand Up @@ -67,6 +58,10 @@
it { is_expected.to contain_file(keys_d_dir) }
it { is_expected.to contain_file(hints_file) }

context 'on Linux', if: facts[:kernel] == 'Linux' do
it { is_expected.to contain_systemd__timer('roothints.timer') }
end

it do
expect(subject).to contain_file(unbound_conf_d).with(
'ensure' => 'directory',
Expand Down Expand Up @@ -1038,41 +1033,89 @@
end
end

context 'no root hints in config' do
let(:params) do
{
hints_file: 'builtin'
}
context 'roothints' do
context 'no root hints in config' do
let(:params) do
{
hints_file: 'builtin'
}
end

it do
expect(subject).to contain_concat__fragment(
'unbound-header'
).without_content(%r{root-hints})
end

it { is_expected.not_to contain_systemd__timer('roothints.timer') }
end

it do
expect(subject).to contain_concat__fragment(
'unbound-header'
).without_content(%r{root-hints})
context 'no root hints in config and update_root_hints=unmanaged' do
let(:params) do
{
hints_file: 'builtin',
update_root_hints: 'unmanaged'
}
end

it do
expect(subject).to contain_concat__fragment(
'unbound-header'
).without_content(%r{root-hints})
end

it { is_expected.not_to contain_systemd__timer('roothints.timer') }
end
end

context 'hieradata root hints' do
let(:params) do
{
skip_roothints_download: true,
hints_file_content: File.read('spec/classes/expected/hieradata-root-hint.conf'),
}
context 'no root hints in config and update_root_hints=absent' do
let(:params) do
{
hints_file: 'builtin',
update_root_hints: 'absent'
}
end

it do
expect(subject).to contain_concat__fragment(
'unbound-header'
).without_content(%r{root-hints})
end

it { is_expected.to contain_systemd__timer('roothints.timer').with_ensure('absent') }
end

it do
expect(subject).to contain_file(hints_file).with(
'ensure' => 'file',
'mode' => '0444',
'content' => File.read('spec/classes/expected/hieradata-root-hint.conf')
)
context 'update_root_hints=absent' do
let(:params) do
{
update_root_hints: 'absent'
}
end

it { is_expected.to contain_systemd__timer('roothints.timer').with_ensure('absent') }
end
end

context 'with File defaults' do
let(:pre_condition) { "File { mode => '0644', owner => 'root', group => 'root' }" }
context 'hieradata root hints' do
let(:params) do
{
skip_roothints_download: true,
hints_file_content: File.read('spec/classes/expected/hieradata-root-hint.conf'),
}
end

it { is_expected.to compile.with_all_deps }
it do
expect(subject).to contain_file(hints_file).with(
'ensure' => 'file',
'mode' => '0444',
'content' => File.read('spec/classes/expected/hieradata-root-hint.conf')
)
end
end

context 'with File defaults' do
let(:pre_condition) { "File { mode => '0644', owner => 'root', group => 'root' }" }

it { is_expected.to compile.with_all_deps }
end
end

context 'RPZs config' do
Expand Down
9 changes: 9 additions & 0 deletions templates/roothints.service.epp
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<%- | Stdlib::Absolutepath $hints_file, Stdlib::HTTPSUrl $root_hints_url, String[1] $fetch_client | -%>
# THIS FILE IS MANAGED BY PUPPET
# BASED ON https://wiki.archlinux.org/title/Unbound#Roothints_systemd_timer
[Unit]
Description=Update root hints for unbound
After=network.target

[Service]
ExecStart=<%= $fetch_client %> <%= $hints_file %> <%= $root_hints_url %>