#!/usr/bin/perl
##########################################################################
# $Id$
##########################################################################
# $Log$
########################################################
## Copyright (c) 2011 Nathan Crawford
## Covered under the included MIT/X-Consortium License:
## http://www.opensource.org/licenses/mit-license.php
## All modifications and contributions by other persons to
## this script are assumed to have been donated to the
## Logwatch project and thus assume the above copyright
## and licensing terms. If you want to make contributions
## under your own copyright or a different license this
## must be explicitly stated in the contribution and the
## Logwatch project reserves the right to not accept such
## contributions. If you have made significant
## contributions to this script and want to claim
## copyright please contact logwatch-devel@logwatch.org.
#########################################################
# Detail level
$Detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0;
# Config
my $offline = $ENV{'puppet_offline_ok'};
# Init counters
$FailedRuns = 0;
$SuccessfulRuns = 0;
$ResourceFailures = 0;
$DependencyFailures = 0;
while (defined($ThisLine = <STDIN>)) {
chomp($ThisLine);
if (
($ThisLine =~ /Using cached catalog/) or
($ThisLine =~ /Caching catalog for /) or
($ThisLine =~ /Caching node for /) or
($ThisLine =~ /Caught TERM; calling stop/) or
($ThisLine =~ /[sS]hutting down/) or
($ThisLine =~ /Reopening log files/) or
($ThisLine =~ /Starting Puppet client version /) or
($ThisLine =~ /Restarting with.+puppetd/) or
($ThisLine =~ /Caught HUP; calling restart/) or
($ThisLine =~ /Skipping because of failed dependencies/) or
($ThisLine =~ /Failed to generate additional resources/) or
($ThisLine =~ /Could not evaluate: getaddrinfo: Name or service not known/) or
($ThisLine =~ /replacing from source .+ with contents /) or
($ThisLine =~ /Starting catalog run/) or
($ThisLine =~ /Applying configuration version/) or
($ThisLine =~ /Loading facts in/) or
($ThisLine =~ /Retrieving plugin/) or
($ThisLine =~ /FileBucket adding/) or
($ThisLine =~ /^Caching certificate/) or
($ThisLine =~ /^Certificate Request fingerprint/) or
($ThisLine =~ /^Creating state file/) or
($ThisLine =~ /Provider useradd does not support features manages/)
) {
# Ignore
} elsif (($junk, $failure, $reason) = ($ThisLine =~ /^(\(.*\) |)Could not ([^:]*): (.*)/)) {
if ($reason == "getaddrinfo: Name or service not known" && $offline) {
$FailedRuns--;
} else {
$Failures{$failure}->{$reason}++;
}
} elsif ($ThisLine =~ /Finished catalog run in [0-9]+\.[0-9]+ seconds/) {
$SuccessfulRuns++;
} elsif ($ThisLine =~ /skipping run/) {
$FailedRuns++;
} elsif ($ThisLine =~ /(Did not receive certificate)/) {
$Errors{$1}++;
} elsif (($file) = $ThisLine =~ /Reparsing (.*)/) {
$Reparsed{$file}++;
} elsif (($fileinfo) = ($ThisLine =~ /Filebucketed (.*)/)) {
$FileBucketed{$1}++;
} elsif ($ThisLine =~ /Dependency .+\[.+\] has ([0-9]+ |)failure/) {
$DependencyFailures++;
} elsif (
($ThisLine =~ /Failed to retrieve current state of resource/) or
($ThisLine =~ /Package.+ensure.+Could not find package/) or
($ThisLine =~ /File\[.+\].+ Could not describe /) or
($ThisLine =~ /File\[.+\].+ No specified sources exist/)
) {
$ResourceFailures++;
} elsif ($ThisLine =~ /Package\[(.+)\].+ensure changed/) {
$ChangedPackages{$1}++;
} elsif ($ThisLine =~ /Package\[(.+)\].+ensure\) created/) {
$InstalledPackages{$1}++;
} elsif ($ThisLine =~ /Package\[(.+)\].+ensure\) removed/) {
$RemovedPackages{$1}++;
} elsif ($ThisLine =~ /Exec\[(.+)\].+executed successfully/) {
$ExecRuns{$1}++;
} elsif ($ThisLine =~ /Exec\[(.+)\].+Trigger(?:ing|ed) 'refresh' from [0-9]+ (?:dependencies|events)/) {
$ExecRuns{$1}++;
} elsif ($ThisLine =~ /Exec\[(.+)\].+Triggered 'refresh' from [0-9]+ events/) {
$ExecRuns{$1}++;
} elsif ($ThisLine =~ /Service\[(.+)\].+ensure changed \'.+\' to \'running\'/) {
$ServiceStarts{$1}++;
} elsif ($ThisLine =~ /Service\[(.+)\].+Trigger(?:ing|ed) 'refresh' from [0-9]+ (?:dependencies|events)/) {
$ServiceStarts{$1}++;
} elsif ($ThisLine =~ /Service\[(.+)\].+Triggered 'refresh' from [0-9]+ events/) {
$ServiceStarts{$1}++;
} elsif ($ThisLine =~ /Service\[(.+)\].+ensure changed \'.+\' to \'stopped\'/) {
$ServiceStops{$1}++;
} elsif ($ThisLine =~ /User\[(.+)\].+changed password/) {
$PasswordChanged{$1}++;
} elsif ($ThisLine =~ /User\[(.+)\].+defined \'expiry\' as \'([0-9-]{10})\'/) {
$ExpiryChanged{$1}{$2}++;
# Generic rules need to be last
} elsif (($type, $name, $attr) = $ThisLine =~ /([^\/]+)\[([^\]]+)\]\/([^\/]+)\) (created|defined content)/) {
$Created{$type}->{$name}++;
} elsif (($type, $name, $attr) = $ThisLine =~ /([^\/]+)\[([^\]]+)\]\/([^\/]+)\) removed/) {
$Removed{$type}->{$name}++;
} elsif (($type, $name, $attr, $from, $to) = $ThisLine =~ /([^\/]+)\[([^\]]+)\]\/([^\/]+)\) .+ changed '(.*)' to '(.*)/) {
if ($attr eq 'content' or $attr eq 'checksum') {
# Only count these types of changes
$Changed{$type}->{$name}->{$attr}++;
} else {
# Get details for all other types of changes
$Changed{$type}->{$name}->{$attr}->{'from'} = $from;
$Changed{$type}->{$name}->{$attr}->{'to'} = $to;
}
} elsif (($type, $name, $attr, $from) = $ThisLine =~ /([^\/]+)\[([^\]]+)\]\/([^\/]+)\) undefined '.+' from '(.*)'/) {
$Changed{$type}->{$name}->{$attr}->{'from'} = $from;
$Changed{$type}->{$name}->{$attr}->{'to'} = 'undefined';
} elsif (($type, $name, $content) = $ThisLine =~ /([^\/]+)\[([^\]]+)\]\/content\)(.*)/) {
$content =~ s/#011/\t/g;
$content =~ s/#012/\n /g or $content .= "\n ";
$Changed{$type}->{$name}->{'contents'} .= $content;
} elsif (($source, $target) = $ThisLine =~ /^\(\/(.*)\) Scheduling refresh of (.*)/) {
$ScheduledRefresh{"$source -> $target"}++;
} else {
# Report any unmatched entries...
$OtherList{$ThisLine}++;
}
}
#######################################
if ($SuccessfulRuns > 0 && $Detail > 0) {
print "\nSuccessful runs: $SuccessfulRuns\n";
}
if ($FailedRuns > 0) {
print "\nFailed runs: $FailedRuns\n";
}
if (keys %Errors) {
print "\nERRORS:\n";
foreach $ThisOne (keys %Errors) {
print " $ThisOne: $Errors{$ThisOne} Time(s)\n";
}
}
foreach $failure (sort(keys %Failures)) {
print "\nERROR: Could not $failure:\n";
foreach $ThisOne (keys %{$Failures{$failure}}) {
print " $ThisOne: $Failures{$failure}->{$ThisOne} Time(s)\n";
}
}
if ($ResourceFailures > 0) {
print "\nResource failures: $ResourceFailures\n";
}
if ($DependencyFailures > 0) {
print "\nDependency failures: $DependencyFailures\n";
}
if (keys %Reparsed) {
print "\nReparsed:\n";
foreach $ThisOne (keys %Reparsed) {
print " $ThisOne: $Reparsed{$ThisOne} Time(s)\n";
}
}
if (keys %FileBucketed and $Detail >= 5) {
print "\nFileBucketed files:\n";
foreach $ThisOne (keys %FileBucketed) {
print " $ThisOne\n";
}
}
if (keys %InstalledPackages) {
print "\nInstalled packages:\n";
foreach $ThisOne (keys %InstalledPackages) {
print " $ThisOne: $InstalledPackages{$ThisOne} Time(s)\n";
}
}
if (keys %ChangedPackages) {
print "\nChanged packages:\n";
foreach $ThisOne (keys %ChangedPackages) {
print " $ThisOne: $ChangedPackages{$ThisOne} Time(s)\n";
}
}
if (keys %RemovedPackages) {
print "\nRemoved packages:\n";
foreach $ThisOne (keys %RemovedPackages) {
print " $ThisOne: $RemovedPackages{$ThisOne} Time(s)\n";
}
}
if (keys %ExecRuns) {
print "\nExec runs:\n";
foreach $ThisOne (keys %ExecRuns) {
print " $ThisOne: $ExecRuns{$ThisOne} Time(s)\n";
}
}
if (keys %ServiceStarts) {
print "\nService starts:\n";
foreach $ThisOne (keys %ServiceStarts) {
print " $ThisOne: $ServiceStarts{$ThisOne} Time(s)\n";
}
}
if (keys %ServiceStops) {
print "\nService stops:\n";
foreach $ThisOne (keys %ServiceStops) {
print " $ThisOne: $ServiceStops{$ThisOne} Time(s)\n";
}
}
if (keys %PasswordChanged) {
print "\nPassword changed:\n";
foreach $ThisOne (keys %PasswordChanged) {
print " $ThisOne: $PasswordChanged{$ThisOne} Time(s)\n";
}
}
if (keys %ExpiryChanged) {
print "\nExpiry changed:\n";
foreach $ThisOne (keys %ExpiryChanged) {
print " $ThisOne:\n";
foreach $date (keys %{${ExpiryChanged}{$ThisOne}}) {
print " $date: $ExpiryChanged{$ThisOne}{$date} Time(s)\n";
}
}
}
foreach $Type (sort(keys %Created)) {
print "\n$Type created:\n";
foreach $Name (sort(keys %{$Created{$Type}})) {
print " $Name: $Created{$Type}->{$Name} Time(s)\n";
}
}
foreach $Type (sort(keys %Changed)) {
print "\n$Type changed:\n";
foreach $Name (sort(keys %{$Changed{$Type}})) {
print " $Name:\n";
foreach $Attr (sort(keys %{$Changed{$Type}->{$Name}})) {
if ($Attr eq 'contents') {
if ($Detail >= 3) {
print " $Attr:";
print "$Changed{$Type}->{$Name}->{$Attr}\n";
}
} else {
print " $Attr: ";
if (defined($Changed{$Type}->{$Name}->{$Attr}->{'from'})) {
print "from '$Changed{$Type}->{$Name}->{$Attr}->{from}' to '$Changed{$Type}->{$Name}->{$Attr}->{to}'\n";
} else {
print "$Changed{$Type}->{$Name}->{$Attr} Time(s)\n";
}
}
}
}
}
foreach $Type (sort(keys %Removed)) {
print "\n$Type removed:\n";
foreach $Name (sort(keys %{$Removed{$Type}})) {
print " $Name: $Removed{$Type}->{$Name} Time(s)\n";
}
}
if (keys %ScheduledRefresh) {
print "\nScheduled refresh:\n";
foreach $ThisOne (keys %ScheduledRefresh) {
print " $ThisOne: $ScheduledRefresh{$ThisOne} Time(s)\n";
}
}
if (keys %OtherList) {
print "\n**Unmatched Entries**\n";
foreach $ThisOne (keys %OtherList) {
print " $ThisOne: $OtherList{$ThisOne} Time(s)\n";
}
}
exit(0);
# vi: shiftwidth=3 tabstop=3 syntax=perl et