root / plugins / other / boinc_projs @ 10eb3992
Historique | Voir | Annoter | Télécharger (9,34 ko)
| 1 | 10eb3992 | Palo M | #!/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 | # 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: boinccmd) |
||
| 17 | # host - Host to query (default: none = use local host) |
||
| 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 | # password - Password for BOINC (default: none) !!! UNSAFE !!! |
||
| 22 | # |
||
| 23 | # |
||
| 24 | # $Log$ |
||
| 25 | # |
||
| 26 | # Revision 1.0 2009/09/13 Palo M. |
||
| 27 | # Add documentation and license information |
||
| 28 | # Ready to publish on Munin Exchange |
||
| 29 | # Revision 0.9 2009/09/13 Palo M. |
||
| 30 | # Add possibility to read password from file |
||
| 31 | # Revision 0.8 2009/09/12 Palo M. |
||
| 32 | # Update default binary name: boinc_cmd -> boinccmd |
||
| 33 | # Revision 0.7 2008/08/29 Palo M. |
||
| 34 | # Creation - Attempt to port functionality from C++ code |
||
| 35 | # |
||
| 36 | # (Revisions 0.1 - 0.6) were done in C++ |
||
| 37 | # |
||
| 38 | # |
||
| 39 | # |
||
| 40 | # Magic markers: |
||
| 41 | #%# family=contrib |
||
| 42 | |||
| 43 | use strict; |
||
| 44 | |||
| 45 | |||
| 46 | ######################################################################### |
||
| 47 | # 1. Parse configuration variables |
||
| 48 | # |
||
| 49 | my $BOINCCMD = exists $ENV{'boinccmd'} ? $ENV{'boinccmd'} : "boinccmd";
|
||
| 50 | my $HOST = exists $ENV{'host'} ? $ENV{'host'} : undef;
|
||
| 51 | my $PORT = exists $ENV{'port'} ? $ENV{'port'} : undef;
|
||
| 52 | my $PASSWORD = exists $ENV{'password'} ? $ENV{'password'} : undef;
|
||
| 53 | my $BOINCDIR = exists $ENV{'boincdir'} ? $ENV{'boincdir'} : undef;
|
||
| 54 | |||
| 55 | ######################################################################### |
||
| 56 | # 2. Basic executable |
||
| 57 | # |
||
| 58 | if (defined $HOST) {
|
||
| 59 | $BOINCCMD .= " --host $HOST"; |
||
| 60 | if (defined $PORT) {
|
||
| 61 | $BOINCCMD .= ":$PORT"; |
||
| 62 | } |
||
| 63 | } |
||
| 64 | if (defined $PASSWORD) {
|
||
| 65 | $BOINCCMD .= " --passwd $PASSWORD"; |
||
| 66 | } |
||
| 67 | if (defined $BOINCDIR) {
|
||
| 68 | chdir $BOINCDIR; |
||
| 69 | } |
||
| 70 | |||
| 71 | ######################################################################### |
||
| 72 | # 3. Fetch all needed data from BOINC-client with single call |
||
| 73 | # |
||
| 74 | my $prj_status = ""; |
||
| 75 | my $results = ""; |
||
| 76 | |||
| 77 | my $simpleGuiInfo = `$BOINCCMD --get_simple_gui_info 2>/dev/null`; |
||
| 78 | if ($simpleGuiInfo ne "") {
|
||
| 79 | # Some data were retrieved, so let's split them |
||
| 80 | my @sections; |
||
| 81 | my @section1; |
||
| 82 | @sections = split /=+ Projects =+\n/, $simpleGuiInfo; |
||
| 83 | @section1 = split /=+ [A-z]+ =+\n/, $sections[1]; |
||
| 84 | $prj_status = $section1[0]; |
||
| 85 | |||
| 86 | @sections = split /=+ Results =+\n/, $simpleGuiInfo; |
||
| 87 | @section1 = split /=+ [A-z]+ =+\n/, $sections[1]; |
||
| 88 | $results = $section1[0]; |
||
| 89 | } |
||
| 90 | |||
| 91 | if ($prj_status eq "") { exit -1; }
|
||
| 92 | |||
| 93 | # 3.a) Split --get_project_status into projects |
||
| 94 | my @prjInfos = split /\d+\) -+\n/, $prj_status; |
||
| 95 | shift @prjInfos; # Throw out first empty line |
||
| 96 | |||
| 97 | # 3.b) Fetch project infos |
||
| 98 | my %projects; # Store projects infos here |
||
| 99 | my @projects; # Just to keep the order of projects |
||
| 100 | for my $prj_info (@prjInfos) {
|
||
| 101 | my @lines = split /\n/, $prj_info; |
||
| 102 | my $line1 = shift @lines; # get project name |
||
| 103 | if ($line1 !~ /^\s+name: /) { die "Unexpected output from boinccmd"; }
|
||
| 104 | $line1 =~ s/^\s+name: //; # Make just the project name itself |
||
| 105 | my $line2 = shift @lines; # get project URL |
||
| 106 | if ($line2 !~ /^\s+master URL: /) { die "Unexpected output from boinccmd"; }
|
||
| 107 | $line2 =~ s/^\s+master URL: //; # Make just the URL itself |
||
| 108 | my $prj_url = $line2; |
||
| 109 | my $prj_name = $line1; |
||
| 110 | $line1 =~ s/\@/at/g; |
||
| 111 | $line1 =~ s/[^0-9A-z]/_/g; |
||
| 112 | my $prj_var = "prj_" . $line1; |
||
| 113 | push @projects,$prj_url; |
||
| 114 | $projects{$prj_url} = {
|
||
| 115 | prj_name => $prj_name, |
||
| 116 | prj_var => $prj_var, |
||
| 117 | prj_running => 0 |
||
| 118 | }; |
||
| 119 | } |
||
| 120 | |||
| 121 | |||
| 122 | ######################################################################### |
||
| 123 | # 4. Parse results |
||
| 124 | # |
||
| 125 | # 4.a) Split --get_results |
||
| 126 | my @rsltInfos = split /\d+\) -+\n/, $results; |
||
| 127 | shift @rsltInfos; # Throw out first empty line |
||
| 128 | |||
| 129 | # 4.b) Parse results, find those which are running |
||
| 130 | for my $rslt_info (@rsltInfos) {
|
||
| 131 | my @lines = split /\n/, $rslt_info; |
||
| 132 | my @url = grep /^\s+project URL: /,@lines; |
||
| 133 | my $url = $url[0]; |
||
| 134 | $url =~ s/^\s+project URL: //; # Make just the URL itself |
||
| 135 | my @schedstat = grep /^\s+scheduler state: /,@lines; |
||
| 136 | my $schedstat = $schedstat[0]; |
||
| 137 | $schedstat =~ s/^\s+scheduler state: //; |
||
| 138 | my @state = grep /^\s+state: /,@lines; |
||
| 139 | my $state = $state[0]; |
||
| 140 | $state =~ s/^\s+state: //; |
||
| 141 | my @acttask = grep /^\s+active_task_state: /,@lines; |
||
| 142 | my $acttask = $acttask[0]; |
||
| 143 | $acttask =~ s/^\s+active_task_state: //; |
||
| 144 | if ( ($schedstat eq "2") && ($state eq "2") && ($acttask eq "1") ) {
|
||
| 145 | # This is running task |
||
| 146 | $projects{$url}->{prj_running} += 1;
|
||
| 147 | } |
||
| 148 | } |
||
| 149 | |||
| 150 | |||
| 151 | ######################################################################### |
||
| 152 | # 5. Display output |
||
| 153 | # |
||
| 154 | |||
| 155 | if ( (defined $ARGV[0]) && ($ARGV[0] eq "config") ) {
|
||
| 156 | # |
||
| 157 | # 5.a) Display config |
||
| 158 | # |
||
| 159 | |||
| 160 | if (defined $HOST) {
|
||
| 161 | print "host_name $HOST\n"; |
||
| 162 | } |
||
| 163 | |||
| 164 | print "graph_title Running BOINC processes\n"; |
||
| 165 | print "graph_category BOINC\n"; |
||
| 166 | print "graph_args --base 1000 -l 0\n"; |
||
| 167 | print "graph_vlabel BOINC applications\n"; |
||
| 168 | |||
| 169 | # First project is AREA, next are STACK |
||
| 170 | # Not nice, but fast: |
||
| 171 | my $prj1 = shift @projects; |
||
| 172 | print "$projects{$prj1}->{prj_var}.label $projects{$prj1}->{prj_name}\n";
|
||
| 173 | print "$projects{$prj1}->{prj_var}.draw AREA\n";
|
||
| 174 | print "$projects{$prj1}->{prj_var}.type GAUGE\n";
|
||
| 175 | |||
| 176 | for my $prjN (@projects) {
|
||
| 177 | print "$projects{$prjN}->{prj_var}.label $projects{$prjN}->{prj_name}\n";
|
||
| 178 | print "$projects{$prjN}->{prj_var}.draw STACK\n";
|
||
| 179 | print "$projects{$prjN}->{prj_var}.type GAUGE\n";
|
||
| 180 | } |
||
| 181 | |||
| 182 | exit 0; |
||
| 183 | } |
||
| 184 | |||
| 185 | # |
||
| 186 | # 5.b) Display running state of projects |
||
| 187 | # |
||
| 188 | |||
| 189 | for my $prjN (@projects) {
|
||
| 190 | print "$projects{$prjN}->{prj_var}.value $projects{$prjN}->{prj_running}\n";
|
||
| 191 | } |
||
| 192 | |||
| 193 | exit 0; |
||
| 194 | |||
| 195 | |||
| 196 | ######################################################################### |
||
| 197 | # perldoc section |
||
| 198 | |||
| 199 | =head1 NAME |
||
| 200 | |||
| 201 | boinc_projs - Munin plugin to monitor actively running BOINC projects. |
||
| 202 | |||
| 203 | =head1 APPLICABLE SYSTEMS |
||
| 204 | |||
| 205 | Linux machines running BOINC and munin-node |
||
| 206 | |||
| 207 | - or - |
||
| 208 | |||
| 209 | Linux servers (running munin-node) used to collect data from other systems |
||
| 210 | which are running BOINC, but not running munin-node (e.g. non-Linux systems) |
||
| 211 | |||
| 212 | =head1 CONFIGURATION |
||
| 213 | |||
| 214 | Following configuration variables are supported: |
||
| 215 | |||
| 216 | =over 12 |
||
| 217 | |||
| 218 | =item B<boinccmd> |
||
| 219 | |||
| 220 | command-line control program (default: boinccmd) |
||
| 221 | |||
| 222 | =item B<host> |
||
| 223 | |||
| 224 | Host to query (default: none) |
||
| 225 | |||
| 226 | =item B<port> |
||
| 227 | |||
| 228 | GUI RPC port (default: none = use BOINC-default) |
||
| 229 | |||
| 230 | =item B<boincdir> |
||
| 231 | |||
| 232 | Directory containing appropriate file gui_rpc_auth.cfg (default: none) |
||
| 233 | |||
| 234 | =item B<password> |
||
| 235 | |||
| 236 | Password for BOINC (default: none) |
||
| 237 | |||
| 238 | =back |
||
| 239 | |||
| 240 | =head2 B<Security Consideration:> |
||
| 241 | |||
| 242 | Using of variable B<password> poses a security risk. Even if the Munin |
||
| 243 | configuration file for this plugin containing BOINC-password is properly |
||
| 244 | protected, the password is exposed as environment variable and finally passed |
||
| 245 | to boinccmd as a parameter. It is therefore possible for local users of the |
||
| 246 | machine running this plugin to eavesdrop the BOINC password. |
||
| 247 | |||
| 248 | Using of variable password is therefore strongly discouraged and is left here |
||
| 249 | as a legacy option and for testing purposes. |
||
| 250 | |||
| 251 | It should be always possible to use B<boincdir> variable instead - in such case |
||
| 252 | the file gui_rpc_auth.cfg is read by boinccmd binary directly. |
||
| 253 | If this plugin is used to fetch data from remote system, the gui_rpc_auth.cfg |
||
| 254 | can be copied to special directory in a secure way (e.g. via scp) and properly |
||
| 255 | protected by file permissions. |
||
| 256 | |||
| 257 | =head1 INTERPRETATION |
||
| 258 | |||
| 259 | This plugin shows the number of currently running BOINC tasks on the machine. |
||
| 260 | If machine is attached to several BOINC projects, data for all these projects |
||
| 261 | are displayed. |
||
| 262 | |||
| 263 | =head1 EXAMPLES |
||
| 264 | |||
| 265 | =head2 Local BOINC Example |
||
| 266 | |||
| 267 | BOINC is running on local machine. The BOINC binaries are installed in |
||
| 268 | F</opt/boinc/custom-6.10.1/>, the BOINC is running in directory |
||
| 269 | F</usr/local/boinc/> under username boinc, group boinc and the password is used |
||
| 270 | to protect access to BOINC: |
||
| 271 | |||
| 272 | [boinc_*] |
||
| 273 | group boinc |
||
| 274 | env.boinccmd /opt/boinc/custom-6.10.1/boinccmd |
||
| 275 | env.boincdir /usr/local/boinc |
||
| 276 | |||
| 277 | =head2 Remote BOINC Example |
||
| 278 | |||
| 279 | BOINC is running on 2 remote machines C<foo> and C<bar>. |
||
| 280 | On the local machine the binary of command-line interface is installed in |
||
| 281 | directory F</usr/local/bin/>. |
||
| 282 | The BOINC password used on the remote machine C<foo> is stored in file |
||
| 283 | F</etc/munin/boinc/foo/gui_rpc_auth.cfg>. |
||
| 284 | The BOINC password used on the remote machine C<bar> is stored in file |
||
| 285 | F</etc/munin/boinc/bar/gui_rpc_auth.cfg>. |
||
| 286 | These files are owned and readable by root, readable by group munin and not |
||
| 287 | readable by others. |
||
| 288 | There are 2 symbolic links to this plugin created in the munin plugins |
||
| 289 | directory (usually F</etc/munin/plugins/>): F<snmp_foo_boincprojs> and |
||
| 290 | F<snmp_bar_boincprojs> |
||
| 291 | |||
| 292 | [snmp_foo_boinc*] |
||
| 293 | group munin |
||
| 294 | env.boinccmd /usr/local/bin/boinccmd |
||
| 295 | env.host foo |
||
| 296 | env.boincdir /etc/munin/boinc/foo |
||
| 297 | |||
| 298 | [snmp_bar_boinc*] |
||
| 299 | group munin |
||
| 300 | env.boinccmd /usr/local/bin/boinccmd |
||
| 301 | env.host bar |
||
| 302 | env.boincdir /etc/munin/boinc/bar |
||
| 303 | |||
| 304 | This way the plugin can be used by Munin the same way as the Munin plugins |
||
| 305 | utilizng SNMP (although this plugin itself does not use SNMP). |
||
| 306 | |||
| 307 | =head1 BUGS |
||
| 308 | |||
| 309 | There is no C<autoconf> capability at the moment. This is due to the fact, that |
||
| 310 | BOINC installations may vary over different systems, sometimes using default |
||
| 311 | directory from distribution (e.g. F</var/lib/boinc/> in Debian or Ubuntu), but |
||
| 312 | often running in user directories or in other separate directories. |
||
| 313 | Also the user-ID under which BOINC runs often differs. |
||
| 314 | Under these circumstances the C<autoconf> would be either lame or too |
||
| 315 | complicated. |
||
| 316 | |||
| 317 | =head1 AUTHOR |
||
| 318 | |||
| 319 | Palo M. <palo.gm@gmail.com> |
||
| 320 | |||
| 321 | =head1 LICENSE |
||
| 322 | |||
| 323 | GPLv3 |
||
| 324 | |||
| 325 | =cut |
||
| 326 | |||
| 327 | # vim:syntax=perl |
