Enhance check_pve_sudo with a local cache support to speed up monitoring

tags/zabbix-agent-addons-0.2.115-1
Daniel Berteaud 5 years ago
parent 574a37684b
commit c799f083f5
  1. 80
      zabbix_scripts/check_pve_sudo

@ -5,6 +5,8 @@ use warnings;
use JSON; use JSON;
use Getopt::Long; use Getopt::Long;
use File::Which; use File::Which;
use File::Path qw(make_path);
use File::Basename;
use Data::Dumper; use Data::Dumper;
my $pvesh = which('pvesh'); my $pvesh = which('pvesh');
@ -12,20 +14,38 @@ my $json = {};
my $pretty = 0; my $pretty = 0;
my ($cluster,$guest,$node,$storage,$pool) = undef; my ($cluster,$guest,$node,$storage,$pool) = undef;
# Max age of cached values
my $cache = 60;
my $cache_dir = '/tmp/zbx_pve_cache/';
GetOptions( GetOptions(
'cluster' => \$cluster, 'cluster' => \$cluster,
'guest=i' => \$guest, 'guest=i' => \$guest,
'node=s' => \$node, 'node=s' => \$node,
'storage=s' => \$storage, 'storage=s' => \$storage,
'pool=s' => \$pool, 'pool=s' => \$pool,
'pretty' => \$pretty 'pretty' => \$pretty,
'cache=i' => \$cache,
'cache-dir=s' => \$cache_dir
); );
# Are we using the new pvesh for which we have to specify the output format ? # Before Buster / PVE6, pvesh don't support (or need) --output-format=json
my $pvesh_opt = (system("$pvesh get /version --output-format=json >/dev/null 2>&1") == 0) ? '--output-format=json' : ''; # So try to detect previous version and adapt opt
my $pvesh_opt = '--output-format=json';
if (-f '/etc/os-release'){
open my $fh, '<', '/etc/os-release';
foreach my $line (<$fh>){
my ($var, $val) = split(/=/, $line);
$val =~ s/"(.*)"/$1/;
if ($var eq 'VERSION_ID' and int $val < 10){
$pvesh_opt = '';
last;
}
}
}
if ($cluster){ if ($cluster){
my $cluster = from_json(qx($pvesh get /cluster/status $pvesh_opt 2>/dev/null)); my $cluster = get_api_data('/cluster/status');
# Set default values so monitoring works for single node, without cluster setup # Set default values so monitoring works for single node, without cluster setup
$json->{status} = { $json->{status} = {
all_online => 1, all_online => 1,
@ -54,7 +74,7 @@ if ($cluster){
} }
} }
foreach my $node (@nodes){ foreach my $node (@nodes){
my $n = from_json(qx($pvesh get /nodes/$node/status $pvesh_opt 2>/dev/null)); my $n = get_api_data("/nodes/$node/status");
# Here we gather (and sum) some info about individual nodes to get the total number of # Here we gather (and sum) some info about individual nodes to get the total number of
# CPU, the amount of memory etc... # CPU, the amount of memory etc...
$json->{memory}->{$_} += $n->{memory}->{$_} foreach (qw(free total used)); $json->{memory}->{$_} += $n->{memory}->{$_} foreach (qw(free total used));
@ -65,7 +85,7 @@ if ($cluster){
# We want average load avg of the cluster, not the sum of individual loads # We want average load avg of the cluster, not the sum of individual loads
$json->{loadavg}[$_] = sprintf "%.2f", $json->{loadavg}[$_] / $json->{status}->{nodes} foreach (0..2); $json->{loadavg}[$_] = sprintf "%.2f", $json->{loadavg}[$_] / $json->{status}->{nodes} foreach (0..2);
my $guests = from_json(qx($pvesh get /cluster/resources --type=vm $pvesh_opt 2>/dev/null)); my $guests = get_api_data('/cluster/resources', '--type=vm');
foreach my $guest (@{$guests}){ foreach my $guest (@{$guests}){
$json->{network}->{in} += $guest->{netin} || 0; $json->{network}->{in} += $guest->{netin} || 0;
$json->{network}->{out} += $guest->{netout} || 0; $json->{network}->{out} += $guest->{netout} || 0;
@ -74,10 +94,10 @@ if ($cluster){
} }
} elsif ($node){ } elsif ($node){
foreach my $item (qw(status version subscription)){ foreach my $item (qw(status version subscription)){
$json->{$item} = from_json(qx(pvesh get /nodes/$node/$item $pvesh_opt 2>/dev/null)); $json->{$item} = get_api_data("/nodes/$node/$item");
} }
} elsif ($guest){ } elsif ($guest){
my $guests = from_json(qx($pvesh get /cluster/resources --type=vm $pvesh_opt 2>/dev/null)); my $guests = get_api_data('/cluster/resources', '--type=vm');
foreach my $g (@{$guests}){ foreach my $g (@{$guests}){
if ($g->{vmid} eq $guest){ if ($g->{vmid} eq $guest){
$json = $g; $json = $g;
@ -85,7 +105,7 @@ if ($cluster){
} }
} }
} elsif ($pool){ } elsif ($pool){
my $pool = from_json(qx($pvesh get /pools/$pool $pvesh_opt 2>/dev/null)); my $pool = get_api_data("/pools/$pool");
$json->{comment} = $pool->{comment}; $json->{comment} = $pool->{comment};
foreach my $type (qw(qemu lxc)){ foreach my $type (qw(qemu lxc)){
$json->{$_}->{$type} = 0 foreach (qw(guests templates)); $json->{$_}->{$type} = 0 foreach (qw(guests templates));
@ -105,7 +125,7 @@ if ($cluster){
$json->{templates}->{$_} //= 0 foreach (qw(maxdisk)); $json->{templates}->{$_} //= 0 foreach (qw(maxdisk));
$json->{guests}->{cpu} = ($json->{guests}->{maxcpu} == 0) ? 0 : $json->{guests}->{used_cpu} / $json->{guests}->{maxcpu}; $json->{guests}->{cpu} = ($json->{guests}->{maxcpu} == 0) ? 0 : $json->{guests}->{used_cpu} / $json->{guests}->{maxcpu};
} elsif ($storage){ } elsif ($storage){
my $stores = from_json(qx($pvesh get /cluster/resources --type=storage $pvesh_opt 2>/dev/null)); my $stores = get_api_data('/cluster/resources', '--type=storage');
foreach my $s (@{$stores}){ foreach my $s (@{$stores}){
if ($s->{storage} eq $storage){ if ($s->{storage} eq $storage){
$json->{maxdisk} = $s->{maxdisk}; $json->{maxdisk} = $s->{maxdisk};
@ -119,3 +139,33 @@ if ($cluster){
} }
print to_json($json, { pretty => $pretty }) . "\n"; print to_json($json, { pretty => $pretty }) . "\n";
# Helper which will either get data from
# the cache if its fresh enough, or query the API
# and save the result in the cache for later
sub get_api_data {
my $path = shift;
my $query_opt = shift;
$query_opt ||= '';
my $res;
# Is the cache existing and fresh enough ?
if (-f $cache_dir . $path and int((-M $cache_dir . $path)*60*60*24) < $cache){
{
local $/; # Enable slurp
open my $fh, "<", $cache_dir . $path;
$res = <$fh>;
close $fh;
}
} else {
$res = qx($pvesh get $path $query_opt $pvesh_opt 2>/dev/null);
# Save the result in the cache for later retrival
eval{
my $dir = (fileparse($path))[1];
make_path($cache_dir . $dir, { chmod => 700 });
};
open my $fh, ">", $cache_dir . $path;
print $fh $res;
close $fh;
}
return from_json($res);
}

Loading…
Cancel
Save