diff --git a/REFERENCE.md b/REFERENCE.md index 568629f..ac24c42 100644 --- a/REFERENCE.md +++ b/REFERENCE.md @@ -297,10 +297,10 @@ Default value: ``undef`` ##### `peers` -Data type: `Any` +Data type: `Variant[Hash,Array[Stdlib::Host]]` This selects the servers to use for NTP peers (symmetric association). -It is an array of servers. +It can be an array of peers or a hash of peers with their respective options. Default value: `[]` @@ -309,7 +309,8 @@ Default value: `[]` Data type: `Variant[Hash,Array[Stdlib::Host]]` This selects the servers to use for NTP servers. It can be an array of servers -or a hash of servers to their respective options. +or a hash of servers to their respective options. If an array is used, `iburst` will be configured for each server. +If you don't want to use `iburst`, use a hash instead. Default value: `{ '0.pool.ntp.org' => ['iburst'], @@ -323,7 +324,7 @@ Default value: `{ Data type: `Variant[Hash,Array[Stdlib::Fqdn]]` This is used to specify one or more *pools* of NTP servers to use instead of individual NTP servers. -Similar to [`server`](#server), it can be an array of pools or a hash of pools to their respective options. +Similar to [`server`](#server), it can be an array of pools, (using iburst), or a hash of pools to their respective options. See [pool](https://chrony.tuxfamily.org/doc/3.4/chrony.conf.html#pool) Default value: `{}` diff --git a/manifests/init.pp b/manifests/init.pp index e2050ce..69f9809 100644 --- a/manifests/init.pp +++ b/manifests/init.pp @@ -104,13 +104,14 @@ # Also see [`package_source`](#package_source). # @param peers # This selects the servers to use for NTP peers (symmetric association). -# It is an array of servers. +# It can be an array of peers or a hash of peers with their respective options. # @param servers # This selects the servers to use for NTP servers. It can be an array of servers -# or a hash of servers to their respective options. +# or a hash of servers to their respective options. If an array is used, `iburst` will be configured for each server. +# If you don't want to use `iburst`, use a hash instead. # @param pools # This is used to specify one or more *pools* of NTP servers to use instead of individual NTP servers. -# Similar to [`server`](#server), it can be an array of pools or a hash of pools to their respective options. +# Similar to [`server`](#server), it can be an array of pools, (using iburst), or a hash of pools to their respective options. # See [pool](https://chrony.tuxfamily.org/doc/3.4/chrony.conf.html#pool) # @param refclocks # This should be a Hash of hardware reference clock drivers to use. They hash @@ -201,7 +202,7 @@ Optional[String] $package_source = undef, Optional[String] $package_provider = undef, $refclocks = [], - $peers = [], + Variant[Hash,Array[Stdlib::Host]] $peers = [], Variant[Hash,Array[Stdlib::Host]] $servers = { '0.pool.ntp.org' => ['iburst'], '1.pool.ntp.org' => ['iburst'], diff --git a/spec/classes/chrony_spec.rb b/spec/classes/chrony_spec.rb index 5267803..b2520c9 100644 --- a/spec/classes/chrony_spec.rb +++ b/spec/classes/chrony_spec.rb @@ -16,6 +16,25 @@ let(:facts) do facts end + let(:config_file) do + case facts[:osfamily] + when 'Archlinux', 'RedHat', 'Suse' + '/etc/chrony.conf' + else + '/etc/chrony/chrony.conf' + end + end + let(:keys_file) do + case facts[:osfamily] + when 'Archlinux', 'RedHat', 'Suse' + '/etc/chrony.keys' + else + '/etc/chrony/chrony.keys' + end + end + let(:config_file_contents) do + catalogue.resource('file', config_file).send(:parameters)[:content] + end context 'with defaults' do it { is_expected.to compile.with_all_deps } @@ -237,6 +256,141 @@ end end + describe 'servers' do + context 'by default' do + it do + expected_lines = [ + 'server 0.pool.ntp.org iburst', + 'server 1.pool.ntp.org iburst', + 'server 2.pool.ntp.org iburst', + 'server 3.pool.ntp.org iburst' + ] + expect(config_file_contents.split("\n") & expected_lines).to eq(expected_lines) + end + end + context 'when servers is an array' do + let(:params) do + { + servers: ['ntp1.corp.com', 'ntp2.corp.com'], + } + end + + it do + expected_lines = [ + 'server ntp1.corp.com iburst', + 'server ntp2.corp.com iburst', + ] + expect(config_file_contents.split("\n") & expected_lines).to eq(expected_lines) + end + end + context 'when servers is an (unsorted) hash' do + let(:params) do + { + servers: { + 'ntp3.corp.com' => [], + 'ntp1.corp.com' => ['key 25', 'iburst'], + 'ntp4.corp.com' => :undef, + 'ntp2.corp.com' => ['key 25', 'iburst'], + } + } + end + + it do + expected_lines = [ + 'server ntp1.corp.com key 25 iburst', + 'server ntp2.corp.com key 25 iburst', + 'server ntp3.corp.com', + 'server ntp4.corp.com', + ] + expect(config_file_contents.split("\n") & expected_lines).to eq(expected_lines) + end + end + end + + describe 'pools' do + context 'by default' do + it { expect(config_file_contents).not_to match(%r{^pool}) } + end + context 'when pools is an array' do + let(:params) do + { + pools: ['0.pool.ntp.org', '1.pool.ntp.org'] + } + end + + it do + expected_lines = [ + 'server 0.pool.ntp.org iburst', + 'server 1.pool.ntp.org iburst', + ] + expect(config_file_contents.split("\n") & expected_lines).to eq(expected_lines) + end + end + context 'when pools is a hash' do + let(:params) do + { + pools: { + '3.pool.ntp.org' => [], + '0.pool.ntp.org' => ['maxsources 4'], + '1.pool.ntp.org' => ['maxsources 4'], + '2.pool.ntp.org' => ['maxsources 4'], + } + } + end + + it do + expected_lines = [ + 'pool 0.pool.ntp.org maxsources 4', + 'pool 1.pool.ntp.org maxsources 4', + 'pool 2.pool.ntp.org maxsources 4', + 'pool 3.pool.ntp.org', + ] + expect(config_file_contents.split("\n") & expected_lines).to eq(expected_lines) + end + end + end + + describe 'peers' do + context 'by default' do + it { expect(config_file_contents).not_to match(%r{^peer}) } + end + context 'when peers is an array' do + let(:params) do + { + peers: ['peer1.example.com', 'peer2.example.com'] + } + end + + it do + expected_lines = [ + 'peer peer1.example.com', + 'peer peer2.example.com', + ] + expect(config_file_contents.split("\n") & expected_lines).to eq(expected_lines) + end + end + context 'when peers is a hash' do + let(:params) do + { + peers: { + 'peer1.example.com' => [], + 'peer2.example.com' => ['maxpoll 6'], + 'peer3.example.com' => :undef, + } + } + end + + it do + expected_lines = [ + 'peer peer1.example.com', + 'peer peer2.example.com maxpoll 6', + 'peer peer3.example.com', + ] + expect(config_file_contents.split("\n") & expected_lines).to eq(expected_lines) + end + end + end + context 'unmanaged chrony.keys file' do let(:params) do { diff --git a/templates/chrony.conf.epp b/templates/chrony.conf.epp index 1970f6d..8bc7f0d 100644 --- a/templates/chrony.conf.epp +++ b/templates/chrony.conf.epp @@ -1,12 +1,42 @@ # NTP servers +<% if $chrony::servers.is_a(Hash) { -%> +<% $chrony::servers.keys.sort.each |$server| { -%> +<% if $chrony::servers[$server] and !$chrony::servers[$server].empty { -%> +server <%= $server %> <%= $chrony::servers[$server].join(' ') %> +<% } else { -%> +server <%= $server %> +<% } -%> +<% } -%> +<% } else { -%> <% $chrony::servers.each |$server| { -%> -server <%= $server.flatten.join(' ') %> +server <%= $server %> iburst +<% } -%> +<% } -%> +<% if $chrony::pools.is_a(Hash) { -%> +<% $chrony::pools.keys.sort.each |$pool| { -%> +<% if $chrony::pools[$pool] and !$chrony::pools[$pool].empty { -%> +pool <%= $pool %> <%= $chrony::pools[$pool].join(' ') %> +<% } else { -%> +pool <%= $pool %> +<% } -%> <% } -%> +<% } else { -%> <% $chrony::pools.each |$pool| { -%> -pool <%= $pool.flatten.join(' ') %> +pool <%= $pool %> iburst <% } -%> +<% } -%> +<% if $chrony::peers.is_a(Hash) { -%> +<% $chrony::peers.keys.sort.each |$peer| { -%> +<% if $chrony::peers[$peer] and !$chrony::peers[$peer].empty { -%> +peer <%= $peer %> <%= $chrony::peers[$peer].join(' ') %> +<% } else { -%> +peer <%= $peer %> +<% } -%> +<% } -%> +<% } else { -%> <% $chrony::peers.each |$peer| { -%> -peer <%= $peer.flatten.join(' ') %> +peer <%= $peer %> +<% } -%> <% } -%> <% if $chrony::stratumweight { -%> diff --git a/templates/chrony.conf.epp.bak b/templates/chrony.conf.epp.bak new file mode 100644 index 0000000..f504022 --- /dev/null +++ b/templates/chrony.conf.epp.bak @@ -0,0 +1,149 @@ +# NTP servers +<% if $chrony::servers.is_a(Hash) { -%> +<% $chrony::servers.keys.sort.each |$server| { -%> +<% if $chrony::servers[$server] and !$chrony::servers[$server].empty { -%> +server <%= $server %> <%= $chrony::servers[$server].join(' ') %> +<% } else { -%> +server <%= $server %> +<% } -%> +<% } -%> +<% } else { -%> +<% $chrony::servers.each |$server| { -%> +server <%= $server %> iburst +<% } -%> +<% } -%> +<% $chrony::pools.each |$pool| { -%> +pool <%= $pool.flatten.join(' ') %> +<% } -%> +<% $chrony::peers.each |$peer| { -%> +peer <%= $peer.flatten.join(' ') %> +<% } -%> +<% if $chrony::stratumweight { -%> + +# How much distance should be added per stratum to the synchronisation distance when +# chronyd selects the synchronisation source from available sources. +stratumweight <%= $chrony::stratumweight %> +<% } -%> + +# Record the rate at which the system clock gains/losses time. +driftfile <%= $chrony::driftfile %> +<% if $chrony::rtcsync { -%> + +# Enable kernel RTC synchronization. +rtcsync +<% } -%> +<% if $chrony::makestep_seconds and $chrony::makestep_updates { -%> + +# In first <%= $chrony::makestep_updates %> updates step the system clock instead of slew +# if the adjustment is larger than <%= $chrony::makestep_seconds %> seconds. +makestep <%= $chrony::makestep_seconds %> <%= $chrony::makestep_updates %> +<% } -%> +<% unless $chrony::queryhosts.empty { -%> + +# Allow client access. +<% $chrony::queryhosts.each |$allowed| { -%> +allow <%= $allowed %> +<% } -%> +<% } -%> +<% if $chrony::cmdport { -%> +cmdport <%= $chrony::cmdport %> +<% } -%> +<% unless $chrony::bindcmdaddress.empty { -%> + +<% $chrony::bindcmdaddress.each |$addr| { -%> +bindcmdaddress <%= $addr %> +<% } -%> +<% } -%> +<% $chrony::cmdacl.each |$acl| { -%> +<%= $acl %> +<% } -%> +<% if $chrony::port { -%> + +# http://chrony.tuxfamily.org/manual.html#port-directive +port <%= $chrony::port %> +<% } -%> +<% if $chrony::local_stratum { -%> + +# Serve time even if not synchronized to any NTP server. +local stratum <%= $chrony::local_stratum %> +<% } -%> +<% if $chrony::config_keys { -%> + +keyfile <%= $chrony::config_keys %> +<% } -%> +<% if $chrony::dumpdir { -%> + +# Save the measurement history for the servers to files on exit. +dumponexit +dumpdir <%= $chrony::dumpdir %> +<% } -%> +<% unless $chrony::clientlog { -%> + +# Disable logging of client accesses. +noclientlog +<% } -%> +<% if $chrony::clientloglimit { -%> + +# The clientlog size is limited to 512KB by default. If you have many +# clients, especially in many different subnets, you might want to +# increase the limit. +clientloglimit <%= $chrony::clientloglimit %> +<% } -%> + +# Send a message to syslog if a clock adjustment is larger than 0.5 seconds. +logchange 0.5 +<% if $chrony::mailonchange { -%> + +# Send mail if chronyd applied a correction exceeding given threshold. +mailonchange <%= $chrony::mailonchange %> <%= $chrony::threshold %> +<% } -%> + +logdir /var/log/chrony +<% if $chrony::log_options { -%> +log <%= $chrony::log_options %> +<% } -%> +<% unless $chrony::refclocks.empty { -%> + +<% $chrony::refclocks.each |$driver| { -%> +refclock <%= $driver.flatten.join(' ') %> +<% } -%> +<% } -%> +<% if $chrony::lock_all { -%> + +# Lock chrony to RAM. +lock_all +<% } -%> +<% if $chrony::leapsecmode { -%> + +# https://chrony.tuxfamily.org/doc/3.4/chrony.conf.html#leapsecmode +leapsecmode <%= $chrony::leapsecmode %> +<% } -%> +<% if $chrony::leapsectz { -%> + +# https://chrony.tuxfamily.org/doc/3.4/chrony.conf.html#leapsectz +leapsectz <%= $chrony::leapsectz %> +<% } -%> +<% if $chrony::maxslewrate { -%> + +# https://chrony.tuxfamily.org/doc/3.4/chrony.conf.html#maxslewrate +maxslewrate <%= $chrony::maxslewrate %> +<% } -%> +<% if $chrony::smoothtime { -%> + +# https://chrony.tuxfamily.org/doc/3.4/chrony.conf.html#smoothtime +smoothtime <%= $chrony::smoothtime %> +<% } -%> +<% if $chrony::rtconutc { -%> + +# https://chrony.tuxfamily.org/doc/3.4/chrony.conf.html#rtconutc +rtconutc +<% } -%> +<% unless $chrony::hwtimestamps.empty { -%> + +# Enable hardware timestamping of NTP packets sent to and received from the specified +# network interface. If the specified interface is *, chronyd will try to enable HW +# timestamping on all available interfaces. +<% $chrony::hwtimestamps.each |$interface| { -%> +hwtimestamp <%= $interface.flatten.join(' ') %> +<% } -%> +<% } -%>