1{ config, lib, pkgs, ... }:
2with lib;
3let
4 cfg = config.services.watchdogd;
5
6 mkPluginOpts = plugin: defWarn: defCrit: {
7 enabled = mkEnableOption "watchdogd plugin ${plugin}";
8 interval = mkOption {
9 type = types.ints.unsigned;
10 default = 300;
11 description = ''
12 Amount of seconds between every poll.
13 '';
14 };
15 logmark = mkOption {
16 type = types.bool;
17 default = false;
18 description = ''
19 Whether to log current stats every poll interval.
20 '';
21 };
22 warning = mkOption {
23 type = types.numbers.nonnegative;
24 default = defWarn;
25 description = ''
26 The high watermark level. Alert sent to log.
27 '';
28 };
29 critical = mkOption {
30 type = types.numbers.nonnegative;
31 default = defCrit;
32 description = ''
33 The critical watermark level. Alert sent to log, followed by reboot or script action.
34 '';
35 };
36 };
37in {
38 options.services.watchdogd = {
39 enable = mkEnableOption "watchdogd, an advanced system & process supervisor";
40 package = mkPackageOption pkgs "watchdogd" { };
41
42 settings = mkOption {
43 type = with types; submodule {
44 freeformType = let
45 valueType = oneOf [
46 bool
47 int
48 float
49 str
50 ];
51 in attrsOf (either valueType (attrsOf valueType));
52
53 options = {
54 timeout = mkOption {
55 type = types.ints.unsigned;
56 default = 15;
57 description = ''
58 The WDT timeout before reset.
59 '';
60 };
61 interval = mkOption {
62 type = types.ints.unsigned;
63 default = 5;
64 description = ''
65 The kick interval, i.e. how often {manpage}`watchdogd(8)` should reset the WDT timer.
66 '';
67 };
68
69 safe-exit = mkOption {
70 type = types.bool;
71 default = true;
72 description = ''
73 With {var}`safeExit` enabled, the daemon will ask the driver to disable the WDT before exiting.
74 However, some WDT drivers (or hardware) may not support this.
75 '';
76 };
77
78 filenr = mkPluginOpts "filenr" 0.9 1.0;
79
80 loadavg = mkPluginOpts "loadavg" 1.0 2.0;
81
82 meminfo = mkPluginOpts "meminfo" 0.9 0.95;
83 };
84 };
85 default = { };
86 description = ''
87 Configuration to put in {file}`watchdogd.conf`.
88 See {manpage}`watchdogd.conf(5)` for more details.
89 '';
90 };
91 };
92
93 config = let
94 toConfig = attrs: concatStringsSep "\n" (mapAttrsToList toValue attrs);
95
96 toValue = name: value:
97 if isAttrs value
98 then pipe value [
99 (mapAttrsToList toValue)
100 (map (s: " ${s}"))
101 (concatStringsSep "\n")
102 (s: "${name} {\n${s}\n}")
103 ]
104 else if isBool value
105 then "${name} = ${boolToString value}"
106 else if any (f: f value) [isString isInt isFloat]
107 then "${name} = ${toString value}"
108 else throw ''
109 Found invalid type in `services.watchdogd.settings`: '${typeOf value}'
110 '';
111
112 watchdogdConf = pkgs.writeText "watchdogd.conf" (toConfig cfg.settings);
113 in mkIf cfg.enable {
114 environment.systemPackages = [ cfg.package ];
115
116 systemd.services.watchdogd = {
117 documentation = [
118 "man:watchdogd(8)"
119 "man:watchdogd.conf(5)"
120 ];
121 wantedBy = [ "multi-user.target" ];
122 description = "Advanced system & process supervisor";
123 serviceConfig = {
124 Type = "simple";
125 ExecStart = "${cfg.package}/bin/watchdogd -n -f ${watchdogdConf}";
126 };
127 };
128 };
129
130 meta.maintainers = with maintainers; [ vifino ];
131}