diff --git a/nixos/doc/manual/from_md/release-notes/rl-2205.section.xml b/nixos/doc/manual/from_md/release-notes/rl-2205.section.xml
index 99af050d7baf..9535d441740b 100644
--- a/nixos/doc/manual/from_md/release-notes/rl-2205.section.xml
+++ b/nixos/doc/manual/from_md/release-notes/rl-2205.section.xml
@@ -1655,9 +1655,20 @@
- services.logrotate.enable now defaults to
- true if any rotate path has been defined, and some paths have
- been added by default.
+ services.logrotate.enable
+ now defaults to true if any rotate path has been defined, and
+ some paths have been added by default.
+
+
+
+
+ The logrotate module also has been updated to freeform syntax:
+ services.logrotate.paths
+ and
+ services.logrotate.extraConfig
+ will work, but issue deprecation warnings and
+ services.logrotate.settings
+ should now be used instead.
diff --git a/nixos/doc/manual/release-notes/rl-2205.section.md b/nixos/doc/manual/release-notes/rl-2205.section.md
index 3e883625664e..377dd1b5cae1 100644
--- a/nixos/doc/manual/release-notes/rl-2205.section.md
+++ b/nixos/doc/manual/release-notes/rl-2205.section.md
@@ -578,8 +578,11 @@ In addition to numerous new and upgraded packages, this release has the followin
- `services.mattermost.plugins` has been added to allow the declarative installation of Mattermost plugins.
Plugins are automatically repackaged using autoPatchelf.
-- `services.logrotate.enable` now defaults to true if any rotate path has
+- [services.logrotate.enable](#opt-services.logrotate.enable) now defaults to true if any rotate path has
been defined, and some paths have been added by default.
+- The logrotate module also has been updated to freeform syntax: [services.logrotate.paths](#opt-services.logrotate.paths)
+ and [services.logrotate.extraConfig](#opt-services.logrotate.extraConfig) will work, but issue deprecation
+ warnings and [services.logrotate.settings](#opt-services.logrotate.settings) should now be used instead.
- The `zrepl` package has been updated from 0.4.0 to 0.5:
diff --git a/nixos/modules/services/logging/logrotate.nix b/nixos/modules/services/logging/logrotate.nix
index d16a5a571ba3..6a9ed469fd38 100644
--- a/nixos/modules/services/logging/logrotate.nix
+++ b/nixos/modules/services/logging/logrotate.nix
@@ -5,6 +5,9 @@ with lib;
let
cfg = config.services.logrotate;
+ # deprecated legacy compat settings
+ # these options will be removed before 22.11 in the following PR:
+ # https://github.com/NixOS/nixpkgs/pull/164169
pathOpts = { name, ... }: {
options = {
enable = mkOption {
@@ -86,27 +89,77 @@ let
config.name = name;
};
- mkConf = pathOpts: ''
- # generated by NixOS using the `services.logrotate.paths.${pathOpts.name}` attribute set
- ${concatMapStringsSep " " (path: ''"${path}"'') (toList pathOpts.path)} {
- ${optionalString (pathOpts.user != null || pathOpts.group != null) "su ${pathOpts.user} ${pathOpts.group}"}
- ${pathOpts.frequency}
- rotate ${toString pathOpts.keep}
- ${pathOpts.extraConfig}
- }
- '';
-
- paths = sortProperties (attrValues (filterAttrs (_: pathOpts: pathOpts.enable) cfg.paths));
- configText = concatStringsSep "\n" (
- [ "missingok" "notifempty" cfg.extraConfig ] ++ (map mkConf paths)
+ generateLine = n: v:
+ if builtins.elem n [ "files" "priority" "enable" "global" ] || v == null then null
+ else if builtins.elem n [ "extraConfig" "frequency" ] then "${v}\n"
+ else if builtins.elem n [ "firstaction" "lastaction" "prerotate" "postrotate" "preremove" ]
+ then "${n}\n ${v}\n endscript\n"
+ else if isInt v then "${n} ${toString v}\n"
+ else if v == true then "${n}\n"
+ else if v == false then "no${n}\n"
+ else "${n} ${v}\n";
+ generateSection = indent: settings: concatStringsSep (fixedWidthString indent " " "") (
+ filter (x: x != null) (mapAttrsToList generateLine settings)
+ );
+
+ # generateSection includes a final newline hence weird closing brace
+ mkConf = settings:
+ if settings.global or false then generateSection 0 settings
+ else ''
+ ${concatMapStringsSep "\n" (files: ''"${files}"'') (toList settings.files)} {
+ ${generateSection 2 settings}}
+ '';
+
+ # below two mapPaths are compat functions
+ mapPathOptToSetting = n: v:
+ if n == "keep" then nameValuePair "rotate" v
+ else if n == "path" then nameValuePair "files" v
+ else nameValuePair n v;
+
+ mapPathsToSettings = path: pathOpts:
+ nameValuePair path (
+ filterAttrs (n: v: ! builtins.elem n [ "user" "group" "name" ] && v != "") (
+ (mapAttrs' mapPathOptToSetting pathOpts) //
+ {
+ su =
+ if pathOpts.user != null
+ then "${pathOpts.user} ${pathOpts.group}"
+ else null;
+ }
+ )
+ );
+
+ settings = sortProperties (attrValues (filterAttrs (_: settings: settings.enable) (
+ foldAttrs recursiveUpdate { } [
+ {
+ header = {
+ enable = true;
+ missingok = true;
+ notifempty = true;
+ frequency = "weekly";
+ rotate = 4;
+ };
+ # compat section
+ extraConfig = {
+ enable = (cfg.extraConfig != "");
+ global = true;
+ extraConfig = cfg.extraConfig;
+ priority = 101;
+ };
+ }
+ (mapAttrs' mapPathsToSettings cfg.paths)
+ cfg.settings
+ { header = { global = true; priority = 100; }; }
+ ]
+ )));
+ configFile = pkgs.writeText "logrotate.conf" (
+ concatStringsSep "\n" (
+ map mkConf settings
+ )
);
- configFile = pkgs.writeText "logrotate.conf" configText;
mailOption =
- # add mail option to service if a mail is requested in config
- # this ugly match will be replaced by cleaner attribute check in
- # the near future
- if builtins.match "(.*[[:space:]])?mail[[:space:]].*" configText != null
+ if foldr (n: a: a || n ? mail) false (attrValues cfg.settings)
then "--mail=${pkgs.mailutils}/bin/mail"
else "";
in
@@ -118,8 +171,68 @@ in
options = {
services.logrotate = {
enable = mkEnableOption "the logrotate systemd service" // {
- default = foldr (n: a: a || n.enable) false (attrValues cfg.paths);
- defaultText = literalExpression "cfg.paths != {}";
+ default = foldr (n: a: a || n.enable) false (attrValues cfg.settings);
+ defaultText = literalExpression "cfg.settings != {}";
+ };
+
+ settings = mkOption {
+ default = { };
+ description = ''
+ logrotate freeform settings: each attribute here will define its own section,
+ ordered by priority, which can either define files to rotate with their settings
+ or settings common to all further files settings.
+ Refer to for details.
+ '';
+ type = types.attrsOf (types.submodule ({ name, ... }: {
+ freeformType = with types; attrsOf (nullOr (oneOf [ int bool str ]));
+
+ options = {
+ enable = mkEnableOption "setting individual kill switch" // {
+ default = true;
+ };
+
+ global = mkOption {
+ type = types.bool;
+ default = false;
+ description = ''
+ Whether this setting is a global option or not: set to have these
+ settings apply to all files settings with a higher priority.
+ '';
+ };
+ files = mkOption {
+ type = with types; either str (listOf str);
+ default = name;
+ defaultText = ''
+ The attrset name if not specified
+ '';
+ description = ''
+ Single or list of files for which rules are defined.
+ The files are quoted with double-quotes in logrotate configuration,
+ so globs and spaces are supported.
+ Note this setting is ignored if globals is true.
+ '';
+ };
+
+ frequency = mkOption {
+ type = types.nullOr types.str;
+ default = null;
+ description = ''
+ How often to rotate the logs. Defaults to previously set global setting,
+ which itself defauts to weekly.
+ '';
+ };
+
+ priority = mkOption {
+ type = types.int;
+ default = 1000;
+ description = ''
+ Order of this logrotate block in relation to the others. The semantics are
+ the same as with `lib.mkOrder`. Smaller values are inserted first.
+ '';
+ };
+ };
+
+ }));
};
configFile = mkOption {
@@ -130,7 +243,7 @@ in
'';
description = ''
Override the configuration file used by MySQL. By default,
- NixOS generates one automatically from .
+ NixOS generates one automatically from .
'';
example = literalExpression ''
pkgs.writeText "logrotate.conf" '''
@@ -143,6 +256,7 @@ in
'';
};
+ # deprecated legacy compat settings
paths = mkOption {
type = with types; attrsOf (submodule pathOpts);
default = { };
@@ -150,6 +264,7 @@ in
Attribute set of paths to rotate. The order each block appears in the generated configuration file
can be controlled by the priority option
using the same semantics as `lib.mkOrder`. Smaller values have a greater priority.
+ This setting has been deprecated in favor of logrotate settings.
'';
example = literalExpression ''
{
@@ -178,22 +293,37 @@ in
description = ''
Extra contents to append to the logrotate configuration file. Refer to
for details.
+ This setting has been deprecated in favor of
+ logrotate settings.
'';
};
};
};
config = mkIf cfg.enable {
- assertions = mapAttrsToList
- (name: pathOpts:
- {
- assertion = (pathOpts.user != null) == (pathOpts.group != null);
- message = ''
- If either of `services.logrotate.paths.${name}.user` or `services.logrotate.paths.${name}.group` are specified then *both* must be specified.
- '';
- }
- )
- cfg.paths;
+ assertions =
+ mapAttrsToList
+ (name: pathOpts:
+ {
+ assertion = (pathOpts.user != null) == (pathOpts.group != null);
+ message = ''
+ If either of `services.logrotate.paths.${name}.user` or `services.logrotate.paths.${name}.group` are specified then *both* must be specified.
+ '';
+ })
+ cfg.paths;
+
+ warnings =
+ (mapAttrsToList
+ (name: pathOpts: ''
+ Using config.services.logrotate.paths.${name} is deprecated and will become unsupported in a future release.
+ Please use services.logrotate.settings instead.
+ '')
+ cfg.paths
+ ) ++
+ (optional (cfg.extraConfig != "") ''
+ Using config.services.logrotate.extraConfig is deprecated and will become unsupported in a future release.
+ Please use services.logrotate.settings with globals=true instead.
+ '');
systemd.services.logrotate = {
description = "Logrotate Service";
diff --git a/nixos/modules/services/misc/gitlab.nix b/nixos/modules/services/misc/gitlab.nix
index e48444f71612..488c3be7b653 100644
--- a/nixos/modules/services/misc/gitlab.nix
+++ b/nixos/modules/services/misc/gitlab.nix
@@ -848,10 +848,7 @@ in {
extraConfig = mkOption {
type = types.lines;
- default = ''
- copytruncate
- compress
- '';
+ default = "";
description = ''
Extra logrotate config options for this path. Refer to
for details.
@@ -977,13 +974,14 @@ in {
# Enable rotation of log files
services.logrotate = {
enable = cfg.logrotate.enable;
- paths = {
+ settings = {
gitlab = {
- path = "${cfg.statePath}/log/*.log";
- user = cfg.user;
- group = cfg.group;
+ files = "${cfg.statePath}/log/*.log";
+ su = "${cfg.user} ${cfg.group}";
frequency = cfg.logrotate.frequency;
- keep = cfg.logrotate.keep;
+ rotate = cfg.logrotate.keep;
+ copytruncate = true;
+ compress = true;
extraConfig = cfg.logrotate.extraConfig;
};
};
diff --git a/nixos/modules/services/networking/lxd-image-server.nix b/nixos/modules/services/networking/lxd-image-server.nix
index b119ba8acf63..d326626eed44 100644
--- a/nixos/modules/services/networking/lxd-image-server.nix
+++ b/nixos/modules/services/networking/lxd-image-server.nix
@@ -51,18 +51,14 @@ in
environment.etc."lxd-image-server/config.toml".source = format.generate "config.toml" cfg.settings;
- services.logrotate.paths.lxd-image-server = {
- path = "/var/log/lxd-image-server/lxd-image-server.log";
+ services.logrotate.settings.lxd-image-server = {
+ files = "/var/log/lxd-image-server/lxd-image-server.log";
frequency = "daily";
- keep = 21;
- extraConfig = ''
- create 755 lxd-image-server ${cfg.group}
- missingok
- compress
- delaycompress
- copytruncate
- notifempty
- '';
+ rotate = 21;
+ create = "755 lxd-image-server ${cfg.group}";
+ compress = true;
+ delaycompress = true;
+ copytruncate = true;
};
systemd.tmpfiles.rules = [
diff --git a/nixos/modules/services/web-servers/apache-httpd/default.nix b/nixos/modules/services/web-servers/apache-httpd/default.nix
index d817ff6019a3..3099705acbe2 100644
--- a/nixos/modules/services/web-servers/apache-httpd/default.nix
+++ b/nixos/modules/services/web-servers/apache-httpd/default.nix
@@ -710,20 +710,15 @@ in
services.logrotate = optionalAttrs (cfg.logFormat != "none") {
enable = mkDefault true;
- paths.httpd = {
- path = "${cfg.logDir}/*.log";
- user = cfg.user;
- group = cfg.group;
+ settings.httpd = {
+ files = "${cfg.logDir}/*.log";
+ su = "${cfg.user} ${cfg.group}";
frequency = "daily";
- keep = 28;
- extraConfig = ''
- sharedscripts
- compress
- delaycompress
- postrotate
- systemctl reload httpd.service > /dev/null 2>/dev/null || true
- endscript
- '';
+ rotate = 28;
+ sharedscripts = true;
+ compress = true;
+ delaycompress = true;
+ postrotate = "systemctl reload httpd.service > /dev/null 2>/dev/null || true";
};
};
diff --git a/nixos/modules/services/web-servers/nginx/default.nix b/nixos/modules/services/web-servers/nginx/default.nix
index e046c28dd6bb..1e18956c2dc4 100644
--- a/nixos/modules/services/web-servers/nginx/default.nix
+++ b/nixos/modules/services/web-servers/nginx/default.nix
@@ -989,17 +989,13 @@ in
nginx.gid = config.ids.gids.nginx;
};
- services.logrotate.paths.nginx = mapAttrs (_: mkDefault) {
- path = "/var/log/nginx/*.log";
+ services.logrotate.settings.nginx = mapAttrs (_: mkDefault) {
+ files = "/var/log/nginx/*.log";
frequency = "weekly";
- keep = 26;
- extraConfig = ''
- compress
- delaycompress
- postrotate
- [ ! -f /var/run/nginx/nginx.pid ] || kill -USR1 `cat /var/run/nginx/nginx.pid`
- endscript
- '';
+ rotate = 26;
+ compress = true;
+ delaycompress = true;
+ postrotate = "[ ! -f /var/run/nginx/nginx.pid ] || kill -USR1 `cat /var/run/nginx/nginx.pid`";
};
};
}
diff --git a/nixos/modules/system/boot/systemd.nix b/nixos/modules/system/boot/systemd.nix
index 297a80d4681b..f69c5d3d5a64 100644
--- a/nixos/modules/system/boot/systemd.nix
+++ b/nixos/modules/system/boot/systemd.nix
@@ -612,22 +612,18 @@ in
boot.kernelParams = optional (!cfg.enableUnifiedCgroupHierarchy) "systemd.unified_cgroup_hierarchy=0";
- services.logrotate.paths = {
+ services.logrotate.settings = {
"/var/log/btmp" = mapAttrs (_: mkDefault) {
frequency = "monthly";
- keep = 1;
- extraConfig = ''
- create 0660 root ${config.users.groups.utmp.name}
- minsize 1M
- '';
+ rotate = 1;
+ create = "0660 root ${config.users.groups.utmp.name}";
+ minsize = "1M";
};
"/var/log/wtmp" = mapAttrs (_: mkDefault) {
frequency = "monthly";
- keep = 1;
- extraConfig = ''
- create 0664 root ${config.users.groups.utmp.name}
- minsize 1M
- '';
+ rotate = 1;
+ create = "0664 root ${config.users.groups.utmp.name}";
+ minsize = "1M";
};
};
};
diff --git a/nixos/modules/virtualisation/azure-agent.nix b/nixos/modules/virtualisation/azure-agent.nix
index bd8c7f8c1eea..e2425b44eac4 100644
--- a/nixos/modules/virtualisation/azure-agent.nix
+++ b/nixos/modules/virtualisation/azure-agent.nix
@@ -146,15 +146,11 @@ in
services.logrotate = {
enable = true;
- extraConfig = ''
- /var/log/waagent.log {
- compress
- monthly
- rotate 6
- notifempty
- missingok
- }
- '';
+ settings."/var/log/waagent.log" = {
+ compress = true;
+ frequency = "monthly";
+ rotate = 6;
+ };
};
systemd.targets.provisioned = {
diff --git a/nixos/tests/logrotate.nix b/nixos/tests/logrotate.nix
index 85923465593a..3087119c339f 100644
--- a/nixos/tests/logrotate.nix
+++ b/nixos/tests/logrotate.nix
@@ -1,5 +1,14 @@
# Test logrotate service works and is enabled by default
+let
+ importTest = { ... }: {
+ services.logrotate.settings.import = {
+ olddir = false;
+ };
+ };
+
+in
+
import ./make-test-python.nix ({ pkgs, ... }: rec {
name = "logrotate";
meta = with pkgs.lib.maintainers; {
@@ -9,10 +18,59 @@ import ./make-test-python.nix ({ pkgs, ... }: rec {
nodes = {
defaultMachine = { ... }: { };
machine = { config, ... }: {
- services.logrotate.paths = {
+ imports = [ importTest ];
+
+ services.logrotate.settings = {
+ # remove default frequency header and add another
+ header = {
+ frequency = null;
+ delaycompress = true;
+ };
+ # extra global setting... affecting nothing
+ last_line = {
+ global = true;
+ priority = 2000;
+ shred = true;
+ };
# using mail somewhere should add --mail to logrotate invokation
sendmail = {
- extraConfig = "mail user@domain.tld";
+ mail = "user@domain.tld";
+ };
+ # postrotate should be suffixed by 'endscript'
+ postrotate = {
+ postrotate = "touch /dev/null";
+ };
+ # multiple paths should be aggregated
+ multipath = {
+ files = [ "file1" "file2" ];
+ };
+ # overriding imported path should keep existing attributes
+ # (e.g. olddir is still set)
+ import = {
+ notifempty = true;
+ };
+ };
+ # extraConfig compatibility - should be added to top level, early.
+ services.logrotate.extraConfig = ''
+ nomail
+ '';
+ # paths compatibility
+ services.logrotate.paths = {
+ compat_path = {
+ path = "compat_test_path";
+ };
+ # user/group should be grouped as 'su user group'
+ compat_user = {
+ user = config.users.users.root.name;
+ group = "root";
+ };
+ # extraConfig in path should be added to block
+ compat_extraConfig = {
+ extraConfig = "dateext";
+ };
+ # keep -> rotate
+ compat_keep = {
+ keep = 1;
};
};
};
@@ -44,5 +102,23 @@ import ./make-test-python.nix ({ pkgs, ... }: rec {
defaultMachine.fail("systemctl cat logrotate.service | grep -- --mail")
with subtest("using mails adds mail option"):
machine.succeed("systemctl cat logrotate.service | grep -- --mail")
+ with subtest("check generated config matches expectation"):
+ machine.succeed(
+ # copy conf to /tmp/logrotate.conf for easy grep
+ "conf=$(systemctl cat logrotate | grep -oE '/nix/store[^ ]*logrotate.conf'); cp $conf /tmp/logrotate.conf",
+ "! grep weekly /tmp/logrotate.conf",
+ "grep -E '^delaycompress' /tmp/logrotate.conf",
+ "tail -n 1 /tmp/logrotate.conf | grep shred",
+ "sed -ne '/\"sendmail\" {/,/}/p' /tmp/logrotate.conf | grep 'mail user@domain.tld'",
+ "sed -ne '/\"postrotate\" {/,/}/p' /tmp/logrotate.conf | grep endscript",
+ "grep '\"file1\"\n\"file2\" {' /tmp/logrotate.conf",
+ "sed -ne '/\"import\" {/,/}/p' /tmp/logrotate.conf | grep noolddir",
+ "sed -ne '1,/^\"/p' /tmp/logrotate.conf | grep nomail",
+ "grep '\"compat_test_path\" {' /tmp/logrotate.conf",
+ "sed -ne '/\"compat_user\" {/,/}/p' /tmp/logrotate.conf | grep 'su root root'",
+ "sed -ne '/\"compat_extraConfig\" {/,/}/p' /tmp/logrotate.conf | grep dateext",
+ "[[ $(sed -ne '/\"compat_keep\" {/,/}/p' /tmp/logrotate.conf | grep -w rotate) = \" rotate 1\" ]]",
+ "! sed -ne '/\"compat_keep\" {/,/}/p' /tmp/logrotate.conf | grep -w keep",
+ )
'';
})