#!/usr/bin/perl
use strict;
use warnings;
# process a log with plugins and place the results in a file

# Copyright (C) 2011  Glen Pitt-Pladdy
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# 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; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
#
#
# See: http://www.pitt-pladdy.com/blog/_20111116-201219%2B0000%20OpenVz%20User%20Beancounters%20%28UBC%29%20on%20Cacti%20via%20SNMP/
#
my $VERSION = 20111113;
my $CTPATH = "/var/lib/vz/private";




# usage:  vzbeancheck <stats file>
my ( $statsfile ) = @ARGV;


# santiy check
if ( ! $statsfile ) {
	die "FATAL - stats file not specified\n";
}

# read in the current stats if it exists
my %stats;
if ( -f $statsfile ) {
	open ST, $statsfile or die "FATAL - can't read previous statistics: $!\n";
	while ( defined ( my $line = <ST> ) ) {
		chomp $line;
		if ( $line !~ /^([\w\-_:]+)=([\w\.\-]+)$/ ) {
			die "FATAL - don't understand line \"$line\" in stats\n";
		} elsif ( $line !~ /^([\w\-_:]+failcnt)=(\d+)$/ ) {
			next;	# we are only interested in in failcnt
		}
		$stats{$1} = $2;
	}
	close ST;
}

# initialise basics
$stats{lastrun} = $^T;

# read and check the beancounters against last
my $header;
my $id;
my %messages;
open BC, '/proc/user_beancounters' or die "FATAL - can't read \"/proc/user_beancounters\": $!\n";
while ( defined ( my $line = <BC> ) ) {
	chomp $line;
	if ( $line =~ /^Version/ ) { next; }
	if ( $line =~ /^\s+uid\s+resource\s+held\s+maxheld\s+barrier\s+limit\s+failcnt$/ ) {
		$header = $line;
		next;
	}
	if ( $line =~ s/^\s+(\d+):\s+/            / ) {
		$id = $1;
	}
	if ( $line !~ /^\s+(\w+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)$/ ) {
		warn "WARNING - don't understand line:\n$line\n";
		next;
	}
	my ( $name, $held, $maxheld, $barrier, $limit, $failcnt ) = ( $1, $2, $3, $4, $5, $6 );
	# process the lines
	if ( $id > 0 and defined ( $stats{"$id:$name:failcnt"} ) and  $failcnt > $stats{"$id:$name:failcnt"} ) {
		$messages{$id} .= "New failure on $id (failcnt ".$stats{"$id:$name:failcnt"}." => $failcnt):\n$header\n$line\n";
	}
	$stats{"$id:$name:held"} = $held;
	$stats{"$id:$name:maxheld"} = $maxheld;
	$stats{"$id:$name:barrier"} = $barrier;
	$stats{"$id:$name:limit"} = $limit;
	$stats{"$id:$name:failcnt"} = $failcnt;
}
close BC;

# get machine hostnames from /etc/hostname and /etc/hosts
for my $dir ( glob ( "$CTPATH/*" ) ) {
	if ( ! -f "$dir/etc/hostname" ) { next; }
	if ( $dir !~ /\/(\d+)$/ ) { next; }
	my $ct = $1;
	open HN, "$dir/etc/hostname" or die "FATAL - can't read \"$dir/etc/hostname\": $!\n";
	$stats{"$ct:hostname"} = <HN>;
	chomp $stats{"$ct:hostname"};
	close HN;
	if ( ! -f "$dir/etc/hosts" ) { next; }
	open HST, "$dir/etc/hosts" or die "FATAL - can't read \"$dir/etc/hosts\": $!\n";
	my $fullname = $stats{"$ct:hostname"};
	while ( defined ( my $line = <HST> ) ) {
		chomp $line;
		my @names = split /\s+/, $line;
		if ( grep { $_ eq $stats{"$ct:hostname"} } @names ) {
			foreach my $name (@names) {
				if ( (split /\./, $name)[0] eq $stats{"$ct:hostname"}
					and length ( $name ) > length ( $fullname ) ) {
					$fullname = $name;
				}
			}
		}
	}
	close HST;
	$stats{"$ct:hostname"} = $fullname;
}
$stats{"0:hostname"} = 'host';


# do any complaining needed
foreach my $message (sort keys %messages) {
	warn $messages{$message};
}

# update for our run
$stats{lastrun} = $^T;

# write stats to temporary file
open ST, ">$statsfile.TMP.$$"
	or die "FATAL - can't write \"$statsfile.TMP.$$\": $!\n";
print ST "lastrun=$stats{lastrun}\n";
delete $stats{lastrun};
# dump rest of stats
foreach my $stat (sort keys %stats) {
	print ST "$stat=$stats{$stat}\n";
}
close ST;
rename "$statsfile.TMP.$$", $statsfile
	or die "FATAL - can't move \"$statsfile.TMP.$$\" to \"$statsfile\": $!\n";











