Projet

Général

Profil

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

root / plugins / boinc / boinc_wus @ 17f78427

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

1
#!/usr/bin/perl -w
2
#
3
# boinc_wus - Munin plugin to monitor states of all BOINC WUs
4
#
5
# Run 'perldoc boinc_wus' 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: boinc_cmd)
18
# 	host       - Host to query (default: none)
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
#       verbose    - Whether display more detailed states (default: 0)
23
#       password   - Password for BOINC (default: none) !!! UNSAFE !!!
24
#
25
#
26
# $Log$
27
#
28
# Revision 1.1  2011/03/22  Paul Saunders
29
#   Update for BOINC 6.12
30
#   Add colours from http://boinc.netsoft-online.com/e107_plugins/forum/forum_viewtopic.php?3
31
# Revision 1.0  2009/09/13  Palo M.
32
#   Add documentation and license information
33
#   Ready to publish on Munin Exchange
34
# Revision 0.9  2009/09/13  Palo M.
35
#   Add possibility to read password from file
36
# Revision 0.8  2009/09/12  Palo M.
37
#   Update default binary name: boinc_cmd -> boinccmd
38
# Revision 0.7  2008/08/29  Palo M.
39
#   Creation - Attempt to port functionality from C++ code
40
#
41
# (Revisions 0.1 - 0.6) were done in C++
42
#
43
#
44
#
45
# Magic markers:
46
#%# family=contrib
47

    
48
use strict;
49

    
50

    
51
#########################################################################
52
# 1. Parse configuration variables
53
#
54
my $BOINCCMD = exists $ENV{'boinccmd'} ? $ENV{'boinccmd'} : "boinccmd";
55
my $HOST = exists $ENV{'host'} ? $ENV{'host'} : undef;
56
my $PORT = exists $ENV{'port'} ? $ENV{'port'} : undef;
57
my $PASSWORD = exists $ENV{'password'} ? $ENV{'password'} : undef;
58
my $BOINCDIR = exists $ENV{'boincdir'} ? $ENV{'boincdir'} : undef;
59
my $VERBOSE = exists $ENV{'verbose'} ? $ENV{'verbose'} : "0";
60

    
61
#########################################################################
62
# 2. Basic executable
63
#
64
if (defined $HOST) {
65
  $BOINCCMD .= " --host $HOST";
66
  if (defined $PORT) {
67
    $BOINCCMD .= ":$PORT";
68
  }
69
}
70
if (defined $PASSWORD) {
71
  $BOINCCMD .= " --passwd $PASSWORD";
72
}
73
if (defined $BOINCDIR) {
74
  chdir $BOINCDIR;
75
}
76

    
77
#########################################################################
78
# 3. Initialize output structure
79
#
80
my $wu_states = {
81
		 wu_run => 0,
82
		 wu_pre => 0,
83
		 wu_sus => 0,
84
		 wu_dld => 0,
85
		 wu_rtr => 0,
86
		 wu_dlg => 0,
87
		 wu_upl => 0,
88
		 wu_err => 0,
89
		 wu_abt => 0,
90
		 wu_other => 0
91
		};
92

    
93
#########################################################################
94
# 4. Fetch all needed data from BOINC-client with single call
95
#
96
my $prj_status = "";
97
my $results = "";
98

    
99
my $simpleGuiInfo = `$BOINCCMD --get_simple_gui_info 2>/dev/null`;
100
if ($simpleGuiInfo ne "") {
101
  # Some data were retrieved, so let's split them
102
  my @sections;
103
  my @section1;
104
  @sections = split /=+ Projects =+\n/, $simpleGuiInfo;
105
  @section1 = split /=+ [A-z]+ =+\n/, $sections[1];
106
  $prj_status = $section1[0];
107

    
108
  @sections = split /=+ (?:Results|Tasks) =+\n/, $simpleGuiInfo;
109
  @section1 = split /=+ [A-z]+ =+\n/, $sections[1];
110
  $results = $section1[0];
111
}
112

    
113
#########################################################################
114
# 5. Parse BOINC data
115
#
116
# 5.a) Create project info structure
117
my @prjInfos = split /\d+\) -+\n/, $prj_status;
118
shift @prjInfos; # Throw out first empty line
119

    
120
my @susp_projects;    # array of suspended projects
121
for my $prj_info (@prjInfos) {
122
  my @lines = split /\n/, $prj_info;
123
  my @prjURL = grep /^\s+master URL: /,@lines;
124
  if ($#prjURL != 0) {die "Unexpected output from boinccmd"; }
125
  my $prjURL =$prjURL[0];
126
  $prjURL =~ s/^\s+master URL: //;
127
  my @suspGUI = grep /^\s+suspended via GUI: /,@lines;
128
  if ($#suspGUI != 0) {die "Unexpected output from boinccmd"; }
129
  my $suspGUI =$suspGUI[0];
130
  $suspGUI =~ s/^\s+suspended via GUI: //;
131
  if ($suspGUI eq "yes") {
132
    push @susp_projects, $prjURL
133
  }
134
}
135

    
136
# 5.b) Parse results, check their states
137
my @rsltInfos = split /\d+\) -+\n/, $results;
138
shift @rsltInfos; # Throw out first empty line
139

    
140
for my $rslt_info (@rsltInfos) {
141
  my @lines = split /\n/, $rslt_info;
142
  my @schedstat = grep /^\s+scheduler state: /,@lines;
143
  my $schedstat = $schedstat[0];
144
  $schedstat =~ s/^\s+scheduler state: //;
145
  my @state = grep /^\s+state: /,@lines;
146
  my $state = $state[0];
147
  $state =~ s/^\s+state: //;
148
  my @acttask = grep /^\s+active_task_state: /,@lines;
149
  my $acttask = $acttask[0];
150
  $acttask =~ s/^\s+active_task_state: //;
151
  my @suspGUI = grep /^\s+suspended via GUI: /,@lines;
152
  my $suspGUI =$suspGUI[0];
153
  $suspGUI =~ s/^\s+suspended via GUI: //;
154
  my @prjURL = grep /^\s+project URL: /,@lines;
155
  my $prjURL =$prjURL[0];
156
  $prjURL =~ s/^\s+project URL: //;
157
  if ($suspGUI eq "yes") {
158
    $wu_states->{wu_sus} += 1;
159
    next;
160
  }
161
  my @suspPRJ = grep /^$prjURL$/,@susp_projects;
162
  if ($#suspPRJ == 0) {
163
    $wu_states->{wu_sus} += 1;
164
    next;
165
  }
166
  if ($state eq "1") {
167
    # RESULT_FILES_DOWNLOADING
168
    $wu_states->{wu_dlg} += 1;
169
    next;
170
  }
171
  if ($state eq "2") {
172
    # RESULT_FILES_DOWNLOADED
173
    if ($schedstat eq "0") {
174
      # CPU_SCHED_UNINITIALIZED   0
175
      $wu_states->{wu_dld} += 1;
176
      next;
177
    }
178
    if ($schedstat eq "1") {
179
      # CPU_SCHED_PREEMPTED       1
180
      $wu_states->{wu_pre} += 1;
181
      next;
182
    }
183
    if ($schedstat eq "2") {
184
      # CPU_SCHED_SCHEDULED       2
185
      if ($acttask eq "1") {
186
	# PROCESS_EXECUTING       1
187
	$wu_states->{wu_run} += 1;
188
	next;
189
      }
190
      if ( ($acttask eq "0") || ($acttask eq "9") ) {
191
	# PROCESS_UNINITIALIZED   0
192
	# PROCESS_SUSPENDED       9
193
	# suspended by "user active"?
194
	$wu_states->{wu_sus} += 1;
195
	next;
196
      }
197
      $wu_states->{wu_other} += 1;
198
      next;
199
    }
200
    $wu_states->{wu_other} += 1;
201
    next;
202
  }
203
  if ($state eq "3") {
204
    # RESULT_COMPUTE_ERROR
205
    $wu_states->{wu_err} += 1;
206
    next;
207
  }
208
  if ($state eq "4") {
209
    # RESULT_FILES_UPLOADING
210
    $wu_states->{wu_upl} += 1;
211
    next;
212
  }
213
  if ($state eq "5") {
214
    # RESULT_FILES_UPLOADED
215
    $wu_states->{wu_rtr} += 1;
216
    next;
217
  }
218
  if ($state eq "6") {
219
    # RESULT_ABORTED
220
    $wu_states->{wu_abt} += 1;
221
    next;
222
  }
223
  $wu_states->{wu_other} += 1;
224
}
225

    
226

    
227
#########################################################################
228
# 6. Display output
229
#
230

    
231
if ( (defined $ARGV[0]) && ($ARGV[0] eq "config") ) {
232
#
233
# 6.a) Display config
234
#
235

    
236
  if (defined $HOST) {
237
    print "host_name $HOST\n";
238
  }
239

    
240
  print "graph_title BOINC work status\n";
241
  print "graph_category htc\n";
242
  print "graph_args --base 1000 -l 0\n";
243
  print "graph_vlabel Workunits\n";
244
  print "graph_total total\n";
245

    
246
  # First state is AREA, next are STACK
247
  print "wu_run.label Running\n";
248
  print "wu_run.draw AREA\n";
249
  print "wu_run.type GAUGE\n";
250
  print "wu_pre.label Preempted\n";
251
  print "wu_pre.draw STACK\n";
252
  print "wu_pre.type GAUGE\n";
253
  print "wu_sus.label Suspended\n";
254
  print "wu_sus.draw STACK\n";
255
  print "wu_sus.type GAUGE\n";
256
  print "wu_dld.label Ready to run\n";
257
  print "wu_dld.draw STACK\n";
258
  print "wu_dld.type GAUGE\n";
259
  print "wu_rtr.label Ready to report\n";
260
  print "wu_rtr.draw STACK\n";
261
  print "wu_rtr.type GAUGE\n";
262
  print "wu_dlg.label Downloading\n";
263
  print "wu_dlg.draw STACK\n";
264
  print "wu_dlg.type GAUGE\n";
265
  print "wu_upl.label Uploading\n";
266
  print "wu_upl.draw STACK\n";
267
  print "wu_upl.type GAUGE\n";
268
  if ($VERBOSE ne "0") {
269
    print "wu_err.label Computation Error\n";
270
    print "wu_err.draw STACK\n";
271
    print "wu_err.type GAUGE\n";
272
    print "wu_abt.label Aborted\n";
273
    print "wu_abt.draw STACK\n";
274
    print "wu_abt.type GAUGE\n";
275
  }
276
  print "wu_other.label other states\n";
277
  print "wu_other.draw STACK\n";
278
  print "wu_other.type GAUGE\n";
279

    
280
  exit 0;
281
}
282

    
283
#
284
# 6.b) Display state of WUs
285
#
286

    
287
print "wu_run.value $wu_states->{wu_run}\n";
288
print "wu_pre.value $wu_states->{wu_pre}\n";
289
print "wu_sus.value $wu_states->{wu_sus}\n";
290
print "wu_dld.value $wu_states->{wu_dld}\n";
291
print "wu_rtr.value $wu_states->{wu_rtr}\n";
292
print "wu_dlg.value $wu_states->{wu_dlg}\n";
293
print "wu_upl.value $wu_states->{wu_upl}\n";
294
if ($VERBOSE ne "0") {
295
  print "wu_err.value $wu_states->{wu_err}\n";
296
  print "wu_abt.value $wu_states->{wu_abt}\n";
297
  print "wu_other.value $wu_states->{wu_other}\n";
298
}
299
else {
300
  my $other = $wu_states->{wu_err} + $wu_states->{wu_abt} + $wu_states->{wu_other};
301
  print "wu_other.value $other\n";
302
}
303

    
304
exit 0;
305

    
306

    
307
#########################################################################
308
# perldoc section
309

    
310
=head1 NAME
311

    
312
boinc_wus - Munin plugin to monitor states of all BOINC WUs
313

    
314
=head1 APPLICABLE SYSTEMS
315

    
316
Linux machines running BOINC and munin-node
317

    
318
- or -
319

    
320
Linux servers (running munin-node) used to collect data from other systems
321
which are running BOINC, but not running munin-node (e.g. non-Linux systems)
322

    
323
=head1 CONFIGURATION
324

    
325
Following configuration variables are supported:
326

    
327
=over 12
328

    
329
=item B<boinccmd>
330

    
331
command-line control program (default: boinccmd)
332

    
333
=item B<host>
334

    
335
Host to query (default: none)
336

    
337
=item B<port>
338

    
339
GUI RPC port (default: none = use BOINC-default)
340

    
341
=item B<boincdir>
342

    
343
Directory containing appropriate file gui_rpc_auth.cfg (default: none)
344

    
345
=item B<verbose>
346

    
347
Display unusual states details (default: 0 = Summarize unusual states as C<other>)
348

    
349
=item B<password>
350

    
351
Password for BOINC (default: none)
352

    
353
=back
354

    
355
=head2 B<Security Consideration:>
356

    
357
Using of variable B<password> poses a security risk. Even if the Munin
358
configuration file for this plugin containing BOINC-password is properly
359
protected, the password is exposed as environment variable and finally passed
360
to boinccmd as a parameter. It is therefore possible for local users of the
361
machine running this plugin to eavesdrop the BOINC password.
362

    
363
Using of variable password is therefore strongly discouraged and is left here
364
as a legacy option and for testing purposes.
365

    
366
It should be always possible to use B<boincdir> variable instead - in such case
367
the file gui_rpc_auth.cfg is read by boinccmd binary directly.
368
If this plugin is used to fetch data from remote system, the gui_rpc_auth.cfg
369
can be copied to special directory in a secure way (e.g. via scp) and properly
370
protected by file permissions.
371

    
372
=head1 INTERPRETATION
373

    
374
This plugin shows how many BOINC workunits are in all the various states.
375
The most important states C<Running>, C<Preempted>, C<Suspended>,
376
C<Ready to run>, C<Ready to report>, C<Downloading> and C<Uploading> are always
377
displayed. All other states are shown as C<other>.
378

    
379
If the variable B<verbose> is used, additionally also states
380
C<Computation Error> and C<Aborted> are shown separately (they are included in
381
C<other> otherwise).
382

    
383
=head1 EXAMPLES
384

    
385
=head2 Local BOINC Example
386

    
387
BOINC is running on local machine. The BOINC binaries are installed in
388
F</opt/boinc/custom-6.10.1/>, the BOINC is running in directory
389
F</usr/local/boinc/> under username boinc, group boinc and the password is used
390
to protect access to BOINC:
391

    
392
  [boinc_*]
393
  group boinc
394
  env.boinccmd /opt/boinc/custom-6.10.1/boinccmd
395
  env.boincdir /usr/local/boinc
396
  env.verbose 1
397

    
398
=head2 Remote BOINC Example
399

    
400
BOINC is running on 2 remote machines C<foo> and C<bar>.
401
On the local machine the binary of command-line interface is installed in
402
directory F</usr/local/bin/>.
403
The BOINC password used on the remote machine C<foo> is stored in file
404
F</etc/munin/boinc/foo/gui_rpc_auth.cfg>.
405
The BOINC password used on the remote machine C<bar> is stored in file
406
F</etc/munin/boinc/bar/gui_rpc_auth.cfg>.
407
These files are owned and readable by root, readable by group munin and not
408
readable by others.
409
There are 2 symbolic links to this plugin created in the munin plugins
410
directory (usually F</etc/munin/plugins/>): F<snmp_foo_boincwus> and
411
F<snmp_bar_boincwus>
412

    
413
  [snmp_foo_boinc*]
414
  group munin
415
  env.boinccmd /usr/local/bin/boinccmd
416
  env.host foo
417
  env.boincdir /etc/munin/boinc/foo
418

    
419
  [snmp_bar_boinc*]
420
  group munin
421
  env.boinccmd /usr/local/bin/boinccmd
422
  env.host bar
423
  env.boincdir /etc/munin/boinc/bar
424

    
425
This way the plugin can be used by Munin the same way as the Munin plugins
426
utilizng SNMP (although this plugin itself does not use SNMP).
427

    
428
=head1 BUGS
429

    
430
There is no C<autoconf> capability at the moment. This is due to the fact, that
431
BOINC installations may vary over different systems, sometimes using default
432
directory from distribution (e.g. F</var/lib/boinc/> in Debian or Ubuntu), but
433
often running in user directories or in other separate directories.
434
Also the user-ID under which BOINC runs often differs.
435
Under these circumstances the C<autoconf> would be either lame or too
436
complicated.
437

    
438
=head1 AUTHOR
439

    
440
Palo M. <palo.gm@gmail.com>
441

    
442
=head1 LICENSE
443

    
444
GPLv3 L<http://www.gnu.org/licenses/gpl-3.0.txt>
445

    
446
=cut
447

    
448
# vim:syntax=perl