at 23.11-pre 13 kB view raw
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://guide.munin-monitoring.org/en/latest/example/webserver/apache-cgi.html 8# spawn-fcgi -s /run/munin/fastcgi-graph.sock -U www-data -u munin -g munin /usr/lib/munin/cgi/munin-cgi-graph 9# spawn-fcgi -s /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 https://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 /run/munin 26 27 ${lib.optionalString (cronCfg.extraCSS != "") "staticdir ${customStaticDir}"} 28 29 ${cronCfg.extraGlobalConfig} 30 31 ${cronCfg.hosts} 32 ''; 33 34 nodeConf = pkgs.writeText "munin-node.conf" 35 '' 36 log_level 3 37 log_file Sys::Syslog 38 port 4949 39 host * 40 background 0 41 user root 42 group root 43 host_name ${config.networking.hostName} 44 setsid 0 45 46 # wrapped plugins by makeWrapper being with dots 47 ignore_file ^\. 48 49 allow ^::1$ 50 allow ^127\.0\.0\.1$ 51 52 ${nodeCfg.extraConfig} 53 ''; 54 55 pluginConf = pkgs.writeText "munin-plugin-conf" 56 '' 57 [hddtemp_smartctl] 58 user root 59 group root 60 61 [meminfo] 62 user root 63 group root 64 65 [ipmi*] 66 user root 67 group root 68 69 [munin*] 70 env.UPDATE_STATSFILE /var/lib/munin/munin-update.stats 71 72 ${nodeCfg.extraPluginConfig} 73 ''; 74 75 pluginConfDir = pkgs.stdenv.mkDerivation { 76 name = "munin-plugin-conf.d"; 77 buildCommand = '' 78 mkdir $out 79 ln -s ${pluginConf} $out/nixos-config 80 ''; 81 }; 82 83 # Copy one Munin plugin into the Nix store with a specific name. 84 # This is suitable for use with plugins going directly into /etc/munin/plugins, 85 # i.e. munin.extraPlugins. 86 internOnePlugin = name: path: 87 "cp -a '${path}' '${name}'"; 88 89 # Copy an entire tree of Munin plugins into a single directory in the Nix 90 # store, with no renaming. 91 # This is suitable for use with munin-node-configure --suggest, i.e. 92 # munin.extraAutoPlugins. 93 internManyPlugins = name: path: 94 "find '${path}' -type f -perm /a+x -exec cp -a -t . '{}' '+'"; 95 96 # Use the appropriate intern-fn to copy the plugins into the store and patch 97 # them afterwards in an attempt to get them to run on NixOS. 98 internAndFixPlugins = name: intern-fn: paths: 99 pkgs.runCommand name {} '' 100 mkdir -p "$out" 101 cd "$out" 102 ${lib.concatStringsSep "\n" 103 (lib.attrsets.mapAttrsToList intern-fn paths)} 104 chmod -R u+w . 105 find . -type f -exec sed -E -i ' 106 s,(/usr)?/s?bin/,/run/current-system/sw/bin/,g 107 ' '{}' '+' 108 ''; 109 110 # TODO: write a derivation for munin-contrib, so that for contrib plugins 111 # you can just refer to them by name rather than needing to include a copy 112 # of munin-contrib in your nixos configuration. 113 extraPluginDir = internAndFixPlugins "munin-extra-plugins.d" 114 internOnePlugin nodeCfg.extraPlugins; 115 116 extraAutoPluginDir = internAndFixPlugins "munin-extra-auto-plugins.d" 117 internManyPlugins 118 (builtins.listToAttrs 119 (map 120 (path: { name = baseNameOf path; value = path; }) 121 nodeCfg.extraAutoPlugins)); 122 123 customStaticDir = pkgs.runCommand "munin-custom-static-data" {} '' 124 cp -a "${pkgs.munin}/etc/opt/munin/static" "$out" 125 cd "$out" 126 chmod -R u+w . 127 echo "${cronCfg.extraCSS}" >> style.css 128 echo "${cronCfg.extraCSS}" >> style-new.css 129 ''; 130in 131 132{ 133 134 options = { 135 136 services.munin-node = { 137 138 enable = mkOption { 139 default = false; 140 type = types.bool; 141 description = lib.mdDoc '' 142 Enable Munin Node agent. Munin node listens on 0.0.0.0 and 143 by default accepts connections only from 127.0.0.1 for security reasons. 144 145 See <http://guide.munin-monitoring.org/en/latest/architecture/index.html>. 146 ''; 147 }; 148 149 extraConfig = mkOption { 150 default = ""; 151 type = types.lines; 152 description = lib.mdDoc '' 153 {file}`munin-node.conf` extra configuration. See 154 <http://guide.munin-monitoring.org/en/latest/reference/munin-node.conf.html> 155 ''; 156 }; 157 158 extraPluginConfig = mkOption { 159 default = ""; 160 type = types.lines; 161 description = lib.mdDoc '' 162 {file}`plugin-conf.d` extra plugin configuration. See 163 <http://guide.munin-monitoring.org/en/latest/plugin/use.html> 164 ''; 165 example = '' 166 [fail2ban_*] 167 user root 168 ''; 169 }; 170 171 extraPlugins = mkOption { 172 default = {}; 173 type = with types; attrsOf path; 174 description = lib.mdDoc '' 175 Additional Munin plugins to activate. Keys are the name of the plugin 176 symlink, values are the path to the underlying plugin script. You 177 can use the same plugin script multiple times (e.g. for wildcard 178 plugins). 179 180 Note that these plugins do not participate in autoconfiguration. If 181 you want to autoconfigure additional plugins, use 182 {option}`services.munin-node.extraAutoPlugins`. 183 184 Plugins enabled in this manner take precedence over autoconfigured 185 plugins. 186 187 Plugins will be copied into the Nix store, and it will attempt to 188 modify them to run properly by fixing hardcoded references to 189 `/bin`, `/usr/bin`, 190 `/sbin`, and `/usr/sbin`. 191 ''; 192 example = literalExpression '' 193 { 194 zfs_usage_bigpool = /src/munin-contrib/plugins/zfs/zfs_usage_; 195 zfs_usage_smallpool = /src/munin-contrib/plugins/zfs/zfs_usage_; 196 zfs_list = /src/munin-contrib/plugins/zfs/zfs_list; 197 }; 198 ''; 199 }; 200 201 extraAutoPlugins = mkOption { 202 default = []; 203 type = with types; listOf path; 204 description = lib.mdDoc '' 205 Additional Munin plugins to autoconfigure, using 206 `munin-node-configure --suggest`. These should be 207 the actual paths to the plugin files (or directories containing them), 208 not just their names. 209 210 If you want to manually enable individual plugins instead, use 211 {option}`services.munin-node.extraPlugins`. 212 213 Note that only plugins that have the 'autoconfig' capability will do 214 anything if listed here, since plugins that cannot autoconfigure 215 won't be automatically enabled by 216 `munin-node-configure`. 217 218 Plugins will be copied into the Nix store, and it will attempt to 219 modify them to run properly by fixing hardcoded references to 220 `/bin`, `/usr/bin`, 221 `/sbin`, and `/usr/sbin`. 222 ''; 223 example = literalExpression '' 224 [ 225 /src/munin-contrib/plugins/zfs 226 /src/munin-contrib/plugins/ssh 227 ]; 228 ''; 229 }; 230 231 disabledPlugins = mkOption { 232 # TODO: figure out why Munin isn't writing the log file and fix it. 233 # In the meantime this at least suppresses a useless graph full of 234 # NaNs in the output. 235 default = [ "munin_stats" ]; 236 type = with types; listOf str; 237 description = lib.mdDoc '' 238 Munin plugins to disable, even if 239 `munin-node-configure --suggest` tries to enable 240 them. To disable a wildcard plugin, use an actual wildcard, as in 241 the example. 242 243 munin_stats is disabled by default as it tries to read 244 `/var/log/munin/munin-update.log` for timing 245 information, and the NixOS build of Munin does not write this file. 246 ''; 247 example = [ "diskstats" "zfs_usage_*" ]; 248 }; 249 }; 250 251 services.munin-cron = { 252 253 enable = mkOption { 254 default = false; 255 type = types.bool; 256 description = lib.mdDoc '' 257 Enable munin-cron. Takes care of all heavy lifting to collect data from 258 nodes and draws graphs to html. Runs munin-update, munin-limits, 259 munin-graphs and munin-html in that order. 260 261 HTML output is in {file}`/var/www/munin/`, configure your 262 favourite webserver to serve static files. 263 ''; 264 }; 265 266 extraGlobalConfig = mkOption { 267 default = ""; 268 type = types.lines; 269 description = lib.mdDoc '' 270 {file}`munin.conf` extra global configuration. 271 See <http://guide.munin-monitoring.org/en/latest/reference/munin.conf.html>. 272 Useful to setup notifications, see 273 <http://guide.munin-monitoring.org/en/latest/tutorial/alert.html> 274 ''; 275 example = '' 276 contact.email.command mail -s "Munin notification for ''${var:host}" someone@example.com 277 ''; 278 }; 279 280 hosts = mkOption { 281 default = ""; 282 type = types.lines; 283 description = lib.mdDoc '' 284 Definitions of hosts of nodes to collect data from. Needs at least one 285 host for cron to succeed. See 286 <http://guide.munin-monitoring.org/en/latest/reference/munin.conf.html> 287 ''; 288 example = literalExpression '' 289 ''' 290 [''${config.networking.hostName}] 291 address localhost 292 ''' 293 ''; 294 }; 295 296 extraCSS = mkOption { 297 default = ""; 298 type = types.lines; 299 description = lib.mdDoc '' 300 Custom styling for the HTML that munin-cron generates. This will be 301 appended to the CSS files used by munin-cron and will thus take 302 precedence over the builtin styles. 303 ''; 304 example = '' 305 /* A simple dark theme. */ 306 html, body { background: #222222; } 307 #header, #footer { background: #333333; } 308 img.i, img.iwarn, img.icrit, img.iunkn { 309 filter: invert(100%) hue-rotate(-30deg); 310 } 311 ''; 312 }; 313 314 }; 315 316 }; 317 318 config = mkMerge [ (mkIf (nodeCfg.enable || cronCfg.enable) { 319 320 environment.systemPackages = [ pkgs.munin ]; 321 322 users.users.munin = { 323 description = "Munin monitoring user"; 324 group = "munin"; 325 uid = config.ids.uids.munin; 326 home = "/var/lib/munin"; 327 }; 328 329 users.groups.munin = { 330 gid = config.ids.gids.munin; 331 }; 332 333 }) (mkIf nodeCfg.enable { 334 335 systemd.services.munin-node = { 336 description = "Munin Node"; 337 after = [ "network.target" ]; 338 wantedBy = [ "multi-user.target" ]; 339 path = with pkgs; [ munin smartmontools "/run/current-system/sw" "/run/wrappers" ]; 340 environment.MUNIN_LIBDIR = "${pkgs.munin}/lib"; 341 environment.MUNIN_PLUGSTATE = "/run/munin"; 342 environment.MUNIN_LOGDIR = "/var/log/munin"; 343 preStart = '' 344 echo "Updating munin plugins..." 345 346 mkdir -p /etc/munin/plugins 347 rm -rf /etc/munin/plugins/* 348 349 # Autoconfigure builtin plugins 350 ${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 351 352 # Autoconfigure extra plugins 353 ${pkgs.munin}/bin/munin-node-configure --suggest --shell --families contrib,auto,manual --config ${nodeConf} --libdir=${extraAutoPluginDir} --servicedir=/etc/munin/plugins --sconfdir=${pluginConfDir} 2>/dev/null | ${pkgs.bash}/bin/bash 354 355 ${lib.optionalString (nodeCfg.extraPlugins != {}) '' 356 # Link in manually enabled plugins 357 ln -f -s -t /etc/munin/plugins ${extraPluginDir}/* 358 ''} 359 360 ${lib.optionalString (nodeCfg.disabledPlugins != []) '' 361 # Disable plugins 362 cd /etc/munin/plugins 363 rm -f ${toString nodeCfg.disabledPlugins} 364 ''} 365 ''; 366 serviceConfig = { 367 ExecStart = "${pkgs.munin}/sbin/munin-node --config ${nodeConf} --servicedir /etc/munin/plugins/ --sconfdir=${pluginConfDir}"; 368 }; 369 }; 370 371 # munin_stats plugin breaks as of 2.0.33 when this doesn't exist 372 systemd.tmpfiles.rules = [ "d /run/munin 0755 munin munin -" ]; 373 374 }) (mkIf cronCfg.enable { 375 376 # Munin is hardcoded to use DejaVu Mono and the graphs come out wrong if 377 # it's not available. 378 fonts.fonts = [ pkgs.dejavu_fonts ]; 379 380 systemd.timers.munin-cron = { 381 description = "batch Munin master programs"; 382 wantedBy = [ "timers.target" ]; 383 timerConfig.OnCalendar = "*:0/5"; 384 }; 385 386 systemd.services.munin-cron = { 387 description = "batch Munin master programs"; 388 unitConfig.Documentation = "man:munin-cron(8)"; 389 390 serviceConfig = { 391 Type = "oneshot"; 392 User = "munin"; 393 ExecStart = "${pkgs.munin}/bin/munin-cron --config ${muninConf}"; 394 }; 395 }; 396 397 systemd.tmpfiles.rules = [ 398 "d /run/munin 0755 munin munin -" 399 "d /var/log/munin 0755 munin munin -" 400 "d /var/www/munin 0755 munin munin -" 401 "d /var/lib/munin 0755 munin munin -" 402 ]; 403 })]; 404}