1{ config, lib, pkgs, ... }:
2
3# TODO: support munin-async
4# TODO: LWP/Pg perl libs aren't recognized
5
6# TODO: support fastcgi
7# http://munin-monitoring.org/wiki/CgiHowto2
8# spawn-fcgi -s /var/run/munin/fastcgi-graph.sock -U www-data -u munin -g munin /usr/lib/munin/cgi/munin-cgi-graph
9# spawn-fcgi -s /var/run/munin/fastcgi-html.sock -U www-data -u munin -g munin /usr/lib/munin/cgi/munin-cgi-html
10# https://paste.sh/vofcctHP#-KbDSXVeWoifYncZmLfZzgum
11# nginx http://munin.readthedocs.org/en/latest/example/webserver/nginx.html
12
13
14with lib;
15
16let
17 nodeCfg = config.services.munin-node;
18 cronCfg = config.services.munin-cron;
19
20 muninConf = pkgs.writeText "munin.conf"
21 ''
22 dbdir /var/lib/munin
23 htmldir /var/www/munin
24 logdir /var/log/munin
25 rundir /var/run/munin
26
27 ${cronCfg.extraGlobalConfig}
28
29 ${cronCfg.hosts}
30 '';
31
32 nodeConf = pkgs.writeText "munin-node.conf"
33 ''
34 log_level 3
35 log_file Sys::Syslog
36 port 4949
37 host *
38 background 0
39 user root
40 group root
41 host_name ${config.networking.hostName}
42 setsid 0
43
44 # wrapped plugins by makeWrapper being with dots
45 ignore_file ^\.
46
47 allow ^::1$
48 allow ^127\.0\.0\.1$
49
50 ${nodeCfg.extraConfig}
51 '';
52
53 pluginConf = pkgs.writeText "munin-plugin-conf"
54 ''
55 [hddtemp_smartctl]
56 user root
57 group root
58
59 [meminfo]
60 user root
61 group root
62
63 [ipmi*]
64 user root
65 group root
66 '';
67
68 pluginConfDir = pkgs.stdenv.mkDerivation {
69 name = "munin-plugin-conf.d";
70 buildCommand = ''
71 mkdir $out
72 ln -s ${pluginConf} $out/nixos-config
73 '';
74 };
75in
76
77{
78
79 options = {
80
81 services.munin-node = {
82
83 enable = mkOption {
84 default = false;
85 description = ''
86 Enable Munin Node agent. Munin node listens on 0.0.0.0 and
87 by default accepts connections only from 127.0.0.1 for security reasons.
88
89 See <link xlink:href='http://munin-monitoring.org/wiki/munin-node.conf' />.
90 '';
91 };
92
93 extraConfig = mkOption {
94 default = "";
95 type = types.lines;
96 description = ''
97 <filename>munin-node.conf</filename> extra configuration. See
98 <link xlink:href='http://munin-monitoring.org/wiki/munin-node.conf' />
99 '';
100 };
101
102 # TODO: add option to add additional plugins
103
104 };
105
106 services.munin-cron = {
107
108 enable = mkOption {
109 default = false;
110 description = ''
111 Enable munin-cron. Takes care of all heavy lifting to collect data from
112 nodes and draws graphs to html. Runs munin-update, munin-limits,
113 munin-graphs and munin-html in that order.
114
115 HTML output is in <filename>/var/www/munin/</filename>, configure your
116 favourite webserver to serve static files.
117 '';
118 };
119
120 extraGlobalConfig = mkOption {
121 default = "";
122 description = ''
123 <filename>munin.conf</filename> extra global configuration.
124 See <link xlink:href='http://munin-monitoring.org/wiki/munin.conf' />.
125 Useful to setup notifications, see
126 <link xlink:href='http://munin-monitoring.org/wiki/HowToContact' />
127 '';
128 example = ''
129 contact.email.command mail -s "Munin notification for ''${var:host}" someone@example.com
130 '';
131 };
132
133 hosts = mkOption {
134 example = ''
135 [''${config.networking.hostName}]
136 address localhost
137 '';
138 description = ''
139 Definitions of hosts of nodes to collect data from. Needs at least one
140 hosts for cron to succeed. See
141 <link xlink:href='http://munin-monitoring.org/wiki/munin.conf' />
142 '';
143 };
144
145 };
146
147 };
148
149 config = mkMerge [ (mkIf (nodeCfg.enable || cronCfg.enable) {
150
151 environment.systemPackages = [ pkgs.munin ];
152
153 users.users = [{
154 name = "munin";
155 description = "Munin monitoring user";
156 group = "munin";
157 uid = config.ids.uids.munin;
158 }];
159
160 users.groups = [{
161 name = "munin";
162 gid = config.ids.gids.munin;
163 }];
164
165 }) (mkIf nodeCfg.enable {
166
167 systemd.services.munin-node = {
168 description = "Munin Node";
169 after = [ "network.target" ];
170 wantedBy = [ "multi-user.target" ];
171 path = with pkgs; [ munin smartmontools "/run/current-system/sw" "/run/wrappers" ];
172 environment.MUNIN_LIBDIR = "${pkgs.munin}/lib";
173 environment.MUNIN_PLUGSTATE = "/var/run/munin";
174 environment.MUNIN_LOGDIR = "/var/log/munin";
175 preStart = ''
176 echo "updating munin plugins..."
177
178 mkdir -p /etc/munin/plugins
179 rm -rf /etc/munin/plugins/*
180 ${pkgs.munin}/bin/munin-node-configure --suggest --shell --families contrib,auto,manual --config ${nodeConf} --libdir=${pkgs.munin}/lib/plugins --servicedir=/etc/munin/plugins --sconfdir=${pluginConfDir} 2>/dev/null | ${pkgs.bash}/bin/bash
181
182 # NOTE: we disable disktstats because plugin seems to fail and it hangs html generation (100% CPU + memory leak)
183 rm /etc/munin/plugins/diskstats || true
184 '';
185 serviceConfig = {
186 ExecStart = "${pkgs.munin}/sbin/munin-node --config ${nodeConf} --servicedir /etc/munin/plugins/ --sconfdir=${pluginConfDir}";
187 };
188 };
189
190 # munin_stats plugin breaks as of 2.0.33 when this doesn't exist
191 systemd.tmpfiles.rules = [ "d /var/run/munin 0755 munin munin -" ];
192
193 }) (mkIf cronCfg.enable {
194
195 systemd.timers.munin-cron = {
196 description = "batch Munin master programs";
197 wantedBy = [ "timers.target" ];
198 timerConfig.OnCalendar = "*:0/5";
199 };
200
201 systemd.services.munin-cron = {
202 description = "batch Munin master programs";
203 unitConfig.Documentation = "man:munin-cron(8)";
204
205 serviceConfig = {
206 Type = "oneshot";
207 User = "munin";
208 ExecStart = "${pkgs.munin}/bin/munin-cron --config ${muninConf}";
209 };
210 };
211
212 systemd.tmpfiles.rules = [
213 "d /var/run/munin 0755 munin munin -"
214 "d /var/log/munin 0755 munin munin -"
215 "d /var/www/munin 0755 munin munin -"
216 "d /var/lib/munin 0755 munin munin -"
217 ];
218 })];
219}