#!/usr/bin/env perl

# check_needrestart - Check for outdated runnings kernels and libraries/binaries
#
# Copyright (c) 2015 Amadeus Germany GmbH
#
# SPDX-License-Identifier: MIT
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

use strict;
use warnings;

use autodie;

### START PLUGIN LOADER
sub load_module {
	my $module;
	eval "require $_" and $module = $_ and last for @_;
	$module->import();
	return $module;
}

my $plugin_module;
BEGIN {
	$plugin_module = load_module('Monitoring::Plugin', 'Nagios::Plugin', 'Nagios::Monitoring::Plugin');
}
### END PLUGIN LOADER

my $NEEDRESTART = '/usr/sbin/needrestart';
my (@args, %data);

my $np = $plugin_module->new(
	usage => "Usage: %s [ -v|--verbose ] "
	. "[ --no-kernel ] [ --no-libraries ]",
	version => '1.1.0',
	plugin => 'check_needrestart',
	blurb => 'Check for outdated runnings kernels and libraries/binaries',
	license => 'MIT',
);

$np->add_arg(
	spec => 'kernel|k!',
	help => 'check for obsolete kernel',
	default => 1,
);

$np->add_arg(
	spec => 'libraries|l!',
	help => 'check for obsolete libraries',
	default => 1,
);

$np->getopts;

if (!($np->opts->kernel || $np->opts->libraries)) {
	$np->nagios_exit(UNKNOWN, 'Not checking anything does not make sense');
}

push @args, "-b";
push @args, "-k"  if ($np->opts->kernel);
push @args, "-l"  if ($np->opts->libraries);

if ($np->opts->libraries && $< != 0) {
	$np->nagios_exit(UNKNOWN, 'The library checks need root privileges');
}

# Opening a command as a safe no-shell run
open(my $RUNIT, "-|", $NEEDRESTART, @args);

while( <$RUNIT> ) {
    chomp; my @cut = split( /:\s+/ );

    # Supporting multiple instances of the same key properly (like for the services)
    $data{ $cut[0] } = ( $data{ $cut[0] } ) ? $data{ $cut[0] }.' '.$cut[1] : $cut[1];
}
close($RUNIT);


my $version = ( $data{'NEEDRESTART-VER'} =~ /[\d.]+/ )
            ?   $data{'NEEDRESTART-VER'}
            :   $np->nagios_exit(UNKNOWN, "Failed to validate ($data{'NEEDRESTART-VER'})");

if ($np->opts->kernel) {
	my $kcur = ( $data{'NEEDRESTART-KCUR'} ) ? $data{'NEEDRESTART-KCUR'} : $np->nagios_exit(UNKNOWN, "Line for NEEDRESTART-KCUR not found");
	my $kexp = ( $data{'NEEDRESTART-KEXP'} ) ? $data{'NEEDRESTART-KEXP'} : undef;
	my $ksta = 0+ ( $data{'NEEDRESTART-KSTA'} ) ? $data{'NEEDRESTART-KSTA'} : $np->nagios_exit(UNKNOWN, "Line for NEEDRESTART-KSTA not found");

	# Constants from NeedRestart::Kernel.pm
	if ($ksta == 0) {
		$np->add_message(UNKNOWN, "Unknown result from kernel upgrade check.");
	} elsif ($ksta == 1) {
		# No upgrade
	} elsif ($ksta == 2) {
		$np->add_message(WARNING, "ABI compatible upgrade for ${kcur}.");
	} elsif ($ksta == 3) {
		$np->add_message(WARNING, "Kernel upgraded from ${kcur} to ${kexp}.");
	} else {
		$np->add_message(UNKNOWN, "Unexpected result from kernel upgrade check.");
	}
}

if ($np->opts->libraries) {

	$np->add_perfdata(
		label => "outdated_services",
		value => scalar( split( /\s+/, $data{'NEEDRESTART-SVC'}?$data{'NEEDRESTART-SVC'}:'' ) ),
		min => 0,
		critical => undef,
	);

	$np->add_message(WARNING, "Outdated services: ".$data{'NEEDRESTART-SVC'}.".")  if($data{'NEEDRESTART-SVC'});
}

my $ok_message = 'No obsolete kernels or libraries/binaries running';

if (!$np->opts->kernel) {
	$ok_message = 'No obsolete libraries/binaries running';
}

if (!$np->opts->libraries) {
	$ok_message = 'No obsolete kernels running';
}

$np->add_message(OK, $ok_message);

my ($code, $message) = $np->check_messages();
$np->nagios_exit($code, $message);
