Projet

Général

Profil

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

root / plugins / other / boinc_wus @ 6ce22c9d

Historique | Voir | Annoter | Télécharger (12,2 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
# License: GPLv3 <http://www.gnu.org/licenses/gpl-3.0.txt>
9
#
10
#
11
# Parameters supported:
12
# 	config
13
#
14
#
15
# Configurable variables
16
#       boinccmd   - command-line control program (default: boinc_cmd)
17
# 	host       - Host to query (default: none)
18
#       port       - GUI RPC port (default: none = use BOINC-default)
19
#       boincdir   - Directory containing appropriate password file
20
#                    gui_rpc_auth.cfg (default: none)
21
#       verbose    - Whether display more detailed states (default: 0)
22
#       password   - Password for BOINC (default: none) !!! UNSAFE !!!
23
#
24
#
25
# $Log$
26
#
27
# Revision 1.0  2009/09/13  Palo M.
28
#   Add documentation and license information
29
#   Ready to publish on Munin Exchange
30
# Revision 0.9  2009/09/13  Palo M.
31
#   Add possibility to read password from file
32
# Revision 0.8  2009/09/12  Palo M.
33
#   Update default binary name: boinc_cmd -> boinccmd
34
# Revision 0.7  2008/08/29  Palo M.
35
#   Creation - Attempt to port functionality from C++ code
36
#
37
# (Revisions 0.1 - 0.6) were done in C++
38
#
39
#
40
#
41
# Magic markers:
42
#%# family=contrib
43

    
44
use strict;
45

    
46

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

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

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

    
89
#########################################################################
90
# 4. Fetch all needed data from BOINC-client with single call
91
#
92
my $prj_status = "";
93
my $results = "";
94

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

    
104
  @sections = split /=+ Results =+\n/, $simpleGuiInfo;
105
  @section1 = split /=+ [A-z]+ =+\n/, $sections[1];
106
  $results = $section1[0];
107
}
108

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

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

    
132
# 5.b) Parse results, check their states
133
my @rsltInfos = split /\d+\) -+\n/, $results;
134
shift @rsltInfos; # Throw out first empty line
135

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

    
222

    
223
#########################################################################
224
# 6. Display output
225
#
226

    
227
if ( (defined $ARGV[0]) && ($ARGV[0] eq "config") ) {
228
#
229
# 6.a) Display config
230
#
231

    
232
  if (defined $HOST) {
233
    print "host_name $HOST\n";
234
  }
235

    
236
  print "graph_title BOINC work status\n";
237
  print "graph_category BOINC\n";
238
  print "graph_args --base 1000 -l 0\n";
239
  print "graph_vlabel Workunits\n";
240
  print "graph_total total\n";
241

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

    
276
  exit 0;
277
}
278

    
279
#
280
# 6.b) Display state of WUs
281
#
282

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

    
300
exit 0;
301

    
302

    
303
#########################################################################
304
# perldoc section
305

    
306
=head1 NAME
307

    
308
boinc_wus - Munin plugin to monitor states of all BOINC WUs
309

    
310
=head1 APPLICABLE SYSTEMS
311

    
312
Linux machines running BOINC and munin-node
313

    
314
- or -
315

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

    
319
=head1 CONFIGURATION
320

    
321
Following configuration variables are supported:
322

    
323
=over 12
324

    
325
=item B<boinccmd>
326

    
327
command-line control program (default: boinccmd)
328

    
329
=item B<host>
330

    
331
Host to query (default: none)
332

    
333
=item B<port>
334

    
335
GUI RPC port (default: none = use BOINC-default)
336

    
337
=item B<boincdir>
338

    
339
Directory containing appropriate file gui_rpc_auth.cfg (default: none)
340

    
341
=item B<verbose>
342

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

    
345
=item B<password>
346

    
347
Password for BOINC (default: none) 
348

    
349
=back
350

    
351
=head2 B<Security Consideration:>
352

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

    
359
Using of variable password is therefore strongly discouraged and is left here 
360
as a legacy option and for testing purposes.
361

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

    
368
=head1 INTERPRETATION
369

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

    
375
If the variable B<verbose> is used, additionally also states 
376
C<Computation Error> and C<Aborted> are shown separately (they are included in 
377
C<other> otherwise). 
378

    
379
=head1 EXAMPLES
380

    
381
=head2 Local BOINC Example
382

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

    
388
  [boinc_*]
389
  group boinc
390
  env.boinccmd /opt/boinc/custom-6.10.1/boinccmd
391
  env.boincdir /usr/local/boinc
392
  env.verbose 1
393

    
394
=head2 Remote BOINC Example
395

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

    
409
  [snmp_foo_boinc*]
410
  group munin
411
  env.boinccmd /usr/local/bin/boinccmd
412
  env.host foo
413
  env.boincdir /etc/munin/boinc/foo
414

    
415
  [snmp_bar_boinc*]
416
  group munin
417
  env.boinccmd /usr/local/bin/boinccmd
418
  env.host bar
419
  env.boincdir /etc/munin/boinc/bar
420

    
421
This way the plugin can be used by Munin the same way as the Munin plugins 
422
utilizng SNMP (although this plugin itself does not use SNMP).
423

    
424
=head1 BUGS
425

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

    
434
=head1 AUTHOR
435

    
436
Palo M. <palo.gm@gmail.com>
437

    
438
=head1 LICENSE
439

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

    
442
=cut
443

    
444
# vim:syntax=perl