#!/usr/bin/perl use lib "/usr/share/BackupPC/lib"; use BackupPC::Lib; use BackupPC::CGI::Lib qw(:all); use BackupPC::View; use BackupPC::XS qw(:all); use Encode qw/decode_utf8/; use POSIX; use JSON; use Getopt::Long; use Statistics::Descriptive; use Data::Dumper; my $host = undef; GetOptions( "host=s" => \$host ); # We need to switch to backuppc UID/GID my $uid = getuid(); my $gid = getgid(); my (undef,undef,$bkpuid,$bkpgid) = getpwnam('backuppc'); setuid($bkpuid) if ($uid ne $bkpuid); setgid($bkpgid) if ($gid ne $bkpgid); my $bpc = BackupPC::Lib->new(); my $mainConf = $bpc->ConfigDataRead(); my $json = {}; if ( $host ) { my $hostConf = $bpc->ConfigDataRead($host); my $conf = { %$mainConf, %$hostConf }; my $age = -1; $json = { share => 0, bkp => 0, last_age => 0, errors => 0, new_size => 0, new_size_avg => 0, new_size_median => 0, new_size_q1 => 0, new_size_q3 => 0 }; my @bpc_info = $bpc->BackupInfoRead($host); my $sizes = new Statistics::Descriptive::Full; if ( scalar( @bpc_info ) ){ foreach my $backup ( @bpc_info ) { # Skip partial or active backups next if ( $backup->{type} !~ m/^full|incr$/ ); if ( $backup->{type} eq "full" ) { $last_full_num = $backup->{num}; } # Push all the sizes in our data set to compute avg sizes # Exclude backup N°0 as it'll always have much more new data than normal backups $sizes->add_data($backup->{sizeNew}) unless ( $backup->{num} == 0 ); $json->{bkp}++; } # Ignore the last backup if it's not full or incr (which means it's either partial or active) my $i = ( $bpc_info[-1]->{type} =~ m/^full|incr$/ ) ? -1 : -2; $json->{errors} = $bpc_info[$i]->{xferErrs}; $json->{new_size} = $bpc_info[$i]->{sizeNew}; $json->{share} = $bpc_info[$i]->{share}; $json->{new_size_avg} = int $sizes->mean; $json->{new_size_median} = int $sizes->median; $json->{new_size_q1} = eval { int $sizes->quantile(1) } || 0; $json->{new_size_q3} = eval { int $sizes->quantile(3) } || 0; $json->{age} = time - $bpc_info[$i]->{startTime}; $json->{last_age} = sprintf("%.1f", ($json->{age}) / 84600); } } else { print<<"EOF"; Usage: $0 --host= EOF } # Print results print("\n----------------\n"); print("Last Backup : $json->{last_age}"); print("\n"); print("Errors : $json->{errors}"); print("\n"); print("Size Consistency : "); # TOO BIG ? my $toobig = "1"; if ( $json->{new_size} > ($json->{new_size_q3} + $json->{new_size_q3} - $json->{new_size_q1}) * 1.5 or $json->{new_size} > $json->{new_size_avg} * 6 ) { $toobig = "1"; } else { $toobig = "0"; } # TOO SMALL ? my $toosmall = "1"; if ( $json->{new_size} < ($json->{new_size_q1} - $json->{new_size_q3} - $json->{new_size_q1}) * 1.5 or $json->{new_size} < $json->{new_size_avg} / 3 ) { $toosmall = "1"; } else { $toosmall = "0"; } # Print result if ( $toobig or $toosmall ) { print("ANOMALOUS"); } else { print("Normal"); } print("\n"); print("Random file : "); # Random file print("Random file"); print("\n"); print("\n----------------\n"); # Debug print("\n----------------\n"); print("DEBUG"); print("\n"); print("last_full_num : $last_full_num"); print("\n"); print("new_size : $json->{new_size}"); print("\n"); print("new_size_q1 : $json->{new_size_q1}"); print("\n"); print("new_size_q3 : $json->{new_size_q3}"); print("\n"); print("new_size_avg : $json->{new_size_avg}"); print("\n"); print("toobig : $toobig"); print("\n"); print("toosmall : $toosmall"); print("\n"); print("share : $json->{share}"); print("\n----------------\n"); # /Debug exit(0);