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