From 29d672498f4aff7d692003232e0bd2120e20b323 Mon Sep 17 00:00:00 2001 From: Jamie Magee Date: Sun, 3 May 2026 20:04:19 -0700 Subject: [PATCH 1/3] nixos/timesyncd: drop `with lib;` Prefix `lib.` on `mkOption`, `mkIf`, `types.*`, `literalExpression`, `optionalString` and `concatStringsSep` so the module no longer relies on `with lib;`. No behavioural change. --- nixos/modules/system/boot/timesyncd.nix | 34 ++++++++++++------------- 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/nixos/modules/system/boot/timesyncd.nix b/nixos/modules/system/boot/timesyncd.nix index 4584837896fb..5f4cd1eba424 100644 --- a/nixos/modules/system/boot/timesyncd.nix +++ b/nixos/modules/system/boot/timesyncd.nix @@ -1,7 +1,5 @@ { config, lib, ... }: -with lib; - let cfg = config.services.timesyncd; in @@ -9,18 +7,18 @@ in options = { - services.timesyncd = with types; { - enable = mkOption { + services.timesyncd = { + enable = lib.mkOption { default = !config.boot.isContainer; - defaultText = literalExpression "!config.boot.isContainer"; - type = bool; + defaultText = lib.literalExpression "!config.boot.isContainer"; + type = lib.types.bool; description = '' Enables the systemd NTP client daemon. ''; }; - servers = mkOption { + servers = lib.mkOption { default = null; - type = nullOr (listOf str); + type = lib.types.nullOr (lib.types.listOf lib.types.str); description = '' The set of NTP servers from which to synchronise. @@ -31,10 +29,10 @@ in See {manpage}`timesyncd.conf(5)` for details. ''; }; - fallbackServers = mkOption { + fallbackServers = lib.mkOption { default = config.networking.timeServers; - defaultText = literalExpression "config.networking.timeServers"; - type = nullOr (listOf str); + defaultText = lib.literalExpression "config.networking.timeServers"; + type = lib.types.nullOr (lib.types.listOf lib.types.str); description = '' The set of fallback NTP servers from which to synchronise. @@ -45,9 +43,9 @@ in See {manpage}`timesyncd.conf(5)` for details. ''; }; - extraConfig = mkOption { + extraConfig = lib.mkOption { default = ""; - type = lines; + type = lib.types.lines; example = '' PollIntervalMaxSec=180 ''; @@ -59,7 +57,7 @@ in }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { systemd.additionalUpstreamSystemUnits = [ "systemd-timesyncd.service" ]; @@ -79,11 +77,11 @@ in environment.etc."systemd/timesyncd.conf".text = '' [Time] '' - + optionalString (cfg.servers != null) '' - NTP=${concatStringsSep " " cfg.servers} + + lib.optionalString (cfg.servers != null) '' + NTP=${lib.concatStringsSep " " cfg.servers} '' - + optionalString (cfg.fallbackServers != null) '' - FallbackNTP=${concatStringsSep " " cfg.fallbackServers} + + lib.optionalString (cfg.fallbackServers != null) '' + FallbackNTP=${lib.concatStringsSep " " cfg.fallbackServers} '' + cfg.extraConfig; From 1460350c4cd38590d5fcad7eea32859780c92040 Mon Sep 17 00:00:00 2001 From: Jamie Magee Date: Sun, 3 May 2026 20:09:13 -0700 Subject: [PATCH 2/3] nixos/timesyncd: migrate to RFC 42-style settings Replace `services.timesyncd.extraConfig` with a freeform `services.timesyncd.settings.Time` submodule, rendered via `utils.systemdUtils.lib.settingsToSections`. `extraConfig` is removed via `mkRemovedOptionModule`. `servers` and `fallbackServers` are kept as typed wrappers; they now bridge into `settings.Time.NTP` / `settings.Time.FallbackNTP` via `mkDefault` so users can still override them through `settings.Time`. Adds `nixos/tests/systemd-timesyncd` to assert the rendered `timesyncd.conf` contents. --- .../manual/release-notes/rl-2611.section.md | 2 + nixos/modules/system/boot/timesyncd.nix | 54 ++++++++++++------- nixos/tests/all-tests.nix | 1 + nixos/tests/systemd-timesyncd-nscd-dnssec.nix | 4 +- nixos/tests/systemd-timesyncd.nix | 31 +++++++++++ 5 files changed, 70 insertions(+), 22 deletions(-) create mode 100644 nixos/tests/systemd-timesyncd.nix diff --git a/nixos/doc/manual/release-notes/rl-2611.section.md b/nixos/doc/manual/release-notes/rl-2611.section.md index 3d53f1f20930..028ae5a3c13d 100644 --- a/nixos/doc/manual/release-notes/rl-2611.section.md +++ b/nixos/doc/manual/release-notes/rl-2611.section.md @@ -23,6 +23,8 @@ no longer sets `programs.pqos-wrapper.enable = true` as the corresponding module has been deleted. +- `services.timesyncd.extraConfig` has been removed in favor of the structured [](#opt-services.timesyncd.settings.Time) option. Use `services.timesyncd.settings.Time` to set any `timesyncd.conf(5)` option directly. For example, replace `services.timesyncd.extraConfig = "PollIntervalMaxSec=180";` with `services.timesyncd.settings.Time.PollIntervalMaxSec = 180;`. + ## Other Notable Changes {#sec-release-26.11-notable-changes} diff --git a/nixos/modules/system/boot/timesyncd.nix b/nixos/modules/system/boot/timesyncd.nix index 5f4cd1eba424..ec1deeaad49f 100644 --- a/nixos/modules/system/boot/timesyncd.nix +++ b/nixos/modules/system/boot/timesyncd.nix @@ -1,10 +1,23 @@ -{ config, lib, ... }: +{ + config, + lib, + utils, + ... +}: let cfg = config.services.timesyncd; in { + imports = [ + (lib.mkRemovedOptionModule [ + "services" + "timesyncd" + "extraConfig" + ] "Use services.timesyncd.settings.Time instead.") + ]; + options = { services.timesyncd = { @@ -43,15 +56,17 @@ in See {manpage}`timesyncd.conf(5)` for details. ''; }; - extraConfig = lib.mkOption { - default = ""; - type = lib.types.lines; - example = '' - PollIntervalMaxSec=180 - ''; + settings.Time = lib.mkOption { + default = { }; + type = lib.types.submodule { + freeformType = lib.types.attrsOf utils.systemdUtils.unitOptions.unitOption; + }; + example = { + PollIntervalMaxSec = 180; + }; description = '' - Extra config options for systemd-timesyncd. See - {manpage}`timesyncd.conf(5)` for available options. + Settings for systemd-timesyncd. See {manpage}`timesyncd.conf(5)` for + available options. ''; }; }; @@ -74,16 +89,17 @@ in environment.LD_LIBRARY_PATH = config.system.nssModules.path; }; - environment.etc."systemd/timesyncd.conf".text = '' - [Time] - '' - + lib.optionalString (cfg.servers != null) '' - NTP=${lib.concatStringsSep " " cfg.servers} - '' - + lib.optionalString (cfg.fallbackServers != null) '' - FallbackNTP=${lib.concatStringsSep " " cfg.fallbackServers} - '' - + cfg.extraConfig; + services.timesyncd.settings.Time = lib.mkMerge [ + (lib.mkIf (cfg.servers != null) { + NTP = lib.mkDefault (lib.concatStringsSep " " cfg.servers); + }) + (lib.mkIf (cfg.fallbackServers != null) { + FallbackNTP = lib.mkDefault (lib.concatStringsSep " " cfg.fallbackServers); + }) + ]; + + environment.etc."systemd/timesyncd.conf".text = + utils.systemdUtils.lib.settingsToSections cfg.settings; users.users.systemd-timesync = { uid = config.ids.uids.systemd-timesync; diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index e653dc42b9c2..aad4342f5d7a 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -1653,6 +1653,7 @@ in systemd-sysusers-immutable = runTest ./systemd-sysusers-immutable.nix; systemd-sysusers-mutable = runTest ./systemd-sysusers-mutable.nix; systemd-sysusers-password-option-override-ordering = runTest ./systemd-sysusers-password-option-override-ordering.nix; + systemd-timesyncd = runTest ./systemd-timesyncd.nix; systemd-timesyncd-nscd-dnssec = runTest ./systemd-timesyncd-nscd-dnssec.nix; systemd-user-linger = runTest ./systemd-user-linger.nix; systemd-user-linger-purge = runTest ./systemd-user-linger-purge.nix; diff --git a/nixos/tests/systemd-timesyncd-nscd-dnssec.nix b/nixos/tests/systemd-timesyncd-nscd-dnssec.nix index a57cd4802dec..ce276184d313 100644 --- a/nixos/tests/systemd-timesyncd-nscd-dnssec.nix +++ b/nixos/tests/systemd-timesyncd-nscd-dnssec.nix @@ -50,9 +50,7 @@ in # Configure systemd-timesyncd to use our NTP hostname services.timesyncd.enable = lib.mkForce true; services.timesyncd.servers = [ ntpHostname ]; - services.timesyncd.extraConfig = '' - FallbackNTP=${ntpHostname} - ''; + services.timesyncd.settings.Time.FallbackNTP = ntpHostname; # The debug output is necessary to determine whether systemd-timesyncd successfully resolves our NTP hostname or not systemd.services.systemd-timesyncd.environment.SYSTEMD_LOG_LEVEL = "debug"; diff --git a/nixos/tests/systemd-timesyncd.nix b/nixos/tests/systemd-timesyncd.nix new file mode 100644 index 000000000000..7a88fd7e2499 --- /dev/null +++ b/nixos/tests/systemd-timesyncd.nix @@ -0,0 +1,31 @@ +{ + name = "systemd-timesyncd"; + meta = { + maintainers = [ ]; + }; + + nodes.machine = + { lib, ... }: + { + services.timesyncd = { + enable = lib.mkForce true; + servers = [ "ntp.example.com" ]; + fallbackServers = [ "fallback.example.com" ]; + settings.Time = { + PollIntervalMaxSec = "180"; + RootDistanceMaxSec = "5"; + }; + }; + }; + + testScript = '' + machine.wait_for_unit("multi-user.target") + + with subtest("settings.Time renders timesyncd.conf"): + machine.succeed("grep -F '[Time]' /etc/systemd/timesyncd.conf") + machine.succeed("grep -F 'NTP=ntp.example.com' /etc/systemd/timesyncd.conf") + machine.succeed("grep -F 'FallbackNTP=fallback.example.com' /etc/systemd/timesyncd.conf") + machine.succeed("grep -F 'PollIntervalMaxSec=180' /etc/systemd/timesyncd.conf") + machine.succeed("grep -F 'RootDistanceMaxSec=5' /etc/systemd/timesyncd.conf") + ''; +} From 1f1c72470b4f22a5cd5d671c4330a43296c43bdf Mon Sep 17 00:00:00 2001 From: nikstur Date: Thu, 4 Jun 2026 16:44:16 +0200 Subject: [PATCH 3/3] nixos/tests/systemd-timesyncd-nscd-dnssec.nix: change name to be more specific --- nixos/tests/systemd-timesyncd-nscd-dnssec.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nixos/tests/systemd-timesyncd-nscd-dnssec.nix b/nixos/tests/systemd-timesyncd-nscd-dnssec.nix index ce276184d313..b8eebd4443d9 100644 --- a/nixos/tests/systemd-timesyncd-nscd-dnssec.nix +++ b/nixos/tests/systemd-timesyncd-nscd-dnssec.nix @@ -20,7 +20,7 @@ let ntpIP = "192.0.2.1"; in { - name = "systemd-timesyncd"; + name = "systemd-timesyncd-nscd-dnssec"; nodes.machine = { pkgs,