#!/usr/bin/perl

use strict;
use warnings;

use Time::HiRes qw/time/;
use FindBin;
use lib "$FindBin::Bin/../../lib";
use Wigo::Probe qw/:all/;

# Test if debian
if ( ! `which apt-get` )
{
    exit 13;
}

my $now = time;

init( config => {} );
persist or persist({});

my $persist      = persist;
my $delta_update = $now - $persist->{'last_update'} if $persist->{'last_update'};
my $update_tries = $persist->{'update_tries'} || 0;
my $errorOnUpdate;

###
# Update
###

if ( !$delta_update or $delta_update > 30 * 60 or $update_tries )
{
    my $fnret = `LANGUAGE=C apt-get update 2>&1`;
    chomp($fnret);

    foreach my $line ( split "\n" , $fnret )
    {
        if ( $line =~ /^([WE]):\s(.*)/ )
        {
            my $msg = $2;
            my $level = 'Unknown';
            $level = 'Errors'   if $1 eq 'E';
            $level = 'Warnings' if $1 eq 'W';
            my $ignored = 0;
            foreach my $regex (@{ config->{'lines_to_ignore'} || [] })
            {
                $ignored = 1 if ($msg =~ /$regex/);
            }
            push @{ detail->{'Apt-Get-Update'}->{ $ignored ? "$level-Ignored" : $level } } , $msg;
            $errorOnUpdate = 1 if not $ignored;
        }
    }

    if ($? == 0)
    {
        # Update last_update
        $persist->{'last_update'}   = time;
    }
    else
    {
        my $msg = "returned error ".($? >> 8);
        if ($? == -1)
        {
            $msg = "failed to launch: $!";
        }
        elsif ($? & 127)
        {
            $msg = sprintf("died with signal %d, %s coredump", $? & 127, ($? & 128) ? 'with' : 'without');
        }
        push @{ detail->{'Apt-Get-Update'}->{'Command'} }, "apt-get update command $msg";
        $errorOnUpdate = 1;
    }
}

###
# Upgrade
# Even if update fail, we want to test if there is no package to update anyway
###

my $packagesToUpdate = {};
my $fnret = `LANGUAGE=C apt-get upgrade -s 2>&1`;
chomp $fnret;

my $update = 0;
my $securityUpdate = 0;
foreach my $line ( split "\n" , $fnret )
{
    if ( my ($name,$version,$repo,$arch) = $line =~ /^Inst\s+(\S+)\s+\[(\S+)\]\s+\(\S+\s+(\S+)(\s+\[(\S+)\])?/ )
    {
        detail->{'Apt-Get-Upgrade'}->{$repo} ||= [];
        push @{detail->{'Apt-Get-Upgrade'}->{$repo}}, $name;
        $update++;
        $securityUpdate++ if $repo =~ /(security|lts)/i;
    }
}


# If errors on update, we raise to 101, then to 200
if ( $errorOnUpdate )
{
    $persist->{'update_tries'}++;

    if ( $persist->{'update_tries'} >= 3 )
    {
        raise 200;
    }
    else
    {
        raise 101;
    }

    message "An error happened when doing apt-get update (try " . $persist->{'update_tries'} . ")";
}
else
{
    # Reset counter with successfull update
    $persist->{'update_tries'}  = 0;
}



###
# Packages installed
###
my $packagesInstalled = `dpkg -l | wc -l`;
if ( $? == 0 )
{
    chomp $packagesInstalled;
}


###
# Results
###

my $message;

if ( $update )
{
    if( $securityUpdate )
    {
        raise 300 + ( $securityUpdate < 200 ? $securityUpdate : 199 );
        $message .= "There is $securityUpdate security updates to do. ";
    }
    else
    {
        raise 101;
        $message .= "There is $update packages to update. ";
    }
}
else
{
    $message .= "No security packages available. ";
}

if ( $errorOnUpdate )
{
    $message .= "There were errors while updating package list!";
    
    if ( $persist->{'update_tries'} >= 3 )
    {
        raise 200;
    }
    else
    {
        raise 101;
    }
}

chomp $message;

add_metric { 'Tags' => { 'metric' => 'to_update' },             'Value' => $update };
add_metric { 'Tags' => { 'metric' => 'to_update_security' },    'Value' => $securityUpdate };
add_metric { 'Tags' => { 'metric' => 'installed' },             'Value' => $packagesInstalled };

message $message;
persist $persist;

output 0;
