python3Packages.orjson: Disable failing tests on 32 bit
[NixPkgs.git] / nixos / modules / services / logging / logrotate.nix
blobfd41b982678f3a35725417578dbb7dc80ddea02b
1 { config, lib, pkgs, ... }:
3 with lib;
5 let
6   cfg = config.services.logrotate;
8   generateLine = n: v:
9     if builtins.elem n [ "files" "priority" "enable" "global" ] || v == null then null
10     else if builtins.elem n [ "frequency" ] then "${v}\n"
11     else if builtins.elem n [ "firstaction" "lastaction" "prerotate" "postrotate" "preremove" ]
12          then "${n}\n    ${v}\n  endscript\n"
13     else if isInt v then "${n} ${toString v}\n"
14     else if v == true then "${n}\n"
15     else if v == false then "no${n}\n"
16     else "${n} ${v}\n";
17   generateSection = indent: settings: concatStringsSep (fixedWidthString indent " " "") (
18     filter (x: x != null) (mapAttrsToList generateLine settings)
19   );
21   # generateSection includes a final newline hence weird closing brace
22   mkConf = settings:
23     if settings.global or false then generateSection 0 settings
24     else ''
25       ${concatMapStringsSep "\n" (files: ''"${files}"'') (toList settings.files)} {
26         ${generateSection 2 settings}}
27     '';
29   settings = sortProperties (attrValues (filterAttrs (_: settings: settings.enable) (
30     foldAttrs recursiveUpdate { } [
31       {
32         header = {
33           enable = true;
34           missingok = true;
35           notifempty = true;
36           frequency = "weekly";
37           rotate = 4;
38         };
39       }
40       cfg.settings
41       { header = { global = true; priority = 100; }; }
42     ]
43   )));
44   configFile = pkgs.writeTextFile {
45     name = "logrotate.conf";
46     text = concatStringsSep "\n" (
47       map mkConf settings
48     );
49     checkPhase = optionalString cfg.checkConfig ''
50       # logrotate --debug also checks that users specified in config
51       # file exist, but we only have sandboxed users here so brown these
52       # out. according to man page that means su, create and createolddir.
53       # files required to exist also won't be present, so missingok is forced.
54       user=$(${pkgs.buildPackages.coreutils}/bin/id -un)
55       group=$(${pkgs.buildPackages.coreutils}/bin/id -gn)
56       sed -e "s/\bsu\s.*/su $user $group/" \
57           -e "s/\b\(create\s\+[0-9]*\s*\|createolddir\s\+[0-9]*\s\+\).*/\1$user $group/" \
58           -e "1imissingok" -e "s/\bnomissingok\b//" \
59           $out > logrotate.conf
60       # Since this makes for very verbose builds only show real error.
61       # There is no way to control log level, but logrotate hardcodes
62       # 'error:' at common log level, so we can use grep, taking care
63       # to keep error codes
64       set -o pipefail
65       if ! ${pkgs.buildPackages.logrotate}/sbin/logrotate -s logrotate.status \
66                       --debug logrotate.conf 2>&1 \
67                   | ( ! grep "error:" ) > logrotate-error; then
68               echo "Logrotate configuration check failed."
69               echo "The failing configuration (after adjustments to pass tests in sandbox) was:"
70               printf "%s\n" "-------"
71               cat logrotate.conf
72               printf "%s\n" "-------"
73               echo "The error reported by logrotate was as follow:"
74               printf "%s\n" "-------"
75               cat logrotate-error
76               printf "%s\n" "-------"
77               echo "You can disable this check with services.logrotate.checkConfig = false,"
78               echo "but if you think it should work please report this failure along with"
79               echo "the config file being tested!"
80               false
81       fi
82     '';
83   };
85   mailOption =
86     if foldr (n: a: a || (n.mail or false) != false) false (attrValues cfg.settings)
87     then "--mail=${pkgs.mailutils}/bin/mail"
88     else "";
91   imports = [
92     (mkRemovedOptionModule [ "services" "logrotate" "config" ] "Modify services.logrotate.settings.header instead")
93     (mkRemovedOptionModule [ "services" "logrotate" "extraConfig" ] "Modify services.logrotate.settings.header instead")
94     (mkRemovedOptionModule [ "services" "logrotate" "paths" ] "Add attributes to services.logrotate.settings instead")
95   ];
97   options = {
98     services.logrotate = {
99       enable = mkEnableOption (lib.mdDoc "the logrotate systemd service") // {
100         default = foldr (n: a: a || n.enable) false (attrValues cfg.settings);
101         defaultText = literalExpression "cfg.settings != {}";
102       };
104       settings = mkOption {
105         default = { };
106         description = lib.mdDoc ''
107           logrotate freeform settings: each attribute here will define its own section,
108           ordered by priority, which can either define files to rotate with their settings
109           or settings common to all further files settings.
110           Refer to <https://linux.die.net/man/8/logrotate> for details.
111         '';
112         example = literalExpression ''
113           {
114             # global options
115             header = {
116               dateext = true;
117             };
118             # example custom files
119             "/var/log/mylog.log" = {
120               frequency = "daily";
121               rotate = 3;
122             };
123             "multiple paths" = {
124                files = [
125                 "/var/log/first*.log"
126                 "/var/log/second.log"
127               ];
128             };
129           };
130           '';
131         type = types.attrsOf (types.submodule ({ name, ... }: {
132           freeformType = with types; attrsOf (nullOr (oneOf [ int bool str ]));
134           options = {
135             enable = mkEnableOption (lib.mdDoc "setting individual kill switch") // {
136               default = true;
137             };
139             global = mkOption {
140               type = types.bool;
141               default = false;
142               description = lib.mdDoc ''
143                 Whether this setting is a global option or not: set to have these
144                 settings apply to all files settings with a higher priority.
145               '';
146             };
147             files = mkOption {
148               type = with types; either str (listOf str);
149               default = name;
150               defaultText = ''
151                 The attrset name if not specified
152               '';
153               description = lib.mdDoc ''
154                 Single or list of files for which rules are defined.
155                 The files are quoted with double-quotes in logrotate configuration,
156                 so globs and spaces are supported.
157                 Note this setting is ignored if globals is true.
158               '';
159             };
161             frequency = mkOption {
162               type = types.nullOr types.str;
163               default = null;
164               description = lib.mdDoc ''
165                 How often to rotate the logs. Defaults to previously set global setting,
166                 which itself defauts to weekly.
167               '';
168             };
170             priority = mkOption {
171               type = types.int;
172               default = 1000;
173               description = lib.mdDoc ''
174                 Order of this logrotate block in relation to the others. The semantics are
175                 the same as with `lib.mkOrder`. Smaller values are inserted first.
176               '';
177             };
178           };
180         }));
181       };
183       configFile = mkOption {
184         type = types.path;
185         default = configFile;
186         defaultText = ''
187           A configuration file automatically generated by NixOS.
188         '';
189         description = lib.mdDoc ''
190           Override the configuration file used by MySQL. By default,
191           NixOS generates one automatically from [](#opt-services.logrotate.settings).
192         '';
193         example = literalExpression ''
194           pkgs.writeText "logrotate.conf" '''
195             missingok
196             "/var/log/*.log" {
197               rotate 4
198               weekly
199             }
200           ''';
201         '';
202       };
204       checkConfig = mkOption {
205         type = types.bool;
206         default = true;
207         description = lib.mdDoc ''
208           Whether the config should be checked at build time.
210           Some options are not checkable at build time because of the build sandbox:
211           for example, the test does not know about existing files and system users are
212           not known.
213           These limitations mean we must adjust the file for tests (missingok is forced
214           and users are replaced by dummy users), so tests are complemented by a
215           logrotate-checkconf service that is enabled by default.
216           This extra check can be disabled by disabling it at the systemd level with the
217           {option}`services.systemd.services.logrotate-checkconf.enable` option.
219           Conversely there are still things that might make this check fail incorrectly
220           (e.g. a file path where we don't have access to intermediate directories):
221           in this case you can disable the failing check with this option.
222         '';
223       };
224     };
225   };
227   config = mkIf cfg.enable {
228     systemd.services.logrotate = {
229       description = "Logrotate Service";
230       startAt = "hourly";
232       serviceConfig = {
233         Restart = "no";
234         User = "root";
235         ExecStart = "${pkgs.logrotate}/sbin/logrotate ${mailOption} ${cfg.configFile}";
236       };
237     };
238     systemd.services.logrotate-checkconf = {
239       description = "Logrotate configuration check";
240       wantedBy = [ "multi-user.target" ];
241       serviceConfig = {
242         Type = "oneshot";
243         RemainAfterExit = true;
244         ExecStart = "${pkgs.logrotate}/sbin/logrotate --debug ${cfg.configFile}";
245       };
246     };
247   };