#!/usr/bin/perl -w # -*- perl -*- # vim: sts=8 sw=8 ts=8 # # Run "perldoc thisfilename" to get a well-formatted set of documentation # for this munin plugin. # =head1 NAME openvzcpu - Munin plugin to monitor the amount of CPU used by each OpenVZ container running on this machine. =head2 SYNOPSIS Draws a stacked graph showing system/user/nice CPU usage for each container running on a OpenVZ hardware node. Must be run from outside of any container in order to gain access to the values generated by the OpenVZ kernel code in C =head1 CONFIGURATION The following perl libraries are used: Graphics::ColorNames Graphics::ColorObject ... on Debian based systems (i.e. Ubuntu etc.) you may just: aptitude install libcolor-calc-perl libgraphics-colorobject-perl Must be run as root in order to read C Place the following in a file such as C B. [openvzcpu] user root =head2 OPTIONS The following may be added to the file above, in order to enable the graphing of idle and iowait times: env.drawidle 1 For kernels which have other than 100 jiffies per second (sic) n.b. this is unlikely to be necessary - you may add the following to the plugin-specific configuration: env.HZ 1000 If you have a high number of containers running on the machine, you may be able to gain extra clarity by asking munin to create a "taller" graph by adding the following to /etc/munin.conf, or in a file under C if you are using Munin v1.4 or above: openvzcpu.graph_height 700 =head1 SEE ALSO http://wiki.openvz.org/Vestat =head1 TODO . Add Munin 1.4 multigraph support . Sort graphing order so that the smallest container is rendered at the bottom of the graph. . Make the colour list into a configuration item. . Fix graphing of non-container CPU usage. =head1 VERSION 0.6 Initial Public Release =head1 AUTHOR Tim Small Copyright 2010 South East Open Source Solutions Ltd. The creation of this plugin was funded by Latitude Hosting http://www.latitudehosting.net/ =head1 LICENSE GPLv2 =begin comment This program 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. 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. =end comment =head1 MAGIC MARKERS #%# family=auto #%# capabilities=autoconf =cut use strict; use Carp; use Graphics::ColorNames 2.10; use Graphics::ColorObject; my $vestat = '/proc/vz/vestat'; my $stat = '/proc/stat'; my @vestatitems = ('user', 'system', 'nice'); my @colorlist = ('purple', 'green', 'red', 'pink2', 'green', 'brown', 'cyan', 'orange', 'blue', 'grey'); ############ # autoconf # ############ if ( defined $ARGV[0] && $ARGV[0] eq 'autoconf' ) { if ( -r '/proc/stat' && -r '/proc/vz/vestat' ) { print "yes\n"; } else { print "no\n"; } exit 0; } my $hz = 100; #use Data::Dumper; croak Dumper(\%ENV); $hz = $ENV{'HZ'} if ( defined $ENV{'HZ'} ); my $drawidle = 0; $drawidle = $ENV{'drawidle'} if ( defined $ENV{'drawidle'} ); open VESTAT, "<$vestat" or croak "Failed to open $vestat\n"; my %vejif; while () { my ($veid, $user, $nice, $system); ($veid, $user, $nice, $system) = m,^\W+(\d+)\W+(\d+)\W+(\d+)\W+(\d+)\W+(\d+),; if (defined $veid) { $vejif{$veid}->{'user'} = $user; $vejif{$veid}->{'nice'} = $nice; $vejif{$veid}->{'system'} = $system; } } close VESTAT or croak "Failed to close $vestat\n"; open STAT, "<$stat" or croak "Failed to open $stat\n"; my $line = 0; my $cores = 0; while () { my ($user, $nice, $system, $idle, $iowait, $irq, $softirq); ($user, $nice, $system, $idle, $iowait, $irq, $softirq) = m,^cpu\W+(\d+)\W+(\d+)\W+(\d+)\W+(\d+)\W+(\d+)\W+(\d+)\W+(\d+)\W+(\d+),; if (defined $user) { $vejif{'global'}->{'user'} = $user; $vejif{'global'}->{'nice'} = $nice; $vejif{'global'}->{'system'} = $system; $vejif{'global'}->{'idle'} = $idle; $vejif{'global'}->{'iowait'} = $iowait; $vejif{'global'}->{'irq'} = $irq; $vejif{'global'}->{'softirq'} = $softirq; } # Count number of CPU cores on this system while we are here $cores++ if m,cpu\d,; } $cores = 1 if $cores == 0; foreach my $thing (@vestatitems) { ##FIXME this doesn't appear to work on 2.6.32. OpenVZ bug? ## #Subtract total container usage from overall usage to get non-openvz ## # usage (AKA VEID 0) ## $vejif{'0'}->{$thing} = $vejif{'global'}->{$thing}; ## foreach my $veid (keys %vejif) { ## next if $veid eq 'global'; ## $vejif{'0'}->{$thing} = $vejif{'0'}->{$thing} - $vejif{$veid}->{$thing}; ## } delete $vejif{'global'}->{$thing}; } ########## # config # ########## if ( defined $ARGV[0] && $ARGV[0] eq 'config' ) { my $uplimit = $cores; my $first = 1; my $veprocessed = 0; #print 'graph_args --base 1000 -r --lower-limit 0 --units-length 4 --y-grid 0.01:10'; print 'graph_args --base 1000 -r --lower-limit 0 -Y'; print " --upper-limit $uplimit" if $drawidle; print <new_RGBhex( $cnameobj->hex($color) ))->as_LCHab() }; foreach my $item ('system', 'user', 'nice') { my @itemc; @itemc = @lchab; $itemc[0] = 1.3 * $itemc[0] if ($item eq 'nice'); $itemc[0] = 0.7 * $itemc[0] if ($item eq 'system'); my $itemcolor = Graphics::ColorObject->new_LCHab(\@itemc); print "v${veid}${item}.label $vename $item\n"; if($first) { print "v${veid}${item}.draw AREA\n"; $first = 0; } else { print "v${veid}${item}.draw STACK\n"; } print "v${veid}${item}.colour " . $itemcolor->as_RGBhex() . "\n"; print "v${veid}${item}.min 0\n"; print "v${veid}${item}.type DERIVE\n"; print "v${veid}${item}.cdef v${veid}${item},100,/\n"; } } print <{$datapoint} / $hz * 100; } }