From d1ce56657a229dab7a1ddbbe3c3321fca7d92659 Mon Sep 17 00:00:00 2001 From: Matt Simerson Date: Fri, 21 Mar 2014 11:21:09 -0700 Subject: [PATCH] loadcheck: refactored. See =CHANGES section --- plugins/loadcheck | 141 ++++++++++++++++++++++++++++------------------ 1 file changed, 85 insertions(+), 56 deletions(-) mode change 100755 => 100644 plugins/loadcheck diff --git a/plugins/loadcheck b/plugins/loadcheck old mode 100755 new mode 100644 index ae06d10..a76718c --- a/plugins/loadcheck +++ b/plugins/loadcheck @@ -7,15 +7,16 @@ loadcheck =head1 DESCRIPTION Only takes email transactions if the system load is at or below a -specified level. +specified level. -If this is running on a system that provides /kern/loadavg or +If this is running on a system that provides /kern/loadavg or /proc/loadavg it will be used instead of the 'uptime' command. Once a load value is determined, it is cached for a period of time. See the cache_time below. -Since fork/exec is expensive in perl you'll want to use cache_time to avoid increasing your load on every connection by checking system load. +Since fork/exec is expensive in perl, if using the 'uptime' method, +use cache_time to avoid increasing your load on every connection. =head1 CONFIG @@ -31,7 +32,7 @@ assigned number of seconds. (Default: 10) uptime - The path to the command 'uptime' if different than the default. + The path to the command 'uptime' if different than the default. (Default: /usr/bin/uptime) Example: @@ -52,74 +53,50 @@ Steve Kemp's announcement of an alternate load limiter: http://www.nntp.perl.org Written by Peter Eisch . +=head1 CHANGES + +v0.03 - msimerson - 2014-03-21 + + * refactored "find the way to get load avg" out of loadcheck (every + connection) into get_load_method which is run in register. If we can't + get the load average, don't register the hook. + + * added BSD::getloadavg method (tested on FreeBSD) + +v0.02 - github@rsiddall - resurrected from list archives + =cut -my $VERSION = 0.02; +my $VERSION = 0.03; sub register { my ($self, $qp, @args) = @_; - %{$self->{_args}} = @args; - - $self->{_args}->{max_load} = 7 - if (!defined $self->{_args}->{max_load}); - - $self->{_args}->{uptime} = '/usr/bin/uptime' - if (!defined $self->{_args}->{uptime}); - - $self->{_args}->{cache_time} = 10 - if (!defined $self->{_args}->{cache_time}); + $self->{_args} = { @args }; + $self->{_args}{max_load} ||= 7; + $self->{_args}{uptime} ||= '/usr/bin/uptime'; + $self->{_args}{cache_time} ||= 10; $self->{_load} = -1; $self->{_time} = 0; + $self->{_method} = $self->get_load_method(); - $self->register_hook("connect", "loadcheck"); + # only register the hook if we can measure load + if (ref $self->{_method} eq 'CODE') { + $self->register_hook("connect", "loadcheck"); + } } sub loadcheck { my ($self, $transaction) = @_; - if (time() > ($self->{_time} + $self->{_args}->{cache_time})) { + if (time() > ($self->{_time} + $self->{_args}{cache_time})) { + # cache value expired, update + $self->{_method}->(); + $self->{_time} = time(); + }; - # cached value expired - - if (-r '/kern/loadavg') { # *BSD - # contains fix-point scaling value - open(LD, "; - close LD; - my @vals = split(/ /, $res); - $self->{_load} = ($val[0] / $val[3]); - $self->{_time} = time(); - $self->log(LOGDEBUG, "/kern/loadavg reported: $self->{_load}"); - } - elsif (-r '/proc/loadavg') { # *inux - # contains decimal value - # contains fix-point scaling value - open(LD, "; - close LD; - $self->{_load} = (split(/ /, $res))[0]; - $self->{_time} = time(); - $self->log(LOGDEBUG, "/proc/loadavg reported: $self->{_load}"); - } - else { - # the various formats returned: - #10:33AM up 2:06, 1 user, load averages: 6.55, 3.76, 2.48 - # 12:29am 2 users, load average: 0.05, 0.05, 0.06 - # 12:30am up 5 days, 12:43, 1 user, load average: 0.00, 0.00, 0.00 - - my $res = `$self->{_args}->{uptime}`; - if ($res =~ /aver\S+: (\d+\.\d+)/) { - $self->{_load} = $1; - $self->{_time} = time(); - $self->log(LOGDEBUG, - "$self->{_args}->{uptime} reported: $self->{_load}"); - } - } - } - - if ($self->{_load} > $self->{_args}->{max_load}) { + if ($self->{_load} > $self->{_args}{max_load}) { $self->log(LOGERROR, "local load too high: $self->{_load}"); return DENYSOFT; } @@ -127,3 +104,55 @@ sub loadcheck { return (DECLINED, "continuing with load: $self->{_load}"); } +sub get_load_method { + my ($self) = @_; + + eval "use BSD::getloadavg;"; + if (!$@) { + return sub { + require BSD::getloadavg; + $self->{_load} = (getloadavg())[0]; + $self->log(LOGDEBUG, "BSD::getloadavg reported: $self->{_load}"); + } + } + + if (-r '/kern/loadavg') { # *BSD + return sub { + open(LD, '<', "/kern/loadavg"); # contains fix-point scaling value + my $res = ; + close LD; + my @vals = split(/ /, $res); + $self->{_load} = ($vals[0] / $vals[3]); + $self->log(LOGDEBUG, "/kern/loadavg reported: $self->{_load}"); + } + } + + if (-r '/proc/loadavg') { # *inux + return sub { + open(LD, "<", "/proc/loadavg"); # contains decimal value + my $res = ; # contains fix-point scaling value + close LD; + $self->{_load} = (split(/ /, $res))[0]; + $self->log(LOGDEBUG, "/proc/loadavg reported: $self->{_load}"); + } + } + + if (-x $self->{_args}{uptime}) { + return sub { + # the various formats returned: + # 10:33AM up 2:06, 1 user, load averages: 6.55, 3.76, 2.48 + # 12:29am 2 users, load average: 0.05, 0.05, 0.06 + # 12:30am up 5 days, 12:43, 1 user, load average: 0.00, 0.00, 0.00 + + my $res = `$self->{_args}{uptime}`; + if ($res =~ /aver\S+: (\d+\.\d+)/) { + $self->{_load} = $1; + $self->log(LOGDEBUG, "$self->{_args}{uptime} reported: $self->{_load}"); + } + } + } + + $self->log(LOGERROR, "unable to acquire system load"); + return; +}; +