root / plugins / boinc / boinc_projs @ de047e8f
Historique | Voir | Annoter | Télécharger (12,7 ko)
| 1 | 562e63a7 | Paul Saunders | #!/usr/bin/perl -w |
|---|---|---|---|
| 2 | # |
||
| 3 | # boinc_projs - Munin plugin to monitor actively running BOINC projects |
||
| 4 | # |
||
| 5 | # Run 'perldoc boinc_projs' for full man page |
||
| 6 | # |
||
| 7 | # Author: Palo M. <palo.gm@gmail.com> |
||
| 8 | # Modified by: Paul Saunders <darac+munin@darac.org.uk> |
||
| 9 | # License: GPLv3 <http://www.gnu.org/licenses/gpl-3.0.txt> |
||
| 10 | # |
||
| 11 | # |
||
| 12 | # Parameters supported: |
||
| 13 | # config |
||
| 14 | # |
||
| 15 | # |
||
| 16 | # Configurable variables |
||
| 17 | # boinccmd - command-line control program (default: boinccmd) |
||
| 18 | # host - Host to query (default: none = use local host) |
||
| 19 | # port - GUI RPC port (default: none = use BOINC-default) |
||
| 20 | # boincdir - Directory containing appropriate password file |
||
| 21 | # gui_rpc_auth.cfg (default: none) |
||
| 22 | # password - Password for BOINC (default: none) !!! UNSAFE !!! |
||
| 23 | # |
||
| 24 | # |
||
| 25 | # $Log$ |
||
| 26 | # |
||
| 27 | 1568bf67 | darac | # Revision 1.2 2016/10/04 Paul Saunders |
| 28 | # BoincCmd now translates states into words, so consider a "downloaded, scheduled, EXECUTING" task |
||
| 29 | # to be equivalent to a "2, 2, 1" task |
||
| 30 | # Really, this should be ported to use the proper RPC, rather than parsing boinccmd's output. |
||
| 31 | 562e63a7 | Paul Saunders | # Revision 1.1 2011/03/22 Paul Saunders |
| 32 | # Update for BOINC 6.12 |
||
| 33 | # Add colours from http://boinc.netsoft-online.com/e107_plugins/forum/forum_viewtopic.php?3 |
||
| 34 | # Revision 1.0 2009/09/13 Palo M. |
||
| 35 | # Add documentation and license information |
||
| 36 | # Ready to publish on Munin Exchange |
||
| 37 | # Revision 0.9 2009/09/13 Palo M. |
||
| 38 | # Add possibility to read password from file |
||
| 39 | # Revision 0.8 2009/09/12 Palo M. |
||
| 40 | # Update default binary name: boinc_cmd -> boinccmd |
||
| 41 | # Revision 0.7 2008/08/29 Palo M. |
||
| 42 | # Creation - Attempt to port functionality from C++ code |
||
| 43 | # |
||
| 44 | # (Revisions 0.1 - 0.6) were done in C++ |
||
| 45 | # |
||
| 46 | # |
||
| 47 | # |
||
| 48 | # Magic markers: |
||
| 49 | #%# family=contrib |
||
| 50 | |||
| 51 | use strict; |
||
| 52 | |||
| 53 | |||
| 54 | ######################################################################### |
||
| 55 | # 1. Parse configuration variables |
||
| 56 | # |
||
| 57 | my $BOINCCMD = exists $ENV{'boinccmd'} ? $ENV{'boinccmd'} : "boinccmd";
|
||
| 58 | my $HOST = exists $ENV{'host'} ? $ENV{'host'} : undef;
|
||
| 59 | my $PORT = exists $ENV{'port'} ? $ENV{'port'} : undef;
|
||
| 60 | my $PASSWORD = exists $ENV{'password'} ? $ENV{'password'} : undef;
|
||
| 61 | my $BOINCDIR = exists $ENV{'boincdir'} ? $ENV{'boincdir'} : undef;
|
||
| 62 | |||
| 63 | ######################################################################### |
||
| 64 | # 2. Basic executable |
||
| 65 | # |
||
| 66 | if (defined $HOST) {
|
||
| 67 | $BOINCCMD .= " --host $HOST"; |
||
| 68 | if (defined $PORT) {
|
||
| 69 | $BOINCCMD .= ":$PORT"; |
||
| 70 | } |
||
| 71 | } |
||
| 72 | if (defined $PASSWORD) {
|
||
| 73 | $BOINCCMD .= " --passwd $PASSWORD"; |
||
| 74 | } |
||
| 75 | if (defined $BOINCDIR) {
|
||
| 76 | chdir $BOINCDIR || die "Could not chdir to $BOINCDIR"; |
||
| 77 | } |
||
| 78 | |||
| 79 | ######################################################################### |
||
| 80 | # 3. Fetch all needed data from BOINC-client with single call |
||
| 81 | # |
||
| 82 | my $prj_status = ""; |
||
| 83 | my $results = ""; |
||
| 84 | |||
| 85 | my $simpleGuiInfo = `$BOINCCMD --get_simple_gui_info 2>/dev/null`; |
||
| 86 | if ($simpleGuiInfo ne "") {
|
||
| 87 | # Some data were retrieved, so let's split them |
||
| 88 | my @sections; |
||
| 89 | my @section1; |
||
| 90 | @sections = split /=+ Projects =+\n/, $simpleGuiInfo; |
||
| 91 | @section1 = split /=+ [A-z]+ =+\n/, $sections[1]; |
||
| 92 | $prj_status = $section1[0]; |
||
| 93 | |||
| 94 | @sections = split /=+ (?:Results|Tasks) =+\n/, $simpleGuiInfo; |
||
| 95 | @section1 = split /=+ [A-z]+ =+\n/, $sections[1]; |
||
| 96 | $results = $section1[0]; |
||
| 97 | } |
||
| 98 | |||
| 99 | if ($prj_status eq "") { exit -1; }
|
||
| 100 | |||
| 101 | # 3.a) Split --get_project_status into projects |
||
| 102 | my @prjInfos = split /\d+\) -+\n/, $prj_status; |
||
| 103 | shift @prjInfos; # Throw out first empty line |
||
| 104 | |||
| 105 | # 3.b) Fetch project infos |
||
| 106 | my %projects; # Store projects infos here |
||
| 107 | my @projects; # Just to keep the order of projects |
||
| 108 | for my $prj_info (@prjInfos) {
|
||
| 109 | my @lines = split /\n/, $prj_info; |
||
| 110 | my $line1 = shift @lines; # get project name |
||
| 111 | if ($line1 !~ /^\s+name: /) { die "Unexpected output from boinccmd"; }
|
||
| 112 | $line1 =~ s/^\s+name: //; # Make just the project name itself |
||
| 113 | my $line2 = shift @lines; # get project URL |
||
| 114 | if ($line2 !~ /^\s+master URL: /) { die "Unexpected output from boinccmd"; }
|
||
| 115 | $line2 =~ s/^\s+master URL: //; # Make just the URL itself |
||
| 116 | my $prj_url = $line2; |
||
| 117 | my $prj_name = $line1; |
||
| 118 | $line1 =~ s/\@/at/g; |
||
| 119 | $line1 =~ s/[^0-9A-z]/_/g; |
||
| 120 | my $prj_var = "prj_" . $line1; |
||
| 121 | push @projects,$prj_url; |
||
| 122 | $projects{$prj_url} = {
|
||
| 123 | prj_name => $prj_name, |
||
| 124 | prj_var => $prj_var, |
||
| 125 | prj_running => 0 |
||
| 126 | }; |
||
| 127 | } |
||
| 128 | |||
| 129 | |||
| 130 | ######################################################################### |
||
| 131 | # 4. Parse results |
||
| 132 | # |
||
| 133 | # 4.a) Split --get_results |
||
| 134 | my @rsltInfos = split /\d+\) -+\n/, $results; |
||
| 135 | shift @rsltInfos; # Throw out first empty line |
||
| 136 | |||
| 137 | # 4.b) Parse results, find those which are running |
||
| 138 | for my $rslt_info (@rsltInfos) {
|
||
| 139 | my @lines = split /\n/, $rslt_info; |
||
| 140 | my @url = grep /^\s+project URL: /,@lines; |
||
| 141 | my $url = $url[0]; |
||
| 142 | $url =~ s/^\s+project URL: //; # Make just the URL itself |
||
| 143 | my @schedstat = grep /^\s+scheduler state: /,@lines; |
||
| 144 | my $schedstat = $schedstat[0]; |
||
| 145 | $schedstat =~ s/^\s+scheduler state: //; |
||
| 146 | my @state = grep /^\s+state: /,@lines; |
||
| 147 | my $state = $state[0]; |
||
| 148 | $state =~ s/^\s+state: //; |
||
| 149 | my @acttask = grep /^\s+active_task_state: /,@lines; |
||
| 150 | my $acttask = $acttask[0]; |
||
| 151 | $acttask =~ s/^\s+active_task_state: //; |
||
| 152 | 1568bf67 | darac | if (( ($schedstat eq "2") && ($state eq "2") && ($acttask eq "1") ) || |
| 153 | de047e8f | Lars Kruse | ( ($schedstat eq "scheduled") && ($state eq "downloaded") && ($acttask eq "EXECUTING") )) {
|
| 154 | 562e63a7 | Paul Saunders | # This is running task |
| 155 | $projects{$url}->{prj_running} += 1;
|
||
| 156 | } |
||
| 157 | } |
||
| 158 | |||
| 159 | |||
| 160 | ######################################################################### |
||
| 161 | # 5. Display output |
||
| 162 | # |
||
| 163 | |||
| 164 | # Project Colours from http://boinc.netsoft-online.com/e107_plugins/forum/forum_viewtopic.php?3 |
||
| 165 | sub rgb($$$){
|
||
| 166 | return sprintf ('%02x%02x%02x', shift, shift, shift);
|
||
| 167 | } |
||
| 168 | my %project_colour = ( |
||
| 169 | 'climatepredition.net' => rgb(0,139,69), |
||
| 170 | 'Predictor@Home' => rgb(135,206,235), |
||
| 171 | 'SETI@home' => rgb(65,105,225), |
||
| 172 | 'Einstein@Home' => rgb(255,165,0), |
||
| 173 | 'Rosetta@home' => rgb(238,130,238), |
||
| 174 | 'PrimeGrid' => rgb(205,197,191), |
||
| 175 | 'LHC@home' => rgb(255,127,80), |
||
| 176 | 'World Community Grid' => rgb(250,128,114), |
||
| 177 | 'BURP' => rgb(0,255,127), |
||
| 178 | 'SZTAKI Desktop Grid' => rgb(205,79,57), |
||
| 179 | 'uFluids' => rgb(0,0,0), |
||
| 180 | 'SIMAP' => rgb(143,188,143), |
||
| 181 | 'Folding@Home' =>rgb(153,50,204), |
||
| 182 | 'MalariaControl' => rgb(30,144,255), |
||
| 183 | 'The Lattice Project' => rgb(0,100,0), |
||
| 184 | 'Pirates@Home' => rgb(127,255,0), |
||
| 185 | 'BBC Climate Change Experiment' => rgb(205,173,0), |
||
| 186 | 'Leiden Classical' => rgb(140,34,34), |
||
| 187 | 'SETI@home Beta' => rgb(152,245,255), |
||
| 188 | 'RALPH@Home' => rgb(250,240,230), |
||
| 189 | 'QMC@HOME' => rgb(144,238,144), |
||
| 190 | 'XtremLab' => rgb(130,130,130), |
||
| 191 | 'HashClash' => rgb(255,105,180), |
||
| 192 | 'cpdn seasonal' => rgb(255,255,255), |
||
| 193 | 'Chess960@Home Alpha' => rgb(165,42,42), |
||
| 194 | 'vtu@home' => rgb(255,0,0), |
||
| 195 | 'LHC@home alpha' => rgb(205,133,63), |
||
| 196 | 'TANPAKU' => rgb(189,183,107), |
||
| 197 | 'other' => rgb(255,193,37), |
||
| 198 | 'Rectilinear Crossing Number' => rgb(83,134,139), |
||
| 199 | 'Nano-Hive@Home' => rgb(193,205,193), |
||
| 200 | 'Spinhenge@home' => rgb(255,240,245), |
||
| 201 | 'RieselSieve' => rgb(205,183,158), |
||
| 202 | 'Project Neuron' => rgb(139,58,98), |
||
| 203 | 'RenderFarm@Home' => rgb(210,105,30), |
||
| 204 | 'Docking@Home' => rgb(178,223,238), |
||
| 205 | 'proteins@home' => rgb(0,0,255), |
||
| 206 | 'DepSpid' => rgb(139,90,43), |
||
| 207 | 'ABC@home' => rgb(222,184,135), |
||
| 208 | 'BOINC alpha test' => rgb(245,245,220), |
||
| 209 | 'WEP-M+2' => rgb(0,250,154), |
||
| 210 | 'Zivis Superordenador Ciudadano' => rgb(255,239,219), |
||
| 211 | 'SciLINC' => rgb(240,248,255), |
||
| 212 | 'APS@Home' => rgb(205,91,69), |
||
| 213 | 'PS3GRID' => rgb(0,139,139), |
||
| 214 | 'Superlink@Technion' => rgb(202,255,112), |
||
| 215 | 'BRaTS@Home' => rgb(255,106,106), |
||
| 216 | 'Cosmology@Home' => rgb(240,230,140), |
||
| 217 | 'SHA 1 Collision Search' => rgb(255,250,205), |
||
| 218 | ); |
||
| 219 | |||
| 220 | |||
| 221 | if ( (defined $ARGV[0]) && ($ARGV[0] eq "config") ) {
|
||
| 222 | # |
||
| 223 | # 5.a) Display config |
||
| 224 | # |
||
| 225 | |||
| 226 | if (defined $HOST) {
|
||
| 227 | print "host_name $HOST\n"; |
||
| 228 | } |
||
| 229 | |||
| 230 | print "graph_title Running BOINC processes\n"; |
||
| 231 | print "graph_category BOINC\n"; |
||
| 232 | print "graph_args --base 1000 -l 0\n"; |
||
| 233 | print "graph_vlabel BOINC applications\n"; |
||
| 234 | 5c9228a9 | Paul Saunders | print "graph_total Total\n"; |
| 235 | 562e63a7 | Paul Saunders | |
| 236 | # First project is AREA, next are STACK |
||
| 237 | # Not nice, but fast: |
||
| 238 | my $prj1 = shift @projects; |
||
| 239 | print "$projects{$prj1}->{prj_var}.label $projects{$prj1}->{prj_name}\n";
|
||
| 240 | if (exists $project_colour{$projects{$prj1}->{prj_name}}){
|
||
| 241 | print "$projects{$prj1}->{prj_var}.colour $project_colour{$projects{$prj1}->{prj_name}}\n";
|
||
| 242 | } |
||
| 243 | print "$projects{$prj1}->{prj_var}.draw AREA\n";
|
||
| 244 | print "$projects{$prj1}->{prj_var}.type GAUGE\n";
|
||
| 245 | |||
| 246 | for my $prjN (@projects) {
|
||
| 247 | print "$projects{$prjN}->{prj_var}.label $projects{$prjN}->{prj_name}\n";
|
||
| 248 | if (exists $project_colour{$projects{$prjN}->{prj_name}}){
|
||
| 249 | print "$projects{$prjN}->{prj_var}.colour $project_colour{$projects{$prjN}->{prj_name}}\n";
|
||
| 250 | } |
||
| 251 | print "$projects{$prjN}->{prj_var}.draw STACK\n";
|
||
| 252 | print "$projects{$prjN}->{prj_var}.type GAUGE\n";
|
||
| 253 | } |
||
| 254 | |||
| 255 | exit 0; |
||
| 256 | } |
||
| 257 | |||
| 258 | # |
||
| 259 | # 5.b) Display running state of projects |
||
| 260 | # |
||
| 261 | |||
| 262 | for my $prjN (@projects) {
|
||
| 263 | print "$projects{$prjN}->{prj_var}.value $projects{$prjN}->{prj_running}\n";
|
||
| 264 | } |
||
| 265 | |||
| 266 | exit 0; |
||
| 267 | |||
| 268 | |||
| 269 | ######################################################################### |
||
| 270 | # perldoc section |
||
| 271 | |||
| 272 | =head1 NAME |
||
| 273 | |||
| 274 | boinc_projs - Munin plugin to monitor actively running BOINC projects. |
||
| 275 | |||
| 276 | =head1 APPLICABLE SYSTEMS |
||
| 277 | |||
| 278 | Linux machines running BOINC and munin-node |
||
| 279 | |||
| 280 | - or - |
||
| 281 | |||
| 282 | Linux servers (running munin-node) used to collect data from other systems |
||
| 283 | which are running BOINC, but not running munin-node (e.g. non-Linux systems) |
||
| 284 | |||
| 285 | =head1 CONFIGURATION |
||
| 286 | |||
| 287 | Following configuration variables are supported: |
||
| 288 | |||
| 289 | =over 12 |
||
| 290 | |||
| 291 | =item B<boinccmd> |
||
| 292 | |||
| 293 | command-line control program (default: boinccmd) |
||
| 294 | |||
| 295 | =item B<host> |
||
| 296 | |||
| 297 | Host to query (default: none) |
||
| 298 | |||
| 299 | =item B<port> |
||
| 300 | |||
| 301 | GUI RPC port (default: none = use BOINC-default) |
||
| 302 | |||
| 303 | =item B<boincdir> |
||
| 304 | |||
| 305 | Directory containing appropriate file gui_rpc_auth.cfg (default: none) |
||
| 306 | |||
| 307 | =item B<password> |
||
| 308 | |||
| 309 | Password for BOINC (default: none) |
||
| 310 | |||
| 311 | =back |
||
| 312 | |||
| 313 | =head2 B<Security Consideration:> |
||
| 314 | |||
| 315 | Using of variable B<password> poses a security risk. Even if the Munin |
||
| 316 | configuration file for this plugin containing BOINC-password is properly |
||
| 317 | protected, the password is exposed as environment variable and finally passed |
||
| 318 | to boinccmd as a parameter. It is therefore possible for local users of the |
||
| 319 | machine running this plugin to eavesdrop the BOINC password. |
||
| 320 | |||
| 321 | Using of variable password is therefore strongly discouraged and is left here |
||
| 322 | as a legacy option and for testing purposes. |
||
| 323 | |||
| 324 | It should be always possible to use B<boincdir> variable instead - in such case |
||
| 325 | the file gui_rpc_auth.cfg is read by boinccmd binary directly. |
||
| 326 | If this plugin is used to fetch data from remote system, the gui_rpc_auth.cfg |
||
| 327 | can be copied to special directory in a secure way (e.g. via scp) and properly |
||
| 328 | protected by file permissions. |
||
| 329 | |||
| 330 | =head1 INTERPRETATION |
||
| 331 | |||
| 332 | This plugin shows the number of currently running BOINC tasks on the machine. |
||
| 333 | If machine is attached to several BOINC projects, data for all these projects |
||
| 334 | are displayed. |
||
| 335 | |||
| 336 | =head1 EXAMPLES |
||
| 337 | |||
| 338 | =head2 Local BOINC Example |
||
| 339 | |||
| 340 | BOINC is running on local machine. The BOINC binaries are installed in |
||
| 341 | F</opt/boinc/custom-6.10.1/>, the BOINC is running in directory |
||
| 342 | F</usr/local/boinc/> under username boinc, group boinc and the password is used |
||
| 343 | to protect access to BOINC: |
||
| 344 | |||
| 345 | [boinc_*] |
||
| 346 | group boinc |
||
| 347 | env.boinccmd /opt/boinc/custom-6.10.1/boinccmd |
||
| 348 | env.boincdir /usr/local/boinc |
||
| 349 | |||
| 350 | =head2 Remote BOINC Example |
||
| 351 | |||
| 352 | BOINC is running on 2 remote machines C<foo> and C<bar>. |
||
| 353 | On the local machine the binary of command-line interface is installed in |
||
| 354 | directory F</usr/local/bin/>. |
||
| 355 | The BOINC password used on the remote machine C<foo> is stored in file |
||
| 356 | F</etc/munin/boinc/foo/gui_rpc_auth.cfg>. |
||
| 357 | The BOINC password used on the remote machine C<bar> is stored in file |
||
| 358 | F</etc/munin/boinc/bar/gui_rpc_auth.cfg>. |
||
| 359 | These files are owned and readable by root, readable by group munin and not |
||
| 360 | readable by others. |
||
| 361 | There are 2 symbolic links to this plugin created in the munin plugins |
||
| 362 | 715d059c | Diego Elio Pettenò | directory (usually F</etc/munin/plugins/>): F<boincprojs_foo> and |
| 363 | F<boincprojs_bar> |
||
| 364 | 562e63a7 | Paul Saunders | |
| 365 | 715d059c | Diego Elio Pettenò | [boincprojs_foo] |
| 366 | 562e63a7 | Paul Saunders | group munin |
| 367 | env.boinccmd /usr/local/bin/boinccmd |
||
| 368 | env.host foo |
||
| 369 | env.boincdir /etc/munin/boinc/foo |
||
| 370 | |||
| 371 | 715d059c | Diego Elio Pettenò | [boincprojs_bar] |
| 372 | 562e63a7 | Paul Saunders | group munin |
| 373 | env.boinccmd /usr/local/bin/boinccmd |
||
| 374 | env.host bar |
||
| 375 | env.boincdir /etc/munin/boinc/bar |
||
| 376 | |||
| 377 | 715d059c | Diego Elio Pettenò | This way the plugin can be used by Munin as a virtual node, akin to |
| 378 | SNMP and IPMI plugins. |
||
| 379 | 562e63a7 | Paul Saunders | |
| 380 | =head1 BUGS |
||
| 381 | |||
| 382 | There is no C<autoconf> capability at the moment. This is due to the fact, that |
||
| 383 | BOINC installations may vary over different systems, sometimes using default |
||
| 384 | directory from distribution (e.g. F</var/lib/boinc/> in Debian or Ubuntu), but |
||
| 385 | often running in user directories or in other separate directories. |
||
| 386 | Also the user-ID under which BOINC runs often differs. |
||
| 387 | Under these circumstances the C<autoconf> would be either lame or too |
||
| 388 | complicated. |
||
| 389 | |||
| 390 | =head1 AUTHOR |
||
| 391 | |||
| 392 | Palo M. <palo.gm@gmail.com> |
||
| 393 | |||
| 394 | =head1 LICENSE |
||
| 395 | |||
| 396 | GPLv3 |
||
| 397 | |||
| 398 | =cut |
||
| 399 | |||
| 400 | # vim:syntax=perl |
