Munin
Contingut
Install Munin to the Ubuntu server
sudo apt-get install munin
Dynamic graphics
To be able to zoom in the graphics, edit /etc/munin/munin.conf and change:
html_strategy cgi graph_strategy cgi
Nginx webserver
If using Nginx, add to your host config (ex. /etc/nginx/sites-enabled/default ):
location /munin/static/ { alias /etc/munin/static/; expires modified +1w; } # location /munin { # # auth_basic "Restricted"; # # Create the htpasswd file with the htpasswd tool. # # auth_basic_user_file /etc/nginx/htpasswd; # # alias /var/cache/munin/www; # expires modified +310s; # } location /munin/ { fastcgi_split_path_info ^(/munin)(.*); fastcgi_param PATH_INFO $fastcgi_path_info; fastcgi_pass unix:/var/run/munin/fastcgi-html.sock; include fastcgi_params; } location ^~ /munin-cgi/munin-cgi-graph/ { fastcgi_split_path_info ^(/munin-cgi/munin-cgi-graph)(.*); fastcgi_param PATH_INFO $fastcgi_path_info; fastcgi_pass unix:/var/run/munin/fastcgi-graph.sock; include fastcgi_params; }
Create a new service file:
cat /etc/init.d/munin-fcgi-marti #!/bin/bash ### BEGIN INIT INFO # Provides: munin-fcgi # Required-Start: $remote_fs $syslog $network # Required-Stop: $remote_fs $syslog $network # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: Start munin FCGI processes at boot time # Description: Start the FCGI processes behind http://munin.*/ ### END INIT INFO graph_pidfile="/var/run/munin/fcgi_graph.pid" # Ubuntu 12.10: /usr/lib/cgi-bin/munin-cgi-graph graph_cgi="/usr/lib/munin/cgi/munin-cgi-graph" html_pidfile="/var/run/munin/fcgi_html.pid" # Ubuntu 12.10: /usr/lib/cgi-bin/munin-cgi-html html_cgi="/usr/lib/munin/cgi/munin-cgi-html" retval=0 . /lib/lsb/init-functions start() { chown munin:munin /var/log/munin/* echo -n "Starting munin graph FastCGI: " start_daemon -p ${graph_pidfile} /usr/bin/spawn-fcgi -u munin -g munin \ -s /var/run/munin/fastcgi-graph.sock -U www-data ${graph_cgi} echo echo -n "Starting munin html FastCGI: " start_daemon -p ${html_pidfile} /usr/bin/spawn-fcgi -u munin -g munin \ -s /var/run/munin/fastcgi-html.sock -U www-data ${html_cgi} echo retval=$? } stop() { echo -n "Stopping munin graph FastCGI: " killproc -p ${graph_pidfile} ${graph_cgi} -QUIT echo echo -n "Stopping munin html FastCGI: " killproc -p ${html_pidfile} ${html_cgi} -QUIT echo retval=$? rm /var/run/munin/fastcgi-graph.sock rm /var/run/munin/fastcgi-html.sock } case "$1" in start) start ;; stop) stop ;; restart) stop start ;; *) echo "Usage: munin-fcgi {start|stop|restart}" exit 1 ;; esac exit $retval
Start it:
service munin-fcgi-marti restart
Add it to autostart:
update-rc.d munin-fcgi-marti defaults
Install Munin to the Fedora/Centos server
yum install munin munin-nginx
Nginx_webserver
Same steps for the Dynamic graphics as in the Ubuntu server
Same steps for Nginx as in the Ubuntu server Munin#Nginx_webserver
Create a new service file: /etc/init.d/munin-fcgi-marti2
#!/bin/sh ### BEGIN INIT INFO # Provides: munin-fcgi-marti2 # Required-Start: $remote_fs $network # Required-Stop: $remote_fs $network # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: starts munin-fastcgi # Description: Spawn Munin FCGI sockets for Web access ### END INIT INFO # # munin-fastcgi Startup script for Munin CGI services # # chkconfig: - 84 15 # description: Loading Munin CGI services using spawn-cgi # HTML files and CGI. # # Author: Ryan Norbauer # Modified: Geoffrey Grosenbach http://topfunky.com # Modified: David Krmpotic http://davidhq.com # Modified: Kun Xi http://kunxi.org # Modified: http://drumcoder.co.uk/ # Modified: http://uname.pingveno.net/ # Modified: the_architecht http://iwbyt.com/ PATH=/usr/local/bin/:/usr/local/sbin:$PATH DAEMON=$(which spawn-fcgi) FCGI_GRAPH_SOCK=/var/run/munin/fcgi-graph.sock FCGI_HTML_SOCK=/var/run/munin/fcgi-html.sock WWW_USER=nginx FCGI_USER=munin FCGI_GROUP=munin FCGI_SPAWN_GRAPH=/var/www/cgi-bin/munin-cgi-graph FCGI_SPAWN_HTML=/var/www/cgi-bin/munin-cgi-html PIDFILE_GRAPH=/var/run/munin/fastcgi-munin-graph.pid PIDFILE_HTML=/var/run/munin/fastcgi-munin-html.pid DESC="Munin FCGI for Graph and HTML" # Gracefully exit if the package has been removed. test -x $DAEMON || exit 0 test -x $FCGI_SPAWN_GRAPH || exit 0 test -x $FCGI_SPAWN_HTML || exit 0 start() { $DAEMON -s $FCGI_GRAPH_SOCK -U $WWW_USER -u $FCGI_USER -g $FCGI_GROUP -P $PIDFILE_GRAPH $FCGI_SPAWN_GRAPH 2> /dev/null || echo "Graph Already running" $DAEMON -s $FCGI_HTML_SOCK -U $WWW_USER -u $FCGI_USER -g $FCGI_GROUP -P $PIDFILE_HTML $FCGI_SPAWN_HTML 2> /dev/null || echo "HTML Already running" } stop() { kill -QUIT `cat $PIDFILE_GRAPH` || echo "Graph not running" kill -QUIT `cat $PIDFILE_HTML` || echo "HTML Not running" } restart() { kill -HUP `cat $PIDFILE_GRAPH` || echo "Can't reload Graph" kill -HUP `cat $PIDFILE_HTML` || echo "Can't reload HTML" } case "$1" in start) echo "Starting $DESC: " start ;; stop) echo "Stopping $DESC: " stop ;; restart|reload) echo "Restarting $DESC: " stop # One second might not be time enough for a daemon to stop, # if this happens, d_start will fail (and dpkg will break if # the package is being upgraded). Change the timeout if needed # be, or change d_stop to have start-stop-daemon use --retry. # Notice that using --retry slows down the shutdown process somewhat. sleep 1 start ;; *) echo "Usage: $SCRIPTNAME {start|stop|restart|reload}" >&2 exit 3 ;; esac exit $?
Start it:
service munin-fcgi-marti2 restart or systemctl restart munin-fcgi-marti2
Add it to autostart:
systemctl enable munin-fcgi-marti2
Install Munin to a client
First you need to install munin client package using the following commands
sudo apt-get install munin-node
Now you need to edit the munin-node.conf file to specify that your monitoring server is allowed to poll the client for information.
sudo vi /etc/munin/munin-node.conf
Search for the section that has the line "allow ^127\.0\.0\.1$". Modify the IP address to reflect your monitoring server's IP address.If your server ip is 172.30.2.100
allow ^\.172\.30\.2\.100$
In case you use a reverse tunnel to connect, you can limit the munin-node to listen only to localhost:
#host * #by mar: posat el host 127.0.0.1 enlloc de * ja que es connecta a traves del tunel invers host 127.0.0.1
You probably want to cahnge the port too.
Save and exit the file
You need to restart the munin client using the following information
sudo service munin-node restart
Now you need to login in to your munin server and edit the munin.conf file
sudo vi /etc/munin/munin.conf
Copy the following section and change the ip address to your remote server client ip address
[MuninMonitor] address 127.0.0.1 use_node_name yes
to
[MuninMonitor] address 172.30.2.101 use_node_name yes
Finall you need to restart the apache server using the following command
sudo service apache2 restart
Add variables
/usr/sbin/munin-node-configure --suggest /usr/sbin/munin-node-configure --shell | sh /etc/init.d/munin-node restart
Additional Plugins
The munin-plugins-extra package contains performance checks additional services such as DNS, DHCP, Samba, etc. To install the package run the following command from the terminal
sudo apt-get install munin-plugins-extra
Make sure you have install this package on both the server and node machines.
Info from: http://www.ubuntugeek.com/install-munin-monitoring-tool-on-ubuntu-14-04-server.html
Other plugins added manually
Add SNMP Routers and Printers
dd-wrt allows SNMP to be enabled under the Services menu.
If you're connecting using OpenVPN you need to open the UPD port 161 in the firewall (Administration tab / firewall commands):
iptables -I INPUT 1 -p udp --dport 161 -j ACCEPT
Then you add it to one machine working as munin-node:
munin-node-configure --shell --snmp 192.168.100.250 munin-node-configure --shell --snmp 192.168.100.250 |/bin/sh
More info: http://munin-monitoring.org/wiki/Using_SNMP_plugins
multi_tcp_ping - TCP ping plugin
Improved but originally downloaded from: http://gallery.munin-monitoring.org/contrib/plugins/network/multi_tcp_ping or http://munin-monitoring.org/browser/munin-contrib/plugins/network/multi_tcp_ping
/etc/munin/plugins/multi_tcp_ping
#!/usr/bin/perl =head1 NAME multi_tcp_ping - Graphs together the TCP ping results for several hosts =head1 SYNOPSIS This plugin is meant to be called from Munin. You should set the 'hosts' environment variable from Munin's configuration (i.e. /etc/munin/munin.conf) to specify which hosts and ports to query. =head1 DESCRIPTION This plugin expects to receive the following environment variables: =over 4 =item hosts (REQUIRED!) Comma-separated list of hosts to query. You can specify the TCP port to connect to on each of the hosts by listing them as host:port - The port defaults to 80. The following is a valid hosts declaration: hosts='192.168.0.15, 192.168.0.18:22' It will query host 192.168.0.15 on the default port (80), as well as host 192.168.0.18 on port 22. =back If the connection was opened successfully, it gives as the return value the time it took to establish the connection. If the requested host is not reachable, a hard-wired '-0.01' will be returned. Why -0.01? Because giving a negative value is the best way to easily get -visually- that something failed. Connection establishment times are usually in the 5-500ms range. 100ms will be not too little (and thus invisible), not too much (and thus killing the details in our graphs). =head1 DEPENDS ON L<Net::Ping> =head1 SEE ALSO L<munin>, L<munin-node> =head1 AUTHOR Gunnar Wolf <[email protected]> =head1 COPYRIGHT Copyright 2008 Gunnar Wolf, Instituto de Investigaciones Economicas, UNAM. This plugin is Free Software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 dated June, 1991, or any later version (at your choice). This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. =cut use strict; use warnings; # This evil "eval" is to make Travis CI able to test the plugin syntax # without having a perl built with threads. # # Also: The use of interpreter-based threads in perl is officially # discouraged. eval 'use threads; 1;' or die 'Could not use threads'; use Net::Ping; my (%defaults, @hosts, @hostscritic, @hostsnotcritic, $cmd_arg); %defaults = (port => 80, timeout => 2, unreachable => -0.1); @hostscritic = get_hosts($ENV{hosts}); @hostsnotcritic = get_hosts($ENV{hostsnotcritic}); # marti @hosts = (@hostscritic, @hostsnotcritic); #ordenem pel camp etiqueta # @hosts = sort { host_etiqueta_for($a) cmp host_etiqueta_for($b) } @hosts; die "Hosts not set - cannot continue\n" unless @hosts; $cmd_arg = $ARGV[0] || ''; config() if($cmd_arg eq "config"); autoconf() if ($cmd_arg eq 'autoconf'); for my $host (@hosts) { threads->new(\&ping_host, $host) } map {$_->join} threads->list; exit 0; sub ping_host { my ($host, $addr, $p, $ret, $time, $ip); $host = shift; $addr = host_label_for($host); $p=Net::Ping->new("tcp", $defaults{timeout}); $p->hires(); my $port = $host->[1] || $defaults{port}; $p->{port_num} = $port; $p->service_check('1'); $p->port_number($port); ($ret, $time, $ip) = $p->ping($host->[0]); $time = $defaults{unreachable} if !$ret; print "${addr}.value $time\n"; } sub get_hosts { # Hosts are defined in the 'hosts' environment variable. It's a list of # hosts (and optionally ports) - We parse the list and arrange it neatly # to be easily consumed. my ($hostsdef, @hosts); $hostsdef = shift; return unless $hostsdef; for my $host (split(/,/, $hostsdef)) { # $host =~ s/\s//g; $host =~ /^(?:([^:]+)) (?::(\d+))? (?::([^:,]+))?$/x; #$host =~ /^(?:([^:]+)) # (?::(\d+))?$/x; my $martinom = $1; my $martiport = $2; my $martietiqueta = $3; $martinom =~ s/\s//g; $martiport =~ s/\s//g; push @hosts, [$martinom, $martiport || $defaults{port}, $martietiqueta || "$martinom $martiport"]; } return @hosts; } sub config { my @res = ("graph_title TCP connection times", "graph_args --base 1000 --units-exponent -3 --lower-limit -0.099", # "graph_args --base 1000 -l 0" "graph_scale no", "graph_printf %6.6lf", # per posar tot en ms "graph_printf %6.3lf%S" "graph_vlabel seconds", "graph_category network", "graph_info Shows the time to establish a TCP connection"); for my $host (@hostscritic) { my $addr = host_label_for($host); my $martietiqueta = host_etiqueta_for($host); push @res, "$addr.label $martietiqueta"; # push @res, "$addr.extinfo $martietiqueta"; push @res, "$addr.draw LINE2"; push @res, "$addr.info Time to establish TCP connection to " . "$host->[0]:$host->[1]"; push @res, "$addr.critical 0:"; # en cas que sigu per sota de 0, es un error ja que quan falla el valor es -0.10 } for my $host (@hostsnotcritic) { my $addr = host_label_for($host); my $martietiqueta = host_etiqueta_for($host); push @res, "$addr.label $martietiqueta"; # push @res, "$addr.extinfo $martietiqueta"; push @res, "$addr.draw LINE2"; push @res, "$addr.info Time to establish TCP connection to " . "$host->[0]:$host->[1]"; push @res, "$addr.critical :"; # aquest es un host no critic i per tan no ha denviar alertes } print map {"$_\n"} @res; exit 0; } sub autoconf { print "yes\n"; exit 0; } sub host_label_for { my ($ip, $port, $etiqueta) = @{$_[0]}; # Periods and colonsare not allowed in variable names my $addr = "src_${ip}_${port}"; $addr =~ s/\./_/g; return $addr; } sub host_etiqueta_for { my ($ip, $port, $etiqueta) = @{$_[0]}; return $etiqueta; }
And put it to:
sudo vi /etc/munin/plugins/multi_tcp_ping sudo chmod +x /etc/munin/plugins/multi_tcp_ping
Add the hosts to the following new file:
sudo vi /etc/munin/plugin-conf.d/multi_tcp_ping
or at the end of:
sudo vi /etc/munin/plugin-conf.d/munin-node
[multi_tcp_ping] env.hosts 192.168.1.2, google.com, 192.168.100.1, 192.168.100.2, 192.168.100.100:3389:This is a label for this server, 192.168.101.1 env.hostsnotcritic google.com, ocell1.min.cat:23:Ocell1 # env.hostsnotcritic are hosts that no alerts have to be sent if unreachable
Restart munin-node
service munin-node restart
Old system with a dedicated hosts file
(the ports specified in the file do not work yet, so only 80 is working)
From: https://forum.xakep.ru/topic/1398094/
Create file /usr/share/munin-marti/tcp_multi_ping'
cat tcp_multi_ping #!/usr/bin/perl =head1 NAME multi_tcp_ping - Graphs together the TCP ping results for several hosts =head1 SYNOPSIS This plugin is meant to be called from Munin. You should set the 'hosts' environment variable from Munin's configuration (i.e. /etc/munin/munin.conf) to specify which hosts and ports to query. =head1 DESCRIPTION This plugin expects to receive the following environment variables: =over 4 =item hosts (REQUIRED!) Comma-separated list of hosts to query. You can specify the TCP port to connect to on each of the hosts by listing them as host:port - The port defaults to 80. The following is a valid hosts declaration: hosts='192.168.0.15, 192.168.0.18:22' It will query host 192.168.0.15 on the default port (80), as well as host 192.168.0.18 on port 22. =back If the connection was opened successfully, it gives as the return value the time it took to establish the connection. If the requested host is not reachable, a hard-wired '-0.01' will be returned. Why -0.01? Because giving a negative value is the best way to easily get -visually- that something failed. Connection establishment times are usually in the 5-500ms range. 100ms will be not too little (and thus invisible), not too much (and thus killing the details in our graphs). =head1 DEPENDS ON L<Net::Ping> =head1 SEE ALSO L<munin>, L<munin-node> =head1 AUTHOR Gunnar Wolf <[email protected]> =head1 COPYRIGHT Copyright 2008 Gunnar Wolf, Instituto de Investigaciones Economicas, UNAM. This plugin is Free Software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 dated June, 1991, or any later version (at your choice). This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. =cut use strict; use warnings; # This evil "eval" is to make Travis CI able to test the plugin syntax # without having a perl built with threads. # # Also: The use of interpreter-based threads in perl is officially # discouraged. eval 'use threads; 1;' or die 'Could not use threads'; use Net::Ping; my (%defaults, @hosts, $cmd_arg, $config_file_name); %defaults = (port => 80, timeout => 2, unreachable => -0.01); #$config_file_name = "/usr/share/munin/plugins/hostslist.ip"; $config_file_name = "/usr/share/munin-marti/tcp_multi_ping.ip"; open (IN_FILE,"<$config_file_name") or die "Unable to open file hostslist.ip"; while (<IN_FILE>){ # if (/\d+\.\d+\.\d+\.\d+/){ s/\s//g; push (@hosts,[$_,$defaults{port}]); # } } # @hosts = get_hosts($ENV{hosts}); die "Hosts not set - cannot continue\n" unless @hosts; $cmd_arg = $ARGV[0] || ''; config() if($cmd_arg eq "config"); autoconf() if ($cmd_arg eq 'autoconf'); for my $host (@hosts) { threads->new(\&ping_host, $host) } map {$_->join} threads->list; exit 0; sub ping_host { my ($host, $addr, $p, $ret, $time, $ip); $host = shift; $addr = host_label_for($host); $p=Net::Ping->new("tcp", $defaults{timeout}); $p->hires(); $p->{port_num} = $host->[1] || $defaults{port}; ($ret, $time, $ip) = $p->ping($host->[0]); $time = $defaults{unreachable} if !$ret; print "${addr}.value $time\n"; } sub get_hosts { # Hosts are defined in the 'hosts' environment variable. It's a list of # hosts (and optionally ports) - We parse the list and arrange it neatly # to be easily consumed. my ($hostsdef, @hosts); $hostsdef = shift; return unless $hostsdef; for my $host (split(/,/, $hostsdef)) { $host =~ s/\s//g; $host =~ /^(?:([^:]+)) (?::(\d+))?$/x; push @hosts, [$1, $2 || $defaults{port}]; } return @hosts; } sub config { my @res = ("graph_title TCP connection times", "graph_args --base 1000 -l 0", "graph_vlabel seconds", "graph_category network", "graph_info Shows the time to establish a TCP connection"); for my $host (@hosts) { my $addr = host_label_for($host); push @res, "$addr.label $addr"; push @res, "$addr.draw LINE2"; push @res, "$addr.info Time to establish TCP connection to " . "$host->[0]:$host->[1]"; } print map {"$_\n"} @res; exit 0; } sub autoconf { print "yes\n"; exit 0; } sub host_label_for { my ($ip, $port) = @{$_[0]}; # Periods and colonsare not allowed in variable names my $addr = "src_${ip}_${port}"; $addr =~ s/\./_/g; return $addr; }
Put all your hosts to /usr/share/munin-marti/tcp_multi_ping.ip
google.com hostssh.com:22
Create link:
sudo ln -s '/usr/share/munin-marti/tcp_multi_ping' '/etc/munin/plugins/tcp_multi_ping'
Restart munin-node
multi_backup_times
/usr/share/munin-marti/multi_backup_times
#!/usr/bin/perl =head1 NAME multi_time_backup - Time since last succesful backup for several backup systems =head1 SYNOPSIS This plugin is meant to be called from Munin. =head1 DESCRIPTION This plugin expects to receive the following config : =over 4 =commands file (REQUIRED!) File with each line containing 4 fields separated by : in the following format dayswarn:dayscrit:id:label:command dayswarn is maximun amount of days before warning alert (empty for no alert) dayscrit is maximun amount of days before critical alert (empty for no alert) id is a unique id used to store the data label is the label displayed (if empty then the id is going to be used) command is the command to run in bash =back If the command to run is executed correctly it should return the number of seconds since the last backup. In case of error it should return -1 =head1 SEE ALSO L<munin>, L<munin-node> =head1 AUTHOR M Minoves <info at sitoplex . com> =head1 COPYRIGHT Copyright 2017 M Minoves <info at sitoplex . com> This plugin is Free Software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 dated June, 1991, or any later version (at your choice). This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. =cut use strict; use warnings; # This evil "eval" is to make Travis CI able to test the plugin syntax # without having a perl built with threads. # # Also: The use of interpreter-based threads in perl is officially # discouraged. eval 'use threads; 1;' or die 'Could not use threads'; use Net::Ping; my (%defaults, @backups, $cmd_arg, $config_file_name); # %defaults = (diesmax => 10); $config_file_name = "/usr/share/munin-marti/multi_backup_times.list"; open (IN_FILE,"<$config_file_name") or die "Unable to open file " . $config_file_name; my ($linia, $diesmaxwarning, $diesmaxcritical, $id, $etiqueta, $commanda); while (<IN_FILE>){ $linia = $_; if($linia =~ /^([^#:]*):([^:]+):([^:]+):([^:]*):(.{3,})$/x) { $diesmaxwarning = $1; $diesmaxcritical = $2; $id = $3; $etiqueta = $4 || $3; $commanda = $5; $diesmaxwarning =~ s/[^0-9.]//g; $diesmaxcritical =~ s/[^0-9.]//g; $id =~ s/\s/_/g; $id =~ s/\./_/g; $id =~ s/[^0-9a-zA-Z_\-]//g; if (length ($commanda) > 3) { push @backups, [$diesmaxwarning, $diesmaxcritical, $id, $etiqueta, $commanda]; } } } die "$config_file_name file not correctly set - cannot continue\n" unless @backups; $cmd_arg = $ARGV[0] || ''; config() if($cmd_arg eq "config"); autoconf() if ($cmd_arg eq 'autoconf'); for my $backup (@backups) { threads->new(\&exectuarCommanda, $backup) } # esperem a que tots els threads acabin: map {$_->join} threads->list; exit 0; sub exectuarCommanda { my ($backup, $addr); $backup = shift; $addr = get_label_for($backup); my $commanda = get_commanda_for($backup); # my $time = `/bin/bash -c '$commanda'`; # or die "Cannot open Dir: $!"; my $time = `$commanda`; # or die "Cannot open Dir: $!"; if ( $? != 0 ) { # print "command failed: $!\n"; # printf "command exited with value %d\n", $? >> 8; $time = "-1"; } else { $time = $time/(60*60*24); # convertim de segons a dies } print "${addr}.value $time\n"; } sub config { my @res = ("graph_title Times since last backups", "graph_args --base 1000 --units-exponent 0 -l 0", "graph_scale no", "graph_printf %6.2lf", "graph_vlabel days", "graph_category security", "graph_info Shows the time since the last successful backups"); for my $backup (@backups) { my $addr = get_label_for($backup); my $martietiqueta = get_etiqueta_for($backup); push @res, "$addr.label $martietiqueta"; # push @res, "$addr.extinfo Command: " . get_commanda_for($backup); push @res, "$addr.draw LINE2"; push @res, "$addr.info " . get_commanda_for($backup); push @res, "$addr.warning 0:" . get_diesmaxwarning_for($backup); push @res, "$addr.critical 0:" . get_diesmaxcritical_for($backup); } print map {"$_\n"} @res; exit 0; } sub autoconf { print "yes\n"; exit 0; } sub get_label_for { my ($diesmaxwarning, $diesmaxcritical, $id, $etiqueta, $commanda) = @{$_[0]}; # Periods and colons are not allowed in variable names my $label = "src_${id}"; # $label =~ s/ /_/g; # $label =~ s/\./_/g; return $label; } sub get_etiqueta_for { my ($diesmaxwarning, $diesmaxcritical, $id, $etiqueta, $commanda) = @{$_[0]}; return $etiqueta; } sub get_commanda_for { my ($diesmaxwarning, $diesmaxcritical, $id, $etiqueta, $commanda) = @{$_[0]}; return $commanda; } sub get_diesmaxwarning_for { my ($diesmaxwarning, $diesmaxcritical, $id, $etiqueta, $commanda) = @{$_[0]}; return $diesmaxwarning; } sub get_diesmaxcritical_for { my ($diesmaxwarning, $diesmaxcritical, $id, $etiqueta, $commanda) = @{$_[0]}; return $diesmaxcritical; }
/usr/share/munin-marti/multi_backup_times.list
8:15:subcube3_to_subcube2_etc:Subcube3 to Subcube2 web backup:f=$(ls -tr -d -1 /seguretat/subcube3/basedades/*.* | tail -n 1); [ $(du -m "$f" | cut -f 1) -ge 100 ] && echo $(( ($(date +%s) - $(date -r "$f" +%s)) )) 8:15:subcube3_to_subcube2_web:Subcube3 to Subcube2 web backup:f=/var/log/backup-subcube3-subcube2-web-success.log; [ $(du -b "$f" | cut -f 1) -ge 10 ] && echo $(( ($(date +%s) - $(date --date="$(tail -n 1 $f)" +%s)) ))
Apt Ubuntu
sudo vi /etc/munin/plugins/apt_ubuntu
From: https://raw.githubusercontent.com/munin-monitoring/contrib/master/plugins/ubuntu/apt_ubuntu
#!/usr/bin/env python # -*- encoding: iso-8859-1 -*- # # apt_ubuntu # # Plugin to monitor packages that should be installed on Ubuntu systems. # # Author: Stefan Daniel Schwarz <[email protected]> # # v1.0 2008-11-07 - First draft # v1.1 2008-11-08 - critical = #: First # critical, rest warning # v1.2 2008-11-09 - Code cleanup for MuninExchange submission # # Usage: place in /etc/munin/plugins/ (or link it there using ln -s) # # Parameters understood: # # config (required) # autoconf (optional - used by munin-config) # # Magic markers - optional - used by installation scripts and # munin-config: # #%# capabilities=autoconf #%# family=contrib ########################################################### category = 'security' # 'upgrades' title = 'Upgradable packages' # 'Upgradeable packages' vlabel = 'Total packages' other = 'other' total = 'total' archives = ['security', 'updates', 'proposed', 'backports'] colour = ['ff0000', '22ff22', '0022ff', '00aaaa', 'ff00ff'] origins = ['Ubuntu'] critical = 1 ########################################################### import os import sys import warnings warnings.filterwarnings('ignore', 'apt API not stable yet', FutureWarning) def autoconf(): if os.path.exists('/etc/lsb-release'): for line in open('/etc/lsb-release'): if line.strip() == 'DISTRIB_ID=Ubuntu': try: import apt except ImportError: print 'no (python-apt not installed)' sys.exit(1) cache = apt.Cache() if not cache.has_key('update-notifier-common'): print 'no (update-notifier-common not found)' sys.exit(1) if not cache['update-notifier-common'].isInstalled: print 'no (update-notifier-common not installed)' sys.exit(1) if not os.path.exists('/etc/apt/apt.conf.d/10periodic'): print 'no (/etc/apt/apt.conf.d/10periodic not found)' sys.exit(1) for line in open('/etc/apt/apt.conf.d/10periodic'): if line.strip() == 'APT::Periodic::Update-Package-Lists "1";': print 'yes' sys.exit(0) print 'no (APT::Periodic::Update-Package-Lists not "1")' sys.exit(1) print 'no' sys.exit(1) def config(): print 'graph_category security' print 'graph_title %s' % (title) #print 'graph_total %s' % (total) print 'graph_vlabel %s' % (vlabel) for i, archive in enumerate(archives + [other]): if len(colour) > i: print '%s.colour %s' % (archive, colour[i]) if i < critical: print '%s.critical 0:0' % (archive) if i == 0: print '%s.draw AREA' % (archive) else: print '%s.draw STACK' % (archive) print '%s.label %s' % (archive, archive) if i + 1 > critical: print '%s.warning 0:0' % (archive) print 'total.colour 000000' print 'total.draw LINE1' print 'total.label %s' % (total) sys.exit(0) def check_origin(pkg): #print 'Checking: %s (%s)' % (pkg.name, map(str, pkg.candidateOrigin)) if pkg.candidate.origins: for archive in archives: for origin in pkg.candidate.origins: #a = origin.archive.rpartition('-')[2] a = origin.archive.split('-')[origin.archive.count('-')] if a == archive and origin.origin in origins: return a return other if len(sys.argv) > 1: if sys.argv[1] == 'autoconf': autoconf() elif sys.argv[1] == 'config': config() elif sys.argv[1]: print('unknown argument "' + sys.argv[1] + '"') sys.exit(1) try: import apt except ImportError: print "The module 'apt' is currently not installed. You can install it by typing:\nsudo apt-get install python-apt\nImportError: No module named apt" sys.exit(1) pkgs = {} total = 0 for pkg in apt.Cache(): if pkg.is_upgradable: a = check_origin(pkg) pkgs[a] = pkgs.get(a, 0) + 1 total += 1 for archive in archives + [other]: print '%s.value %s' % (archive, pkgs.pop(archive, 0)) print 'total.value %s' % (total)
chmod +x /etc/munin/plugins/apt_ubuntu
Restart munin-node
Yum Fedora Centos RHEL
Originally from https://www.potsky.com/yum-plugin-for-munin/ but upgraded to also list the Security packages and not requiring an extra cronjob.
/usr/share/munin-marti/yum
#!/usr/bin/perl -w # -*- perl -*- # vim: ft=perl : sw=4 : ts=4 : et =head1 NAME yum - Plugin for monitoring pending package upgrades with yum =head1 USAGE This plugin needs to be called with the 'update' argument from cron to work as intended. =head1 AUTHOR Copyright 2006 Dagfinn Ilmari Mannsåker <[email protected]> Copyright 2011 Adds by potsky <[email protected]> Copyright 2017 Adds by M M <info at sitoplex .com> =head1 LICENSE GPLv2 =head1 MAGIC MARKERS #%# family=auto #%# capabilities=autoconf =cut #use strict; #use Munin::Common::Defaults; # #my $statefile = "$Munin::Common::Defaults::MUNIN_PLUGSTATE/yum.state"; # #sub update { # if (-l $statefile) { # die "$statefile is a symlink, not touching.\n"; # } # # open my $state, '>', $statefile # or die "Can't open $statefile for writing: $!\n"; # # open my $yum, '-|', 'yum list updates' # or die "Can't run 'yum list updates': $!"; # # # Skip header crap # while (<$yum>) { # last if /^Updated/; # } # # while (<$yum>) { # next unless /^(\S+)\.\S+\s+\S+\s+\S+/; # print $state "$1\n"; # } # # close $yum or die "Error running 'yum list updates': $!\n"; # close $state or die "Error writing $statefile: $!\n"; #} sub autoconf { if (system('yum --version >/dev/null 2>/dev/null') != 0) { print "no (Could not run yum)\n"; } # elsif (! -r $statefile) { # print "no (Could not find statefile. Please read 'munindoc yum')\n"; # } else { print "yes\n"; } exit 0; } sub config { print "graph_title Upgradable packages in yum\n"; print "graph_category security\n"; print "graph_vlabel Total packages\n"; print "graph yes\n"; print "updates.label updates\n"; print "updates.warning 0:0\n"; print "updates.colour 22ff22\n"; print "updates.draw AREA\n"; print "security.label security\n"; print "security.critical 0:0\n"; print "security.colour ff0000\n"; print "security.draw AREA\n"; } sub report { # my @packages; # # open my $state, '<', $statefile # or die "Can't open $statefile for reading: $! #Please read 'munindoc yum' to understand why if the file does not exist.\n"; # # chomp(@packages = <$state>); # close $state; $outputyum = `yum --security check-update |tail -n1`; #chomp $outputyum; if($outputyum =~ /^(\d+) package\(s\) needed for security, out of (\d+) available$/) # rhel6 { print 'updates.value ', $2, "\n"; print 'security.value ', $1, "\n"; }elsif($outputyum =~ /^No packages needed for security; (\d+) packages available$/) # rhel6 { print 'updates.value ', $1, "\n"; print 'security.value 0', "\n"; }elsif($outputyum =~ /^Needed (\d+) of (\d+) packages, for security$/) # rhel5 { print 'updates.value ', $2, "\n"; print 'security.value ', $1, "\n"; }elsif($outputyum =~ /^No packages needed, for security, (\d+) available$/) # rhel5 { print 'updates.value ', $1, "\n"; print 'security.value 0', "\n"; }else { print 'Error parsing: "' . $outputyum . '"' ; print 'updates.value -1', "\n"; print 'security.value -1', "\n"; } # print 'pending.value ', scalar(@packages), "\n"; # print 'pending.extinfo ', join(' ', @packages), "\n" # if @packages; } if ($ARGV[0]) { my $arg = $ARGV[0]; my %funcs = ( # update => \&update, config => \&config, autoconf => \&autoconf, ); if (exists $funcs{$arg}) { $funcs{$arg}->(); } else { die "Unknown argument '$arg'\n"; } } else { report(); }
multi_icmp_ping
/etc/munin/plugin-conf.d/multi_icmp_ping
[multi_icmp_ping] user root env.hosts 10.0.0.15, 10.0.0.16
/etc/munin/plugins/multi_icmp_ping
#!/usr/bin/perl =head1 NAME multi_icmp_ping - Graphs together the ICMP ping results for several hosts =head1 SYNOPSIS This plugin is meant to be called from Munin. You should set the 'hosts' environment variable from Munin's configuration (i.e. /etc/munin/munin.conf) to specify which hosts and ports to query. =head1 DESCRIPTION This plugin expects to receive the following environment variables: =over 4 =item hosts (REQUIRED!) Comma-separated list of hosts to query. The following is a valid hosts declaration: hosts='192.168.0.15, 192.168.0.18' =back If the connection was opened successfully, it gives as the return value the time it took to establish the connection. If the requested host is not reachable, a hard-wired '-0.01' will be returned. Why -0.01? Because giving a negative value is the best way to easily get -visually- that something failed. Connection establishment times are usually in the 5-500ms range. 100ms will be not too little (and thus invisible), not too much (and thus killing the details in our graphs). =head1 DEPENDS ON L<Net::Ping> =head1 SEE ALSO L<munin>, L<munin-node> =head1 AUTHOR M Minoves =head1 COPYRIGHT This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. =cut use strict; use warnings; # This evil "eval" is to make Travis CI able to test the plugin syntax # without having a perl built with threads. # # Also: The use of interpreter-based threads in perl is officially # discouraged. eval 'use threads; 1;' or die 'Could not use threads'; use Net::Ping; my (%defaults, @hosts, $cmd_arg); %defaults = (port => 80, timeout => 2, unreachable => -0.01); @hosts = get_hosts($ENV{hosts}); die "Hosts not set - cannot continue\n" unless @hosts; $cmd_arg = $ARGV[0] || ''; config() if($cmd_arg eq "config"); autoconf() if ($cmd_arg eq 'autoconf'); for my $host (@hosts) { threads->new(\&ping_host, $host) } map {$_->join} threads->list; exit 0; sub ping_host { my ($host, $addr, $p, $ret, $time, $ip); $host = shift; $addr = host_label_for($host); $p=Net::Ping->new("icmp", $defaults{timeout}); $p->hires(); #$p->{port_num} = $host->[1] || $defaults{port}; ($ret, $time, $ip) = $p->ping($host->[0]); $time = $defaults{unreachable} if !$ret; print "${addr}.value $time\n"; } sub get_hosts { # Hosts are defined in the 'hosts' environment variable. It's a list of # hosts (and optionally ports) - We parse the list and arrange it neatly # to be easily consumed. my ($hostsdef, @hosts); $hostsdef = shift; return unless $hostsdef; for my $host (split(/,/, $hostsdef)) { $host =~ s/\s//g; $host =~ /^(?:([^:]+)) (?::(\d+))?$/x; push @hosts, [$1, $2 || $defaults{port}]; } return @hosts; } sub config { my @res = ("graph_title ICMP connection times", "graph_args --base 1000 -l 0", "graph_vlabel seconds", "graph_category network", "graph_info Shows the time to respond to an ICMP ping"); for my $host (@hosts) { my $addr = host_label_for($host); push @res, "$addr.label $addr"; push @res, "$addr.draw LINE2"; push @res, "$addr.info Time to respond to an ICMP ping to " . "$host->[0]:$host->[1]"; } print map {"$_\n"} @res; exit 0; } sub autoconf { print "yes\n"; exit 0; } sub host_label_for { my ($ip, $port) = @{$_[0]}; # Periods and colonsare not allowed in variable names #my $addr = "src_${ip}_${port}"; my $addr = "src_${ip}"; $addr =~ s/\./_/g; return $addr; }
multi_ssh_ping
/etc/munin/plugin-conf.d/multi_ssh_ping
[multi_ssh_ping] env.hosts [email protected]:9.9.9.9, [email protected]:9.9.9.10 env.sshcommand sshpass -p password ssh -o StrictHostKeyChecking=no env.pingcommand ping -A -w 2 -c 5
/etc/munin/plugins/multi_ssh_ping
#!/usr/bin/perl =head1 NAME multi_ssh_ping - Graphs together the pings mesured from a another host connecting using SSH =head1 SYNOPSIS This plugin is meant to be called from Munin. You should set the 'hosts' environment variable from Munin's configuration (i.e. /etc/munin/munin.conf) to specify which hosts and ports to query. =head1 DESCRIPTION This plugin expects to receive the following environment variables: =over 4 =item hosts (REQUIRED!) Comma-separated list of sshhost:pinghosts to query. It connects to sshhost using ssh and from there it pings pinghost. The following is a valid hosts declaration: hosts='[email protected]:192.168.0.17, [email protected]:192.168.0.18' =item sshcommand (REQUIRED!) The ssh command to use before each of the hosts above sshcommand='sshpass -p password ssh -o StrictHostKeyChecking=no' =item pingcommand (REQUIRED!) The ping command to use after each of the hosts above pingcommand='ping -c 2 -w 1' =back If the connection was opened successfully, it gives as the return value the time it took to establish the connection. If the requested host is not reachable, a hard-wired '-0.01' will be returned. Why -0.01? Because giving a negative value is the best way to easily get -visually- that something failed. Connection establishment times are usually in the 5-500ms range. 100ms will be not too little (and thus invisible), not too much (and thus killing the details in our graphs). =head1 DEPENDS ON L<Net::Ping> =head1 SEE ALSO L<munin>, L<munin-node> =head1 AUTHOR Minoves =head1 COPYRIGHT This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. =cut use strict; use warnings; # This evil "eval" is to make Travis CI able to test the plugin syntax # without having a perl built with threads. # # Also: The use of interpreter-based threads in perl is officially # discouraged. eval 'use threads; 1;' or die 'Could not use threads'; #use Net::Ping; my (%defaults, @hosts, $cmd_arg, $pingcommand, $sshcommand); %defaults = (unreachable => -0.01); @hosts = get_hosts($ENV{hosts}); die "hosts not set - cannot continue\n" unless @hosts; $sshcommand = $ENV{sshcommand}; die "sshcommand not set - cannot continue\n" unless $sshcommand; $pingcommand = $ENV{pingcommand}; die "pingcommand not set - cannot continue\n" unless $pingcommand; $cmd_arg = $ARGV[0] || ''; config() if($cmd_arg eq "config"); autoconf() if ($cmd_arg eq 'autoconf'); for my $host (@hosts) { threads->new(\&ping_host, $host) } map {$_->join} threads->list; exit 0; sub ping_host { my ($host, $addr, $p, $ret, $time, $ip); $host = shift; $addr = host_label_for($host); my $execcommand = $sshcommand . ' ' . $host->[0] . ' ' . $pingcommand . ' ' . $host->[1]; my @ping = `$execcommand`; chomp @ping; my $ping = join(" ", @ping); #my $ping_time = "U"; #my $packet_loss = "U"; my $ping_time = $defaults{unreachable}; $ping_time = ($1 / 1000) if ($ping =~ m@min/avg/max.*\s\d+(?:\.\d+)?/(\d+(?:\.\d+)?)/\d+(?:\.\d+)?@); # $packet_loss = $1 if ($ping =~ /(\d+)% packet loss/); print "${addr}.value ". $ping_time . "\n"; } sub get_hosts { # Hosts are defined in the 'hosts' environment variable. my ($hostsdef, @hosts); $hostsdef = shift; return unless $hostsdef; for my $host (split(/,/, $hostsdef)) { $host =~ s/\s//g; $host =~ /^(?:([^:]+)) (?::(.+))?$/x; push @hosts, [$1, $2]; } return @hosts; } sub config { my @res = ("graph_title SSH ping delay times", "graph_args --base 1000 -l 0", "graph_vlabel seconds", "graph_category network", "graph_info Shows the time to respond to an ICMP ping from a SSH host"); for my $host (@hosts) { my $addr = host_label_for($host); push @res, "$addr.label $addr"; push @res, "$addr.draw LINE2"; push @res, "$addr.info ICMP ping time from " . "$host->[0]" . " to " . "$host->[1]"; } print map {"$_\n"} @res; exit 0; } sub autoconf { print "yes\n"; exit 0; } sub host_label_for { my ($ssh, $host) = @{$_[0]}; # Periods and colonsare not allowed in variable names $ssh =~ s/.*\@//g; my $addr = "src_${ssh}__${host}"; $addr =~ s/\./_/g; return $addr; }