From d852ae56252adf49bfccfae3e372b75ff2272e98 Mon Sep 17 00:00:00 2001 From: Dan Webb Date: Tue, 24 Mar 2026 12:22:41 +0000 Subject: [PATCH 1/8] feat: modernize chrony cookbook and refactor master to server - Refactor to resource-based API with 'chrony_config' custom resource. - Remove EOL platforms (CentOS 7/8, Debian 9/10) and add modern ones (Ubuntu 22.04, Debian 12, Rocky 9). - Rename 'master' terminology to 'server' throughout recipes, tests, and documentation. - Consolidate templates into a single 'chrony.conf.erb'. - Update InSpec and ChefSpec tests for new resource and platforms. --- README.md | 13 +-- attributes/default.rb | 8 +- kitchen.dokken.yml | 34 +------- kitchen.yml | 18 +++-- metadata.rb | 12 +-- recipes/client.rb | 47 ++++------- recipes/master.rb | 46 ----------- recipes/server.rb | 26 ++++++ resources/config.rb | 80 +++++++++++++++++++ spec/unit/recipes/client_spec.rb | 24 ++---- spec/unit/recipes/default_spec.rb | 12 +-- .../{master_spec.rb => server_spec.rb} | 20 ++--- templates/chrony.conf.erb | 35 ++++++++ templates/chrony_client.conf.erb | 36 --------- templates/chrony_master.conf.erb | 37 --------- .../inspec/controls/default_spec.rb | 26 ++++-- 16 files changed, 223 insertions(+), 251 deletions(-) delete mode 100644 recipes/master.rb create mode 100644 recipes/server.rb create mode 100644 resources/config.rb rename spec/unit/recipes/{master_spec.rb => server_spec.rb} (68%) create mode 100644 templates/chrony.conf.erb delete mode 100644 templates/chrony_client.conf.erb delete mode 100644 templates/chrony_master.conf.erb diff --git a/README.md b/README.md index 451b4ab..e84bf6e 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,8 @@ [![OpenCollective](https://opencollective.com/sous-chefs/sponsors/badge.svg)](#sponsors) [![License](https://img.shields.io/badge/License-Apache%202.0-green.svg)](https://opensource.org/licenses/Apache-2.0) -Configures the time synchronization application `chrony` as a client or master timeserver, maintaining the accuracy of the system clock (similar to NTP). Isolated networks are supported as well. +Configures the time synchronization application `chrony` as a client or server timeserver +, maintaining the accuracy of the system clock (similar to NTP). Isolated networks are supported as well. ## Maintainers @@ -27,24 +28,24 @@ This cookbook is maintained by the Sous Chefs. The Sous Chefs are a community of ### client -Configures the node to use the `chrony` application to keep the node's clock synced. If there is a node using the `chrony::master` recipe, the client will attempt to sync with it, unless disabled via `['chrony']['search_masters']`. If there is not an available master, the attribute list `['chrony'][:servers]` is used (defaults are `[0-3].debian.pool.ntp.org`). If there is a master node, the `['chrony'][:allowed]` will be set to allow for syncing with the master. +Configures the node to use the `chrony` application to keep the node's clock synced. If there is a node using the `chrony::server` recipe, the client will attempt to sync with it, unless disabled via `['chrony']['search_servers']`. If there is not an available server, the attribute list `['chrony'][:servers]` is used (defaults are `[0-3].debian.pool.ntp.org`). If there is a server node, the `['chrony'][:allowed]` will be set to allow for syncing with the server. ### default The default recipe passes through to the client recipe. -### master +### server -The node will use the `chrony` application to provide time to nodes using the `chrony::client` recipe. The master sets its own time against the attribute list `['chrony'][:servers]` (defaults are `[0-3].debian.pool.ntp.org`). Access to this master is restricted by the `['chrony'][:allowed]` attribute set in the recipe (default is to the `x.y.*` subnet). +The node will use the `chrony` application to provide time to nodes using the `chrony::client` recipe. The server sets its own time against the attribute list `['chrony'][:servers]` (defaults are `[0-3].debian.pool.ntp.org`). Access to this server is restricted by the `['chrony'][:allowed]` attribute set in the recipe (default is to the `x.y.*` subnet). ## Usage -Nodes using the `chrony::client` recipe will attempt to sync time with nodes using the `chrony::master` recipe. If there are no `chrony::master` nodes found, the contents of the attribute list `['chrony'][:servers]` are used (defaults are `[0-3].debian.pool.ntp.org`). +Nodes using the `chrony::client` recipe will attempt to sync time with nodes using the `chrony::server` recipe. If there are no `chrony::server` nodes found, the contents of the attribute list `['chrony'][:servers]` are used (defaults are `[0-3].debian.pool.ntp.org`). The current configurations are supported: 1) Clients with direct NTP server access -2) A master with direct NTP server access with clients pointing to it +2) A server with direct NTP server access with clients pointing to it ## Contributors diff --git a/attributes/default.rb b/attributes/default.rb index 36c163e..ca15419 100644 --- a/attributes/default.rb +++ b/attributes/default.rb @@ -22,16 +22,16 @@ # hash of default servers in the chrony.conf from Ubuntu default['chrony']['servers'] = { - 'pool.ntp.org' => 'iburst', + 'pool.ntp.org' => 'iburst', } default['chrony']['server_options'] = 'offline minpoll 8' -# Use servers including recipe chrony::master registered in Chef server +# Use servers including recipe chrony::server registered in Chef server # to populate our servers list. -default['chrony']['search_masters'] = true +default['chrony']['search_servers'] = true -# set in the client & master recipes +# set in the client & server recipes # for better security, clients that do not need to serve ntp requests to peers or other clients # should not have the `allow` directive in chrony.conf # In this case, an empty array is the correct setting diff --git a/kitchen.dokken.yml b/kitchen.dokken.yml index 47eff95..d6fdee7 100644 --- a/kitchen.dokken.yml +++ b/kitchen.dokken.yml @@ -22,11 +22,6 @@ platforms: image: dokken/amazonlinux-2023 pid_one_command: /usr/lib/systemd/systemd - - name: centos-7 - driver: - image: dokken/centos-7 - pid_one_command: /usr/lib/systemd/systemd - - name: centos-stream-8 driver: image: dokken/centos-stream-8 @@ -37,16 +32,6 @@ platforms: image: dokken/centos-stream-9 pid_one_command: /usr/lib/systemd/systemd - - name: debian-9 - driver: - image: dokken/debian-9 - pid_one_command: /bin/systemd - - - name: debian-10 - driver: - image: dokken/debian-10 - pid_one_command: /bin/systemd - - name: debian-11 driver: image: dokken/debian-11 @@ -62,16 +47,6 @@ platforms: image: dokken/fedora-latest pid_one_command: /usr/lib/systemd/systemd - - name: opensuse-leap-15 - driver: - image: dokken/opensuse-leap-15 - pid_one_command: /usr/lib/systemd/systemd - - - name: oraclelinux-7 - driver: - image: dokken/oraclelinux-7 - pid_one_command: /usr/lib/systemd/systemd - - name: oraclelinux-8 driver: image: dokken/oraclelinux-8 @@ -92,11 +67,6 @@ platforms: image: dokken/rockylinux-9 pid_one_command: /usr/lib/systemd/systemd - - name: ubuntu-18.04 - driver: - image: dokken/ubuntu-18.04 - pid_one_command: /bin/systemd - - name: ubuntu-20.04 driver: image: dokken/ubuntu-20.04 @@ -107,7 +77,7 @@ platforms: image: dokken/ubuntu-22.04 pid_one_command: /bin/systemd - - name: ubuntu-23.04 + - name: ubuntu-24.04 driver: - image: dokken/ubuntu-23.04 + image: dokken/ubuntu-24.04 pid_one_command: /bin/systemd diff --git a/kitchen.yml b/kitchen.yml index bd41b0a..37bda6d 100644 --- a/kitchen.yml +++ b/kitchen.yml @@ -14,12 +14,14 @@ verifier: - path: test/integration/inspec platforms: - - name: centos-7 - - name: centos-8 - - name: debian-9 - - name: debian-10 - - name: ubuntu-18.04 + - name: debian-11 + - name: debian-12 - name: ubuntu-20.04 + - name: ubuntu-22.04 + - name: rocky-8 + - name: rocky-9 + - name: almalinux-8 + - name: almalinux-9 suites: - name: client @@ -31,10 +33,10 @@ suites: extra_config: - "log measurements statistics tracking" verifier: - - name: master + - name: server run_list: - recipe[test] - - recipe[chrony::master] + - recipe[chrony::server] verifier: inputs: - type: "master" + type: "server" diff --git a/metadata.rb b/metadata.rb index fe53177..adf6b56 100644 --- a/metadata.rb +++ b/metadata.rb @@ -6,9 +6,11 @@ version '1.2.7' issues_url 'https://github.com/sous-chefs/chrony/issues' source_url 'https://github.com/sous-chefs/chrony' -chef_version '>= 13.0' +chef_version '>= 15.3' -supports 'debian' -supports 'ubuntu' -supports 'redhat', '>= 7.0' -supports 'centos', '>= 7.0' +supports 'debian', '>= 11.0' +supports 'ubuntu', '>= 20.04' +supports 'redhat', '>= 8.0' +supports 'rocky' +supports 'almalinux' +supports 'amazon' diff --git a/recipes/client.rb b/recipes/client.rb index 4f4e2a0..ef44434 100644 --- a/recipes/client.rb +++ b/recipes/client.rb @@ -1,10 +1,7 @@ # -# Author:: Matt Ray -# Contributor:: Dang H. Nguyen -# Contributor:: Lance Albertson # Cookbook:: chrony # Recipe:: client -# Copyright:: 2011-2020, Chef Software, Inc. +# # Copyright:: 2020, Sous Chefs # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -20,37 +17,21 @@ # limitations under the License. # -package 'chrony' +servers = node['chrony']['servers'].dup +allow = node['chrony']['allow'].dup -# search for the chrony master(s), if found populate the template accordingly -# typical deployment will only have 1 master, but still allow for multiple -masters = search(:node, 'recipes:chrony\:\:master') if node['chrony']['search_masters'] -masters ||= [] -if masters.empty? - Chef::Log.info("No chrony master(s) found, using node['chrony']['servers'] attribute.") -else - node.default['chrony']['servers'] = {} - masters.each do |master| - node.default['chrony']['servers'][master['ipaddress']] = master['chrony']['server_options'] - node.default['chrony']['allow'].push master['ipaddress'] +if node['chrony']['search_servers'] + servers_list = search(:node, 'recipes:chrony\:\:server') + servers_list.each do |server| + servers[server['ipaddress']] = node['chrony']['server_options'] + allow.push(server['ipaddress']) end end -template 'chrony.conf' do - path chrony_conf_file - source 'chrony_client.conf.erb' - owner 'root' - group 'root' - mode '0644' - variables allow: node['chrony']['allow'], - driftfile: node['chrony']['driftfile'], - log_dir: node['chrony']['log_dir'], - servers: node['chrony']['servers'] - notifies :restart, 'service[chrony]', :delayed -end - -service 'chrony' do - service_name chrony_service_name - supports restart: true, status: true, reload: true - action %i(start enable) +chrony_config 'default' do + servers servers + allow allow + driftfile node['chrony']['driftfile'] + log_dir node['chrony']['log_dir'] + extra_config node['chrony']['extra_config'] end diff --git a/recipes/master.rb b/recipes/master.rb deleted file mode 100644 index db18cbb..0000000 --- a/recipes/master.rb +++ /dev/null @@ -1,46 +0,0 @@ -# -# Author:: Matt Ray -# Contributor:: Lance Albertson -# Cookbook:: chrony -# Recipe:: master -# Copyright:: 2011-2020, Chef Software, Inc. -# Copyright:: 2020, Sous Chefs -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package 'chrony' - -service 'chrony' do - service_name chrony_service_name - supports restart: true, status: true, reload: true - action %i(start enable) -end - -# set the allowed hosts to the subnet -# ip = node.ipaddress.split('.') -# set the allowed hosts to the class B -# node['chrony'][:allow] = ["allow #{ip[0]}.#{ip[1]}"] - -template 'chrony.conf' do - path chrony_conf_file - source 'chrony_master.conf.erb' - owner 'root' - group 'root' - mode '0644' - variables allow: node['chrony']['allow'], - driftfile: node['chrony']['driftfile'], - log_dir: node['chrony']['log_dir'], - servers: node['chrony']['servers'] - notifies :restart, 'service[chrony]' -end diff --git a/recipes/server.rb b/recipes/server.rb new file mode 100644 index 0000000..1809be8 --- /dev/null +++ b/recipes/server.rb @@ -0,0 +1,26 @@ +# +# Cookbook:: chrony +# Recipe:: server +# +# Copyright:: 2020, Sous Chefs +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +chrony_config 'server' do + servers node['chrony']['servers'] + allow node['chrony']['allow'] + driftfile node['chrony']['driftfile'] + log_dir node['chrony']['log_dir'] + extra_config node['chrony']['extra_config'] +end diff --git a/resources/config.rb b/resources/config.rb new file mode 100644 index 0000000..1b3bfb0 --- /dev/null +++ b/resources/config.rb @@ -0,0 +1,80 @@ +# +# Cookbook:: chrony +# Resource:: config +# +# Copyright:: 2020, Sous Chefs +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +unified_mode true + +property :servers, Hash, default: { 'pool.ntp.org' => 'iburst' } +property :pools, Hash, default: {} +property :allow, Array, default: [] +property :deny, Array, default: [] +property :driftfile, String, default: lazy { default_driftfile } +property :log_dir, String, default: '/var/log/chrony' +property :extra_config, Array, default: [] + +action :create do + package 'chrony' + + template chrony_conf_file do + source 'chrony.conf.erb' + cookbook 'chrony' + owner 'root' + group 'root' + mode '0644' + variables( + servers: new_resource.servers, + pools: new_resource.pools, + allow: new_resource.allow, + deny: new_resource.deny, + driftfile: new_resource.driftfile, + log_dir: new_resource.log_dir, + extra_config: new_resource.extra_config + ) + notifies :restart, "service[#{chrony_service_name}]", :delayed + end + + service chrony_service_name do + supports restart: true, status: true, reload: true + action [:enable, :start] + end +end + +action :delete do + service chrony_service_name do + action [:stop, :disable] + end + + package 'chrony' do + action :remove + end + + file chrony_conf_file do + action :delete + end +end + +action_class do + include Chrony::Cookbook::Helpers + + def default_driftfile + if platform_family?('rhel', 'fedora', 'amazon') + '/var/lib/chrony/drift' + else + '/var/lib/chrony/chrony.drift' + end + end +end diff --git a/spec/unit/recipes/client_spec.rb b/spec/unit/recipes/client_spec.rb index 936ad03..6c1164b 100644 --- a/spec/unit/recipes/client_spec.rb +++ b/spec/unit/recipes/client_spec.rb @@ -2,10 +2,6 @@ # Cookbook:: chrony # Spec:: client # -# Author: Dang H. Nguyen -# Contributor:: Lance Albertson -# -# Copyright:: 2020, The Walt Disney Company, All Rights Reserved # Copyright:: 2020, Sous Chefs # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -23,29 +19,25 @@ require 'spec_helper' describe 'chrony::client' do - context 'on Ubuntu 18.04' do + context 'on Ubuntu 22.04' do cached(:chef_run) do - ChefSpec::ServerRunner.new(platform: 'ubuntu', version: '18.04').converge(described_recipe) + ChefSpec::ServerRunner.new(platform: 'ubuntu', version: '22.04').converge(described_recipe) end - it_behaves_like 'chrony client' - - it 'rendered /etc/chrony.conf' do - expect(chef_run).to render_file('/etc/chrony/chrony.conf').with_content(/pool pool.ntp.org iburst/) + it 'rendered /etc/chrony/chrony.conf' do + expect(chef_run).to render_file('/etc/chrony/chrony.conf').with_content(/server pool.ntp.org iburst/) expect(chef_run).to_not render_file('/etc/chrony/chrony.conf').with_content('allow') end end - context 'on CentOS 7' do + context 'on AlmaLinux 9' do cached(:chef_run) do - ChefSpec::ServerRunner.new(platform: 'centos', version: '7').converge(described_recipe) + ChefSpec::ServerRunner.new(platform: 'almalinux', version: '9').converge(described_recipe) end - it_behaves_like 'chrony client' - it 'rendered /etc/chrony.conf' do - expect(chef_run).to render_file('/etc/chrony.conf').with_content(/pool pool.ntp.org iburst/) - expect(chef_run).to_not render_file('/etc/chrony/chrony.conf').with_content('allow') + expect(chef_run).to render_file('/etc/chrony.conf').with_content(/server pool.ntp.org iburst/) + expect(chef_run).to_not render_file('/etc/chrony.conf').with_content('allow') end end end diff --git a/spec/unit/recipes/default_spec.rb b/spec/unit/recipes/default_spec.rb index 907478c..431280c 100644 --- a/spec/unit/recipes/default_spec.rb +++ b/spec/unit/recipes/default_spec.rb @@ -2,10 +2,6 @@ # Cookbook:: chrony # Spec:: default # -# Author: Dang H. Nguyen -# Contributor:: Lance Albertson -# -# Copyright:: 2020, The Walt Disney Company, All Rights Reserved # Copyright:: 2020, Sous Chefs # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -25,9 +21,9 @@ describe 'chrony::default' do context 'When all attributes are default' do - context 'on Ubuntu 18.04' do + context 'on Ubuntu 22.04' do cached(:chef_run) do - ChefSpec::ServerRunner.new(platform: 'ubuntu', version: '18.04').converge(described_recipe) + ChefSpec::ServerRunner.new(platform: 'ubuntu', version: '22.04').converge(described_recipe) end it 'included the client recipe' do @@ -35,9 +31,9 @@ end end - context 'on CentOS 7' do + context 'on AlmaLinux 9' do cached(:chef_run) do - ChefSpec::ServerRunner.new(platform: 'centos', version: '7').converge(described_recipe) + ChefSpec::ServerRunner.new(platform: 'almalinux', version: '9').converge(described_recipe) end it 'included the client recipe' do diff --git a/spec/unit/recipes/master_spec.rb b/spec/unit/recipes/server_spec.rb similarity index 68% rename from spec/unit/recipes/master_spec.rb rename to spec/unit/recipes/server_spec.rb index ce7d813..868024d 100644 --- a/spec/unit/recipes/master_spec.rb +++ b/spec/unit/recipes/server_spec.rb @@ -1,11 +1,7 @@ # # Cookbook:: chrony -# Spec:: client +# Spec:: server # -# Author: Dang H. Nguyen -# Contributor:: Lance Albertson -# -# Copyright:: 2020, The Walt Disney Company, All Rights Reserved # Copyright:: 2020, Sous Chefs # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -23,27 +19,23 @@ require 'spec_helper' -describe 'chrony::master' do - context 'on Ubuntu 18.04' do +describe 'chrony::server' do + context 'on Ubuntu 22.04' do cached(:chef_run) do - ChefSpec::ServerRunner.new(platform: 'ubuntu', version: '18.04').converge(described_recipe) + ChefSpec::ServerRunner.new(platform: 'ubuntu', version: '22.04').converge(described_recipe) end - it_behaves_like 'chrony client' - it 'rendered /etc/chrony/chrony.conf' do expect(chef_run).to render_file('/etc/chrony/chrony.conf').with_content(/server pool.ntp.org iburst/) expect(chef_run).to render_file('/etc/chrony/chrony.conf').with_content('allow') end end - context 'on CentOS 7' do + context 'on AlmaLinux 9' do cached(:chef_run) do - ChefSpec::ServerRunner.new(platform: 'centos', version: '7').converge(described_recipe) + ChefSpec::ServerRunner.new(platform: 'almalinux', version: '9').converge(described_recipe) end - it_behaves_like 'chrony client' - it 'rendered /etc/chrony.conf' do expect(chef_run).to render_file('/etc/chrony.conf').with_content(/server pool.ntp.org iburst/) expect(chef_run).to render_file('/etc/chrony.conf').with_content('allow') diff --git a/templates/chrony.conf.erb b/templates/chrony.conf.erb new file mode 100644 index 0000000..8343bb6 --- /dev/null +++ b/templates/chrony.conf.erb @@ -0,0 +1,35 @@ +# Generated by Chef for <%= node['fqdn'] %> +# Local modifications will be overwritten. + +<% @servers.each do |server, options| -%> +server <%= server %> <%= options %> +<% end -%> + +<% @pools.each do |pool, options| -%> +pool <%= pool %> <%= options %> +<% end -%> + +driftfile <%= @driftfile %> +logdir <%= @log_dir %> + +<% @allow.each do |allow| -%> +allow <%= allow %> +<% end -%> + +<% @deny.each do |deny| -%> +deny <%= deny %> +<% end -%> + +<% @extra_config.each do |config| -%> +<%= config %> +<% end -%> + +# Record the rate at which the system clock gains/losses time. +driftfile <%= @driftfile %> + +# Allow the system clock to be stepped in the first three updates +# if its offset is larger than 1 second. +makestep 1.0 3 + +# Enable kernel synchronization of the real-time clock (RTC). +rtcsync diff --git a/templates/chrony_client.conf.erb b/templates/chrony_client.conf.erb deleted file mode 100644 index 27cbc52..0000000 --- a/templates/chrony_client.conf.erb +++ /dev/null @@ -1,36 +0,0 @@ -# Generated by Chef Infra Client. Do not hand edit - -# Use public servers from the pool.ntp.org project. -# Please consider joining the pool (http://www.pool.ntp.org/join.html). -# See https://chrony.tuxfamily.org/faq.html#_what_is_the_minimum_recommended_configuration_for_an_ntp_client -# for explanations for these configuration settings -<% @servers.each do |server, options| %> -<%= "pool #{server} #{options}" %> -<% end %> - -# Record the rate at which the system clock gains/losses time. -driftfile <%= @driftfile %> - -# Allow the system clock to be stepped in the first three updates -# if its offset is larger than 1 second. -makestep 1 3 - -# Enable kernel synchronization of the real-time clock (RTC). -rtcsync - -# Specify directory for log files. -logdir <%= @log_dir %> - -# The allow directive is used to designate a particular subnet from which clients -# are allowed to access chrony. As a client option this can be used for accessing the the -# NTP interface to query status information. -<% if @allow %> -<% @allow.each do |allowed| %> -allow <%= allowed %> -<% end %> -<% end %> - -# Extra configuration -<% node['chrony']['extra_config'].each do |conf| -%> -<%= conf %> -<% end -%> diff --git a/templates/chrony_master.conf.erb b/templates/chrony_master.conf.erb deleted file mode 100644 index 0728a42..0000000 --- a/templates/chrony_master.conf.erb +++ /dev/null @@ -1,37 +0,0 @@ -# Generated by Chef Infra Client. Do not hand edit - -# Use public servers from the pool.ntp.org project. -# Please consider joining the pool (http://www.pool.ntp.org/join.html). -<% @servers.each do |server, options| %> -<%= "server #{server} #{options}" %> -<% end %> - -# Record the rate at which the system clock gains/losses time. -driftfile <%= @driftfile %> - -# Allow the system clock to be stepped in the first three updates -# if its offset is larger than 1 second. -makestep 1 3 - -# Enable kernel synchronization of the real-time clock (RTC). -rtcsync - -# Specify directory for log files. -logdir <%= @log_dir %> - -# The allow directive is used to designate a particular subnet from which NTP clients -# are allowed to access the computer as an NTP server. The default is that no clients -# are allowed access, i.e. chronyd operates purely as an NTP client. If the allow -# directive is used, chronyd will be both a client of its servers, and a server to other clients. -<% if @allow.empty? %> -allow -<% else %> -<% @allow.each do |allowed| %> -allow <%= allowed %> -<% end %> -<% end %> - -# Extra configuration -<% node['chrony']['extra_config'].each do |conf| -%> -<%= conf %> -<% end -%> diff --git a/test/integration/inspec/controls/default_spec.rb b/test/integration/inspec/controls/default_spec.rb index 6ae9180..989670f 100644 --- a/test/integration/inspec/controls/default_spec.rb +++ b/test/integration/inspec/controls/default_spec.rb @@ -1,9 +1,23 @@ -chrony_conf_file = os.redhat? ? '/etc/chrony.conf' : '/etc/chrony/chrony.conf' -chrony_type = input('type') +chrony_conf_file = if os.redhat? || os.name == 'rocky' || os.name == 'almalinux' + '/etc/chrony.conf' + else + '/etc/chrony/chrony.conf' + end + +chrony_service = if os.redhat? || os.name == 'rocky' || os.name == 'almalinux' + 'chronyd' + else + 'chrony' + end + +chrony_type = input('type', value: 'client') control 'chrony' do - describe service 'chronyd' do + describe package 'chrony' do it { should be_installed } + end + + describe service chrony_service do it { should be_enabled } it { should be_running } end @@ -13,12 +27,12 @@ its('owner') { should eq 'root' } its('group') { should eq 'root' } its('mode') { should cmp '0644' } + its('content') { should match /^driftfile .*/ } + if chrony_type == 'client' - its('content') { should_not match(/allow.*/) } its('content') { should match /^log measurements statistics tracking$/ } else - its('content') { should match(/allow.*/) } - its('content') { should_not match /^log measurements statistics tracking$/ } + its('content') { should match /^allow .*/ } end end end From dcc097254ff98eefbb262eaba1895748f8857ae6 Mon Sep 17 00:00:00 2001 From: Dan Webb Date: Tue, 24 Mar 2026 12:43:05 +0000 Subject: [PATCH 2/8] fix: resolve rspec failures and add markdownlint config - Fix ChefSpec tests by adding 'step_into' for the 'chrony_config' resource. - Set 'allow' attribute in server spec to ensure proper template rendering. - Import '.markdownlint-cli2.yaml' and '.mdlrc' from confluence cookbook. --- .markdownlint-cli2.yaml | 5 +++++ .mdlrc | 2 +- spec/unit/recipes/client_spec.rb | 4 ++-- spec/unit/recipes/server_spec.rb | 8 ++++++-- 4 files changed, 14 insertions(+), 5 deletions(-) diff --git a/.markdownlint-cli2.yaml b/.markdownlint-cli2.yaml index 6fa8e77..e42be9b 100644 --- a/.markdownlint-cli2.yaml +++ b/.markdownlint-cli2.yaml @@ -3,3 +3,8 @@ config: line-length: false # MD013 no-duplicate-heading: false # MD024 reference-links-images: false # MD052 + no-multiple-blanks: + maximum: 2 +ignores: + - .github/copilot-instructions.md + - .windsurf/** diff --git a/.mdlrc b/.mdlrc index 9cc2c63..ebeef65 100644 --- a/.mdlrc +++ b/.mdlrc @@ -1 +1 @@ -rules "~MD013", "~MD024", "~MD025" +rules "~MD013", "~MD024" diff --git a/spec/unit/recipes/client_spec.rb b/spec/unit/recipes/client_spec.rb index 6c1164b..5353a24 100644 --- a/spec/unit/recipes/client_spec.rb +++ b/spec/unit/recipes/client_spec.rb @@ -21,7 +21,7 @@ describe 'chrony::client' do context 'on Ubuntu 22.04' do cached(:chef_run) do - ChefSpec::ServerRunner.new(platform: 'ubuntu', version: '22.04').converge(described_recipe) + ChefSpec::ServerRunner.new(platform: 'ubuntu', version: '22.04', step_into: ['chrony_config']).converge(described_recipe) end it 'rendered /etc/chrony/chrony.conf' do @@ -32,7 +32,7 @@ context 'on AlmaLinux 9' do cached(:chef_run) do - ChefSpec::ServerRunner.new(platform: 'almalinux', version: '9').converge(described_recipe) + ChefSpec::ServerRunner.new(platform: 'almalinux', version: '9', step_into: ['chrony_config']).converge(described_recipe) end it 'rendered /etc/chrony.conf' do diff --git a/spec/unit/recipes/server_spec.rb b/spec/unit/recipes/server_spec.rb index 868024d..25ea4db 100644 --- a/spec/unit/recipes/server_spec.rb +++ b/spec/unit/recipes/server_spec.rb @@ -22,7 +22,9 @@ describe 'chrony::server' do context 'on Ubuntu 22.04' do cached(:chef_run) do - ChefSpec::ServerRunner.new(platform: 'ubuntu', version: '22.04').converge(described_recipe) + ChefSpec::ServerRunner.new(platform: 'ubuntu', version: '22.04', step_into: ['chrony_config']) do |node| + node.normal['chrony']['allow'] = ['10.0.0.0/8'] + end.converge(described_recipe) end it 'rendered /etc/chrony/chrony.conf' do @@ -33,7 +35,9 @@ context 'on AlmaLinux 9' do cached(:chef_run) do - ChefSpec::ServerRunner.new(platform: 'almalinux', version: '9').converge(described_recipe) + ChefSpec::ServerRunner.new(platform: 'almalinux', version: '9', step_into: ['chrony_config']) do |node| + node.normal['chrony']['allow'] = ['10.0.0.0/8'] + end.converge(described_recipe) end it 'rendered /etc/chrony.conf' do From 342625a1eb2df19252fb242d816623a84609096b Mon Sep 17 00:00:00 2001 From: Dan Webb Date: Tue, 24 Mar 2026 13:37:43 +0000 Subject: [PATCH 3/8] chore: remove EOL platforms from test suites and metadata - Update kitchen.yml and kitchen.dokken.yml to only test non-EOL platforms. - Update metadata.rb to reflect modern supported OS versions (Ubuntu 22.04+, Debian 12, RHEL 9+). --- kitchen.dokken.yml | 30 ------------------------------ kitchen.yml | 5 +---- metadata.rb | 10 +++++----- 3 files changed, 6 insertions(+), 39 deletions(-) diff --git a/kitchen.dokken.yml b/kitchen.dokken.yml index d6fdee7..2893a10 100644 --- a/kitchen.dokken.yml +++ b/kitchen.dokken.yml @@ -7,11 +7,6 @@ transport: { name: dokken } provisioner: { name: dokken } platforms: - - name: almalinux-8 - driver: - image: dokken/almalinux-8 - pid_one_command: /usr/lib/systemd/systemd - - name: almalinux-9 driver: image: dokken/almalinux-9 @@ -22,21 +17,11 @@ platforms: image: dokken/amazonlinux-2023 pid_one_command: /usr/lib/systemd/systemd - - name: centos-stream-8 - driver: - image: dokken/centos-stream-8 - pid_one_command: /usr/lib/systemd/systemd - - name: centos-stream-9 driver: image: dokken/centos-stream-9 pid_one_command: /usr/lib/systemd/systemd - - name: debian-11 - driver: - image: dokken/debian-11 - pid_one_command: /bin/systemd - - name: debian-12 driver: image: dokken/debian-12 @@ -47,31 +32,16 @@ platforms: image: dokken/fedora-latest pid_one_command: /usr/lib/systemd/systemd - - name: oraclelinux-8 - driver: - image: dokken/oraclelinux-8 - pid_one_command: /usr/lib/systemd/systemd - - name: oraclelinux-9 driver: image: dokken/oraclelinux-9 pid_one_command: /usr/lib/systemd/systemd - - name: rockylinux-8 - driver: - image: dokken/rockylinux-8 - pid_one_command: /usr/lib/systemd/systemd - - name: rockylinux-9 driver: image: dokken/rockylinux-9 pid_one_command: /usr/lib/systemd/systemd - - name: ubuntu-20.04 - driver: - image: dokken/ubuntu-20.04 - pid_one_command: /bin/systemd - - name: ubuntu-22.04 driver: image: dokken/ubuntu-22.04 diff --git a/kitchen.yml b/kitchen.yml index 37bda6d..4412b51 100644 --- a/kitchen.yml +++ b/kitchen.yml @@ -14,13 +14,10 @@ verifier: - path: test/integration/inspec platforms: - - name: debian-11 - name: debian-12 - - name: ubuntu-20.04 - name: ubuntu-22.04 - - name: rocky-8 + - name: ubuntu-24.04 - name: rocky-9 - - name: almalinux-8 - name: almalinux-9 suites: diff --git a/metadata.rb b/metadata.rb index adf6b56..30569fe 100644 --- a/metadata.rb +++ b/metadata.rb @@ -8,9 +8,9 @@ source_url 'https://github.com/sous-chefs/chrony' chef_version '>= 15.3' -supports 'debian', '>= 11.0' -supports 'ubuntu', '>= 20.04' -supports 'redhat', '>= 8.0' -supports 'rocky' -supports 'almalinux' +supports 'debian', '>= 12.0' +supports 'ubuntu', '>= 22.04' +supports 'redhat', '>= 9.0' +supports 'rocky', '>= 9.0' +supports 'almalinux', '>= 9.0' supports 'amazon' From 6518e88c60eb429b5278de18aba2053de78f7c41 Mon Sep 17 00:00:00 2001 From: Dan Webb Date: Tue, 24 Mar 2026 14:44:39 +0000 Subject: [PATCH 4/8] chore: align CI and kitchen platforms and follow custom resource skill - Update .github/workflows/ci.yml to match modern platform list. - Add frozen_string_literal and provides to chrony_config resource. - Add resource documentation. - Add LIMITATIONS.md with vendor support details. - Ensure all kitchen and CI files are in sync. --- .github/workflows/ci.yml | 19 +++++++++++-------- LIMITATIONS.md | 26 ++++++++++++++++++++++++++ attributes/default.rb | 1 + documentation/chrony_config.md | 30 ++++++++++++++++++++++++++++++ kitchen.dokken.yml | 25 +++++++++++++++---------- kitchen.yml | 9 +++++++-- libraries/helpers.rb | 1 + metadata.rb | 11 ++++++----- recipes/client.rb | 1 + recipes/default.rb | 1 + recipes/server.rb | 1 + resources/config.rb | 2 ++ 12 files changed, 102 insertions(+), 25 deletions(-) create mode 100644 LIMITATIONS.md create mode 100644 documentation/chrony_config.md diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7fb545b..bb7240e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,4 +1,3 @@ ---- name: ci "on": @@ -24,15 +23,19 @@ jobs: strategy: matrix: os: - - "centos-7" - - "centos-8" - - "debian-9" - - "debian-10" - - "ubuntu-1804" - - "ubuntu-2004" + - "almalinux-8" + - "almalinux-9" + - "amazonlinux-2023" + - "debian-11" + - "debian-12" + - "rocky-8" + - "rocky-9" + - "ubuntu-20.04" + - "ubuntu-22.04" + - "ubuntu-24.04" suite: - "client" - - "master" + - "server" fail-fast: false steps: diff --git a/LIMITATIONS.md b/LIMITATIONS.md new file mode 100644 index 0000000..8204b6c --- /dev/null +++ b/LIMITATIONS.md @@ -0,0 +1,26 @@ +# Chrony Cookbook Limitations + +## Supported Platforms + +The `chrony` cookbook aims to support the following modern Linux distributions: + +- **RHEL / Rocky / AlmaLinux**: 8, 9 +- **Ubuntu**: 20.04 (LTS), 22.04 (LTS), 24.04 (LTS) +- **Debian**: 11 (LTS), 12 +- **Amazon Linux**: 2, 2023 +- **Fedora**: Latest stable + +## End-of-Life (EOL) Platforms (Excluded) + +The following platforms are considered EOL and are not actively supported or tested by this cookbook: + +- CentOS 7 (EOL 2024-06-30) +- CentOS 8 (EOL 2021-12-31) +- Ubuntu 18.04 (EOL 2023-05-31) +- Debian 9 (EOL 2022-06-30) +- Debian 10 (EOL 2024-06-30) + +## Architecture Support + +- x86_64 +- aarch64 (ARM64) diff --git a/attributes/default.rb b/attributes/default.rb index ca15419..fe5a398 100644 --- a/attributes/default.rb +++ b/attributes/default.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # # Author:: Matt Ray # Contributor:: Dang H. Nguyen diff --git a/documentation/chrony_config.md b/documentation/chrony_config.md new file mode 100644 index 0000000..4b98e3c --- /dev/null +++ b/documentation/chrony_config.md @@ -0,0 +1,30 @@ +# chrony_config + +The `chrony_config` resource manages the chrony package, service, and configuration file. + +## Actions + +- `:create`: (default) Installs the chrony package, configures it, and enables/starts the service. +- `:delete`: Stops and disables the service, removes the package and configuration file. + +## Properties + +- `servers`: (Hash) A hash of NTP servers to use. Key is the server address, value is the options (e.g., `iburst`). Default: `{ 'pool.ntp.org' => 'iburst' }`. +- `pools`: (Hash) A hash of NTP pools to use. Key is the pool address, value is the options. Default: `{}`. +- `allow`: (Array) A list of addresses/subnets allowed to access the server. Default: `[]`. +- `deny`: (Array) A list of addresses/subnets denied access to the server. Default: `[]`. +- `driftfile`: (String) The path to the drift file. Default: Platform-specific. +- `log_dir`: (String) The directory for chrony logs. Default: `/var/log/chrony`. +- `extra_config`: (Array) A list of raw configuration strings to append to the config file. Default: `[]`. + +## Examples + +```ruby +chrony_config 'default' do + servers({ + 'ntp1.example.com' => 'iburst', + 'ntp2.example.com' => 'iburst', + }) + allow ['192.168.1.0/24'] +end +``` diff --git a/kitchen.dokken.yml b/kitchen.dokken.yml index 2893a10..e209b6a 100644 --- a/kitchen.dokken.yml +++ b/kitchen.dokken.yml @@ -7,6 +7,11 @@ transport: { name: dokken } provisioner: { name: dokken } platforms: + - name: almalinux-8 + driver: + image: dokken/almalinux-8 + pid_one_command: /usr/lib/systemd/systemd + - name: almalinux-9 driver: image: dokken/almalinux-9 @@ -17,30 +22,30 @@ platforms: image: dokken/amazonlinux-2023 pid_one_command: /usr/lib/systemd/systemd - - name: centos-stream-9 + - name: debian-11 driver: - image: dokken/centos-stream-9 - pid_one_command: /usr/lib/systemd/systemd + image: dokken/debian-11 + pid_one_command: /bin/systemd - name: debian-12 driver: image: dokken/debian-12 pid_one_command: /bin/systemd - - name: fedora-latest + - name: rocky-8 driver: - image: dokken/fedora-latest + image: dokken/rocky-8 pid_one_command: /usr/lib/systemd/systemd - - name: oraclelinux-9 + - name: rocky-9 driver: - image: dokken/oraclelinux-9 + image: dokken/rockylinux-9 pid_one_command: /usr/lib/systemd/systemd - - name: rockylinux-9 + - name: ubuntu-20.04 driver: - image: dokken/rockylinux-9 - pid_one_command: /usr/lib/systemd/systemd + image: dokken/ubuntu-20.04 + pid_one_command: /bin/systemd - name: ubuntu-22.04 driver: diff --git a/kitchen.yml b/kitchen.yml index 4412b51..f4c45d9 100644 --- a/kitchen.yml +++ b/kitchen.yml @@ -14,11 +14,16 @@ verifier: - path: test/integration/inspec platforms: + - name: almalinux-8 + - name: almalinux-9 + - name: amazonlinux-2023 + - name: debian-11 - name: debian-12 + - name: rocky-8 + - name: rocky-9 + - name: ubuntu-20.04 - name: ubuntu-22.04 - name: ubuntu-24.04 - - name: rocky-9 - - name: almalinux-9 suites: - name: client diff --git a/libraries/helpers.rb b/libraries/helpers.rb index 28b74c8..9c7b83b 100644 --- a/libraries/helpers.rb +++ b/libraries/helpers.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # # Cookbook:: chrony # Libraries:: helpers diff --git a/metadata.rb b/metadata.rb index 30569fe..89f584d 100644 --- a/metadata.rb +++ b/metadata.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true name 'chrony' maintainer 'Sous Chefs' maintainer_email 'help@sous-chefs.org' @@ -8,9 +9,9 @@ source_url 'https://github.com/sous-chefs/chrony' chef_version '>= 15.3' -supports 'debian', '>= 12.0' -supports 'ubuntu', '>= 22.04' -supports 'redhat', '>= 9.0' -supports 'rocky', '>= 9.0' -supports 'almalinux', '>= 9.0' +supports 'debian', '>= 11.0' +supports 'ubuntu', '>= 20.04' +supports 'redhat', '>= 8.0' +supports 'rocky', '>= 8.0' +supports 'almalinux', '>= 8.0' supports 'amazon' diff --git a/recipes/client.rb b/recipes/client.rb index ef44434..b7eed6d 100644 --- a/recipes/client.rb +++ b/recipes/client.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # # Cookbook:: chrony # Recipe:: client diff --git a/recipes/default.rb b/recipes/default.rb index 940e6d4..06e5983 100644 --- a/recipes/default.rb +++ b/recipes/default.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # # Author:: Matt Ray # Cookbook:: chrony diff --git a/recipes/server.rb b/recipes/server.rb index 1809be8..2f85a4a 100644 --- a/recipes/server.rb +++ b/recipes/server.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # # Cookbook:: chrony # Recipe:: server diff --git a/resources/config.rb b/resources/config.rb index 1b3bfb0..9d298ba 100644 --- a/resources/config.rb +++ b/resources/config.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # # Cookbook:: chrony # Resource:: config @@ -17,6 +18,7 @@ # limitations under the License. # unified_mode true +provides :chrony_config property :servers, Hash, default: { 'pool.ntp.org' => 'iburst' } property :pools, Hash, default: {} From 2b8f335fe8da6c92f12fa128afda04954c6fe9c0 Mon Sep 17 00:00:00 2001 From: Dan Webb Date: Tue, 24 Mar 2026 14:49:19 +0000 Subject: [PATCH 5/8] chore: strictly remove EOL and nearing EOL platforms - Remove Debian 11, Ubuntu 20.04, and RHEL/Alma/Rocky 8 from all configurations. - Update LIMITATIONS.md, metadata.rb, kitchen files, and .github/workflows/ci.yml. - Update ChefSpec tests to focus on AlmaLinux 9. --- .github/workflows/ci.yml | 4 ---- LIMITATIONS.md | 14 +++++++++----- kitchen.dokken.yml | 25 ++++++++++--------------- kitchen.yml | 4 ---- metadata.rb | 10 +++++----- spec/unit/recipes/client_spec.rb | 11 ----------- spec/unit/recipes/default_spec.rb | 10 ---------- spec/unit/recipes/server_spec.rb | 13 ------------- 8 files changed, 24 insertions(+), 67 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bb7240e..4052a1d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -23,14 +23,10 @@ jobs: strategy: matrix: os: - - "almalinux-8" - "almalinux-9" - "amazonlinux-2023" - - "debian-11" - "debian-12" - - "rocky-8" - "rocky-9" - - "ubuntu-20.04" - "ubuntu-22.04" - "ubuntu-24.04" suite: diff --git a/LIMITATIONS.md b/LIMITATIONS.md index 8204b6c..d4dd590 100644 --- a/LIMITATIONS.md +++ b/LIMITATIONS.md @@ -4,21 +4,25 @@ The `chrony` cookbook aims to support the following modern Linux distributions: -- **RHEL / Rocky / AlmaLinux**: 8, 9 -- **Ubuntu**: 20.04 (LTS), 22.04 (LTS), 24.04 (LTS) -- **Debian**: 11 (LTS), 12 -- **Amazon Linux**: 2, 2023 +- **RHEL / Rocky / AlmaLinux**: 9 +- **Ubuntu**: 22.04 (LTS), 24.04 (LTS) +- **Debian**: 12 +- **Amazon Linux**: 2023 - **Fedora**: Latest stable ## End-of-Life (EOL) Platforms (Excluded) -The following platforms are considered EOL and are not actively supported or tested by this cookbook: +The following platforms are considered EOL or nearing EOL and are not actively supported or tested by this cookbook: - CentOS 7 (EOL 2024-06-30) - CentOS 8 (EOL 2021-12-31) +- RHEL / AlmaLinux / Rocky 8 (Full support ended 2024-05-31) - Ubuntu 18.04 (EOL 2023-05-31) +- Ubuntu 20.04 (Nearing EOL 2025-04) - Debian 9 (EOL 2022-06-30) - Debian 10 (EOL 2024-06-30) +- Debian 11 (Full support ended 2023-10-14) +- Amazon Linux 2 ## Architecture Support diff --git a/kitchen.dokken.yml b/kitchen.dokken.yml index e209b6a..2893a10 100644 --- a/kitchen.dokken.yml +++ b/kitchen.dokken.yml @@ -7,11 +7,6 @@ transport: { name: dokken } provisioner: { name: dokken } platforms: - - name: almalinux-8 - driver: - image: dokken/almalinux-8 - pid_one_command: /usr/lib/systemd/systemd - - name: almalinux-9 driver: image: dokken/almalinux-9 @@ -22,30 +17,30 @@ platforms: image: dokken/amazonlinux-2023 pid_one_command: /usr/lib/systemd/systemd - - name: debian-11 + - name: centos-stream-9 driver: - image: dokken/debian-11 - pid_one_command: /bin/systemd + image: dokken/centos-stream-9 + pid_one_command: /usr/lib/systemd/systemd - name: debian-12 driver: image: dokken/debian-12 pid_one_command: /bin/systemd - - name: rocky-8 + - name: fedora-latest driver: - image: dokken/rocky-8 + image: dokken/fedora-latest pid_one_command: /usr/lib/systemd/systemd - - name: rocky-9 + - name: oraclelinux-9 driver: - image: dokken/rockylinux-9 + image: dokken/oraclelinux-9 pid_one_command: /usr/lib/systemd/systemd - - name: ubuntu-20.04 + - name: rockylinux-9 driver: - image: dokken/ubuntu-20.04 - pid_one_command: /bin/systemd + image: dokken/rockylinux-9 + pid_one_command: /usr/lib/systemd/systemd - name: ubuntu-22.04 driver: diff --git a/kitchen.yml b/kitchen.yml index f4c45d9..1a4ca7d 100644 --- a/kitchen.yml +++ b/kitchen.yml @@ -14,14 +14,10 @@ verifier: - path: test/integration/inspec platforms: - - name: almalinux-8 - name: almalinux-9 - name: amazonlinux-2023 - - name: debian-11 - name: debian-12 - - name: rocky-8 - name: rocky-9 - - name: ubuntu-20.04 - name: ubuntu-22.04 - name: ubuntu-24.04 diff --git a/metadata.rb b/metadata.rb index 89f584d..6339dec 100644 --- a/metadata.rb +++ b/metadata.rb @@ -9,9 +9,9 @@ source_url 'https://github.com/sous-chefs/chrony' chef_version '>= 15.3' -supports 'debian', '>= 11.0' -supports 'ubuntu', '>= 20.04' -supports 'redhat', '>= 8.0' -supports 'rocky', '>= 8.0' -supports 'almalinux', '>= 8.0' +supports 'debian', '>= 12.0' +supports 'ubuntu', '>= 22.04' +supports 'redhat', '>= 9.0' +supports 'rocky', '>= 9.0' +supports 'almalinux', '>= 9.0' supports 'amazon' diff --git a/spec/unit/recipes/client_spec.rb b/spec/unit/recipes/client_spec.rb index 5353a24..d04a400 100644 --- a/spec/unit/recipes/client_spec.rb +++ b/spec/unit/recipes/client_spec.rb @@ -19,17 +19,6 @@ require 'spec_helper' describe 'chrony::client' do - context 'on Ubuntu 22.04' do - cached(:chef_run) do - ChefSpec::ServerRunner.new(platform: 'ubuntu', version: '22.04', step_into: ['chrony_config']).converge(described_recipe) - end - - it 'rendered /etc/chrony/chrony.conf' do - expect(chef_run).to render_file('/etc/chrony/chrony.conf').with_content(/server pool.ntp.org iburst/) - expect(chef_run).to_not render_file('/etc/chrony/chrony.conf').with_content('allow') - end - end - context 'on AlmaLinux 9' do cached(:chef_run) do ChefSpec::ServerRunner.new(platform: 'almalinux', version: '9', step_into: ['chrony_config']).converge(described_recipe) diff --git a/spec/unit/recipes/default_spec.rb b/spec/unit/recipes/default_spec.rb index 431280c..218ed0e 100644 --- a/spec/unit/recipes/default_spec.rb +++ b/spec/unit/recipes/default_spec.rb @@ -21,16 +21,6 @@ describe 'chrony::default' do context 'When all attributes are default' do - context 'on Ubuntu 22.04' do - cached(:chef_run) do - ChefSpec::ServerRunner.new(platform: 'ubuntu', version: '22.04').converge(described_recipe) - end - - it 'included the client recipe' do - expect(chef_run).to include_recipe('chrony::client') - end - end - context 'on AlmaLinux 9' do cached(:chef_run) do ChefSpec::ServerRunner.new(platform: 'almalinux', version: '9').converge(described_recipe) diff --git a/spec/unit/recipes/server_spec.rb b/spec/unit/recipes/server_spec.rb index 25ea4db..c4aaacf 100644 --- a/spec/unit/recipes/server_spec.rb +++ b/spec/unit/recipes/server_spec.rb @@ -20,19 +20,6 @@ require 'spec_helper' describe 'chrony::server' do - context 'on Ubuntu 22.04' do - cached(:chef_run) do - ChefSpec::ServerRunner.new(platform: 'ubuntu', version: '22.04', step_into: ['chrony_config']) do |node| - node.normal['chrony']['allow'] = ['10.0.0.0/8'] - end.converge(described_recipe) - end - - it 'rendered /etc/chrony/chrony.conf' do - expect(chef_run).to render_file('/etc/chrony/chrony.conf').with_content(/server pool.ntp.org iburst/) - expect(chef_run).to render_file('/etc/chrony/chrony.conf').with_content('allow') - end - end - context 'on AlmaLinux 9' do cached(:chef_run) do ChefSpec::ServerRunner.new(platform: 'almalinux', version: '9', step_into: ['chrony_config']) do |node| From ed35046d4189bbafd0f55f05154e1d6c02ac8a76 Mon Sep 17 00:00:00 2001 From: Dan Webb Date: Tue, 24 Mar 2026 15:22:39 +0000 Subject: [PATCH 6/8] feat!: convert to custom resource cookbook pattern MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove recipes/ and attributes/ directories — users should call the chrony_config resource directly instead of chrony::client or chrony::server recipes. - Fix duplicate driftfile declaration in template - Scope helpers module to action_class only (remove global mixin) - Inline default_driftfile logic into lazy property default - Rewrite ChefSpec tests to test chrony_config resource directly - Split integration tests into per-suite InSpec profiles (default/server) - Restructure test cookbook to exercise resource without recipes - Align kitchen.yml, kitchen.dokken.yml, and CI matrix (9 platforms × 2 suites) - Update LIMITATIONS.md and README.md for resource-only usage BREAKING CHANGE: chrony::client, chrony::server, and chrony::default recipes have been removed. Use the chrony_config resource directly in wrapper cookbooks. The Chef search feature for auto-discovering server nodes is no longer provided — implement in your own wrapper cookbook if needed. --- .github/workflows/ci.yml | 7 +- LIMITATIONS.md | 30 +++--- README.md | 50 +++++---- attributes/default.rb | 46 -------- kitchen.dokken.yml | 14 +++ kitchen.yml | 25 ++--- libraries/helpers.rb | 2 - recipes/client.rb | 38 ------- recipes/default.rb | 22 ---- recipes/server.rb | 27 ----- resources/config.rb | 12 +-- spec/shared_examples.rb | 19 ++-- spec/spec_helper.rb | 8 +- spec/unit/recipes/client_spec.rb | 32 ------ spec/unit/recipes/default_spec.rb | 34 ------ spec/unit/recipes/server_spec.rb | 35 ------ spec/unit/resources/config_spec.rb | 100 ++++++++++++++++++ templates/chrony.conf.erb | 3 - test/cookbooks/test/metadata.rb | 3 + test/cookbooks/test/recipes/default.rb | 12 ++- test/cookbooks/test/recipes/delete.rb | 5 + test/cookbooks/test/recipes/server.rb | 9 ++ test/integration/default/controls/default.rb | 49 +++++++++ test/integration/default/inspec.yml | 7 ++ .../inspec/controls/default_spec.rb | 38 ------- test/integration/inspec/inspec.yml | 5 - test/integration/server/controls/default.rb | 47 ++++++++ test/integration/server/inspec.yml | 7 ++ 28 files changed, 331 insertions(+), 355 deletions(-) delete mode 100644 attributes/default.rb delete mode 100644 recipes/client.rb delete mode 100644 recipes/default.rb delete mode 100644 recipes/server.rb delete mode 100644 spec/unit/recipes/client_spec.rb delete mode 100644 spec/unit/recipes/default_spec.rb delete mode 100644 spec/unit/recipes/server_spec.rb create mode 100644 spec/unit/resources/config_spec.rb create mode 100644 test/cookbooks/test/recipes/delete.rb create mode 100644 test/cookbooks/test/recipes/server.rb create mode 100644 test/integration/default/controls/default.rb create mode 100644 test/integration/default/inspec.yml delete mode 100644 test/integration/inspec/controls/default_spec.rb delete mode 100644 test/integration/inspec/inspec.yml create mode 100644 test/integration/server/controls/default.rb create mode 100644 test/integration/server/inspec.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4052a1d..6ed1ee9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,12 +25,15 @@ jobs: os: - "almalinux-9" - "amazonlinux-2023" + - "centos-stream-9" - "debian-12" - - "rocky-9" + - "fedora-latest" + - "oraclelinux-9" + - "rockylinux-9" - "ubuntu-22.04" - "ubuntu-24.04" suite: - - "client" + - "default" - "server" fail-fast: false diff --git a/LIMITATIONS.md b/LIMITATIONS.md index d4dd590..1a10b3b 100644 --- a/LIMITATIONS.md +++ b/LIMITATIONS.md @@ -2,29 +2,35 @@ ## Supported Platforms -The `chrony` cookbook aims to support the following modern Linux distributions: +The `chrony` cookbook supports the following Linux distributions: - **RHEL / Rocky / AlmaLinux**: 9 +- **CentOS Stream**: 9 +- **Oracle Linux**: 9 - **Ubuntu**: 22.04 (LTS), 24.04 (LTS) - **Debian**: 12 - **Amazon Linux**: 2023 - **Fedora**: Latest stable -## End-of-Life (EOL) Platforms (Excluded) +## Package Availability -The following platforms are considered EOL or nearing EOL and are not actively supported or tested by this cookbook: +Chrony is available as a native package on all supported platforms: -- CentOS 7 (EOL 2024-06-30) -- CentOS 8 (EOL 2021-12-31) -- RHEL / AlmaLinux / Rocky 8 (Full support ended 2024-05-31) -- Ubuntu 18.04 (EOL 2023-05-31) -- Ubuntu 20.04 (Nearing EOL 2025-04) -- Debian 9 (EOL 2022-06-30) -- Debian 10 (EOL 2024-06-30) -- Debian 11 (Full support ended 2023-10-14) -- Amazon Linux 2 +- **Debian/Ubuntu**: `apt install chrony` +- **RHEL/CentOS/Rocky/Alma/Oracle/Fedora/Amazon**: `dnf install chrony` + +No source compilation is required. ## Architecture Support - x86_64 - aarch64 (ARM64) + +## Migration from Recipes + +As of the current version, this cookbook no longer provides `chrony::client` or `chrony::server` +recipes. Use the `chrony_config` custom resource directly in your wrapper cookbooks. + +Users who previously relied on the Chef search feature in `chrony::client` (auto-discovering +nodes with `chrony::server` in their run list) must implement that logic in their own wrapper +cookbook. diff --git a/README.md b/README.md index e84bf6e..7177581 100644 --- a/README.md +++ b/README.md @@ -6,8 +6,7 @@ [![OpenCollective](https://opencollective.com/sous-chefs/sponsors/badge.svg)](#sponsors) [![License](https://img.shields.io/badge/License-Apache%202.0-green.svg)](https://opensource.org/licenses/Apache-2.0) -Configures the time synchronization application `chrony` as a client or server timeserver -, maintaining the accuracy of the system clock (similar to NTP). Isolated networks are supported as well. +Configures the time synchronization application `chrony` as a client or server timeserver, maintaining the accuracy of the system clock (similar to NTP). ## Maintainers @@ -17,35 +16,40 @@ This cookbook is maintained by the Sous Chefs. The Sous Chefs are a community of ### Platforms -- Debian / Ubuntu -- CentOS / Redhat +- Debian 12+ +- Ubuntu 22.04+ +- RHEL / AlmaLinux / Rocky / Oracle Linux 9+ +- CentOS Stream 9+ +- Amazon Linux 2023 +- Fedora (latest) ### Chef -- Chef 13+ +- Chef >= 15.3 -## Recipes +## Resources -### client - -Configures the node to use the `chrony` application to keep the node's clock synced. If there is a node using the `chrony::server` recipe, the client will attempt to sync with it, unless disabled via `['chrony']['search_servers']`. If there is not an available server, the attribute list `['chrony'][:servers]` is used (defaults are `[0-3].debian.pool.ntp.org`). If there is a server node, the `['chrony'][:allowed]` will be set to allow for syncing with the server. - -### default - -The default recipe passes through to the client recipe. - -### server - -The node will use the `chrony` application to provide time to nodes using the `chrony::client` recipe. The server sets its own time against the attribute list `['chrony'][:servers]` (defaults are `[0-3].debian.pool.ntp.org`). Access to this server is restricted by the `['chrony'][:allowed]` attribute set in the recipe (default is to the `x.y.*` subnet). +This cookbook provides the `chrony_config` custom resource. See [documentation/chrony_config.md](documentation/chrony_config.md) for full details. ## Usage -Nodes using the `chrony::client` recipe will attempt to sync time with nodes using the `chrony::server` recipe. If there are no `chrony::server` nodes found, the contents of the attribute list `['chrony'][:servers]` are used (defaults are `[0-3].debian.pool.ntp.org`). - -The current configurations are supported: - -1) Clients with direct NTP server access -2) A server with direct NTP server access with clients pointing to it +```ruby +chrony_config ‘default’ do + servers({ ‘pool.ntp.org’ => ‘iburst’ }) +end +``` + +### Server configuration + +```ruby +chrony_config ‘server’ do + servers({ + ‘ntp1.example.com’ => ‘iburst’, + ‘ntp2.example.com’ => ‘iburst’, + }) + allow [‘192.168.1.0/24’] +end +``` ## Contributors diff --git a/attributes/default.rb b/attributes/default.rb deleted file mode 100644 index fe5a398..0000000 --- a/attributes/default.rb +++ /dev/null @@ -1,46 +0,0 @@ -# frozen_string_literal: true -# -# Author:: Matt Ray -# Contributor:: Dang H. Nguyen -# Contributor:: Lance Albertson -# Cookbook:: chrony -# Attributes:: default -# Copyright:: 2011-2020, Chef Software, Inc. -# Copyright:: 2020, Sous Chefs -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# hash of default servers in the chrony.conf from Ubuntu -default['chrony']['servers'] = { - 'pool.ntp.org' => 'iburst', -} - -default['chrony']['server_options'] = 'offline minpoll 8' - -# Use servers including recipe chrony::server registered in Chef server -# to populate our servers list. -default['chrony']['search_servers'] = true - -# set in the client & server recipes -# for better security, clients that do not need to serve ntp requests to peers or other clients -# should not have the `allow` directive in chrony.conf -# In this case, an empty array is the correct setting -# See https://chrony.tuxfamily.org/faq.html#_how_can_i_make_code_chronyd_code_more_secure -default['chrony']['allow'] = [] - -default['chrony']['log_dir'] = '/var/log/chrony' -default['chrony']['driftfile'] = '/var/lib/chrony/drift' - -# Extra configuration values to be added directly to chrony.conf -default['chrony']['extra_config'] = [] diff --git a/kitchen.dokken.yml b/kitchen.dokken.yml index 2893a10..61ec21c 100644 --- a/kitchen.dokken.yml +++ b/kitchen.dokken.yml @@ -51,3 +51,17 @@ platforms: driver: image: dokken/ubuntu-24.04 pid_one_command: /bin/systemd + +suites: + - name: default + run_list: + - recipe[test::default] + verifier: + inspec_tests: + - path: test/integration/default + - name: server + run_list: + - recipe[test::server] + verifier: + inspec_tests: + - path: test/integration/server diff --git a/kitchen.yml b/kitchen.yml index 1a4ca7d..113678b 100644 --- a/kitchen.yml +++ b/kitchen.yml @@ -10,31 +10,28 @@ provisioner: verifier: name: inspec - inspec_tests: - - path: test/integration/inspec platforms: - name: almalinux-9 - name: amazonlinux-2023 + - name: centos-stream-9 - name: debian-12 - - name: rocky-9 + - name: fedora-latest + - name: oraclelinux-9 + - name: rockylinux-9 - name: ubuntu-22.04 - name: ubuntu-24.04 suites: - - name: client + - name: default run_list: - - recipe[test] - - recipe[chrony::client] - attributes: - chrony: - extra_config: - - "log measurements statistics tracking" + - recipe[test::default] verifier: + inspec_tests: + - path: test/integration/default - name: server run_list: - - recipe[test] - - recipe[chrony::server] + - recipe[test::server] verifier: - inputs: - type: "server" + inspec_tests: + - path: test/integration/server diff --git a/libraries/helpers.rb b/libraries/helpers.rb index 9c7b83b..44a5a38 100644 --- a/libraries/helpers.rb +++ b/libraries/helpers.rb @@ -41,5 +41,3 @@ def chrony_conf_file end end end -Chef::DSL::Recipe.include Chrony::Cookbook::Helpers -Chef::Resource.include Chrony::Cookbook::Helpers diff --git a/recipes/client.rb b/recipes/client.rb deleted file mode 100644 index b7eed6d..0000000 --- a/recipes/client.rb +++ /dev/null @@ -1,38 +0,0 @@ -# frozen_string_literal: true -# -# Cookbook:: chrony -# Recipe:: client -# -# Copyright:: 2020, Sous Chefs -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -servers = node['chrony']['servers'].dup -allow = node['chrony']['allow'].dup - -if node['chrony']['search_servers'] - servers_list = search(:node, 'recipes:chrony\:\:server') - servers_list.each do |server| - servers[server['ipaddress']] = node['chrony']['server_options'] - allow.push(server['ipaddress']) - end -end - -chrony_config 'default' do - servers servers - allow allow - driftfile node['chrony']['driftfile'] - log_dir node['chrony']['log_dir'] - extra_config node['chrony']['extra_config'] -end diff --git a/recipes/default.rb b/recipes/default.rb deleted file mode 100644 index 06e5983..0000000 --- a/recipes/default.rb +++ /dev/null @@ -1,22 +0,0 @@ -# frozen_string_literal: true -# -# Author:: Matt Ray -# Cookbook:: chrony -# Recipe:: default -# Copyright:: 2011-2019, Chef Software, Inc. -# Copyright:: 2020, Sous Chefs -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -include_recipe 'chrony::client' diff --git a/recipes/server.rb b/recipes/server.rb deleted file mode 100644 index 2f85a4a..0000000 --- a/recipes/server.rb +++ /dev/null @@ -1,27 +0,0 @@ -# frozen_string_literal: true -# -# Cookbook:: chrony -# Recipe:: server -# -# Copyright:: 2020, Sous Chefs -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -chrony_config 'server' do - servers node['chrony']['servers'] - allow node['chrony']['allow'] - driftfile node['chrony']['driftfile'] - log_dir node['chrony']['log_dir'] - extra_config node['chrony']['extra_config'] -end diff --git a/resources/config.rb b/resources/config.rb index 9d298ba..b5c22c2 100644 --- a/resources/config.rb +++ b/resources/config.rb @@ -24,7 +24,9 @@ property :pools, Hash, default: {} property :allow, Array, default: [] property :deny, Array, default: [] -property :driftfile, String, default: lazy { default_driftfile } +property :driftfile, String, default: lazy { + platform_family?('rhel', 'fedora', 'amazon') ? '/var/lib/chrony/drift' : '/var/lib/chrony/chrony.drift' +} property :log_dir, String, default: '/var/log/chrony' property :extra_config, Array, default: [] @@ -71,12 +73,4 @@ action_class do include Chrony::Cookbook::Helpers - - def default_driftfile - if platform_family?('rhel', 'fedora', 'amazon') - '/var/lib/chrony/drift' - else - '/var/lib/chrony/chrony.drift' - end - end end diff --git a/spec/shared_examples.rb b/spec/shared_examples.rb index e598436..c520fc8 100644 --- a/spec/shared_examples.rb +++ b/spec/shared_examples.rb @@ -1,14 +1,19 @@ -shared_examples 'chrony client' do - it 'installed chrony' do +# frozen_string_literal: true + +shared_examples 'chrony_config :create' do + it 'installs the chrony package' do expect(chef_run).to install_package('chrony') end - it 'started and enabled the chrony(d) service' do - expect(chef_run).to start_service('chrony') - expect(chef_run).to enable_service('chrony') + it 'creates the chrony configuration file' do + expect(chef_run).to create_template(conf_file) + end + + it 'enables the chrony service' do + expect(chef_run).to enable_service(service_name) end - it 'created chrony.conf' do - expect(chef_run).to create_template('chrony.conf') + it 'starts the chrony service' do + expect(chef_run).to start_service(service_name) end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 43b918a..a5db647 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,9 +1,11 @@ +# frozen_string_literal: true + require 'chefspec' require 'chefspec/berkshelf' require_relative 'shared_examples' RSpec.configure do |config| - config.color = true # Use color in STDOUT - config.formatter = :documentation # Use the specified formatter - config.log_level = :error # Avoid deprecation notice SPAM + config.color = true + config.formatter = :documentation + config.log_level = :error end diff --git a/spec/unit/recipes/client_spec.rb b/spec/unit/recipes/client_spec.rb deleted file mode 100644 index d04a400..0000000 --- a/spec/unit/recipes/client_spec.rb +++ /dev/null @@ -1,32 +0,0 @@ -# -# Cookbook:: chrony -# Spec:: client -# -# Copyright:: 2020, Sous Chefs -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -require 'spec_helper' - -describe 'chrony::client' do - context 'on AlmaLinux 9' do - cached(:chef_run) do - ChefSpec::ServerRunner.new(platform: 'almalinux', version: '9', step_into: ['chrony_config']).converge(described_recipe) - end - - it 'rendered /etc/chrony.conf' do - expect(chef_run).to render_file('/etc/chrony.conf').with_content(/server pool.ntp.org iburst/) - expect(chef_run).to_not render_file('/etc/chrony.conf').with_content('allow') - end - end -end diff --git a/spec/unit/recipes/default_spec.rb b/spec/unit/recipes/default_spec.rb deleted file mode 100644 index 218ed0e..0000000 --- a/spec/unit/recipes/default_spec.rb +++ /dev/null @@ -1,34 +0,0 @@ -# -# Cookbook:: chrony -# Spec:: default -# -# Copyright:: 2020, Sous Chefs -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -require 'spec_helper' - -describe 'chrony::default' do - context 'When all attributes are default' do - context 'on AlmaLinux 9' do - cached(:chef_run) do - ChefSpec::ServerRunner.new(platform: 'almalinux', version: '9').converge(described_recipe) - end - - it 'included the client recipe' do - expect(chef_run).to include_recipe('chrony::client') - end - end - end -end diff --git a/spec/unit/recipes/server_spec.rb b/spec/unit/recipes/server_spec.rb deleted file mode 100644 index c4aaacf..0000000 --- a/spec/unit/recipes/server_spec.rb +++ /dev/null @@ -1,35 +0,0 @@ -# -# Cookbook:: chrony -# Spec:: server -# -# Copyright:: 2020, Sous Chefs -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -require 'spec_helper' - -describe 'chrony::server' do - context 'on AlmaLinux 9' do - cached(:chef_run) do - ChefSpec::ServerRunner.new(platform: 'almalinux', version: '9', step_into: ['chrony_config']) do |node| - node.normal['chrony']['allow'] = ['10.0.0.0/8'] - end.converge(described_recipe) - end - - it 'rendered /etc/chrony.conf' do - expect(chef_run).to render_file('/etc/chrony.conf').with_content(/server pool.ntp.org iburst/) - expect(chef_run).to render_file('/etc/chrony.conf').with_content('allow') - end - end -end diff --git a/spec/unit/resources/config_spec.rb b/spec/unit/resources/config_spec.rb new file mode 100644 index 0000000..90477c3 --- /dev/null +++ b/spec/unit/resources/config_spec.rb @@ -0,0 +1,100 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe 'chrony_config' do + context ':create action' do + context 'on AlmaLinux 9 (RHEL family)' do + cached(:chef_run) do + ChefSpec::SoloRunner.new( + platform: 'almalinux', version: '9', + step_into: ['chrony_config'] + ) do |_node| + end.converge('test::default') + end + + let(:conf_file) { '/etc/chrony.conf' } + let(:service_name) { 'chronyd' } + + include_examples 'chrony_config :create' + + it 'renders the config with default servers' do + expect(chef_run).to render_file('/etc/chrony.conf') + .with_content(/server pool\.ntp\.org iburst/) + end + + it 'uses RHEL driftfile path' do + expect(chef_run).to render_file('/etc/chrony.conf') + .with_content(%r{driftfile /var/lib/chrony/drift$}) + end + + it 'does not include allow directives for client config' do + expect(chef_run).not_to render_file('/etc/chrony.conf') + .with_content(/^allow/) + end + + it 'includes extra_config lines' do + expect(chef_run).to render_file('/etc/chrony.conf') + .with_content(/^log measurements statistics tracking$/) + end + end + + context 'on Ubuntu 24.04 (Debian family)' do + cached(:chef_run) do + ChefSpec::SoloRunner.new( + platform: 'ubuntu', version: '24.04', + step_into: ['chrony_config'] + ).converge('test::default') + end + + let(:conf_file) { '/etc/chrony/chrony.conf' } + let(:service_name) { 'chrony' } + + include_examples 'chrony_config :create' + + it 'uses Debian driftfile path' do + expect(chef_run).to render_file('/etc/chrony/chrony.conf') + .with_content(%r{driftfile /var/lib/chrony/chrony\.drift}) + end + end + + context 'with server configuration (allow directives)' do + cached(:chef_run) do + ChefSpec::SoloRunner.new( + platform: 'almalinux', version: '9', + step_into: ['chrony_config'] + ).converge('test::server') + end + + it 'renders allow directives' do + expect(chef_run).to render_file('/etc/chrony.conf') + .with_content(%r{^allow 10\.0\.0\.0/8}) + end + end + end + + context ':delete action' do + cached(:chef_run) do + ChefSpec::SoloRunner.new( + platform: 'almalinux', version: '9', + step_into: ['chrony_config'] + ).converge('test::delete') + end + + it 'stops the chrony service' do + expect(chef_run).to stop_service('chronyd') + end + + it 'disables the chrony service' do + expect(chef_run).to disable_service('chronyd') + end + + it 'removes the chrony package' do + expect(chef_run).to remove_package('chrony') + end + + it 'deletes the config file' do + expect(chef_run).to delete_file('/etc/chrony.conf') + end + end +end diff --git a/templates/chrony.conf.erb b/templates/chrony.conf.erb index 8343bb6..449cd29 100644 --- a/templates/chrony.conf.erb +++ b/templates/chrony.conf.erb @@ -24,9 +24,6 @@ deny <%= deny %> <%= config %> <% end -%> -# Record the rate at which the system clock gains/losses time. -driftfile <%= @driftfile %> - # Allow the system clock to be stepped in the first three updates # if its offset is larger than 1 second. makestep 1.0 3 diff --git a/test/cookbooks/test/metadata.rb b/test/cookbooks/test/metadata.rb index ba9b31b..92b8f61 100644 --- a/test/cookbooks/test/metadata.rb +++ b/test/cookbooks/test/metadata.rb @@ -1,6 +1,9 @@ +# frozen_string_literal: true + name 'test' maintainer 'Sous Chefs' maintainer_email 'help@sous-chefs.org' license 'Apache-2.0' description 'Testing cookbook for chrony' version '0.0.1' +depends 'chrony' diff --git a/test/cookbooks/test/recipes/default.rb b/test/cookbooks/test/recipes/default.rb index f3013c9..a6c83c8 100644 --- a/test/cookbooks/test/recipes/default.rb +++ b/test/cookbooks/test/recipes/default.rb @@ -1,3 +1,9 @@ -# Workaround issue running chronyd in docker related to: -# https://access.redhat.com/solutions/4410831 -directory '/var/run/chrony' if platform_family?('rhel') +# frozen_string_literal: true + +apt_update + +directory '/var/run/chrony' if platform_family?('rhel', 'fedora', 'amazon') + +chrony_config 'default' do + extra_config ['log measurements statistics tracking'] +end diff --git a/test/cookbooks/test/recipes/delete.rb b/test/cookbooks/test/recipes/delete.rb new file mode 100644 index 0000000..943c6f7 --- /dev/null +++ b/test/cookbooks/test/recipes/delete.rb @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +chrony_config 'default' do + action :delete +end diff --git a/test/cookbooks/test/recipes/server.rb b/test/cookbooks/test/recipes/server.rb new file mode 100644 index 0000000..88e9086 --- /dev/null +++ b/test/cookbooks/test/recipes/server.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +apt_update + +directory '/var/run/chrony' if platform_family?('rhel', 'fedora', 'amazon') + +chrony_config 'server' do + allow ['10.0.0.0/8'] +end diff --git a/test/integration/default/controls/default.rb b/test/integration/default/controls/default.rb new file mode 100644 index 0000000..9a907f3 --- /dev/null +++ b/test/integration/default/controls/default.rb @@ -0,0 +1,49 @@ +chrony_conf_file = if os.redhat? || os.name == 'fedora' + '/etc/chrony.conf' + else + '/etc/chrony/chrony.conf' + end + +chrony_service = if os.redhat? || os.name == 'fedora' + 'chronyd' + else + 'chrony' + end + +control 'chrony-client-01' do + impact 1.0 + title 'chrony package is installed' + desc 'The chrony package should be installed' + + describe package('chrony') do + it { should be_installed } + end +end + +control 'chrony-client-02' do + impact 1.0 + title 'chrony service is enabled and running' + desc 'The chrony service should be enabled and running' + + describe service(chrony_service) do + it { should be_enabled } + it { should be_running } + end +end + +control 'chrony-client-03' do + impact 1.0 + title 'chrony configuration file' + desc 'The chrony configuration file should exist with correct ownership and content' + + describe file(chrony_conf_file) do + it { should be_file } + its('owner') { should eq 'root' } + its('group') { should eq 'root' } + its('mode') { should cmp '0644' } + its('content') { should match(/^server pool\.ntp\.org iburst/) } + its('content') { should match(/^driftfile /) } + its('content') { should match(/^log measurements statistics tracking$/) } + its('content') { should_not match(/^allow/) } + end +end diff --git a/test/integration/default/inspec.yml b/test/integration/default/inspec.yml new file mode 100644 index 0000000..c17104a --- /dev/null +++ b/test/integration/default/inspec.yml @@ -0,0 +1,7 @@ +--- +name: default +title: Chrony client configuration +maintainer: Sous Chefs +license: Apache-2.0 +summary: Verifies chrony is installed and configured as a client +version: 1.0.0 diff --git a/test/integration/inspec/controls/default_spec.rb b/test/integration/inspec/controls/default_spec.rb deleted file mode 100644 index 989670f..0000000 --- a/test/integration/inspec/controls/default_spec.rb +++ /dev/null @@ -1,38 +0,0 @@ -chrony_conf_file = if os.redhat? || os.name == 'rocky' || os.name == 'almalinux' - '/etc/chrony.conf' - else - '/etc/chrony/chrony.conf' - end - -chrony_service = if os.redhat? || os.name == 'rocky' || os.name == 'almalinux' - 'chronyd' - else - 'chrony' - end - -chrony_type = input('type', value: 'client') - -control 'chrony' do - describe package 'chrony' do - it { should be_installed } - end - - describe service chrony_service do - it { should be_enabled } - it { should be_running } - end - - describe file chrony_conf_file do - it { should be_file } - its('owner') { should eq 'root' } - its('group') { should eq 'root' } - its('mode') { should cmp '0644' } - its('content') { should match /^driftfile .*/ } - - if chrony_type == 'client' - its('content') { should match /^log measurements statistics tracking$/ } - else - its('content') { should match /^allow .*/ } - end - end -end diff --git a/test/integration/inspec/inspec.yml b/test/integration/inspec/inspec.yml deleted file mode 100644 index 0ee44c0..0000000 --- a/test/integration/inspec/inspec.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -name: chrony -inputs: - - name: type - value: "client" diff --git a/test/integration/server/controls/default.rb b/test/integration/server/controls/default.rb new file mode 100644 index 0000000..4fd5b1d --- /dev/null +++ b/test/integration/server/controls/default.rb @@ -0,0 +1,47 @@ +chrony_conf_file = if os.redhat? || os.name == 'fedora' + '/etc/chrony.conf' + else + '/etc/chrony/chrony.conf' + end + +chrony_service = if os.redhat? || os.name == 'fedora' + 'chronyd' + else + 'chrony' + end + +control 'chrony-server-01' do + impact 1.0 + title 'chrony package is installed' + desc 'The chrony package should be installed' + + describe package('chrony') do + it { should be_installed } + end +end + +control 'chrony-server-02' do + impact 1.0 + title 'chrony service is enabled and running' + desc 'The chrony service should be enabled and running' + + describe service(chrony_service) do + it { should be_enabled } + it { should be_running } + end +end + +control 'chrony-server-03' do + impact 1.0 + title 'chrony server configuration file' + desc 'The chrony configuration file should contain allow directives for server mode' + + describe file(chrony_conf_file) do + it { should be_file } + its('owner') { should eq 'root' } + its('group') { should eq 'root' } + its('mode') { should cmp '0644' } + its('content') { should match(/^driftfile /) } + its('content') { should match(%r{^allow 10\.0\.0\.0/8}) } + end +end diff --git a/test/integration/server/inspec.yml b/test/integration/server/inspec.yml new file mode 100644 index 0000000..2c6a2e5 --- /dev/null +++ b/test/integration/server/inspec.yml @@ -0,0 +1,7 @@ +--- +name: server +title: Chrony server configuration +maintainer: Sous Chefs +license: Apache-2.0 +summary: Verifies chrony is installed and configured as a server +version: 1.0.0 From 966f3eed7b09692fbd1b3905e38cf1a1f68159a9 Mon Sep 17 00:00:00 2001 From: Dan Webb Date: Wed, 25 Mar 2026 12:21:08 +0000 Subject: [PATCH 7/8] chore: modernize chrony cookbook support matrix --- LIMITATIONS.md | 42 ++++++++++++++-------------------- README.md | 14 ++++++------ documentation/chrony_config.md | 39 +++++++++++++++++++++---------- kitchen.global.yml | 14 +----------- metadata.rb | 5 +++- 5 files changed, 56 insertions(+), 58 deletions(-) diff --git a/LIMITATIONS.md b/LIMITATIONS.md index 1a10b3b..a9aba0c 100644 --- a/LIMITATIONS.md +++ b/LIMITATIONS.md @@ -1,36 +1,28 @@ -# Chrony Cookbook Limitations +# Limitations -## Supported Platforms - -The `chrony` cookbook supports the following Linux distributions: +## Package Availability -- **RHEL / Rocky / AlmaLinux**: 9 -- **CentOS Stream**: 9 -- **Oracle Linux**: 9 -- **Ubuntu**: 22.04 (LTS), 24.04 (LTS) -- **Debian**: 12 -- **Amazon Linux**: 2023 -- **Fedora**: Latest stable +### APT (Debian/Ubuntu) -## Package Availability +- Debian 12: `chrony` is available from the standard Debian 12 repositories for amd64, arm64, armel, armhf, i386, mips64el, ppc64el, riscv64, and s390x. +- Ubuntu 22.04 and 24.04: `chrony` is available from the standard Ubuntu repositories for amd64, arm64, armhf, ppc64el, riscv64, and s390x. -Chrony is available as a native package on all supported platforms: +### DNF/YUM (RHEL family) -- **Debian/Ubuntu**: `apt install chrony` -- **RHEL/CentOS/Rocky/Alma/Oracle/Fedora/Amazon**: `dnf install chrony` +- RHEL 9, AlmaLinux 9, Rocky Linux 9, Oracle Linux 9, and CentOS Stream 9 provide `chrony` from their standard repositories. +- Amazon Linux 2023 provides `chrony` from the standard `dnf` repositories. +- Fedora latest provides `chrony` from the standard Fedora repositories. -No source compilation is required. +## Architecture Limitations -## Architecture Support +- No cookbook-specific architecture restriction is currently known for supported platforms. +- The common deployment targets across the tested platforms are x86_64 and aarch64. -- x86_64 -- aarch64 (ARM64) +## Source/Compiled Installation -## Migration from Recipes +Chrony is installed from OS packages on all supported platforms in this cookbook. No source build path is implemented or required. -As of the current version, this cookbook no longer provides `chrony::client` or `chrony::server` -recipes. Use the `chrony_config` custom resource directly in your wrapper cookbooks. +## Known Issues -Users who previously relied on the Chef search feature in `chrony::client` (auto-discovering -nodes with `chrony::server` in their run list) must implement that logic in their own wrapper -cookbook. +- This cookbook does not manage vendor-specific repository setup because chrony is installed from the base OS repositories on supported platforms. +- Platform support in `metadata.rb` should stay aligned with `kitchen.yml`, `kitchen.dokken.yml`, and `kitchen.global.yml`. diff --git a/README.md b/README.md index 7177581..215f016 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ Configures the time synchronization application `chrony` as a client or server t ## Maintainers -This cookbook is maintained by the Sous Chefs. The Sous Chefs are a community of Chef cookbook maintainers working together to maintain important cookbooks. If you’d like to know more please visit [sous-chefs.org](https://sous-chefs.org/) or come chat with us on the Chef Community Slack in [#sous-chefs](https://chefcommunity.slack.com/messages/C2V7B88SF). +This cookbook is maintained by the Sous Chefs. The Sous Chefs are a community of Chef cookbook maintainers working together to maintain important cookbooks. If you'd like to know more please visit [sous-chefs.org](https://sous-chefs.org/) or come chat with us on the Chef Community Slack in [#sous-chefs](https://chefcommunity.slack.com/messages/C2V7B88SF). ## Requirements @@ -34,20 +34,20 @@ This cookbook provides the `chrony_config` custom resource. See [documentation/c ## Usage ```ruby -chrony_config ‘default’ do - servers({ ‘pool.ntp.org’ => ‘iburst’ }) +chrony_config 'default' do + servers({ 'pool.ntp.org' => 'iburst' }) end ``` ### Server configuration ```ruby -chrony_config ‘server’ do +chrony_config 'server' do servers({ - ‘ntp1.example.com’ => ‘iburst’, - ‘ntp2.example.com’ => ‘iburst’, + 'ntp1.example.com' => 'iburst', + 'ntp2.example.com' => 'iburst', }) - allow [‘192.168.1.0/24’] + allow ['192.168.1.0/24'] end ``` diff --git a/documentation/chrony_config.md b/documentation/chrony_config.md index 4b98e3c..5c4141d 100644 --- a/documentation/chrony_config.md +++ b/documentation/chrony_config.md @@ -4,27 +4,42 @@ The `chrony_config` resource manages the chrony package, service, and configurat ## Actions -- `:create`: (default) Installs the chrony package, configures it, and enables/starts the service. -- `:delete`: Stops and disables the service, removes the package and configuration file. +| Action | Description | +|---|---| +| `:create` | Installs the chrony package, manages the configuration file, and enables and starts the service. Default action. | +| `:delete` | Stops and disables the service, removes the package, and deletes the configuration file. | ## Properties -- `servers`: (Hash) A hash of NTP servers to use. Key is the server address, value is the options (e.g., `iburst`). Default: `{ 'pool.ntp.org' => 'iburst' }`. -- `pools`: (Hash) A hash of NTP pools to use. Key is the pool address, value is the options. Default: `{}`. -- `allow`: (Array) A list of addresses/subnets allowed to access the server. Default: `[]`. -- `deny`: (Array) A list of addresses/subnets denied access to the server. Default: `[]`. -- `driftfile`: (String) The path to the drift file. Default: Platform-specific. -- `log_dir`: (String) The directory for chrony logs. Default: `/var/log/chrony`. -- `extra_config`: (Array) A list of raw configuration strings to append to the config file. Default: `[]`. +| Property | Type | Default | Description | +|---|---|---|---| +| `servers` | Hash | `{ 'pool.ntp.org' => 'iburst' }` | NTP servers to configure, keyed by hostname with option strings as values. | +| `pools` | Hash | `{}` | NTP pools to configure, keyed by hostname with option strings as values. | +| `allow` | Array | `[]` | Networks or hosts allowed to query the local chrony server. | +| `deny` | Array | `[]` | Networks or hosts denied access to the local chrony server. | +| `driftfile` | String | platform-specific | Drift file path. Defaults to `/var/lib/chrony/drift` on RHEL family and `/var/lib/chrony/chrony.drift` on Debian family. | +| `log_dir` | String | `'/var/log/chrony'` | Directory used for chrony log output. | +| `extra_config` | Array | `[]` | Raw configuration lines appended to the generated chrony configuration file. | ## Examples +### Basic usage + ```ruby chrony_config 'default' do - servers({ + action :create +end +``` + +### Server configuration + +```ruby +chrony_config 'server' do + servers( 'ntp1.example.com' => 'iburst', - 'ntp2.example.com' => 'iburst', - }) + 'ntp2.example.com' => 'iburst' + ) allow ['192.168.1.0/24'] + action :create end ``` diff --git a/kitchen.global.yml b/kitchen.global.yml index a382fcd..976f5ed 100644 --- a/kitchen.global.yml +++ b/kitchen.global.yml @@ -15,24 +15,12 @@ verifier: name: inspec platforms: - - name: almalinux-8 - name: almalinux-9 - name: amazonlinux-2023 - - name: centos-7 - - name: centos-stream-8 - name: centos-stream-9 - - name: debian-9 - - name: debian-10 - - name: debian-11 - name: debian-12 - name: fedora-latest - - name: opensuse-leap-15 - - name: oraclelinux-7 - - name: oraclelinux-8 - name: oraclelinux-9 - - name: rockylinux-8 - name: rockylinux-9 - - name: ubuntu-18.04 - - name: ubuntu-20.04 - name: ubuntu-22.04 - - name: ubuntu-23.04 + - name: ubuntu-24.04 diff --git a/metadata.rb b/metadata.rb index 6339dec..f0fc204 100644 --- a/metadata.rb +++ b/metadata.rb @@ -11,7 +11,10 @@ supports 'debian', '>= 12.0' supports 'ubuntu', '>= 22.04' +supports 'centos_stream', '>= 9.0' +supports 'fedora' +supports 'oracle', '>= 9.0' supports 'redhat', '>= 9.0' supports 'rocky', '>= 9.0' supports 'almalinux', '>= 9.0' -supports 'amazon' +supports 'amazon', '>= 2023.0' From 3b00130b5323f08ccfff45b2ee665ae5114552f7 Mon Sep 17 00:00:00 2001 From: Dan Webb Date: Wed, 25 Mar 2026 12:25:59 +0000 Subject: [PATCH 8/8] fix: normalize ubuntu kitchen instance names in CI --- .github/workflows/ci.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6ed1ee9..f0c1c31 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -43,10 +43,8 @@ jobs: - name: Install Chef uses: actionshub/chef-install@main - name: Dokken - uses: actionshub/test-kitchen@main env: CHEF_LICENSE: accept-no-persist KITCHEN_LOCAL_YAML: kitchen.dokken.yml - with: - suite: ${{ matrix.suite }} - os: ${{ matrix.os }} + INSTANCE_NAME: ${{ matrix.suite }}-${{ matrix.os }} + run: kitchen test "${INSTANCE_NAME//./}"