File check_obs_scheduler of Package monitoring-plugins-obs_scheduler

#!/usr/bin/env perl
#
# Copyright (c) 2017 SUSE LLC.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 3 as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program (see the file COPYING); if not, write to the
# Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
#
################################################################

use strict;
use warnings;
use Getopt::Long;
use Data::Dumper;
#use YAML qw/LoadFile/;

BEGIN {
  unshift @::INC, '/usr/lib/obs/server';
}


if (! caller) {

  my $ret = eval {
    my $mcos = Monitoring::Check::OBS::Scheduler->new();
    $mcos->getopt();
    $mcos->get_config();
    $mcos->check_schedulers();
    $mcos->check_results();
  };

  if (! defined $ret) {
     print "UNKNOWN - $@";
     exit 3;
  }
}

package Monitoring::Check::OBS::Scheduler;
our $VERSION = '0.0.1';
use strict;
use warnings;

use Getopt::Long qw/GetOptionsFromArray/;
use Data::Dumper;
#use YAML qw/LoadFile/;
use Carp;
use XML::Structured ':bytes';

use BSConfiguration;
use BSXML;
use BSUtil;

# ATTRIBUTES
sub critical     { return shift->_attribute(@_) } ## no critic (Subroutines::RequireArgUnpacking)
sub warning      { return shift->_attribute(@_) } ## no critic (Subroutines::RequireArgUnpacking)
sub age          { return shift->_attribute(@_) } ## no critic (Subroutines::RequireArgUnpacking)
sub config       { return shift->_attribute(@_) } ## no critic (Subroutines::RequireArgUnpacking)
sub config_file  { return shift->_attribute(@_) } ## no critic (Subroutines::RequireArgUnpacking)
sub results      { return shift->_attribute(@_) } ## no critic (Subroutines::RequireArgUnpacking)

# METHODS
sub new {
  my ($class,@args) = @_;
  my $self  =
    {
      critical    => 0,
      warning     => 0,
      age         => 0,
      config_file => '/etc/monitoring-plugins/check_obs_scheduler.yml',
      results     => [],
      failed         => [],
      @args
    };
  bless $self, $class;
  return $self;
}

sub _attribute {
  my $self   = shift;
  my $value  = shift;
  my @caller = caller 1;
  my $attr   = $caller[3];
  $attr      =~ s/.*::([^:]*)$/$1/smx;
  if (defined $value) { $self->{$attr} = $value };
  return $self->{$attr};
}

sub failed {
  my ($self) = @_;
  $self->{failed} = [];
  @{$self->{failed}} = grep { $_->{state} > 0 } @{$self->results};
  @{$self->{failed}} = sort { $b->{state} <=> $a->{state} } @{$self->{failed}};
  return $self->{failed};
}

sub get_failed_max_state {
  my ($self) = @_;
  return $self->{failed}->[0]->{state} || 0;
}

sub getopt {
  my ($self) = @_;

  if (! GetOptionsFromArray(\@ARGV, 'warning|w=i' => \$self->{warning}, 'critical|c=i' => \$self->{critical}, 'age|a=i' => \$self->{age}, 'config=s' => \$self->{config_file} )) {
    my $bn = $0;
    $bn =~ s{.*/(.*)$}{$1}smx;
    print "Usage: $bn <-w warning> <-c critical> <--dir events_subdir>\n";
    die "Error: Wrong arguments!\n";
  }

  return $self;
}

sub get_config {
  my ($self) = @_;
  my $cfile = $self->config_file;
  #die "Config file '$cfile' not found!\n" if (! -f $cfile);
  #return $self->config(LoadFile($cfile));
}

sub check_schedulers {
  my ($self) = @_;
  # cleanup results
  $self->results([]);
  my $cfg = $self->config;
  opendir(INFO,"/bs/info");
  my @INFOS = grep {/^schedulerinfo/} readdir (INFO);
  close (INFO);
  foreach my $info (sort @INFOS) {
    $self->check_scheduler_single("/bs/info/$info", $cfg);
  }
  return $self->failed();
}

sub check_scheduler_single {
  my ($self, $filename, $cfg) = @_;
  my $si = readxml("$filename", $BSXML::schedulerinfo, 1);
  my $si_arch = $si->{'arch'};
  my $si_age = time() - $si->{'time'};
  my $critical;
  $critical->{'high'} = (defined($cfg->{$si_arch}->{critical})) ? $cfg->{$si_arch}->{critical} : $self->critical;
  $critical->{'low'} = $critical->{'high'};
  $critical->{'med'} = $critical->{'high'};
  $critical->{'med'} *= 10;
  $critical->{'low'} *= 100;
  my $warning;
  $warning->{'high'} = (defined($cfg->{$si_arch}->{warning})) ? $cfg->{$si_arch}->{warning} : $self->warning;
  $warning->{'low'} = $warning->{'high'};
  $warning->{'med'} = $warning->{'high'};
  $warning->{'med'} *= 10;
  $warning->{'low'} *= 100;
  my $state = 0;
  my $diff = 0;
  my @perfdata;
  my $summary;
  my @summary;
  for my $q (qw(high med low)) {
    if ($si->{'queue'}->{$q} >= $warning->{$q}) {
      $state = 1;
      $diff = $si->{'queue'}->{$q} - $warning->{$q};
      $summary->{$q} = "W:$si->{'queue'}->{$q}";
    }
  }
  for my $q (qw(high med low)) {
    if ($si->{'queue'}->{$q} >= $critical->{$q}) {
      $state = 2;
      $diff = $si->{'queue'}->{$q} - $critical->{$q};
      $summary->{$q} = "C:$si->{'queue'}->{$q}";
    }
    if ($q eq "high") {
      push @perfdata, "s_${si_arch}_$q=$si->{'queue'}->{$q};$warning->{$q};$critical->{$q}";
    } else {
      push @perfdata, "s_${si_arch}_$q=$si->{'queue'}->{$q};;$critical->{$q}";
    }
  }
  my $si_max_age = $self->{age} ? $self->{age} : 0;
  if ($si_max_age) {
    push @perfdata, "s_${si_arch}_age=$si_age;;$si_max_age";
    if ($si_max_age && $si_age >= $si_max_age) {
      $state = 2;
      $summary->{'age'} = "C:age";
    }
  }
  push @summary, "$_:$summary->{$_}" for keys(%$summary);
  
  push @{$self->results},
    {
      state => $state,
      perfdata => join(" ",@perfdata),
      diff     => $diff,
      name     => $si_arch,
      queue    => join(",",@summary),
    }
  ;

  return;
}

sub check_results {
  my ($self) = @_;
  my $state = $self->get_failed_max_state();

  if ($state) {
    print $self->format_output_fail($state);
    exit $state
  } else {
    print $self->format_output_ok();
    exit 0;
  }
}

sub format_output_fail {
  my ($self, $state) = @_;
  my $sname = { 0 => 'OK', 1 => 'WARNING', 2 => 'CRITICAL', 3 => 'UNKNOWN'};
  croak('State "'.($state || q{}).'" not known') if ! $state;
  my $out="$sname->{$state} - ";

  for my $res (sort { $b->{state} <=> $a->{state} or $b->{diff} <=> $a->{diff} } @{$self->results} ) {
    next if ! $res->{state};
    $out = "$out $res->{name} ($res->{state}/$res->{queue}/$res->{diff})";
  }

  return "$out | ".$self->get_perfdata;
}

sub format_output_ok {
  my ($self) = @_;
  return 'OK - all schedulers checked | '.$self->get_perfdata."\n";

}

sub get_perfdata {
  my ($self) = @_;
  my @perfdata;
  for my $res (@{$self->{results}}) {
     push @perfdata, $res->{perfdata};
  }
  return join '; ', @perfdata;
}
1;
openSUSE Build Service is sponsored by