%PDF- %PDF-
| Direktori : /proc/self/root/data/old/usr/share/munin/plugins/ |
| Current File : //proc/self/root/data/old/usr/share/munin/plugins/apt_all |
#!/usr/bin/perl -w
# -*- perl -*-
=head1 NAME
apt_all - Plugin to monitor packages that should be installed on
systems using apt-get (mostly Debian, but also RedHat).
=head1 NOTES
The differences between this plugin and the apt plugins, is that this
plugin separates each distro with its own plot, and actually draws
graphs.
=head1 CONFIGURATION
You can add some extra options to the apt call, in order to override
your /etc/apt.conf defaults.
[apt_all]
env.options -o Debug::pkgDepCache::AutoInstall=false -o APT::Get::Show-Versions=false
env.releases stable experimental
=head2 options
This settings defaults to the example given above.
This default overrides potential local customization within
/etc/apt.conf, which could interfere with the intended operation of
apt or the output format required for this plugin.
Please note that "apt" honors your /etc/apt.conf defaults.
Thus you may need to override specific options, if you adjusted your
local apt.conf setup.
=head2 releases
This configuration may contain a space separated list of release names.
It defaults to the empty string. This default triggers the automatic
detection of available distributions from the URLs of all configured
repositories.
=head1 USAGE
This plugin needs a cronjob that runs apt-get update every hour or so
Example conjob
/etc/cron.d/munin-plugin-apt
53 * * * * root apt-get update > /dev/null 2>&1
23 08 * * * root apt-get update > /dev/null
Remember to randomize when these cronjobs are run on your servers
This plugin can also be called with the argument "update", which will
run apt-get update
update <maxinterval> <probability>
Updates the APT database randomly, guaranteeing there
won't be more than <maxinterval> seconds between each
update. Otherwise, there is a a 1 in <probability>
chance that an update will occur.
=head1 MAGIC MARKERS
#%# family=manual
#%# capabilities=autoconf
=cut
# Now for the real work...
use strict;
use Munin::Plugin;
$ENV{'LANG'}="C";
$ENV{'LC_ALL'}="C";
# The plugin is called in two ways:
# - via a cron job (without the munin environment provided by "munin-run")
# - as a regular plugin
# Thus the location evaluation below relies on the following assumptions:
# - the plugin is configured to run as "nobody"
# - the munin plugin state directory location was not reconfigured
my $statefile = ($ENV{MUNIN_PLUGSTATE} || '/var/lib/munin-node/plugin-state/nobody/') . "/plugin-apt_all.state";
my $apt_options = $ENV{options} || "-o Debug::pkgDepCache::AutoInstall=false -o APT::Get::Show-Versions=false";
# try to determine the currently available distributions by inspecting the repository URLs
sub guess_releases() {
open(my $fh, "-|", "apt-get $apt_options update --print-uris")
or die("Failed to determine distribution releases via 'apt-get update --print-uris");
my %release_names;
my $line;
while ( ! eof($fh) ) {
defined( $line = readline $fh ) or die "Failed to read line from output of 'apt-get': $!";
# example line:
# 'http://ftp.debian.org/debian/dists/stable/InRelease' ftp.debian.org_debian_dists_stable_InRelease 0
if ($line =~ m#^.*/dists/([^']+)/[^/]+/[^/]+/Packages#) {
my $release_name = $1;
# The security updates are named like "buster/updates". The first part (before the
# slash) is sufficient to mach these packages.
$release_name =~ s|/updates$||;
$release_names{$release_name} = 1;
}
}
return sort keys %release_names;
}
# use a given 'releases' environment variable (space separated names) or inspect the repository URLs
my @releases = split(/\s/, ($ENV{releases} || ""));
@releases = guess_releases() unless @releases;
sub get_clean_release_fieldname {
my ($fieldname) = @_;
# apply some minor URI-like substitution (avoiding ambiguity between slash and hyphen)
$fieldname =~ s#/#_2F#g;
return clean_fieldname($fieldname);
}
sub print_state() {
if (-l $statefile) {
die("$statefile is a symbolic link, refusing to read it.");
}
if (! -e "$statefile") {
update_state();
}
if (! -e "$statefile") {
die("$statefile does not exist. Something wicked happened.");
}
open(STATE, "$statefile")
or die("Couldn't open state file $statefile for reading.");
while (my $line = <STATE>) {
foreach my $release (@releases) {
my $release_cleaned = get_clean_release_fieldname($release);
# print only lines that are exected for the currently requested releases
if ($line =~ /^(hold|pending)_$release_cleaned\.(value|extinfo)/) {
print $line ;
last;
}
}
}
close STATE;
}
sub update_state() {
if(-l $statefile) {
die("$statefile is a symbolic link, refusing to touch it.");
}
open(STATE, ">$statefile")
or die("Couldn't open state file $statefile for writing.");
foreach my $release (@releases) {
my $apt="apt-get $apt_options -u dist-upgrade --print-uris --yes -t $release |";
open (APT, "$apt") or exit 22;
my @pending = ();
my $hold = 0;
my @remove = ();
my @install = ();
while (<APT>) {
if (/^The following packages will be REMOVED:/) {
my $where = 0;
while (<APT>) {
last if (/^\S/);
foreach my $package (split /\s+/) {
next unless ($package =~ /\S/);
push (@remove, "-$package");
}
}
}
if (/^The following NEW packages will be installed:/) {
my $where = 0;
while (<APT>) {
last if (/^\S/);
foreach my $package (split /\s+/) {
next unless ($package =~ /\S/);
push (@install, "+$package");
}
}
}
if (/^The following packages will be upgraded/) {
my $where = 0;
while (<APT>) {
last if (/^\S/);
foreach my $package (split /\s+/) {
next unless ($package =~ /\S/);
push (@pending, $package);
}
}
}
if (/^\d+\supgraded,\s\d+\snewly installed, \d+ to remove and (\d+) not upgraded/) {
$hold = $1;
}
}
push (@pending, @install) if @install;
push (@pending, @remove ) if @remove;
close APT;
my $release_cleaned = get_clean_release_fieldname($release);
print STATE "pending_$release_cleaned.value ", scalar (@pending), "\n";
if (@pending) {
print STATE "pending_$release_cleaned.extinfo ", join (' ', @pending), "\n";
}
print STATE "hold_$release_cleaned.value $hold\n";
}
close(STATE);
}
sub update_helpandexit() {
print("apt update <maxinterval> <probability> -- update apt databases randomly\n\n",
" maxinterval:\n",
" Enforce the updating of the apt database if it has\n",
" been more than 'maxinterval' many seconds since the last update.\n\n",
" probability:\n",
" There's a 1 in 'probability' chance that the database\n",
" will be updated.\n");
exit(1);
}
if ($ARGV[0] and $ARGV[0] eq "autoconf") {
`apt-get -v >/dev/null 2>/dev/null`;
if ($? eq "0") {
print "yes\n";
exit 0;
} else {
print "no (apt-get not found)\n";
exit 0;
}
}
if ($ARGV[0] and $ARGV[0] eq "config") {
print "graph_title Pending packages\n";
print "graph_vlabel Total packages\n";
print "graph_category system\n";
foreach my $release (@releases) {
my $release_cleaned = get_clean_release_fieldname($release);
print "pending_$release_cleaned.label pending ($release)\n";
print "pending_$release_cleaned.warning 0:0\n";
print "hold_$release_cleaned.label hold ($release)\n";
}
exit 0;
}
if ($ARGV[0] and $ARGV[0] eq "update") {
my $maxinterval = $ARGV[1] ? $ARGV[1] : update_helpandexit;
my $probability = $ARGV[2] ? $ARGV[2] : update_helpandexit;
# The state file needs an update in three situations:
# * it does not exist
# * $maxinterval seconds elapsed since the last update
# * random $probability was hit (one out of $probability)
if (!-e $statefile
|| ((stat($statefile))[10] + $maxinterval < time())
|| (int(rand($probability)) == 0)) {
system("/usr/bin/apt-get update") == 0
or die("Failed to run 'apt-get update'");
update_state();
}
exit(0);
}
print_state ();
exit 0;
# vim:syntax=perl