contrib-munin/plugins/boinc/boinc_credit

235 lines
7.3 KiB
Perl
Executable File

#!/usr/bin/perl
# -*- cperl -*-
=head1 NAME
boinc_credit - Munin plugin to monitor BOINC credit for a user
=head1 APPLICABLE SYSTEMS
Any
=head1 CONFIGURATION
All that should be needed is to add the following to your config:
[boinc_credit]
env.cpid 1234abcd....
Where the value is your Cross Project ID (CPID).
=head1 MAGIC MARKERS
#%# family=auto contrib
#%# capabilities=autoconf
=head1 VERSION
1.0
=head1 AUTHOR
Paul Saunders <darac+munin@darac.org.uk>
=cut
use strict;
use warnings;
use lib $ENV{'MUNIN_LIBDIR'};
use Munin::Plugin;
my $CPID = $ENV{cpid};
my $STATSURL = $ENV{statsurl}
|| "http://boinc.netsoft-online.com/get_user.php?cpid=$CPID";
my $TICK = $ENV{tick} || 60; # minutes
my $ret;
if ( !eval "require XML::Simple;" ) {
$ret += "Could not load XML::Simple; ";
}
if ( !eval "require LWP::Simple;" ) {
$ret += "Could not load LWP::Simple; ";
}
if ( defined $ARGV[0] and $ARGV[0] eq 'autoconf' ) {
# Can't auto configure at the moment.
# At least, until we can calculate CPID
print "no\n";
exit 0;
}
my $lastread;
sub save_data {
my @projdata = @_;
# Do we need to save this data?
if ( !defined $lastread or time >= $lastread + ( $TICK * 60 ) ) {
$lastread = time;
my @save_vector;
push @save_vector, $lastread;
foreach (@projdata) {
# Serialise the hash
my @tempbuf;
foreach my $key ( keys %{$_} ) {
push @tempbuf, $key . '¬' . $_->{$key};
}
push @save_vector, join( '^^', @tempbuf );
}
save_state(@save_vector);
}
}
sub load_data {
# Bring the data back in
my @save_vector = restore_state();
# Read the timestamp, Do we need to refresh the data?
$lastread = shift @save_vector;
my @projarray;
foreach (@save_vector) {
my $hashref;
foreach ( split /\^\^/ ) {
my ( $key, $value ) = split /¬/;
$hashref->{$key} = $value;
}
push @projarray, $hashref;
}
if ( !defined $lastread or time >= ( $lastread + ( $TICK * 60 ) ) ) {
# Data is stale
eval {
# Fetch the XML
my $content;
unless ( defined( $content = LWP::Simple::get $STATSURL) ) {
die "Could not get $STATSURL";
}
my $xmlref = XML::Simple::XMLin( $content, ForceArray => 1 );
my @temparray;
foreach ( @{ $xmlref->{project} } ) {
my $temphash;
$temphash->{name} = $_->{name}[0];
$temphash->{id} = $_->{project_id}[0];
$temphash->{credit} = $_->{total_credit}[0];
$temphash->{creditfract} =
$_->{total_credit}[0] / $xmlref->{total_credit}[0];
$temphash->{totalcredit} = $xmlref->{total_credit}[0];
$temphash->{rank} = $_->{project_rank_total_credit}[0];
push @temparray, $temphash;
}
# If the above threw an error, we won't overwrite the old data
@projarray = @temparray;
1;
} or do {
print $@;
}
}
return @projarray;
}
# Project Colours from http://boinc.netsoft-online.com/e107_plugins/forum/forum_viewtopic.php?3
sub rgb($$$) {
return sprintf( '%02x%02x%02x', shift, shift, shift );
}
my %project_colour = (
'climatepredition.net' => rgb( 0, 139, 69 ),
'Predictor@Home' => rgb( 135, 206, 235 ),
'SETI@home' => rgb( 65, 105, 225 ),
'Einstein@Home' => rgb( 255, 165, 0 ),
'Rosetta@home' => rgb( 238, 130, 238 ),
'PrimeGrid' => rgb( 205, 197, 191 ),
'LHC@home' => rgb( 255, 127, 80 ),
'World Community Grid' => rgb( 250, 128, 114 ),
'BURP' => rgb( 0, 255, 127 ),
'SZTAKI Desktop Grid' => rgb( 205, 79, 57 ),
'uFluids' => rgb( 0, 0, 0 ),
'SIMAP' => rgb( 143, 188, 143 ),
'Folding@Home' => rgb( 153, 50, 204 ),
'MalariaControl' => rgb( 30, 144, 255 ),
'The Lattice Project' => rgb( 0, 100, 0 ),
'Pirates@Home' => rgb( 127, 255, 0 ),
'BBC Climate Change Experiment' => rgb( 205, 173, 0 ),
'Leiden Classical' => rgb( 140, 34, 34 ),
'SETI@home Beta' => rgb( 152, 245, 255 ),
'RALPH@Home' => rgb( 250, 240, 230 ),
'QMC@HOME' => rgb( 144, 238, 144 ),
'XtremLab' => rgb( 130, 130, 130 ),
'HashClash' => rgb( 255, 105, 180 ),
'cpdn seasonal' => rgb( 255, 255, 255 ),
'Chess960@Home Alpha' => rgb( 165, 42, 42 ),
'vtu@home' => rgb( 255, 0, 0 ),
'LHC@home alpha' => rgb( 205, 133, 63 ),
'TANPAKU' => rgb( 189, 183, 107 ),
'other' => rgb( 255, 193, 37 ),
'Rectilinear Crossing Number' => rgb( 83, 134, 139 ),
'Nano-Hive@Home' => rgb( 193, 205, 193 ),
'Spinhenge@home' => rgb( 255, 240, 245 ),
'RieselSieve' => rgb( 205, 183, 158 ),
'Project Neuron' => rgb( 139, 58, 98 ),
'RenderFarm@Home' => rgb( 210, 105, 30 ),
'Docking@Home' => rgb( 178, 223, 238 ),
'proteins@home' => rgb( 0, 0, 255 ),
'DepSpid' => rgb( 139, 90, 43 ),
'ABC@home' => rgb( 222, 184, 135 ),
'BOINC alpha test' => rgb( 245, 245, 220 ),
'WEP-M+2' => rgb( 0, 250, 154 ),
'Zivis Superordenador Ciudadano' => rgb( 255, 239, 219 ),
'SciLINC' => rgb( 240, 248, 255 ),
'APS@Home' => rgb( 205, 91, 69 ),
'PS3GRID' => rgb( 0, 139, 139 ),
'Superlink@Technion' => rgb( 202, 255, 112 ),
'BRaTS@Home' => rgb( 255, 106, 106 ),
'Cosmology@Home' => rgb( 240, 230, 140 ),
'SHA 1 Collision Search' => rgb( 255, 250, 205 ),
);
if ( defined $ARGV[0] and $ARGV[0] eq 'config' ) {
if ($ret) {
print $ret;
exit 1;
}
my @projdata = load_data();
print <<EOF;
graph_args --base 1000 --logarithmic
graph_vlabel Cobblestones
graph_category htc
graph_title BOINC Total Credit
EOF
foreach ( sort { $a->{id} <=> $b->{id} } @projdata ) {
my $fieldname = 'proj' . $_->{id};
print <<EOF;
$fieldname.label $_->{name}
$fieldname.type GAUGE
$fieldname.info Total Credit for project $_->{name}
EOF
if ( exists $project_colour{ $_->{name} } ) {
print "$fieldname.colour $project_colour{$_->{name}}\n";
}
}
save_data(@projdata);
exit 0;
}
my @projdata = load_data();
foreach ( sort { $a->{id} <=> $b->{id} } @projdata ) {
my $fieldname = 'proj' . $_->{id};
print "$fieldname.value $_->{credit}\n";
printf "$fieldname.extinfo %.2f%% of Total Credit (%.2f out of %.2f)\n",
$_->{creditfract} * 100, $_->{credit}, $_->{totalcredit};
}
save_data(@projdata);
exit 0;