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 muninPlugins = pkgs.stdenv.mkDerivation { 21 name = "munin-available-plugins"; 22 buildCommand = '' 23 mkdir -p $out 24 25 cp --preserve=mode ${pkgs.munin}/lib/plugins/* $out/ 26 27 for file in $out/*; do 28 case "$file" in 29 plugin.sh) continue;; 30 esac 31 32 # read magic makers from the file 33 family=$(sed -nr 's/.*#%#\s+family\s*=\s*(\S+)\s*/\1/p' $file) 34 cap=$(sed -nr 's/.*#%#\s+capabilities\s*=\s*(.+)/\1/p' $file) 35 36 wrapProgram $file \ 37 --set PATH "/var/setuid-wrappers:/run/current-system/sw/bin:/run/current-system/sw/bin" \ 38 --set MUNIN_LIBDIR "${pkgs.munin}/lib" \ 39 --set MUNIN_PLUGSTATE "/var/run/munin" 40 41 # munin uses markers to tell munin-node-configure what a plugin can do 42 echo "#%# family=$family" >> $file 43 echo "#%# capabilities=$cap" >> $file 44 done 45 46 # NOTE: we disable disktstats because plugin seems to fail and it hangs html generation (100% CPU + memory leak) 47 rm -f $out/diskstats 48 ''; 49 buildInputs = [ pkgs.makeWrapper ]; 50 }; 51 52 muninConf = pkgs.writeText "munin.conf" 53 '' 54 dbdir /var/lib/munin 55 htmldir /var/www/munin 56 logdir /var/log/munin 57 rundir /var/run/munin 58 59 ${cronCfg.extraGlobalConfig} 60 61 ${cronCfg.hosts} 62 ''; 63 64 nodeConf = pkgs.writeText "munin-node.conf" 65 '' 66 log_level 3 67 log_file Sys::Syslog 68 port 4949 69 host * 70 background 0 71 user root 72 group root 73 host_name ${config.networking.hostName} 74 setsid 0 75 76 # wrapped plugins by makeWrapper being with dots 77 ignore_file ^\. 78 79 allow ^127\.0\.0\.1$ 80 81 ${nodeCfg.extraConfig} 82 ''; 83in 84 85{ 86 87 options = { 88 89 services.munin-node = { 90 91 enable = mkOption { 92 default = false; 93 description = '' 94 Enable Munin Node agent. Munin node listens on 0.0.0.0 and 95 by default accepts connections only from 127.0.0.1 for security reasons. 96 97 See <link xlink:href='http://munin-monitoring.org/wiki/munin-node.conf' />. 98 ''; 99 }; 100 101 extraConfig = mkOption { 102 default = ""; 103 description = '' 104 <filename>munin-node.conf</filename> extra configuration. See 105 <link xlink:href='http://munin-monitoring.org/wiki/munin-node.conf' /> 106 ''; 107 }; 108 109 # TODO: add option to add additional plugins 110 111 }; 112 113 services.munin-cron = { 114 115 enable = mkOption { 116 default = false; 117 description = '' 118 Enable munin-cron. Takes care of all heavy lifting to collect data from 119 nodes and draws graphs to html. Runs munin-update, munin-limits, 120 munin-graphs and munin-html in that order. 121 122 HTML output is in <filename>/var/www/munin/</filename>, configure your 123 favourite webserver to serve static files. 124 ''; 125 }; 126 127 extraGlobalConfig = mkOption { 128 default = ""; 129 description = '' 130 <filename>munin.conf</filename> extra global configuration. 131 See <link xlink:href='http://munin-monitoring.org/wiki/munin.conf' />. 132 Useful to setup notifications, see 133 <link xlink:href='http://munin-monitoring.org/wiki/HowToContact' /> 134 ''; 135 example = '' 136 contact.email.command mail -s "Munin notification for ''${var:host}" someone@example.com 137 ''; 138 }; 139 140 hosts = mkOption { 141 example = '' 142 [''${config.networking.hostName}] 143 address localhost 144 ''; 145 description = '' 146 Definitions of hosts of nodes to collect data from. Needs at least one 147 hosts for cron to succeed. See 148 <link xlink:href='http://munin-monitoring.org/wiki/munin.conf' /> 149 ''; 150 }; 151 152 }; 153 154 }; 155 156 config = mkMerge [ (mkIf (nodeCfg.enable || cronCfg.enable) { 157 158 environment.systemPackages = [ pkgs.munin ]; 159 160 users.extraUsers = [{ 161 name = "munin"; 162 description = "Munin monitoring user"; 163 group = "munin"; 164 uid = config.ids.uids.munin; 165 }]; 166 167 users.extraGroups = [{ 168 name = "munin"; 169 gid = config.ids.gids.munin; 170 }]; 171 172 }) (mkIf nodeCfg.enable { 173 174 systemd.services.munin-node = { 175 description = "Munin Node"; 176 after = [ "network.target" ]; 177 wantedBy = [ "multi-user.target" ]; 178 path = [ pkgs.munin ]; 179 environment.MUNIN_PLUGSTATE = "/var/run/munin"; 180 preStart = '' 181 echo "updating munin plugins..." 182 183 mkdir -p /etc/munin/plugins 184 rm -rf /etc/munin/plugins/* 185 PATH="/var/setuid-wrappers:/run/current-system/sw/bin:/run/current-system/sw/bin" ${pkgs.munin}/sbin/munin-node-configure --shell --families contrib,auto,manual --config ${nodeConf} --libdir=${muninPlugins} --servicedir=/etc/munin/plugins 2>/dev/null | ${pkgs.bash}/bin/bash 186 ''; 187 serviceConfig = { 188 ExecStart = "${pkgs.munin}/sbin/munin-node --config ${nodeConf} --servicedir /etc/munin/plugins/"; 189 }; 190 }; 191 192 }) (mkIf cronCfg.enable { 193 194 services.cron.systemCronJobs = [ 195 "*/5 * * * * munin ${pkgs.munin}/bin/munin-cron --config ${muninConf}" 196 ]; 197 198 system.activationScripts.munin-cron = stringAfter [ "users" "groups" ] '' 199 mkdir -p /var/{run,log,www,lib}/munin 200 chown -R munin:munin /var/{run,log,www,lib}/munin 201 ''; 202 203 })]; 204}