Skip to content

Instantly share code, notes, and snippets.

@danbst
Last active May 19, 2017 14:34
Show Gist options
  • Save danbst/03ea8e50de5b1b4b06dfe049f8a103c7 to your computer and use it in GitHub Desktop.
Save danbst/03ea8e50de5b1b4b06dfe049f8a103c7 to your computer and use it in GitHub Desktop.
Munin service ver 2.999.5 (NixOS)
Munin service ver 2.999.5
Use like
```
services.mm.munin-cron.enable = true;
services.mm.munin-cron.hosts = ''
[server1]
address server1
[server2]
address server2
'';
```
on master and
```
services.mm.munin-node.enable = true;
services.mm.munin-node.extraConfig = ''
cidr_allow 0.0.0.0/0
'';
services.mm.munin-node.pluginConfig = ''
[postgres_*]
env.PGUSER postgres
'';
```
on nodes
{ config, lib, pkgs, ... }:
# TODO: support munin-async
with lib;
let
nodeCfg = config.services.mm.munin-node;
cronCfg = config.services.mm.munin-cron;
munin = (import ./muninng.nix).munin;
muninConf = pkgs.writeText "munin.conf"
''
dbdir /var/lib/munin
logdir /var/log/munin
rundir /var/run/munin
tmpldir ${munin}/share/templates
${cronCfg.extraGlobalConfig}
${cronCfg.hosts}
'';
nodeConf = pkgs.writeText "munin-node.conf"
''
port 4949
log_level 3
log_file Sys::Syslog
background 0
host_name ${config.networking.hostName}
setsid 0
cidr_allow 127.0.0.1/32
${nodeCfg.extraConfig}
'';
pluginsConf = pkgs.writeTextDir "plugin-conf.d" nodeCfg.pluginConfig;
in
{
options = {
services.mm.munin-node = {
enable = mkOption {
default = false;
description = ''
Enable Munin Node agent. Munin node listens on 0.0.0.0 and
by default accepts connections only from 127.0.0.1 for security reasons.
See <link xlink:href='http://munin-monitoring.org/wiki/munin-node.conf' />.
'';
};
extraConfig = mkOption {
default = "";
description = ''
<filename>munin-node.conf</filename> extra configuration. See
<link xlink:href='http://munin-monitoring.org/wiki/munin-node.conf' />
'';
};
# TODO: add option to add additional plugins
pluginConfig = mkOption {
default = "";
type = types.lines;
description = ''
<filename>plugin-conf.d</filename> extra configuration. See
<link xlink:href='https://munin.readthedocs.io/en/latest/plugin/use.html#configuring' />
'';
};
};
services.mm.munin-cron = {
enable = mkOption {
default = false;
description = ''
Enable munin-cron. Takes care of all heavy lifting to collect data from
nodes and draws graphs to html. Runs munin-update, munin-limits,
munin-graphs and munin-html in that order.
HTML output is in <filename>/var/www/munin/</filename>, configure your
favourite webserver to serve static files.
'';
};
extraGlobalConfig = mkOption {
default = "";
description = ''
<filename>munin.conf</filename> extra global configuration.
See <link xlink:href='http://munin-monitoring.org/wiki/munin.conf' />.
Useful to setup notifications, see
<link xlink:href='http://munin-monitoring.org/wiki/HowToContact' />
'';
example = ''
contact.email.command mail -s "Munin notification for ''${var:host}" someone@example.com
'';
};
hosts = mkOption {
example = ''
[''${config.networking.hostName}]
address localhost
'';
description = ''
Definitions of hosts of nodes to collect data from. Needs at least one
hosts for cron to succeed. See
<link xlink:href='http://munin-monitoring.org/wiki/munin.conf' />
'';
};
nginxCache.enable = mkOption {
default = false;
};
debugHttpd = mkOption {
default = false;
};
};
};
config = mkMerge [ (mkIf (nodeCfg.enable || cronCfg.enable) {
environment.systemPackages = [ munin ];
}) (mkIf nodeCfg.enable {
systemd.services.munin-node = {
description = "Munin Node";
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
path = with pkgs; [ munin gawk procps ntp nettools ];
preStart = ''
echo "updating munin plugins..."
mkdir -p /etc/munin/plugins
rm -rf /etc/munin/plugins/*
mkdir -p /var/lib/munin-node/plugin-state
PATH="/var/setuid-wrappers:/run/current-system/sw/bin:$PATH" \
munin-node-configure --shell --families=contrib,auto,manual \
--config=${nodeConf} \
--servicedir=/etc/munin/plugins \
--sconfdir=${pluginsConf} \
2>/dev/null | ${pkgs.bash}/bin/bash
'';
serviceConfig = {
ExecStart = ''${munin}/bin/munin-node \
--config ${nodeConf} \
--servicedir /etc/munin/plugins \
--sconfdir=${pluginsConf}'';
};
};
}) (mkIf cronCfg.enable {
users.extraUsers = [{
name = "munin";
description = "Munin monitoring user";
group = "munin";
uid = config.ids.uids.munin;
}];
users.extraGroups = [{
name = "munin";
gid = config.ids.gids.munin;
}];
services.cron.systemCronJobs = [
"*/5 * * * * munin ${munin}/bin/munin-cron --config ${muninConf}"
];
systemd.services.munin-httpd = {
path = [ munin ];
wantedBy = [ "multi-user.target" ];
after = [ "network.target" ];
serviceConfig.User = "munin";
serviceConfig.Group = "munin";
script = "munin-httpd --config ${muninConf} ${lib.optionalString (!cronCfg.debugHttpd) "2>&1 >/dev/null"}";
};
system.activationScripts.munin-cron = stringAfter [ "users" "groups" ] ''
mkdir -p /var/{run,log,lib}/munin
chown -R munin:munin /var/{run,log,lib}/munin
'';
}) (mkIf (cronCfg.enable && cronCfg.nginxCache.enable) {
services.nginx.httpConfig = ''
proxy_cache_path /var/nginx/munin_cache levels=1:2 keys_zone=munin_cache:10m max_size=1g inactive=60m use_temp_path=off;
server {
listen 4947;
server_name _;
charset UTF-8;
proxy_read_timeout 20;
location ~ /(static.*|.*.png)$ {
proxy_cache munin_cache;
expires modified +310s;
proxy_cache_revalidate on;
proxy_ignore_headers Cache-Control;
proxy_cache_valid any 200s;
proxy_pass http://localhost:4948;
}
location / {
proxy_pass http://localhost:4948;
}
}
'';
})
];
}
let
pkgs = import <nixpkgs> {};
inherit (pkgs) rrdtool perlPackages makeWrapper;
HTTPServerSimpleCGI = pkgs.buildPerlPackage {
name = "HTTP-Server-Simple-0.51";
src = pkgs.fetchurl {
url = mirror://cpan/authors/id/B/BP/BPS/HTTP-Server-Simple-0.51.tar.gz;
sha256 = "1yvd2g57z2kq00q5i3zzfi15k98qgbif3vghjsda6v612agmrp5r";
};
doCheck = false;
};
HTTPServerSimpleCGIPreFork = pkgs.buildPerlPackage {
name = "HTTP-Server-Simple-CGI-PreFork-6";
src = pkgs.fetchurl {
url = mirror://cpan/authors/id/C/CA/CAVAC/HTTP-Server-Simple-CGI-PreFork-6.tar.gz;
sha256 = null;
};
doCheck = false;
};
HTMLTemplatePro = pkgs.buildPerlPackage {
name = "HTML-Template-Pro-0.9510";
src = pkgs.fetchurl {
url = mirror://cpan/authors/id/V/VI/VIY/HTML-Template-Pro-0.9510.tar.gz;
sha256 = "11la3z0ajvm6mv1hjywwf7mj3ihdnx2xbkag2jfl7l80jvz7gjv7";
};
doCheck = false;
};
XMLDumper = pkgs.buildPerlPackage {
name = "XML-Dumper-0.81";
src = pkgs.fetchurl {
url = mirror://cpan/authors/id/M/MI/MIKEWONG/XML-Dumper-0.81.tar.gz;
sha256 = "1q7q0fs4dvfx3pq89pb2ynx89nrvwx7xsiswxfx624kf4fshw5zl";
};
doCheck = false;
};
muninDeps = pkgs.stdenv.mkDerivation {
name = "munin-deps";
buildInputs = with perlPackages; [pkgs.perl
Log4Perl IOSocketInet6 Socket6 URI DBFile DateManip
HTMLTemplate FileCopyRecursive FCGI NetCIDR NetSNMP NetServer
ListMoreUtils TimeHiRes DBDPg LWPUserAgent rrdtool
LogDispatch DBDSQLite HTTPServerSimpleCGI HTTPServerSimpleCGIPreFork
IOString HTMLTemplatePro XMLDumper XMLParser JSON
];
src = ./.;
phases = [ "installPhase" ];
installPhase = "echo $PERL5LIB > $out";
};
munin = pkgs.stdenv.mkDerivation rec {
name = "munin-${version}";
version = "2.999.5";
src = pkgs.fetchurl {
url = "https://github.com/munin-monitoring/munin/archive/${version}.tar.gz";
sha256 = null;
};
buildInputs = with pkgs; [ perl makeWrapper rrdtool ]
++ (with perlPackages; [
ModuleBuild
LogDispatch
ParamsValidate
LWPUserAgent
HTMLTemplate
NetCIDR
NetSSLeay
NetServer
Log4Perl
IOSocketInet6
Socket6
URI
DBFile
DateManip
FileCopyRecursive
FCGI
NetSNMP
NetServer
ListMoreUtils
TimeHiRes
DBDPg
]);
preBuild = ''
# their Makefile isn't very flexible, buildPhase shouldn't use it
rm -f Makefile
# didn't find better way to set MUNIN_BINDIR
sed -i 's/$Config{installsitebin}/$build->install_path('"'"'script'"'"')/g' Build.PL
perl Build.PL --destdir $out \
--install_path script=$out/bin \
--install_path lib=lib/perl5/site_perl \
--install_path bindoc=share/man/man1 \
--install_path libdoc=share/man/man3 \
--install_path share=$out/share \
--install_path etc=$out/share \
--install_path web=$out/share \
--install_path plugins=$out/share/plugins \
--install_path arch=/dev/null \
--install_path var=/var \
--install_path MUNIN_BINDIR=$out/bin
# munin hardcodes PATH, we need it to obey $PATH
sed -i '/ENV{PATH}/d' lib/Munin/Node/Service.pm
sed -i 's|"rrdtool"|"${rrdtool}/bin/rrdtool"|g' lib/Munin/Master/Graph.pm
# this fixes rrdtool graph generation
sed -i 's|\\\\l||g' lib/Munin/Master/Graph.pm
'';
installPhase = ''
./Build install --destdir $out \
--install_path script=bin \
--install_path lib=lib/perl5/site_perl \
--install_path bindoc=share/man/man1 \
--install_path libdoc=share/man/man3 \
--install_path share=share \
--install_path etc=share \
--install_path web=share \
--install_path plugins=share/plugins \
--install_path arch=/dev/null \
--install_path var=/var \
=-install_path MUNIN_BINDIR=$out/bin
'';
postFixup = ''
perlDeps=$(cat ${muninDeps})
echo "Removing references to /usr/{bin,sbin}/ from munin plugins..."
find "$out/share/plugins" -type f -print0 | xargs -0 -L1 sed -i -e "s|/usr/bin/||g" -e "s|/usr/sbin/||g"
for file in "$out"/bin/* ; do
# don't wrap .jar files
case "$file" in
*.jar) continue;;
esac
wrapProgram "$file" \
--set PERL5LIB "$out/lib/perl5/site_perl:$perlDeps"
done
'';
};
in { inherit munin muninDeps; }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment