#!/usr/bin/perl # nagios: -epn ##################################################### # # Proxmox VE cluster monitoring tool # ##################################################### # # Requires Net::Proxmox::VE librairy: # git://github.com/dpiquet/proxmox-ve-api-perl.git # # License Information: # 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 3 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, see . # # Authors & contributors # Damien PIQUET damien.piquet@iutbeziers.fr || piqudam@gmail.com # Alexey Dvoryanchikov github.com/dvoryanchikov # use strict; # use warnings; use Net::Proxmox::VE; use IO::Socket::SSL; use Getopt::Long; use Switch; my $configurationFile = './pve-monitor.conf'; my $pluginVersion = '1.07'; my %status = ( 'UNDEF' => -1, 'OK' => 0, 'WARNING' => 1, 'CRITICAL' => 2, 'UNKNOWN' => 3, ); my %rstatus = reverse %status; my %arguments = ( 'nodes' => undef, 'storages' => undef, 'openvz' => undef, 'qemu' => undef, 'pools' => undef, 'qdisk' => undef, 'conf' => undef, 'show_help' => undef, 'show_version' => undef, 'timeout' => 5, 'debug' => undef, 'singlenode' => undef, ); sub usage { print "Usage: $0 [--nodes] [--storages] [--qemu] [--openvz] [--pools] [--perfdata] [--html] --conf \n"; print "\n"; print " --nodes\n"; print " Check the state of the cluster's members\n"; print " --storages\n"; print " Check the state of the cluster's storages\n"; print " --qemu\n"; print " Check the state of the cluster's Qemu virtual machines\n"; print " --openvz\n"; print " Check the state of the cluster's OpenVZ virtual machines\n"; print " [DEPRECATED] We keep it for pve-monitor < 1.07 back compat\n"; print " --containers\n"; print " Check the state of the cluster's containers (both openvz and lxc)\n"; print " --pools\n"; print " Check the state of the cluster's virtual machines and/or storages in defined pools\n"; print " --qdisk\n"; print " Check the state of the cluster's quorum disk\n"; print " --singlenode\n"; print " Consider there is no cluster, just a single node\n"; print " --perfdata\n"; print " Print nagios performance data for graphs (PNP4Nagios supported check_multi style) \n"; print " --html\n"; print " Replace linebreaks with
in output\n"; print " --debug\n"; print " Get more log output\n"; } sub is_number { ($_[0] =~ m/^[0-9]+$/) ? return 1 : return 0; } GetOptions ("nodes" => \$arguments{nodes}, "storages" => \$arguments{storages}, "openvz" => \$arguments{openvz}, "containers" => \$arguments{openvz}, "qemu" => \$arguments{qemu}, "pools" => \$arguments{pools}, "qdisk" => \$arguments{qdisk}, "singlenode" => \$arguments{singlenode}, "perfdata" => \$arguments{perfdata}, "html" => \$arguments{html}, "conf=s" => \$arguments{conf}, 'version|V' => \$arguments{show_version}, 'help|h' => \$arguments{show_help}, 'timeout|t=s' => \$arguments{timeout}, 'debug' => \$arguments{debug}, ); print "Starting pve-monitor $pluginVersion\n" if $arguments{debug}; print "Setting timeout to $arguments{timeout}\n" if $arguments{debug}; if (defined $arguments{show_version}) { print "$0 version $pluginVersion\n"; exit $status{OK}; } if (defined $arguments{show_help}) { usage(); exit $status{UNKNOWN}; } if (! defined $arguments{conf}) { usage(); exit $status{UNKNOWN}; } # Arrays for objects to monitor my @monitoredStorages; my @monitoredNodes; my @monitoredOpenvz; my @monitoredQemus; my @monitoredPools; my $connected = 0; my $host = undef; my $username = undef; my $password = undef; my $realm = undef; my $pve; my $qdiskStatus = undef; my %qdisk = ( id => undef, name => undef, estranged => undef, cstate => undef, status => $status{UNKNOWN}, ); my $readingObject = 0; # Output option my $br = "\n"; $br = "
" if (defined $arguments{html}); # Read the configuration file if (! open FILE, "<", "$arguments{conf}") { print "$!\n" if $arguments{debug}; print "Cannot load configuration file $arguments{conf} !\n"; exit $status{UNKNOWN}; } while ( ) { my $line = $_; # Skip commented lines (starting with #) next if $line =~ m/^#/i; # we got an object definition here ! if ( $line =~ m/([\S]+)\s+([\S]+)\s+\{/i ) { switch ($1) { case "node" { my $name = $2; my $warnCpu = undef; my $warnMem = undef; my $warnDisk = undef; my $critCpu = undef; my $critMem = undef; my $critDisk = undef; my $nAddr = undef; my $nPort = 8006; my $nUser = undef; my $nPwd = undef; my $nRealm = 'pam'; my $warnMemAlloc = undef; my $critMemAlloc = undef; my $warnCpuAlloc = undef; my $critCpuAlloc = undef; $readingObject = 1; while () { my $objLine = $_; next if ( $objLine =~ m/^(\s+)?#/ ); if ( $objLine =~ m/([\S]+)\s+([\S]+)(\s+([\S]+))?/i ) { switch ($1) { case "cpu" { if ((is_number $2)and(is_number $4)) { $warnCpu = $2; $critCpu = $4; } else { close(FILE); print "Invalid CPU declaration " . "in $name definition\n"; exit $status{UNKNOWN}; } } case "cpu_alloc" { if((is_number $2)and(is_number $4)) { $warnCpuAlloc = $2; $critCpuAlloc = $4; } else { close(FILE); print "Invalid CPU_ALLOC declaration " . "in $name definition\n"; exit $status{UNKNOWN}; } } case "mem" { if ((is_number $2)and(is_number $4)) { $warnMem = $2; $critMem = $4; } else { close(FILE); print "Invalid MEM declaration " . "in $name definition\n"; exit $status{UNKNOWN}; } } case "disk" { if ((is_number $2)and(is_number $4)) { $warnDisk = $2; $critDisk = $4; } else { close(FILE); print "Invalid DISK declaration " . "in $name definition\n"; exit $status{UNKNOWN}; } } case "mem_alloc" { if ((is_number $2)and(is_number $4)) { $warnMemAlloc = $2; $critMemAlloc = $4; } else { close(FILE); print "Invalid MEM_ALLOC declaration " . "in $name definition\n"; exit $status{UNKNOWN}; } } case "address" { $nAddr = $2; } case "port" { if (is_number $2) { $nPort = $2; } else { close(FILE); print "Invalid PORT declaration " . "in $name definition\n"; exit $status{UNKNOWN}; } } case "monitor_account" { $nUser = $2; } case "monitor_password" { $nPwd = $2; } case "realm" { $nRealm = $2; } else { close(FILE); print "Invalid token $1 in $name definition !\n"; exit $status{UNKNOWN}; } } } elsif ( $objLine =~ m/\}/i ) { # check object requirements are met, save it, break if (! defined $name ) { close(FILE); print "Invalid configuration !"; exit $status{UNKNOWN}; } print "Loaded node $name\n" if $arguments{debug}; $monitoredNodes[scalar(@monitoredNodes)] = ({ name => $name, address => $nAddr, port => $nPort, username => $nUser, realm => $nRealm, password => $nPwd, warn_cpu => $warnCpu, warn_cpu_alloc => $warnCpuAlloc, warn_mem => $warnMem, warn_mem_alloc => $warnMemAlloc, warn_disk => $warnDisk, crit_cpu => $critCpu, crit_cpu_alloc => $critCpuAlloc, crit_mem => $critMem, crit_mem_alloc => $critMemAlloc, crit_disk => $critDisk, cpu_status => $status{OK}, mem_status => $status{OK}, disk_status => $status{OK}, mem_alloc_status => $status{OK}, cpu_alloc_status => $status{OK}, alive => 0, curmem => undef, curdisk => undef, curcpu => undef, status => $status{UNDEF}, uptime => undef, mem_alloc => 0, maxmem => undef, cpu_alloc => undef, maxcpu => undef, }, ); $readingObject = 0; last; } else { print "Invalid line " . chomp($objLine) . " at line $. !\n" if $arguments{debug}; } } } case "storage" { my $name = $2; my $warnDisk = undef; my $critDisk = undef; my $node = undef; $readingObject = 1; while () { my $objLine = $_; next if ( $objLine =~ m/^#/i ); if ( $objLine =~ m/([\S]+)\s+([\S]+)(\s+([\S]+))?/i ) { switch ($1) { case "disk" { if ((is_number $2)and(is_number $4)) { $warnDisk = $2; $critDisk = $4; } else { close(FILE); print "Invalid DISK declaration " . "in $name definition\n"; exit $status{UNKNOWN}; } } case "node" { $node = $2; } else { close(FILE); print "Invalid token $1 " . "in $name definition !\n"; exit $status{UNKNOWN}; } } } elsif ( $objLine =~ m/\}/i ) { # check object requirements are met, save it, break if (! defined $name ) { close(FILE); print "Invalid configuration !"; exit $status{UNKNOWN}; } if (! defined $node ) { close(FILE); print "Invalid configuration, " . "missing node in $name storage definition !\n"; exit $status{UNKNOWN}; } print "Loaded storage $name\n" if $arguments{debug}; $monitoredStorages[scalar(@monitoredStorages)] = ({ name => $name, node => $node, warn_disk => $warnDisk, crit_disk => $critDisk, curdisk => undef, disk_status => $status{OK}, status => $status{UNDEF}, }, ); $readingObject = 0; last; } } } case /openvz|lxc|container/ { my $name = $2; my $warnCpu = undef; my $warnMem = undef; my $warnDisk = undef; my $critCpu = undef; my $critMem = undef; my $critDisk = undef; $readingObject = 1; while () { my $objLine = $_; next if ( $objLine =~ m/^#/i ); if ( $objLine =~ m/([\S]+)\s+([\S]+)\s+([\S]+)/i ) { switch ($1) { case "cpu" { if ((is_number $2) and (is_number $3)) { $warnCpu = $2; $critCpu = $3; } else { close(FILE); print "Invalid CPU declaration " . "in $name definition\n"; exit $status{UNKNOWN}; } } case "mem" { if ((is_number $2) and (is_number $3)) { $warnMem = $2; $critMem = $3; } else { close(FILE); print "Invalid MEM declaration " . "in $name definition\n"; exit $status{UNKNOWN}; } } case "disk" { if ((is_number $2) and (is_number $3)) { $warnDisk = $2; $critDisk = $3; } else { close(FILE); print "Invalid DISK declaration " . "in $name definition\n"; exit $status{UNKNOWN}; } } else { close(FILE); print "Invalid token $1 " . "in $name definition !\n"; exit $status{UNKNOWN}; } } } elsif ( $objLine =~ m/\}/i ) { # check object requirements are met, save it, break if (! defined $name ) { close(FILE); print "Invalid configuration !"; exit $status{UNKNOWN}; } print "Loaded openvz $name\n" if $arguments{debug}; $monitoredOpenvz[scalar(@monitoredOpenvz)] = ({ name => $name, warn_cpu => $warnCpu, warn_mem => $warnMem, warn_disk => $warnDisk, crit_cpu => $critCpu, crit_mem => $critMem, crit_disk => $critDisk, alive => undef, curmem => undef, curdisk => undef, curcpu => undef, cpu_status => $status{OK}, mem_status => $status{OK}, disk_status => $status{OK}, status => $status{UNDEF}, uptime => undef, node => undef, }, ); $readingObject = 0; last; } } } case "qemu" { my $name = $2; my $warnCpu = undef; my $warnMem = undef; my $warnDisk = undef; my $critCpu = undef; my $critMem = undef; my $critDisk = undef; $readingObject = 1; while () { my $objLine = $_; next if ( $objLine =~ m/^#/i ); if ( $objLine =~ m/([\S]+)\s+([\S]+)\s+([\S]+)/i ) { switch ($1) { case "cpu" { if ((is_number $2)and(is_number $3)) { $warnCpu = $2; $critCpu = $3; } else { close(FILE); print "Invalid CPU declaration " . "in $name definition\n"; exit $status{UNKNOWN}; } } case "mem" { if ((is_number $2)and(is_number $3)) { $warnMem = $2; $critMem = $3; } else { close(FILE); print "Invalid MEM declaration " . "in $name definition\n"; exit $status{UNKNOWN}; } } case "disk" { if ((is_number $2)and(is_number $3)) { $warnDisk = $2; $critDisk = $3; } else { close(FILE); print "Invalid DISK declaration " . "in $name definition\n"; exit $status{UNKNOWN}; } } else { close(FILE); print "Invalid token $1 " . "in $name definition !\n"; exit $status{UNKNOWN}; } } } elsif ( $objLine =~ m/\}/i ) { # check object requirements are met, save it, break if (! defined $name ) { close(FILE); print "Invalid configuration !\n"; exit $status{UNKNOWN}; } print "Loaded qemu $name\n" if $arguments{debug}; $monitoredQemus[scalar(@monitoredQemus)] = ( { name => $name, warn_cpu => $warnCpu, warn_mem => $warnMem, warn_disk => $warnDisk, crit_cpu => $critCpu, crit_mem => $critMem, crit_disk => $critDisk, alive => undef, curmem => undef, curdisk => undef, curcpu => undef, cpu_status => $status{OK}, mem_status => $status{OK}, disk_status => $status{OK}, status => $status{UNDEF}, uptime => undef, node => undef, }, ); $readingObject = 0; last; } } } case "pool" { my $name = $2; my $warnCpu = undef; my $warnMem = undef; my $warnDisk = undef; my $critCpu = undef; my $critMem = undef; my $critDisk = undef; $readingObject = 1; while () { my $objLine = $_; next if ( $objLine =~ m/^#/i ); if ( $objLine =~ m/([\S]+)\s+([\S]+)\s+([\S]+)/i ) { switch ($1) { case "cpu" { if ((is_number $2)and(is_number $3)) { $warnCpu = $2; $critCpu = $3; } else { close(FILE); print "Invalid CPU declaration " . "in $name definition\n"; exit $status{UNKNOWN}; } } case "mem" { if ((is_number $2)and(is_number $3)) { $warnMem = $2; $critMem = $3; } else { close(FILE); print "Invalid MEM declaration " . "in $name definition\n"; exit $status{UNKNOWN}; } } case "disk" { if ((is_number $2)and(is_number $3)) { $warnDisk = $2; $critDisk = $3; } else { close(FILE); print "Invalid DISK declaration " . "in $name definition\n"; exit $status{UNKNOWN}; } } else { close(FILE); print "Invalid token $1 " . "in $name definition !\n"; exit $status{UNKNOWN}; } } } elsif ( $objLine =~ m/\}/i ) { # check object requirements are met, save it, break if (! defined $name ) { close(FILE); print "Invalid configuration !\n"; exit $status{UNKNOWN}; } print "Loaded pool $name\n" if $arguments{debug}; $monitoredPools[scalar(@monitoredPools)] = ( { name => $name, warn_cpu => $warnCpu, warn_mem => $warnMem, warn_disk => $warnDisk, crit_cpu => $critCpu, crit_mem => $critMem, crit_disk => $critDisk, }, ); $readingObject = 0; last; } } } else { close(FILE); print "Invalid token $1 " . "in configuration file $arguments{conf} !\n"; exit $status{UNKNOWN}; } } } } close(FILE); if ( $readingObject ) { print "Invalid configuration ! (Probably missing '}' ) \n"; exit $status{UNKNOWN}; } for($a = 0; $a < scalar(@monitoredNodes); $a++) { my $host = $monitoredNodes[$a]->{address} or next; my $port = $monitoredNodes[$a]->{port} or next; my $username = $monitoredNodes[$a]->{username} or next; my $password = $monitoredNodes[$a]->{password} or next; my $realm = $monitoredNodes[$a]->{realm} or next; my $isClusterMember = 0; print "Trying " . $host . "...\n" if $arguments{debug}; $pve = Net::Proxmox::VE->new( host => $host, username => $username, password => $password, debug => $arguments{debug}, realm => $realm, timeout => $arguments{timeout}, ssl_opts => { SSL_verify_mode => SSL_VERIFY_NONE, verify_hostname => 0 } ); next unless $pve->login; next unless $pve->check_login_ticket; next unless $pve->api_version_check; # Here we are connected, quit the loop print "Successfully connected to " . $host . " !\n" if $arguments{debug}; # skip cluster status checks if we are not in cluster if (defined $arguments{singlenode}) { print "Skipping cluster checks (--singlenode passed to command line)\n" if $arguments{debug}; $connected = 1; last; } # check if node is quorate, if it's not then # we are probably on a dead node and data is irrelevant my $cstatuses = $pve->get('/cluster/status'); foreach my $item( @$cstatuses ) { switch ($item->{type}) { case "node" { # qdisks are also type "node" if ($item->{qdisk} eq "1") { print "Found qdisk $item->{name} in cluster\n" if $arguments{debug}; $qdisk{id} = $item->{id}; $qdisk{name} = $item->{name}; $qdisk{estranged} = $item->{estranged}; # boolean value $qdisk{cstate} = $item->{state}; # boolean value } elsif ($item->{local} eq "1") { if ($item->{estranged} eq "0" || $item->{estranged} eq "") { $isClusterMember = 1; print "Node $item->{ip} is in cluster and seems sane. Using it to query cluster status\n" if $arguments{debug}; } else { print "Node $item->{ip} is estranged ! Skipping it !\n" if $arguments{debug}; } } } default { next; } } } if ($isClusterMember) { $connected = 1; last; # we queried a valid cluster member, quit the loop } } if (! $connected ) { print "Could not connect to any server !"; exit $status{UNKNOWN}; } if (defined $arguments{qdisk}) { my $statusStr = ''; if ( defined $qdisk{id} ) { $qdisk{status} = $status{OK}; if ($qdisk{estranged} eq "1") { $statusStr .= "Qdisk $qdisk{name} is estranged !\n"; $qdisk{status} += $status{WARNING}; } if ($qdisk{cstate} eq "0") { $statusStr .= "Qdisk $qdisk{name} is in invalid status !\n"; $qdisk{status} += $status{WARNING}; } print "Qdisk $rstatus{$qdisk{status}}\n$statusStr"; exit $qdisk{status}; } else { print "No qdisk found in cluster !\n"; exit $status{UNKNOWN}; } } # list all ressources of the cluster my $objects = $pve->get('/cluster/resources'); print "Found " . scalar(@$objects) . " objects:\n" if $arguments{debug}; # loop the objects to find our pool definitions if (defined $arguments{pools}) { foreach my $item( @$objects ) { next unless (defined $item->{pool}); # loop the pool array to see if that one is monitored foreach my $mpool( @monitoredPools ) { next unless ($item->{pool} eq $mpool->{name}); print "Found $mpool->{name} in resource list\n" if $arguments{debug}; #get pool members my $pool = $pve->get('/pools/' . $mpool->{name}); my $members = $pool->{members}; #fill monitored pool members not defined in config already foreach my $member( @$members ) { switch ($member->{type}) { case /openvz|lxc/ { unless (grep $_->{name} eq $member->{name}, @monitoredOpenvz) { $monitoredOpenvz[scalar(@monitoredOpenvz)] = ( { name => $member->{name}, warn_cpu => $mpool->{warn_cpu}, warn_mem => $mpool->{warn_mem}, warn_disk => $mpool->{warn_disk}, crit_cpu => $mpool->{crit_cpu}, crit_mem => $mpool->{crit_mem}, crit_disk => $mpool->{crit_disk}, alive => undef, curmem => undef, curdisk => undef, curcpu => undef, cpu_status => $status{OK}, mem_status => $status{OK}, disk_status => $status{OK}, status => $status{UNDEF}, uptime => undef, node => undef, pool => $mpool->{name}, },); print "Loaded container " . $member->{name} . " from pool " . $mpool->{name} . "\n" if $arguments{debug}; } } case "qemu" { unless (grep $_->{name} eq $member->{name}, @monitoredQemus) { $monitoredQemus[scalar(@monitoredQemus)] = ( { name => $member->{name}, warn_cpu => $mpool->{warn_cpu}, warn_mem => $mpool->{warn_mem}, warn_disk => $mpool->{warn_disk}, crit_cpu => $mpool->{crit_cpu}, crit_mem => $mpool->{crit_mem}, crit_disk => $mpool->{crit_disk}, alive => undef, curmem => undef, curdisk => undef, curcpu => undef, cpu_status => $status{OK}, mem_status => $status{OK}, disk_status => $status{OK}, status => $status{UNDEF}, uptime => undef, node => undef, pool => $mpool->{name}, },); print "Loaded qemu " . $member->{name} . " from pool " . $mpool->{name} . "\n" if $arguments{debug}; } } case "storage" { unless (grep $_->{name} eq $member->{storage}, @monitoredStorages) { $monitoredStorages[scalar(@monitoredStorages)] = ({ name => $member->{storage}, node => $member->{node}, warn_disk => $mpool->{warn_disk}, crit_disk => $mpool->{crit_disk}, curdisk => undef, disk_status => $status{OK}, status => $status{UNDEF}, pool => $mpool->{name}, },); print "Loaded storage " . $member->{storage} . " from pool " . $mpool->{name} . "\n" if $arguments{debug}; } } } } } } } # loop the objects to compare our definitions with the current state of the cluster foreach my $item( @$objects ) { switch ($item->{type}) { case "node" { # loop the node array to see if that one is monitored foreach my $mnode( @monitoredNodes ) { next unless ($item->{node} eq $mnode->{name}); print "Found $mnode->{name} in resource list\n" if $arguments{debug}; # if a node is down, many values are not set if(defined $item->{uptime}) { $mnode->{status} = $status{OK}; $mnode->{uptime} = $item->{uptime}; $mnode->{maxmem} = $item->{maxmem}; $mnode->{maxcpu} = $item->{maxcpu}; if ($item->{maxmem} > 0) { my $curMem = $item->{mem} / $item->{maxmem} * 100; $mnode->{curmem} = sprintf("%.2f", $curMem); } if ($item->{maxdisk} > 0) { my $curDisk = $item->{disk} / $item->{maxdisk} * 100; $mnode->{curdisk} = sprintf("%.2f", $curDisk); } if ($item->{maxcpu} > 0) { my $curCpu = $item->{cpu} / $item->{maxcpu} * 100; $mnode->{curcpu} = sprintf("%.2f", $curCpu); } } else { $mnode->{status} = -1; $mnode->{uptime} = 0; $mnode->{curmem} = 0; $mnode->{curdisk} = 0; $mnode->{curcpu} = 0; } last; } } case "storage" { foreach my $mstorage( @monitoredStorages ) { next unless ($item->{storage} eq $mstorage->{name}); next unless ($item->{node} eq $mstorage->{node}); print "Found $mstorage->{name} in resource list\n" if $arguments{debug}; if (defined $item->{disk} ) { $mstorage->{status} = $status{OK}; if ($item->{maxdisk} > 0) { my $curDisk = $item->{disk} / $item->{maxdisk} * 100; $mstorage->{curdisk} = sprintf("%.2f", $curDisk); } } else { $mstorage->{status} = -1; $mstorage->{curdisk} = 0; } last; } next; } case /openvz|lxc/ { #loop monitored nodes to increase mem_hi_limit foreach my $mnode( @monitoredNodes ) { next unless $mnode->{name} eq $item->{node}; if (defined $item->{status}) { if ($item->{status} eq "running") { $mnode->{mem_alloc} += $item->{maxmem}; $mnode->{cpu_alloc} += $item->{maxcpu}; } } last; } foreach my $mopenvz( @monitoredOpenvz ) { next unless ($item->{name} eq $mopenvz->{name}); print "Found $mopenvz->{name} in resource list\n" if $arguments{debug}; if (defined $item->{status}) { $mopenvz->{status} = $status{OK}; $mopenvz->{alive} = $item->{status}; $mopenvz->{uptime} = $item->{uptime}; $mopenvz->{node} = $item->{node}; if ($item->{maxmem} > 0) { my $curMem = $item->{mem} / $item->{maxmem} * 100; $mopenvz->{curmem} = sprintf("%.2f", $curMem); } if ($item->{maxdisk} > 0) { my $curDisk = $item->{disk} / $item->{maxdisk} * 100; $mopenvz->{curdisk} = sprintf("%.2f", $curDisk); } if ($item->{maxcpu} > 0) { my $curCpu = $item->{cpu} / $item->{maxcpu} * 100; $mopenvz->{curcpu} = sprintf("%.2f", $curCpu); } } else { $mopenvz->{alive} = "on dead node"; $mopenvz->{uptime} = 0; $mopenvz->{curmem} = 0; $mopenvz->{curdisk} = 0; $mopenvz->{curcpu} = 0; } last; } next; } case "qemu" { #loop monitored nodes to increase mem_hi_limit foreach my $mnode( @monitoredNodes ) { next unless $mnode->{name} eq $item->{node}; if (defined $item->{status}) { if ($item->{status} eq "running") { $mnode->{mem_alloc} += $item->{maxmem}; $mnode->{cpu_alloc} += $item->{maxcpu}; } } last; } foreach my $mqemu( @monitoredQemus ) { next unless ($item->{name} eq $mqemu->{name}); print "Found $mqemu->{name} in resource list\n" if $arguments{debug}; if(defined $item->{status}) { $mqemu->{status} = $status{OK}; $mqemu->{alive} = $item->{status}; $mqemu->{uptime} = $item->{uptime}; $mqemu->{node} = $item->{node}; if ($item->{maxmem} > 0) { my $maxMem = $item->{mem} / $item->{maxmem} * 100; $mqemu->{curmem} = sprintf("%.2f", $maxMem); } if ($item->{maxdisk}) { my $curDisk = $item->{disk} / $item->{maxdisk} * 100; $mqemu->{curdisk} = sprintf("%.2f", $curDisk); } if ($item->{maxcpu} > 0) { my $curCpu = $item->{cpu} / $item->{maxcpu} * 100; $mqemu->{curcpu} = sprintf("%.2f", $curCpu); } } else { $mqemu->{alive} = "on dead node"; $mqemu->{uptime} = 0; $mqemu->{curmem} = 0; $mqemu->{curdisk} = 0; $mqemu->{curcpu} = 0; } last; } next; } } } # Finally, loop the monitored objects arrays to report situation my $totalScore = 0; my $totalPerfData = "|"; if (defined $arguments{nodes}) { my $statusScore = 0; my $workingNodes = 0; my $reportSummary = ''; foreach my $mnode( @monitoredNodes ) { $statusScore += $mnode->{status}; if ($mnode->{status} ne $status{UNDEF}) { # compute max memory usage my $memAlloc = 0; $memAlloc = sprintf("%.2f", $mnode->{mem_alloc} / $mnode->{maxmem} * 100) if ($mnode->{maxmem} > 0); my $cpuAlloc = 0; $cpuAlloc = sprintf("%.2f", $mnode->{cpu_alloc} / $mnode->{maxcpu} * 100) if ($mnode->{maxcpu} > 0); if (defined $mnode->{warn_mem_alloc}) { $mnode->{mem_alloc_status} = $status{WARNING} if ($memAlloc > $mnode->{warn_mem_alloc}); } if (defined $mnode->{crit_mem_alloc}) { $mnode->{mem_alloc_status} = $status{CRITICAL} if ($memAlloc > $mnode->{crit_mem_alloc}); } if (defined $mnode->{warn_cpu_alloc}) { $mnode->{cpu_alloc_status} = $status{WARNING} if ($cpuAlloc > $mnode->{warn_cpu_alloc}); } if (defined $mnode->{crit_cpu_alloc}) { $mnode->{cpu_alloc_status} = $status{CRITICAL} if ($cpuAlloc > $mnode->{crit_cpu_alloc}); } if (defined $mnode->{warn_mem}) { $mnode->{mem_status} = $status{WARNING} if ($mnode->{curmem} > $mnode->{warn_mem}); } if (defined $mnode->{crit_mem}) { $mnode->{mem_status} = $status{CRITICAL} if ($mnode->{curmem} > $mnode->{crit_mem}); } if (defined $mnode->{warn_disk}) { $mnode->{disk_status} = $status{WARNING} if ($mnode->{curdisk} > $mnode->{warn_disk}); } if (defined $mnode->{crit_disk}) { $mnode->{disk_status} = $status{CRITICAL} if ($mnode->{curdisk} > $mnode->{crit_disk}); } if (defined $mnode->{warn_cpu}) { $mnode->{cpu_status} = $status{WARNING} if ($mnode->{curcpu} > $mnode->{warn_cpu}); } if (defined $mnode->{crit_cpu}) { $mnode->{crit_cpu} = $status{CRITICAL} if ($mnode->{curcpu} > $mnode->{crit_cpu}); } my $curNodeStatus = $mnode->{cpu_status} + $mnode->{mem_status} + $mnode->{disk_status} + $mnode->{cpu_alloc_status} + $mnode->{mem_alloc_status}; $curNodeStatus = $status{CRITICAL} if ($curNodeStatus >= $status{UNKNOWN}); if ($mnode->{status} ne $status{UNDEF}) { $reportSummary .= "$mnode->{name} $rstatus{$curNodeStatus} : " . "cpu $rstatus{$mnode->{cpu_status}} ($mnode->{curcpu}%), " . "mem $rstatus{$mnode->{mem_status}} ($mnode->{curmem}%), " . "disk $rstatus{$mnode->{disk_status}} ($mnode->{curdisk}%) " . "cpu alloc $rstatus{$mnode->{cpu_alloc_status}} ($cpuAlloc%), " . "mem alloc $rstatus{$mnode->{mem_alloc_status}} ($memAlloc%), " . "uptime $mnode->{uptime}" . $br; $workingNodes++ if $mnode->{status} eq $status{OK}; } else { $reportSummary .= "$mnode->{name} $rstatus{$status{CRITICAL}} : ". "node is out of cluster (dead?)" . $br; } $statusScore += $curNodeStatus; # Do not leave $statusScore at level unknown here $statusScore++ if $statusScore eq $status{UNKNOWN}; } else { $reportSummary .= "$mnode->{name} " . "is in status $rstatus{$status{UNKNOWN}}" . $br; } } $statusScore = $status{CRITICAL} if (( $statusScore > $status{UNKNOWN}) or ($statusScore < 0)); print "NODES $rstatus{$statusScore} $workingNodes / " . scalar(@monitoredNodes) . " working nodes" . $br . $reportSummary; $totalScore += $statusScore; }; if (defined $arguments{storages}) { my $statusScore = 0; my $workingStorages = 0; my $reportSummary = ''; my $perfData = ''; foreach my $mstorage( @monitoredStorages ) { #Add pool name to output #$mstorage->{name} .= "/" . $mstorage->{pool} if defined $mstorage->{pool}; if ($mstorage->{status} eq -1) { $statusScore += $status{CRITICAL}; $reportSummary .= "$mstorage->{name} ($mstorage->{node}) " . "$rstatus{$status{CRITICAL}}: " . "storage is on a dead node" . $br; } elsif ($mstorage->{status} ne $status{UNKNOWN}) { if (defined $mstorage->{warn_disk}) { $mstorage->{disk_status} = $status{WARNING} if $mstorage->{curdisk} > $mstorage->{warn_disk}; } if (defined $mstorage->{crit_disk}) { $mstorage->{disk_status} = $status{CRITICAL} if $mstorage->{curdisk} > $mstorage->{crit_disk}; } $reportSummary .= "$mstorage->{name} ($mstorage->{node}) " . "$rstatus{$mstorage->{status}} : " . "disk $mstorage->{curdisk}%" . $br; $perfData .= "$mstorage->{name}-$mstorage->{node}::check_pve_storage::" . "disk=$mstorage->{curdisk}%;$mstorage->{warn_disk};$mstorage->{crit_disk} "; $workingStorages++; $statusScore += $mstorage->{disk_status}; $statusScore++ if $statusScore eq $status{UNKNOWN}; } else { $reportSummary .= "$mstorage->{name} " . "is in status $rstatus{$status{UNKNOWN}}" . $br; } } $statusScore = $status{CRITICAL} if ($statusScore > $status{UNKNOWN}); print "STORAGE $rstatus{$statusScore} $workingStorages / " . scalar(@monitoredStorages) . " working storages" . $br . $reportSummary; $totalPerfData .= "STORAGE::check_pve_storages::storages=$workingStorages;;;0;" . scalar(@monitoredStorages) . " " . $perfData; $totalScore += $statusScore; }; if (defined $arguments{openvz}) { my $statusScore = 0; my $workingVms = 0; my $reportSummary = ''; my $perfData = ''; foreach my $mopenvz( @monitoredOpenvz ) { #Add pool name to output #$mopenvz->{name} .= "/" . $mopenvz->{pool} if defined $mopenvz->{pool}; if ($mopenvz->{status} ne $status{UNDEF}) { if (defined $mopenvz->{warn_mem}) { $mopenvz->{mem_status} = $status{WARNING} if ($mopenvz->{curmem} > $mopenvz->{warn_mem}); } if (defined $mopenvz->{crit_mem}) { $mopenvz->{mem_status} = $status{CRITICAL} if $mopenvz->{curmem} > $mopenvz->{crit_mem}; } if (defined $mopenvz->{warn_disk}) { $mopenvz->{disk_status} = $status{WARNING} if $mopenvz->{curdisk} > $mopenvz->{warn_disk}; } if (defined $mopenvz->{crit_disk}) { $mopenvz->{disk_status} = $status{CRITICAL} if $mopenvz->{curdisk} > $mopenvz->{crit_disk}; } if (defined $mopenvz->{warn_cpu}) { $mopenvz->{cpu_status} = $status{WARNING} if $mopenvz->{curcpu} > $mopenvz->{warn_cpu}; } if (defined $mopenvz->{crit_cpu}) { $mopenvz->{cpu_status} = $status{CRITICAL} if $mopenvz->{curcpu} > $mopenvz->{crit_cpu}; } if (defined $mopenvz->{alive}) { if ($mopenvz->{alive} eq "running") { $mopenvz->{status} = $status{OK}; $workingVms++; $reportSummary .= "$mopenvz->{name} ($mopenvz->{node}) " . "$rstatus{$mopenvz->{status}} : " . "cpu $rstatus{$mopenvz->{cpu_status}} ($mopenvz->{curcpu}%), " . "mem $rstatus{$mopenvz->{mem_status}} ($mopenvz->{curmem}%), " . "disk $rstatus{$mopenvz->{disk_status}} ($mopenvz->{curdisk}%) " . "uptime $mopenvz->{uptime}" . $br; $perfData .= "$mopenvz->{name}::check_pve_openvz::" . "cpu=$mopenvz->{curcpu}%;$mopenvz->{warn_cpu};$mopenvz->{crit_cpu} " . "mem=$mopenvz->{curmem}%;$mopenvz->{warn_mem};$mopenvz->{crit_mem} "; } else { $mopenvz->{status} = $status{CRITICAL}; $statusScore += $status{CRITICAL}; $reportSummary .= "$mopenvz->{name} " . "$rstatus{$mopenvz->{status}} : " . "VM is $mopenvz->{alive}" . $br; } } $statusScore += $mopenvz->{cpu_status} + $mopenvz->{mem_status} + $mopenvz->{disk_status}; $statusScore++ if $statusScore eq $status{UNKNOWN}; } else { $reportSummary .= "$mopenvz->{name} " . "is in status $rstatus{$status{UNKNOWN}}" . $br; $statusScore += $status{UNKNOWN}; } } $statusScore = $status{CRITICAL} if ($statusScore > $status{UNKNOWN}); print "OPENVZ $rstatus{$statusScore} $workingVms / " . scalar(@monitoredOpenvz) . " working VMs" . $br . $reportSummary; $totalPerfData .= "OPENVZ::check_pve_vms::vmcount=$workingVms;;;0;" . scalar(@monitoredOpenvz) . " " . $perfData; $totalScore += $statusScore; }; if (defined $arguments{qemu}) { my $statusScore = 0; my $workingVms = 0; my $reportSummary = ''; my $perfData = ''; foreach my $mqemu( @monitoredQemus ) { #Add pool name to output #$mqemu->{name} .= "/" . $mqemu->{pool} if defined $mqemu->{pool}; if ($mqemu->{status} ne $status{UNDEF}) { if (defined $mqemu->{warn_mem}) { $mqemu->{mem_status} = $status{WARNING} if $mqemu->{curmem} > $mqemu->{warn_mem}; } if (defined $mqemu->{crit_mem}) { $mqemu->{mem_status} = $status{CRITICAL} if $mqemu->{curmem} > $mqemu->{crit_mem}; } if (defined $mqemu->{warn_disk}) { $mqemu->{disk_status} = $status{WARNING} if $mqemu->{curdisk} > $mqemu->{warn_disk}; } if (defined $mqemu->{crit_disk}) { $mqemu->{disk_status} = $status{CRITICAL} if $mqemu->{curdisk} > $mqemu->{crit_disk}; } if (defined $mqemu->{warn_cpu}) { $mqemu->{cpu_status} = $status{WARNING} if $mqemu->{curcpu} > $mqemu->{warn_cpu}; } if (defined $mqemu->{crit_cpu}) { $mqemu->{cpu_status} = $status{CRITICAL} if $mqemu->{curcpu} > $mqemu->{crit_cpu}; } if ($mqemu->{alive} eq "running") { $mqemu->{status} = $status{OK}; $workingVms++; $reportSummary .= "$mqemu->{name} ($mqemu->{node}) $rstatus{$mqemu->{status}} : " . "cpu $rstatus{$mqemu->{cpu_status}} ($mqemu->{curcpu}%), " . "mem $rstatus{$mqemu->{mem_status}} ($mqemu->{curmem}%), " . "disk $rstatus{$mqemu->{disk_status}} ($mqemu->{curdisk}%) " . "uptime $mqemu->{uptime}" . $br; $perfData .= "$mqemu->{name}::check_pve_qemu::" . "cpu=$mqemu->{curcpu}%;$mqemu->{warn_cpu};$mqemu->{crit_cpu} " . "mem=$mqemu->{curmem}%;$mqemu->{warn_mem};$mqemu->{crit_mem} "; } else { $mqemu->{status} = $status{CRITICAL}; $reportSummary .= "$mqemu->{name} $rstatus{$mqemu->{status}} : " . "VM is $mqemu->{alive}" . $br; $statusScore += $status{CRITICAL}; $mqemu->{status} = $status{CRITICAL}; } $statusScore += $mqemu->{cpu_status} + $mqemu->{mem_status} + $mqemu->{disk_status}; $statusScore++ if $statusScore eq $status{UNKNOWN}; } else { $reportSummary .= "$mqemu->{name} " . "is in status $rstatus{$status{UNKNOWN}}" . $br; $statusScore += $status{UNKNOWN}; } } $statusScore = $status{CRITICAL} if ($statusScore > $status{UNKNOWN}); print "QEMU $rstatus{$statusScore} $workingVms / " . scalar(@monitoredQemus) . " working VMs" . $br . $reportSummary; $totalPerfData .= "QEMU::check_pve_vms::vmcount=$workingVms;;;0;" . scalar(@monitoredQemus) . " " . $perfData; $totalScore += $statusScore; }; if (not defined $arguments{qemu} and not defined $arguments{openvz} and not defined $arguments{storages} and not defined $arguments{nodes}) { usage(); exit $status{UNKNOWN}; } print $totalPerfData if (defined $arguments{perfdata} and $totalPerfData ne "|"); exit $totalScore;