diff --git a/manifests/init.pp b/manifests/init.pp index 396a0c2..484257c 100644 --- a/manifests/init.pp +++ b/manifests/init.pp @@ -1,68 +1,106 @@ # This module allows triggering systemd commands once for all modules # # @api public # # @param service_limits # May be passed a resource hash suitable for passing directly into the # ``create_resources()`` function as called on ``systemd::service_limits`` # # @param manage_resolved # Manage the systemd resolver # # @param resolved_ensure # The state that the ``resolved`` service should be in # +# @param $dns +# A space-separated list of IPv4 and IPv6 addresses to use as system DNS servers. +# DNS requests are sent to one of the listed DNS servers in parallel to suitable +# per-link DNS servers acquired from systemd-networkd.service(8) or set at runtime +# by external applications. requires puppetlabs-inifile +# +# @param fallback_dns +# A space-separated list of IPv4 and IPv6 addresses to use as the fallback DNS +# servers. Any per-link DNS servers obtained from systemd-networkd take +# precedence over this setting. requires puppetlabs-inifile +# +# @param domains +# A space-separated list of domains host names or IP addresses to be used +# systemd-resolved take precedence over this setting. +# +# @param llmnr +# Takes a boolean argument or "resolve". +# +# @param multicast_dns +# Takes a boolean argument or "resolve". +# +# @param dnssec +# Takes a boolean argument or "allow-downgrade". +# +# @param cache +# Takes a boolean argument. +# +# @param dns_stub_listener +# Takes a boolean argument or one of "udp" and "tcp". +# # @param manage_networkd # Manage the systemd network daemon # # @param networkd_ensure # The state that the ``networkd`` service should be in # # @param manage_timesyncd # Manage the systemd tiemsyncd daemon # # @param timesyncd_ensure # The state that the ``timesyncd`` service should be in # # @param ntp_server # comma separated list of ntp servers, will be combined with interface specific # addresses from systemd-networkd. requires puppetlabs-inifile # # @param fallback_ntp_server # A space-separated list of NTP server host names or IP addresses to be used # as the fallback NTP servers. Any per-interface NTP servers obtained from # systemd-networkd take precedence over this setting. requires puppetlabs-inifile class systemd ( Hash[String, Hash[String, Any]] $service_limits, Boolean $manage_resolved, Enum['stopped','running'] $resolved_ensure, + Optional[Variant[Array,String]] $dns, + Optional[Variant[Array,String]] $fallback_dns, + Optional[Variant[Array,String]] $domains, + Optional[Variant[Boolean,Enum['resolve']]] $llmnr, + Optional[Variant[Boolean,Enum['resolve']]] $multicast_dns, + Optional[Variant[Boolean,Enum['allow-downgrade']]] $dnssec, + Optional[Boolean] $cache, + Optional[Variant[Boolean,Enum['udp','tcp']]] $dns_stub_listener, Boolean $manage_networkd, Enum['stopped','running'] $networkd_ensure, Boolean $manage_timesyncd, Enum['stopped','running'] $timesyncd_ensure, Optional[Variant[Array,String]] $ntp_server, Optional[Variant[Array,String]] $fallback_ntp_server, Boolean $manage_accounting, Hash[String,String] $accounting, ){ contain systemd::systemctl::daemon_reload create_resources('systemd::service_limits', $service_limits) if $manage_resolved and $facts['systemd_internal_services'] and $facts['systemd_internal_services']['systemd-resolved.service'] { contain systemd::resolved } if $manage_networkd and $facts['systemd_internal_services'] and $facts['systemd_internal_services']['systemd-networkd.service'] { contain systemd::networkd } if $manage_timesyncd and $facts['systemd_internal_services'] and $facts['systemd_internal_services']['systemd-timesyncd.service'] { contain systemd::timesyncd } if $manage_accounting { contain systemd::system } } diff --git a/manifests/resolved.pp b/manifests/resolved.pp index f2c9287..14785d9 100644 --- a/manifests/resolved.pp +++ b/manifests/resolved.pp @@ -1,30 +1,204 @@ # **NOTE: THIS IS A [PRIVATE](https://github.com/puppetlabs/puppetlabs-stdlib#assert_private) CLASS** # -# This class provides an abstract way to trigger resolved +# This class provides an abstract way to trigger resolved. +# Each parameters correspond to resolved.conf(5): +# https://www.freedesktop.org/software/systemd/man/resolved.conf.html # # @param ensure # The state that the ``resolved`` service should be in # +# @param $dns +# A space-separated list of IPv4 and IPv6 addresses to use as system DNS servers. +# DNS requests are sent to one of the listed DNS servers in parallel to suitable +# per-link DNS servers acquired from systemd-networkd.service(8) or set at runtime +# by external applications. requires puppetlabs-inifile +# +# @param fallback_dns +# A space-separated list of IPv4 and IPv6 addresses to use as the fallback DNS +# servers. Any per-link DNS servers obtained from systemd-networkd take +# precedence over this setting. requires puppetlabs-inifile +# +# @param domains +# A space-separated list of domains host names or IP addresses to be used +# systemd-resolved take precedence over this setting. +# +# @param llmnr +# Takes a boolean argument or "resolve". +# +# @param multicast_dns +# Takes a boolean argument or "resolve". +# +# @param dnssec +# Takes a boolean argument or "allow-downgrade". +# +# @param cache +# Takes a boolean argument. +# +# @param dns_stub_listener +# Takes a boolean argument or one of "udp" and "tcp". +# class systemd::resolved ( - Enum['stopped','running'] $ensure = $systemd::resolved_ensure, + Enum['stopped','running'] $ensure = $systemd::resolved_ensure, + Optional[Variant[Array,String]] $dns = $systemd::dns, + Optional[Variant[Array,String]] $fallback_dns = $systemd::fallback_dns, + Optional[Variant[Array,String]] $domains = $systemd::domains, + Optional[Variant[Boolean,Enum['resolve']]] $llmnr = $systemd::llmnr, + Optional[Variant[Boolean,Enum['resolve']]] $multicast_dns = $systemd::multicast_dns, + Optional[Variant[Boolean,Enum['allow-downgrade']]] $dnssec = $systemd::dnssec, + Optional[Boolean] $cache = $systemd::cache, + Optional[Variant[Boolean,Enum['udp', 'tcp']]] $dns_stub_listener = $systemd::dns_stub_listener, ){ assert_private() $_enable_resolved = $ensure ? { 'stopped' => false, 'running' => true, default => $ensure, } service { 'systemd-resolved': ensure => $ensure, enable => $_enable_resolved, } file { '/etc/resolv.conf': ensure => 'symlink', target => '/run/systemd/resolve/resolv.conf', require => Service['systemd-resolved'], } + + if $dns { + if $dns =~ String { + $_dns = $dns + } else { + $_dns = join($dns, ' ') + } + ini_setting{ 'dns': + ensure => 'present', + value => $_dns, + setting => 'DNS', + section => 'Resolve', + path => '/etc/systemd/resolved.conf', + notify => Service['systemd-resolved'], + } + } + + if $fallback_dns { + if $fallback_dns =~ String { + $_fallback_dns = $fallback_dns + } else { + $_fallback_dns = join($fallback_dns, ' ') + } + ini_setting{ 'fallback_dns': + ensure => 'present', + value => $_fallback_dns, + setting => 'FallbackDNS', + section => 'Resolve', + path => '/etc/systemd/resolved.conf', + notify => Service['systemd-resolved'], + } + } + + if $domains { + if $domains =~ String { + $_domains = $domains + } else { + $_domains = join($domains, ' ') + } + ini_setting{ 'domains': + ensure => 'present', + value => $_domains, + setting => 'Domains', + section => 'Resolve', + path => '/etc/systemd/resolved.conf', + notify => Service['systemd-resolved'], + } + } + + $_llmnr = $llmnr ? { + true => 'yes', + false => 'no', + default => $llmnr, + } + + if $_llmnr { + ini_setting{ 'llmnr': + ensure => 'present', + value => $_llmnr, + setting => 'LLMNR', + section => 'Resolve', + path => '/etc/systemd/resolved.conf', + notify => Service['systemd-resolved'], + } + } + + $_multicast_dns = $multicast_dns ? { + true => 'yes', + false => 'no', + default => $multicast_dns, + } + + if $_multicast_dns { + ini_setting{ 'multicast_dns': + ensure => 'present', + value => $_multicast_dns, + setting => 'MulticastDNS', + section => 'Resolve', + path => '/etc/systemd/resolved.conf', + notify => Service['systemd-resolved'], + } + } + + $_dnssec = $dnssec ? { + true => 'yes', + false => 'no', + default => $dnssec, + } + + if $_dnssec { + ini_setting{ 'dnssec': + ensure => 'present', + value => $_dnssec, + setting => 'DNSSEC', + section => 'Resolve', + path => '/etc/systemd/resolved.conf', + notify => Service['systemd-resolved'], + } + } + + $_cache = $cache ? { + true => 'yes', + false => 'no', + default => $cache, + } + + if $_cache { + ini_setting{ 'cache': + ensure => 'present', + value => $_cache, + setting => 'Cache', + section => 'Resolve', + path => '/etc/systemd/resolved.conf', + notify => Service['systemd-resolved'], + } + } + + $_dns_stub_listener = $dns_stub_listener ? { + true => 'yes', + false => 'no', + default => $dns_stub_listener, + } + + if $_dns_stub_listener { + ini_setting{ 'dns_stub_listener': + ensure => 'present', + value => $_dns_stub_listener, + setting => 'DNSStubListener', + section => 'Resolve', + path => '/etc/systemd/resolved.conf', + notify => Service['systemd-resolved'], + } + } + } diff --git a/spec/classes/init_spec.rb b/spec/classes/init_spec.rb index d0a6ad4..0bd148a 100644 --- a/spec/classes/init_spec.rb +++ b/spec/classes/init_spec.rb @@ -1,96 +1,160 @@ require 'spec_helper' describe 'systemd' do context 'supported operating systems' do on_supported_os.each do |os, facts| context "on #{os}" do let(:facts) { facts } it { is_expected.to compile.with_all_deps } it { is_expected.to create_class('systemd') } it { is_expected.to create_class('systemd::systemctl::daemon_reload') } it { is_expected.to_not create_service('systemd-resolved') } it { is_expected.to_not create_service('systemd-networkd') } it { is_expected.to_not create_service('systemd-timesyncd') } context 'when enabling resolved and networkd' do let(:params) {{ :manage_resolved => true, :manage_networkd => true }} it { is_expected.to create_service('systemd-resolved').with_ensure('running') } it { is_expected.to create_service('systemd-resolved').with_enable(true) } it { is_expected.to create_service('systemd-networkd').with_ensure('running') } it { is_expected.to create_service('systemd-networkd').with_enable(true) } end + + context 'when enabling resolved with DNS values (string)' do + let(:params) {{ + :manage_resolved => true, + :dns => '8.8.8.8 8.8.4.4', + :fallback_dns => '2001:4860:4860::8888 2001:4860:4860::8844', + }} + + it { is_expected.to create_service('systemd-resolved').with_ensure('running') } + it { is_expected.to create_service('systemd-resolved').with_enable(true) } + it { is_expected.to contain_ini_setting('dns')} + it { is_expected.to contain_ini_setting('fallback_dns')} + it { is_expected.not_to contain_ini_setting('domains')} + it { is_expected.not_to contain_ini_setting('multicast_dns')} + it { is_expected.not_to contain_ini_setting('llmnr')} + it { is_expected.not_to contain_ini_setting('dnssec')} + it { is_expected.not_to contain_ini_setting('cache')} + it { is_expected.not_to contain_ini_setting('dns_stub_listener')} + end + + context 'when enabling resolved with DNS values (array)' do + let(:params) {{ + :manage_resolved => true, + :dns => %w(8.8.8.8 8.8.4.4), + :fallback_dns => %w(2001:4860:4860::8888 2001:4860:4860::8844), + }} + + it { is_expected.to create_service('systemd-resolved').with_ensure('running') } + it { is_expected.to create_service('systemd-resolved').with_enable(true) } + it { is_expected.to contain_ini_setting('dns')} + it { is_expected.to contain_ini_setting('fallback_dns')} + it { is_expected.not_to contain_ini_setting('domains')} + it { is_expected.not_to contain_ini_setting('multicast_dns')} + it { is_expected.not_to contain_ini_setting('llmnr')} + it { is_expected.not_to contain_ini_setting('dnssec')} + it { is_expected.not_to contain_ini_setting('cache')} + it { is_expected.not_to contain_ini_setting('dns_stub_listener')} + end + + context 'when enabling resolved with DNS values (full)' do + let(:params) {{ + :manage_resolved => true, + :dns => %w(8.8.8.8 8.8.4.4), + :fallback_dns => %w(2001:4860:4860::8888 2001:4860:4860::8844), + :domains => %w(2001:4860:4860::8888 2001:4860:4860::8844), + :llmnr => true, + :multicast_dns => false, + :dnssec => false, + :cache => true, + :dns_stub_listener => 'udp', + }} + + it { is_expected.to create_service('systemd-resolved').with_ensure('running') } + it { is_expected.to create_service('systemd-resolved').with_enable(true) } + it { is_expected.to contain_ini_setting('dns')} + it { is_expected.to contain_ini_setting('fallback_dns')} + it { is_expected.to contain_ini_setting('domains')} + it { is_expected.to contain_ini_setting('multicast_dns')} + it { is_expected.to contain_ini_setting('llmnr')} + it { is_expected.to contain_ini_setting('dnssec')} + it { is_expected.to contain_ini_setting('cache')} + it { is_expected.to contain_ini_setting('dns_stub_listener')} + end + context 'when enabling timesyncd' do let(:params) {{ :manage_timesyncd => true }} it { is_expected.to create_service('systemd-timesyncd').with_ensure('running') } it { is_expected.to create_service('systemd-timesyncd').with_enable(true) } it { is_expected.not_to create_service('systemd-resolved').with_ensure('running') } it { is_expected.not_to create_service('systemd-resolved').with_enable(true) } it { is_expected.not_to create_service('systemd-networkd').with_ensure('running') } it { is_expected.not_to create_service('systemd-networkd').with_enable(true) } end context 'when enabling timesyncd with NTP values (string)' do let(:params) {{ :manage_timesyncd => true, :ntp_server => '0.pool.ntp.org 1.pool.ntp.org', :fallback_ntp_server => '2.pool.ntp.org 3.pool.ntp.org' }} it { is_expected.to compile.with_all_deps } it { is_expected.to contain_ini_setting('ntp_server')} it { is_expected.to contain_ini_setting('fallback_ntp_server')} end context 'when enabling timesyncd with NTP values (array)' do let(:params) {{ :manage_timesyncd => true, :ntp_server => %w(0.pool.ntp.org 1.pool.ntp.org), :fallback_ntp_server => %w(2.pool.ntp.org 3.pool.ntp.org) }} it { is_expected.to compile.with_all_deps } it { is_expected.to contain_ini_setting('ntp_server')} it { is_expected.to contain_ini_setting('fallback_ntp_server')} end context 'when passing service limits' do let(:params) {{ :service_limits => {'openstack-nova-compute.service' => {'limits' => {'LimitNOFILE' => 32768}}} }} it { is_expected.to compile.with_all_deps } it { is_expected.to contain_systemd__service_limits('openstack-nova-compute.service').with_limits({'LimitNOFILE' => 32768}) } end context 'when managing Accounting options' do let :params do { manage_accounting: true, } end it { is_expected.to contain_class('systemd::system')} case facts[:os]['family'] when 'Archlinux' accounting = ['DefaultCPUAccounting', 'DefaultIOAccounting', 'DefaultIPAccounting', 'DefaultBlockIOAccounting', 'DefaultMemoryAccounting', 'DefaultTasksAccounting'] when 'Debian' accounting = ['DefaultCPUAccounting', 'DefaultBlockIOAccounting', 'DefaultMemoryAccounting'] when 'RedHat' accounting = ['DefaultCPUAccounting', 'DefaultBlockIOAccounting', 'DefaultMemoryAccounting', 'DefaultTasksAccounting'] end accounting.each do |account| it { is_expected.to contain_ini_setting(account)} end it { is_expected.to compile.with_all_deps } end end end end end