File Coverage

blib/lib/Nagios/Plugin/Beanstalk.pm
Criterion Covered Total %
statement 15 90 16.6
branch 0 54 0.0
condition 0 15 0.0
subroutine 5 11 45.4
pod 2 2 100.0
total 22 172 12.7


line stmt bran cond sub pod time code
1             package Nagios::Plugin::Beanstalk;
2             # vim: ts=8:sw=2:expandtab
3              
4 1     1   1413 use strict;
  1         3  
  1         77  
5 1     1   6 use warnings;
  1         3  
  1         39  
6              
7 1     1   16 use base qw(Nagios::Plugin);
  1         2  
  1         7085  
8              
9 1     1   71747 use Nagios::Plugin;
  1         3  
  1         63  
10 1     1   1453 use Beanstalk::Client;
  1         64579  
  1         21  
11              
12             our $VERSION = '0.04';
13              
14              
15             sub new {
16 0     0 1   my $class = shift;
17              
18 0           my $usage = <<'USAGE';
19             Usage: check_beanstalkd -H [-au] [-p ] [-t ] [-w ] [-c ]
20             USAGE
21              
22 0           my $self = $class->SUPER::new(
23             shortname => 'beanstalkd',
24             usage => $usage,
25             version => $VERSION,
26             url => 'http://search.cpan.org/dist/Nagios-Plugin-Beanstalk/check_beanstalkd',
27             license =>
28             qq|This library is free software, you can redistribute it and/or modify\nit under the same terms as Perl itself.|,
29             );
30              
31 0           $self->_add_beanstalk_options;
32              
33 0           return $self;
34             }
35              
36              
37             sub _add_beanstalk_options {
38 0     0     my ($self) = @_;
39              
40 0           my @args = (
41             { spec => 'hostname|H=s',
42             help =>
43             qq|-H, --hostname=ADDRESS\n Host name, IP Address, or unix socket (must be an absolute path)|,
44             required => 1,
45             },
46             { spec => 'port|p=i',
47             help => qq|-p, --port=INTEGER\n Port number (default: 389)|,
48             },
49             { spec => 'active|a!',
50             help => qq|-a [--active]\n check active worker count instead of job age|,
51             },
52             { spec => 'urgent|u!',
53             help => qq|-u [--urgent]\n only check the age of urgent jobs|,
54             },
55             { spec => 'tube|t=s@',
56             help => qq|-t [--tube]\n tube to check, can give multiple|,
57             },
58             { spec => 'warning|w=f',
59             help => qq|-w, --warning=DOUBLE\n Response time to result in warning status (seconds) or min worker count|,
60             },
61             { spec => 'critical|c=f',
62             help => qq|-c, --critical=DOUBLE\n Response time to result in critical status (seconds) or min worker count|,
63             },
64             );
65              
66 0           $self->add_arg(%$_) for (@args);
67             }
68              
69              
70             sub run {
71 0     0 1   my ($self) = @_;
72              
73 0           $self->getopts;
74              
75 0           my $opts = $self->opts;
76              
77 0   0       my $hostname = $opts->get('hostname') || 'localhost';
78 0           my $port = $opts->get('port');
79              
80 0 0         $hostname .= ":$port" if $port;
81              
82 0           my $client = Beanstalk::Client->new({server => $hostname});
83 0 0 0       $client->debug(1) if 1 < ($opts->verbose || 0);
84              
85 0 0         $self->add_message(CRITICAL, "$hostname: " . $client->error)
86             unless _check_beanstalk($self, $client, $opts);
87              
88 0           $self->nagios_exit($self->check_messages(join => ", "));
89 0           return;
90             }
91              
92             sub _check_beanstalk {
93 0     0     my ($self, $client, $opts) = @_;
94              
95 0 0         $client->connect or return;
96              
97 0 0         my @tube = $client->list_tubes or return;
98              
99 0 0         warn "@tube\n" if $opts->verbose;
100              
101 0 0         my @opt_tube = @{$opts->get('tube') || []};
  0            
102 0 0         if (@opt_tube) {
103 0 0         my $v = ($opt_tube[0] =~ /^!/ ? 1 : 0);
104 0           my %tube;
105 0           @tube{@tube} = ($v) x @tube;
106              
107 0           foreach my $opt_tube (@opt_tube) {
108 0 0         my $v = ($opt_tube =~ s/^!// ? 0 : 1); # negate
109 0 0         if ($opt_tube =~ s/^~//) {
110 0           $tube{$_} = $v for grep {/$opt_tube/} keys %tube;
  0            
111             }
112             else {
113 0           $tube{$opt_tube} = $v;
114             }
115             }
116 0           @tube = grep { $tube{$_} } keys %tube;
  0            
117             }
118              
119 0           my $check_active = $self->opts->active;
120              
121 0           foreach my $tube (@tube) {
122             return unless
123 0 0         $check_active
    0          
124             ? _check_tube_active($self, $client, $tube)
125             : _check_tube($self, $client, $tube);
126             }
127              
128 0           return 1;
129             }
130              
131             sub _check_tube {
132 0     0     my ($self, $client, $tube) = @_;
133              
134 0 0         warn "Checking $tube\n" if $self->opts->verbose;
135              
136 0 0         $client->use($tube) or return;
137              
138 0           my $age = 0;
139 0           my $urgent = $self->opts->urgent;
140              
141 0           my $stats_tube;
142 0 0         if ($urgent) {
143 0 0         $stats_tube = $client->stats_tube($tube) or return;
144             }
145              
146 0 0 0       if (!$stats_tube or $stats_tube->current_jobs_urgent) {
147 0           foreach my $i (1 .. 5) {
148 0 0         if (my $job = $client->peek_ready) {
    0          
149 0 0         my $stats = $job->stats or return;
150              
151             # If the job got reserved between the peek and stats, then try again
152 0 0         next if $stats->state eq 'reserved';
153              
154             # If only urgent jobs requested, then exit
155 0 0 0       last if $urgent and $stats->pri >= 1024;
156              
157 0           $age = $stats->age;
158 0           last;
159             }
160             elsif ($client->error =~ /NOT_FOUND/) {
161              
162             # There are no ready jobs, so all is ok
163 0           last;
164             }
165             else {
166 0           return;
167             }
168             }
169             }
170              
171 0           $self->add_message($self->check_threshold($age), "tube $tube is $age seconds old");
172 0           $self->add_perfdata(
173             label => $tube,
174             value => $age,
175             uom => 's',
176             threshold => $self->threshold
177             );
178             }
179              
180             sub _check_tube_active {
181 0     0     my ($self, $client, $tube) = @_;
182              
183 0 0         warn "Checking $tube\n" if $self->opts->verbose;
184              
185 0   0       my $warning = $self->opts->warning || 1;
186 0   0       my $critical = $self->opts->critical || $warning;
187 0           my $workers = 0;
188              
189 0           for (1 .. 10) {
190 0 0         my $stats = $client->stats_tube($tube) or last;
191 0           my $w = $stats->current_jobs_reserved + $stats->current_waiting;
192 0 0         $workers = $w if $w > $workers;
193 0 0         last if $workers >= $warning;
194 0           select(undef, undef, undef, 0.1);
195             }
196              
197 0           $self->set_thresholds(warning => $warning . ":", critical => $critical . ":");
198 0           $self->add_message($self->check_threshold($workers), "tube $tube has $workers workers");
199 0           $self->add_perfdata(
200             label => $tube,
201             value => $workers,
202             threshold => $self->threshold
203             );
204             }
205              
206             __END__