Projet

Général

Profil

Paste
Télécharger au format
Statistiques
| Branche: | Révision:

root / plugins / boinc / boinc_projs @ de047e8f

Historique | Voir | Annoter | Télécharger (12,7 ko)

1
#!/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
# 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
# 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
  if (( ($schedstat eq "2") && ($state eq "2") && ($acttask eq "1") ) ||
153
      ( ($schedstat eq "scheduled") && ($state eq "downloaded") && ($acttask eq "EXECUTING") )) {
154
    # 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
  print "graph_total Total\n";
235

    
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
directory (usually F</etc/munin/plugins/>): F<boincprojs_foo> and 
363
F<boincprojs_bar>
364

    
365
  [boincprojs_foo]
366
  group munin
367
  env.boinccmd /usr/local/bin/boinccmd
368
  env.host foo
369
  env.boincdir /etc/munin/boinc/foo
370

    
371
  [boincprojs_bar]
372
  group munin
373
  env.boinccmd /usr/local/bin/boinccmd
374
  env.host bar
375
  env.boincdir /etc/munin/boinc/bar
376

    
377
This way the plugin can be used by Munin as a virtual node, akin to
378
SNMP and IPMI plugins.
379

    
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