nixos/munin: fix broken plugin wrappers

The munin-node service used wrapProgram to inject environment variables.
This doesn't work because munin plugins depend on argv[0], which is
overwritten when the executable is a script with a shebang line (example
below).

This commit removes the wrappers and instead passes the required
environment variables to munin-node.

Eliminating the wrappers resulted in some broken plugins, e.g., meminfo
and hddtemp_smartctl. That was fixed with the per-plugin configuration.

Example:

The plugin if_eth0 is a symlink to /.../plugins/if_, which uses $0
to determine that it should monitor traffic on the eth0 interface.

if_ is a wrapped program, and runs `exec -a "$0" .if_-wrapped`

.if_-wrapped has a "#!/nix/.../bash" line, which results in bash
changing $0, and as a result the plugin thinks my interface
is called "-wrapped".

Changed files
+31 -37
nixos
modules
services
monitoring
+31 -37
nixos/modules/services/monitoring/munin.nix
···
nodeCfg = config.services.munin-node;
cronCfg = config.services.munin-cron;
-
muninPlugins = pkgs.stdenv.mkDerivation {
-
name = "munin-available-plugins";
-
buildCommand = ''
-
mkdir -p $out
-
-
cp --preserve=mode ${pkgs.munin}/lib/plugins/* $out/
-
-
for file in $out/*; do
-
case "$file" in
-
*/plugin.sh|*/plugins.history)
-
chmod +x "$file"
-
continue;;
-
esac
-
-
# read magic makers from the file
-
family=$(sed -nr 's/.*#%#\s+family\s*=\s*(\S+)\s*/\1/p' $file)
-
cap=$(sed -nr 's/.*#%#\s+capabilities\s*=\s*(.+)/\1/p' $file)
-
-
wrapProgram $file \
-
--set PATH "/run/wrappers/bin:/run/current-system/sw/bin" \
-
--set MUNIN_LIBDIR "${pkgs.munin}/lib" \
-
--set MUNIN_PLUGSTATE "/var/run/munin"
-
-
# munin uses markers to tell munin-node-configure what a plugin can do
-
echo "#%# family=$family" >> $file
-
echo "#%# capabilities=$cap" >> $file
-
done
-
-
# NOTE: we disable disktstats because plugin seems to fail and it hangs html generation (100% CPU + memory leak)
-
rm -f $out/diskstats
-
'';
-
buildInputs = [ pkgs.makeWrapper ];
-
};
-
muninConf = pkgs.writeText "munin.conf"
''
dbdir /var/lib/munin
···
${nodeCfg.extraConfig}
'';
+
+
pluginConf = pkgs.writeText "munin-plugin-conf"
+
''
+
[hddtemp_smartctl]
+
user root
+
group root
+
+
[meminfo]
+
user root
+
group root
+
+
[ipmi*]
+
user root
+
group root
+
'';
+
+
pluginConfDir = pkgs.stdenv.mkDerivation {
+
name = "munin-plugin-conf.d";
+
buildCommand = ''
+
mkdir $out
+
ln -s ${pluginConf} $out/nixos-config
+
'';
+
};
in
{
···
description = "Munin Node";
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
-
path = [ pkgs.munin ];
+
path = with pkgs; [ munin smartmontools "/run/current-system/sw" "/run/wrappers" ];
+
environment.MUNIN_LIBDIR = "${pkgs.munin}/lib";
environment.MUNIN_PLUGSTATE = "/var/run/munin";
+
environment.MUNIN_LOGDIR = "/var/log/munin";
preStart = ''
echo "updating munin plugins..."
mkdir -p /etc/munin/plugins
rm -rf /etc/munin/plugins/*
-
PATH="/run/wrappers/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
+
${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
+
+
# NOTE: we disable disktstats because plugin seems to fail and it hangs html generation (100% CPU + memory leak)
+
rm /etc/munin/plugins/diskstats || true
'';
serviceConfig = {
-
ExecStart = "${pkgs.munin}/sbin/munin-node --config ${nodeConf} --servicedir /etc/munin/plugins/";
+
ExecStart = "${pkgs.munin}/sbin/munin-node --config ${nodeConf} --servicedir /etc/munin/plugins/ --sconfdir=${pluginConfDir}";
};
};