1301 lines
50 KiB
Plaintext
1301 lines
50 KiB
Plaintext
|
#!/usr/bin/perl -w
|
||
|
# $Id: libvirt 24900 2010-03-30 13:50:40Z espen $
|
||
|
#
|
||
|
# Copyright (C) 2010 Espen Braastad
|
||
|
#
|
||
|
# 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; version 2 dated June,
|
||
|
# 1991.
|
||
|
#
|
||
|
# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||
|
#
|
||
|
#
|
||
|
# This multigraph plugin monitors libvirt resource usage.
|
||
|
#
|
||
|
# Configuration variables:
|
||
|
#
|
||
|
# General variables:
|
||
|
# address - to libvirt (default "xen:///")
|
||
|
# username - to libvirt (default: "")
|
||
|
# password - to libvirt (default: "")
|
||
|
# tmpfile - to cache values (default: "/var/lib/munin/plugin-state/libvirt")
|
||
|
#
|
||
|
# Variables to enable or disable graphs:
|
||
|
# show_cpu_used - 1 to enable, 0 to disable [default = 1]
|
||
|
# show_disk_traffic - 1 to enable, 0 to disable [default = 1]
|
||
|
# show_disk_utilization - 1 to enable, 0 to disable [default = 1]
|
||
|
# show_disk_latency - 1 to enable, 0 to disable [default = 1]
|
||
|
# show_memory_allocated - 1 to enable, 0 to disable [default = 1]
|
||
|
# show_network_traffic - 1 to enable, 0 to disable [default = 1]
|
||
|
# show_network_drops - 1 to enable, 0 to disable [default = 1]
|
||
|
#
|
||
|
# Requirements:
|
||
|
# RHEL5: perl-Sys-Virt.x86_64
|
||
|
#
|
||
|
# Revision 1.4 2010/03/30 espen
|
||
|
# Added graphs for i/o utilization
|
||
|
#
|
||
|
# Revision 1.3 2010/03/29 espen
|
||
|
# Added graphs for i/o latency
|
||
|
#
|
||
|
# Revision 1.2 2010/03/19 espen
|
||
|
# Added support for enable/disable graphs from plugin-conf.d.
|
||
|
# Added graphs for disk errors and network drops.
|
||
|
#
|
||
|
# Revision 1.1 2010/03/14 espen
|
||
|
# Added support for monitoring network (bits) and disk (bytes) usage.
|
||
|
#
|
||
|
# Revision 1.0 2010/03/11 espen
|
||
|
# Initial version. Support for cpu and memory per domain.
|
||
|
#
|
||
|
#%# family=auto
|
||
|
#%# capabilities=autoconf
|
||
|
|
||
|
use strict;
|
||
|
use XML::Twig;
|
||
|
use Sys::Virt;
|
||
|
use Sys::Virt::Domain;
|
||
|
use File::stat;
|
||
|
use Storable;
|
||
|
use Time::localtime;
|
||
|
|
||
|
my $address = $ENV{address} || "xen:///";
|
||
|
my $username = $ENV{username} || "";
|
||
|
my $password = $ENV{password} || "";
|
||
|
my $tmpfile = $ENV{tmpfile} || "/var/lib/munin/plugin-state/libvirt";
|
||
|
my $decimals=5;
|
||
|
|
||
|
my %show=();
|
||
|
|
||
|
# Reading values from plugin-conf.d or set defaults.
|
||
|
$show{'cpu_used'} = $ENV{show_cpu_used} || 1;
|
||
|
$show{'disk_traffic'} = $ENV{show_disk_traffic} || 1;
|
||
|
$show{'disk_utilization'} = $ENV{show_disk_utilization} || 1;
|
||
|
$show{'disk_latency'} = $ENV{show_disk_latency} || 1;
|
||
|
$show{'disk_errors'} = $ENV{show_disk_errors} || 1;
|
||
|
$show{'memory_allocated'} = $ENV{show_memory_allocated} || 1;
|
||
|
$show{'network_traffic'} = $ENV{show_network_traffic} || 1;
|
||
|
$show{'network_drops'} = $ENV{show_network_drops} || 1;
|
||
|
|
||
|
sub init() {
|
||
|
my $type=undef;
|
||
|
|
||
|
if ($ARGV[0] and $ARGV[0] eq "config"){
|
||
|
$type="config";
|
||
|
}
|
||
|
if ($ARGV[0] and $ARGV[0] eq "autoconf"){
|
||
|
&autoconf();
|
||
|
exit;
|
||
|
}
|
||
|
if(!$ARGV[0]){
|
||
|
$type="fetch";
|
||
|
}
|
||
|
|
||
|
if(!defined($type)){
|
||
|
print "Argument not supported, see the howto.\n";
|
||
|
}
|
||
|
|
||
|
# Connecting to libvirt
|
||
|
my $vmm=&connect();
|
||
|
|
||
|
my @domains = $vmm->list_domains();
|
||
|
|
||
|
my %hash=();
|
||
|
|
||
|
my $node = $vmm->get_node_info();
|
||
|
# 'model' => 'x86_64',
|
||
|
# 'threads' => 2,
|
||
|
# 'cores' => 4,
|
||
|
# 'memory' => 33545216,
|
||
|
# 'mhz' => 2261,
|
||
|
# 'sockets' => 2,
|
||
|
# 'nodes' => 1,
|
||
|
# 'cpus' => 16
|
||
|
|
||
|
foreach my $domain (@domains) {
|
||
|
|
||
|
my $name = $domain->get_name();
|
||
|
$hash{$name}{'name'} = $name;
|
||
|
$hash{$name}{'id'} = $domain->get_id();
|
||
|
$hash{$name}{'info'} = $domain->get_info();
|
||
|
$hash{$name}{'maxvcpus'} = $domain->get_max_vcpus();
|
||
|
$hash{$name}{'maxmem'} = $domain->get_max_memory();
|
||
|
$hash{$name}{'type'} = $domain->get_os_type();
|
||
|
$hash{$name}{'scheduler'} = $domain->get_scheduler_type();
|
||
|
$hash{$name}{'xml'} = parse_xml($domain->get_xml_description());
|
||
|
$hash{$name}{'label'} = clean_label($name);
|
||
|
|
||
|
# Calculate cputime used in percent
|
||
|
if(defined($hash{$name}{'info'}{'cpuTime'}) && defined($node->{'cpus'})){
|
||
|
$hash{$name}{'info'}{'cpuPercentage'} = sprintf("%d",1.0e-7 * $hash{$name}{'info'}{'cpuTime'} / $node->{'cpus'});
|
||
|
}
|
||
|
|
||
|
# Calculate bytes
|
||
|
if(defined($hash{$name}{'info'}{'memory'})){
|
||
|
$hash{$name}{'info'}{'memory_bytes'} = 1024 * $hash{$name}{'info'}{'memory'};
|
||
|
}
|
||
|
|
||
|
# Extract network usage
|
||
|
if(defined($hash{$name}{'xml'}{'devices'}{'interface'}{'bridge'})){
|
||
|
my $vif_id=0;
|
||
|
for my $vif (keys %{$hash{$name}{'xml'}{'devices'}{'interface'}{'bridge'}}){
|
||
|
$hash{$name}{'devices'}{'network'}{$vif}=$domain->interface_stats($vif);
|
||
|
|
||
|
# The interface number on this $VM. Will be used as ID later in labels
|
||
|
$hash{$name}{'devices'}{'network'}{$vif}{'vif_id'}=$vif_id;
|
||
|
$vif_id++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
# Extract block device usage
|
||
|
if(defined($hash{$name}{'xml'}{'devices'}{'disk'}{'block'})){
|
||
|
for my $block (keys %{$hash{$name}{'xml'}{'devices'}{'disk'}{'block'}}){
|
||
|
$hash{$name}{'devices'}{'block'}{$block}=$domain->block_stats($block);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
# Gather data later used to calculate latency and utilization
|
||
|
if(defined($hash{$name}{'xml'}{'devices'}{'disk'}{'block'})){
|
||
|
for my $block (keys %{$hash{$name}{'xml'}{'devices'}{'disk'}{'block'}}){
|
||
|
if(defined($hash{$name}{'devices'}{'block'}{$block})){
|
||
|
my $source_dev=$hash{$name}{'xml'}{'devices'}{'disk'}{'block'}{$block}{'source'};
|
||
|
$hash{$name}{'devices'}{'block'}{$block}{'source'}{$source_dev}=read_diskstats($source_dev);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
my $prev_time=&get_prev_time($tmpfile);
|
||
|
my $time=time();
|
||
|
my $prev_state_ref=undef;
|
||
|
|
||
|
# Cache the result to disk if we graphs that require cache are enabled
|
||
|
if($show{'disk_latency'} == 1 || $show{'disk_utilization'} == 1){
|
||
|
if(-e $tmpfile){
|
||
|
$prev_state_ref=retrieve($tmpfile);
|
||
|
}
|
||
|
|
||
|
store(\%hash,$tmpfile);
|
||
|
}
|
||
|
|
||
|
#
|
||
|
# Disk utilization
|
||
|
#
|
||
|
|
||
|
if($show{'disk_utilization'} == 1){
|
||
|
|
||
|
#
|
||
|
# Disk utilization, top level
|
||
|
#
|
||
|
|
||
|
if($type eq "config"){
|
||
|
print "multigraph libvirt_disk_utilization\n";
|
||
|
#print "graph_order rd wr\n";
|
||
|
print "graph_title Disk utilization per domain in percent\n";
|
||
|
print "graph_vlabel %\n";
|
||
|
print "graph_category Virtualization\n";
|
||
|
print "graph_args -l 0 --base 1000 --upper-limit 100\n";
|
||
|
#print "graph_width 550\n";
|
||
|
|
||
|
for my $vm (sort keys %hash) {
|
||
|
if(defined($hash{$vm}{'devices'}{'block'})){
|
||
|
print $hash{$vm}{'label'} . ".label " . $hash{$vm}{'name'} . "\n";
|
||
|
print $hash{$vm}{'label'} . ".info The maximum I/O utilization in percent on " . $hash{$vm}{'name'} . ". If the time spent for I/O is close to 1000 msec for a given second, the device is nearly 100% saturated. If the virtual machine have more than one disk, the value from the disk with the highest utilization is being shown.\n";
|
||
|
print $hash{$vm}{'label'} . ".min 0\n";
|
||
|
print $hash{$vm}{'label'} . ".draw LINE2\n";
|
||
|
}
|
||
|
}
|
||
|
print "\n";
|
||
|
|
||
|
} elsif($type eq "fetch"){
|
||
|
print "multigraph libvirt_disk_utilization\n";
|
||
|
for my $vm (sort keys %hash) {
|
||
|
if(defined($hash{$vm}{'devices'}{'block'}) && defined($prev_state_ref->{$vm}->{'devices'}->{'block'})){
|
||
|
|
||
|
my $utilization=0;
|
||
|
|
||
|
for my $device (keys %{$hash{$vm}{'devices'}{'block'}}){
|
||
|
|
||
|
if(defined($prev_state_ref->{$vm}->{'devices'}->{'block'}->{$device})){
|
||
|
|
||
|
for my $source_device (keys %{$hash{$vm}{'devices'}{'block'}{$device}{'source'}}){
|
||
|
|
||
|
for my $slave_device (keys %{$hash{$vm}{'devices'}{'block'}{$device}{'source'}{$source_device}{'slaves'}}){
|
||
|
|
||
|
my $prev_ms_spent_doing_io=$prev_state_ref->{$vm}->{'devices'}->{'block'}->{$device}->{'source'}->{$source_device}->{'slaves'}->{$slave_device}->{'io_ticks'};
|
||
|
my $cur_ms_spent_doing_io=$hash{$vm}{'devices'}{'block'}{$device}{'source'}{$source_device}{'slaves'}{$slave_device}{'io_ticks'};
|
||
|
|
||
|
if($cur_ms_spent_doing_io > $prev_ms_spent_doing_io){
|
||
|
my $ticks=$cur_ms_spent_doing_io-$prev_ms_spent_doing_io;
|
||
|
my $interval_ms=($time-$prev_time)*1000;
|
||
|
if($interval_ms > 0){
|
||
|
my $dev_utilization=($ticks/$interval_ms)*100;
|
||
|
|
||
|
# Will only print show the highest utilization on each VM on the top level graph
|
||
|
if($dev_utilization > $utilization){
|
||
|
$utilization=sprintf("%.${decimals}f",$dev_utilization);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
print $hash{$vm}{'label'} . ".value " . $utilization . "\n";
|
||
|
}
|
||
|
}
|
||
|
print "\n";
|
||
|
}
|
||
|
|
||
|
#
|
||
|
# Disk utilization, second level
|
||
|
#
|
||
|
|
||
|
for my $vm (sort keys %hash) {
|
||
|
my $devices=0;
|
||
|
if(defined($hash{$vm}{'devices'}{'block'})){
|
||
|
for my $device (keys %{$hash{$vm}{'devices'}{'block'}}){
|
||
|
$devices++;
|
||
|
}
|
||
|
}
|
||
|
if($type eq "config"){
|
||
|
print "multigraph libvirt_disk_utilization." . $hash{$vm}{'label'} . "\n";
|
||
|
#print "graph_order rd wr\n";
|
||
|
print "graph_title Disk utilization on " . $vm . " in percent\n";
|
||
|
print "graph_vlabel %\n";
|
||
|
print "graph_category Virtualization\n";
|
||
|
print "graph_args -l 0 --base 1000 --upper-limit 100\n";
|
||
|
#print "graph_width 550\n";
|
||
|
|
||
|
if($devices>0){
|
||
|
if(defined($hash{$vm}{'devices'}{'block'})){
|
||
|
for my $device (keys %{$hash{$vm}{'devices'}{'block'}}){
|
||
|
print $hash{$vm}{'label'} . "_" . $device . ".label " . $device . "\n";
|
||
|
print $hash{$vm}{'label'} . "_" . $device . ".info The maximum I/O utilization in percent on " . $device . ". If the time spent for I/O is close to 1000 msec for a given second, the device is nearly 100% saturated.\n";
|
||
|
print $hash{$vm}{'label'} . "_" . $device . ".min 0\n";
|
||
|
print $hash{$vm}{'label'} . "_" . $device . ".draw LINE2\n";
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
print "\n";
|
||
|
|
||
|
} elsif($type eq "fetch"){
|
||
|
if($devices > 0){
|
||
|
print "multigraph libvirt_disk_utilization." . $hash{$vm}{'label'} . "\n";
|
||
|
if(defined($hash{$vm}{'devices'}{'block'}) && defined($prev_state_ref->{$vm}->{'devices'}->{'block'})){
|
||
|
|
||
|
for my $device (keys %{$hash{$vm}{'devices'}{'block'}}){
|
||
|
|
||
|
my $utilization=0;
|
||
|
|
||
|
if(defined($prev_state_ref->{$vm}->{'devices'}->{'block'}->{$device})){
|
||
|
|
||
|
for my $source_device (keys %{$hash{$vm}{'devices'}{'block'}{$device}{'source'}}){
|
||
|
|
||
|
for my $slave_device (keys %{$hash{$vm}{'devices'}{'block'}{$device}{'source'}{$source_device}{'slaves'}}){
|
||
|
|
||
|
my $prev_ms_spent_doing_io=$prev_state_ref->{$vm}->{'devices'}->{'block'}->{$device}->{'source'}->{$source_device}->{'slaves'}->{$slave_device}->{'io_ticks'};
|
||
|
my $cur_ms_spent_doing_io=$hash{$vm}{'devices'}{'block'}{$device}{'source'}{$source_device}{'slaves'}{$slave_device}{'io_ticks'};
|
||
|
|
||
|
if($cur_ms_spent_doing_io > $prev_ms_spent_doing_io){
|
||
|
my $ticks=$cur_ms_spent_doing_io-$prev_ms_spent_doing_io;
|
||
|
my $interval_ms=($time-$prev_time)*1000;
|
||
|
if($interval_ms > 0){
|
||
|
my $dev_utilization=($ticks/$interval_ms)*100;
|
||
|
$utilization=sprintf("%.${decimals}f",$dev_utilization);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
print $hash{$vm}{'label'} . "_" . $device . ".value " . $utilization . "\n";
|
||
|
}
|
||
|
}
|
||
|
print "\n";
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#
|
||
|
# Disk latency
|
||
|
#
|
||
|
|
||
|
if($show{'disk_latency'} == 1){
|
||
|
|
||
|
#
|
||
|
# Disk latency, top level
|
||
|
#
|
||
|
|
||
|
if($type eq "config"){
|
||
|
print "multigraph libvirt_disk_latency\n";
|
||
|
#print "graph_order rd wr\n";
|
||
|
print "graph_title Disk latency per domain in seconds\n";
|
||
|
print "graph_args --base 1000\n";
|
||
|
print "graph_vlabel read (-) / write (+)\n";
|
||
|
print "graph_category Virtualization\n";
|
||
|
#print "graph_width 550\n";
|
||
|
|
||
|
for my $vm (sort keys %hash) {
|
||
|
if(defined($hash{$vm}{'devices'}{'block'})){
|
||
|
|
||
|
# Will only graph the domains with one or more block device
|
||
|
my $devices=0;
|
||
|
for my $device (keys %{$hash{$vm}{'devices'}{'block'}}){
|
||
|
$devices++;
|
||
|
}
|
||
|
if($devices > 0){
|
||
|
print $hash{$vm}{'label'} . "_rd.label " . $hash{$vm}{'name'} . "_rd\n";
|
||
|
print $hash{$vm}{'label'} . "_rd.info I/O latency in seconds on " . $hash{$vm}{'name'} . "\n";
|
||
|
print $hash{$vm}{'label'} . "_rd.min 0\n";
|
||
|
print $hash{$vm}{'label'} . "_rd.draw LINE2\n";
|
||
|
print $hash{$vm}{'label'} . "_rd.graph no\n";
|
||
|
|
||
|
print $hash{$vm}{'label'} . "_wr.label " . $hash{$vm}{'name'} . "\n";
|
||
|
print $hash{$vm}{'label'} . "_wr.info I/O latency in seconds on " . $hash{$vm}{'name'} . "\n";
|
||
|
print $hash{$vm}{'label'} . "_wr.min 0\n";
|
||
|
print $hash{$vm}{'label'} . "_wr.draw LINE2\n";
|
||
|
print $hash{$vm}{'label'} . "_wr.negative " . $hash{$vm}{'label'} . "_rd\n";
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
print "\n";
|
||
|
|
||
|
} elsif($type eq "fetch"){
|
||
|
print "multigraph libvirt_disk_latency\n";
|
||
|
for my $vm (sort keys %hash) {
|
||
|
if(defined($hash{$vm}{'devices'}{'block'}) && defined($prev_state_ref->{$vm}->{'devices'}->{'block'})){
|
||
|
|
||
|
my $prev_total_time_spent_writing=0;
|
||
|
my $prev_total_time_spent_reading=0;
|
||
|
my $prev_total_ios_read=0;
|
||
|
my $prev_total_ios_written=0;
|
||
|
my $cur_total_time_spent_writing=0;
|
||
|
my $cur_total_time_spent_reading=0;
|
||
|
my $cur_total_ios_read=0;
|
||
|
my $cur_total_ios_written=0;
|
||
|
|
||
|
my $devices=0;
|
||
|
|
||
|
for my $device (keys %{$hash{$vm}{'devices'}{'block'}}){
|
||
|
$devices++;
|
||
|
|
||
|
if(defined($prev_state_ref->{$vm}->{'devices'}->{'block'}->{$device})){
|
||
|
|
||
|
for my $source_device (keys %{$hash{$vm}{'devices'}{'block'}{$device}{'source'}}){
|
||
|
|
||
|
for my $slave_device (keys %{$hash{$vm}{'devices'}{'block'}{$device}{'source'}{$source_device}{'slaves'}}){
|
||
|
|
||
|
my $prev_time_spent_writing=$prev_state_ref->{$vm}->{'devices'}->{'block'}->{$device}->{'source'}->{$source_device}->{'slaves'}->{$slave_device}->{'write_ticks'};
|
||
|
my $prev_time_spent_reading=$prev_state_ref->{$vm}->{'devices'}->{'block'}->{$device}->{'source'}->{$source_device}->{'slaves'}->{$slave_device}->{'read_ticks'};
|
||
|
my $prev_ios_read=$prev_state_ref->{$vm}->{'devices'}->{'block'}->{$device}->{'source'}->{$source_device}->{'slaves'}->{$slave_device}->{'read_ios'};
|
||
|
my $prev_ios_written=$prev_state_ref->{$vm}->{'devices'}->{'block'}->{$device}->{'source'}->{$source_device}->{'slaves'}->{$slave_device}->{'write_ios'};
|
||
|
|
||
|
my $cur_time_spent_writing=$hash{$vm}{'devices'}{'block'}{$device}{'source'}{$source_device}{'slaves'}{$slave_device}{'write_ticks'};
|
||
|
my $cur_time_spent_reading=$hash{$vm}{'devices'}{'block'}{$device}{'source'}{$source_device}{'slaves'}{$slave_device}{'read_ticks'};
|
||
|
my $cur_ios_read=$hash{$vm}{'devices'}{'block'}{$device}{'source'}{$source_device}{'slaves'}{$slave_device}{'read_ios'};
|
||
|
my $cur_ios_written=$hash{$vm}{'devices'}{'block'}{$device}{'source'}{$source_device}{'slaves'}{$slave_device}{'write_ios'};
|
||
|
|
||
|
$prev_total_time_spent_writing+=$prev_time_spent_writing;
|
||
|
$prev_total_time_spent_reading+=$prev_time_spent_reading;
|
||
|
$prev_total_ios_read+=$prev_ios_read;
|
||
|
$prev_total_ios_written+=$prev_ios_written;
|
||
|
|
||
|
$cur_total_time_spent_writing+=$cur_time_spent_writing;
|
||
|
$cur_total_time_spent_reading+=$cur_time_spent_reading;
|
||
|
$cur_total_ios_read+=$cur_ios_read;
|
||
|
$cur_total_ios_written+=$cur_ios_written;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
my $read_latency=0;
|
||
|
my $write_latency=0;
|
||
|
|
||
|
if($prev_total_time_spent_reading > 0 && $prev_total_ios_read > 0 && ($cur_total_ios_read-$prev_total_ios_read) > 0){
|
||
|
$read_latency=(($cur_total_time_spent_reading-$prev_total_time_spent_reading)/($cur_total_ios_read-$prev_total_ios_read))/1000;
|
||
|
}
|
||
|
|
||
|
if($prev_total_time_spent_writing > 0 && $prev_total_ios_written > 0 && ($cur_total_ios_written-$prev_total_ios_written) > 0){
|
||
|
$write_latency=(($cur_total_time_spent_writing-$prev_total_time_spent_writing)/($cur_total_ios_written-$prev_total_ios_written))/1000;
|
||
|
}
|
||
|
|
||
|
if($devices > 0){
|
||
|
print $hash{$vm}{'label'} . "_rd.value " . $read_latency . "\n";
|
||
|
print $hash{$vm}{'label'} . "_wr.value " . $write_latency . "\n";
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
print "\n";
|
||
|
}
|
||
|
|
||
|
#
|
||
|
# Disk latency, second level
|
||
|
#
|
||
|
|
||
|
for my $vm (sort keys %hash) {
|
||
|
my $devices=0;
|
||
|
for my $device (keys %{$hash{$vm}{'devices'}{'block'}}){
|
||
|
$devices++;
|
||
|
}
|
||
|
if($devices > 0){
|
||
|
if($type eq "config"){
|
||
|
print "multigraph libvirt_disk_latency.$hash{$vm}{'label'}\n";
|
||
|
#print "graph_order rd wr\n";
|
||
|
print "graph_title Disk latency per vbd on $vm in seconds\n";
|
||
|
print "graph_args --base 1000\n";
|
||
|
print "graph_vlabel read (-) / write (+)\n";
|
||
|
print "graph_category Virtualization\n";
|
||
|
#print "graph_width 550\n";
|
||
|
|
||
|
if(defined($hash{$vm}{'devices'}{'block'})){
|
||
|
for my $device (keys %{$hash{$vm}{'devices'}{'block'}}){
|
||
|
|
||
|
print $hash{$vm}{'label'} . "_" . $device . "_rd.label " . $device . "_rd\n";
|
||
|
print $hash{$vm}{'label'} . "_" . $device . "_rd.info I/O latency in seconds on " . $hash{$vm}{'name'} . ":" . $device . "\n";
|
||
|
print $hash{$vm}{'label'} . "_" . $device . "_rd.min 0\n";
|
||
|
print $hash{$vm}{'label'} . "_" . $device . "_rd.draw LINE2\n";
|
||
|
print $hash{$vm}{'label'} . "_" . $device . "_rd.graph no\n";
|
||
|
|
||
|
print $hash{$vm}{'label'} . "_" . $device . "_wr.label " . $device . "\n";
|
||
|
print $hash{$vm}{'label'} . "_" . $device . "_wr.info I/O latency in seconds on " . $hash{$vm}{'name'} . ":" . $device . "\n";
|
||
|
print $hash{$vm}{'label'} . "_" . $device . "_wr.min 0\n";
|
||
|
print $hash{$vm}{'label'} . "_" . $device . "_wr.draw LINE2\n";
|
||
|
print $hash{$vm}{'label'} . "_" . $device . "_wr.negative " . $hash{$vm}{'label'} . "_" . $device . "_rd\n";
|
||
|
}
|
||
|
print "\n";
|
||
|
}
|
||
|
|
||
|
} elsif($type eq "fetch"){
|
||
|
print "multigraph libvirt_disk_latency.$hash{$vm}{'label'}\n";
|
||
|
if(defined($hash{$vm}{'devices'}{'block'}) && defined($prev_state_ref->{$vm}->{'devices'}->{'block'})){
|
||
|
for my $device (keys %{$hash{$vm}{'devices'}{'block'}}){
|
||
|
|
||
|
if(defined($prev_state_ref->{$vm}->{'devices'}->{'block'}->{$device})){
|
||
|
|
||
|
for my $source_device (keys %{$hash{$vm}{'devices'}{'block'}{$device}{'source'}}){
|
||
|
|
||
|
my $prev_total_time_spent_writing=0;
|
||
|
my $prev_total_time_spent_reading=0;
|
||
|
my $prev_total_ios_read=0;
|
||
|
my $prev_total_ios_written=0;
|
||
|
my $cur_total_time_spent_writing=0;
|
||
|
my $cur_total_time_spent_reading=0;
|
||
|
my $cur_total_ios_read=0;
|
||
|
my $cur_total_ios_written=0;
|
||
|
|
||
|
for my $slave_device (keys %{$hash{$vm}{'devices'}{'block'}{$device}{'source'}{$source_device}{'slaves'}}){
|
||
|
|
||
|
my $prev_time_spent_writing=$prev_state_ref->{$vm}->{'devices'}->{'block'}->{$device}->{'source'}->{$source_device}->{'slaves'}->{$slave_device}->{'write_ticks'};
|
||
|
my $prev_time_spent_reading=$prev_state_ref->{$vm}->{'devices'}->{'block'}->{$device}->{'source'}->{$source_device}->{'slaves'}->{$slave_device}->{'read_ticks'};
|
||
|
my $prev_ios_read=$prev_state_ref->{$vm}->{'devices'}->{'block'}->{$device}->{'source'}->{$source_device}->{'slaves'}->{$slave_device}->{'read_ios'};
|
||
|
my $prev_ios_written=$prev_state_ref->{$vm}->{'devices'}->{'block'}->{$device}->{'source'}->{$source_device}->{'slaves'}->{$slave_device}->{'write_ios'};
|
||
|
|
||
|
my $cur_time_spent_writing=$hash{$vm}{'devices'}{'block'}{$device}{'source'}{$source_device}{'slaves'}{$slave_device}{'write_ticks'};
|
||
|
my $cur_time_spent_reading=$hash{$vm}{'devices'}{'block'}{$device}{'source'}{$source_device}{'slaves'}{$slave_device}{'read_ticks'};
|
||
|
my $cur_ios_read=$hash{$vm}{'devices'}{'block'}{$device}{'source'}{$source_device}{'slaves'}{$slave_device}{'read_ios'};
|
||
|
my $cur_ios_written=$hash{$vm}{'devices'}{'block'}{$device}{'source'}{$source_device}{'slaves'}{$slave_device}{'write_ios'};
|
||
|
|
||
|
$prev_total_time_spent_writing+=$prev_time_spent_writing;
|
||
|
$prev_total_time_spent_reading+=$prev_time_spent_reading;
|
||
|
$prev_total_ios_read+=$prev_ios_read;
|
||
|
$prev_total_ios_written+=$prev_ios_written;
|
||
|
|
||
|
$cur_total_time_spent_writing+=$cur_time_spent_writing;
|
||
|
$cur_total_time_spent_reading+=$cur_time_spent_reading;
|
||
|
$cur_total_ios_read+=$cur_ios_read;
|
||
|
$cur_total_ios_written+=$cur_ios_written;
|
||
|
}
|
||
|
|
||
|
my $read_latency=0;
|
||
|
my $write_latency=0;
|
||
|
|
||
|
if($prev_total_time_spent_reading > 0 && $prev_total_ios_read > 0 && ($cur_total_ios_read-$prev_total_ios_read) > 0){
|
||
|
$read_latency=(($cur_total_time_spent_reading-$prev_total_time_spent_reading)/($cur_total_ios_read-$prev_total_ios_read))/1000;
|
||
|
}
|
||
|
|
||
|
if($prev_total_time_spent_writing > 0 && $prev_total_ios_written > 0 && ($cur_total_ios_written-$prev_total_ios_written) > 0){
|
||
|
$write_latency=(($cur_total_time_spent_writing-$prev_total_time_spent_writing)/($cur_total_ios_written-$prev_total_ios_written))/1000;
|
||
|
}
|
||
|
|
||
|
print $hash{$vm}{'label'} . "_" . $device . "_rd.value " . $read_latency . "\n";
|
||
|
print $hash{$vm}{'label'} . "_" . $device . "_wr.value " . $write_latency . "\n";
|
||
|
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
print "\n";
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if($show{'disk_traffic'} == 1){
|
||
|
|
||
|
#
|
||
|
# Disk used, top level
|
||
|
#
|
||
|
|
||
|
if($type eq "config"){
|
||
|
print "multigraph libvirt_disk\n";
|
||
|
#print "graph_order rd wr\n";
|
||
|
print "graph_title Disk traffic per domain in bytes\n";
|
||
|
print "graph_args --base 1000\n";
|
||
|
print "graph_vlabel bytes read (-) / written (+) per \${graph_period}\n";
|
||
|
print "graph_category Virtualization\n";
|
||
|
#print "graph_width 550\n";
|
||
|
|
||
|
for my $vm (sort keys %hash) {
|
||
|
my $devices=0;
|
||
|
if(defined($hash{$vm}{'devices'}{'block'})){
|
||
|
for my $device (keys %{$hash{$vm}{'devices'}{'block'}}){
|
||
|
$devices++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if($devices > 0){
|
||
|
if(defined($hash{$vm}{'devices'}{'block'})){
|
||
|
|
||
|
print $hash{$vm}{'label'} . "_rd_bytes.label " . $hash{$vm}{'name'} . "\n";
|
||
|
print $hash{$vm}{'label'} . "_rd_bytes.type COUNTER\n";
|
||
|
print $hash{$vm}{'label'} . "_rd_bytes.info The number of bytes read by " . $hash{$vm}{'name'} . "\n";
|
||
|
print $hash{$vm}{'label'} . "_rd_bytes.min 0\n";
|
||
|
print $hash{$vm}{'label'} . "_rd_bytes.draw LINE2\n";
|
||
|
print $hash{$vm}{'label'} . "_rd_bytes.graph no\n";
|
||
|
|
||
|
print $hash{$vm}{'label'} . "_wr_bytes.label " . $hash{$vm}{'name'} . "\n";
|
||
|
print $hash{$vm}{'label'} . "_wr_bytes.type COUNTER\n";
|
||
|
print $hash{$vm}{'label'} . "_wr_bytes.info The number of bytes written by " . $hash{$vm}{'name'} . "\n";
|
||
|
print $hash{$vm}{'label'} . "_wr_bytes.min 0\n";
|
||
|
print $hash{$vm}{'label'} . "_wr_bytes.draw LINE2\n";
|
||
|
print $hash{$vm}{'label'} . "_wr_bytes.negative " . $hash{$vm}{'label'} . "_rd_bytes\n";
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
print "\n";
|
||
|
|
||
|
} elsif($type eq "fetch"){
|
||
|
print "multigraph libvirt_disk\n";
|
||
|
for my $vm (sort keys %hash) {
|
||
|
if(defined($hash{$vm}{'devices'}{'block'})){
|
||
|
my $total_read=0;
|
||
|
my $total_write=0;
|
||
|
for my $device (keys %{$hash{$vm}{'devices'}{'block'}}){
|
||
|
$total_read+=$hash{$vm}{'devices'}{'block'}{$device}{'rd_bytes'};
|
||
|
$total_write+=$hash{$vm}{'devices'}{'block'}{$device}{'wr_bytes'};
|
||
|
}
|
||
|
print $hash{$vm}{'label'} . "_rd_bytes.value " . $total_read . "\n";
|
||
|
print $hash{$vm}{'label'} . "_wr_bytes.value " . $total_write . "\n";
|
||
|
}
|
||
|
}
|
||
|
print "\n";
|
||
|
}
|
||
|
|
||
|
#
|
||
|
# Disk used, second level
|
||
|
#
|
||
|
|
||
|
for my $vm (sort keys %hash) {
|
||
|
my $devices=0;
|
||
|
if(defined($hash{$vm}{'devices'}{'block'})){
|
||
|
for my $device (keys %{$hash{$vm}{'devices'}{'block'}}){
|
||
|
$devices++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if($devices > 0){
|
||
|
if(defined($hash{$vm}{'devices'}{'block'})){
|
||
|
if($type eq "config"){
|
||
|
print "multigraph libvirt_disk.bytes_" . $hash{$vm}{'label'} . "\n";
|
||
|
#print "graph_order rd wr\n";
|
||
|
print "graph_title Disk traffic for " . $hash{$vm}{'name'} . "\n";
|
||
|
print "graph_args --base 1000\n";
|
||
|
print "graph_vlabel bytes read (-) / written (+) per \${graph_period}\n";
|
||
|
print "graph_category Virtualization\n";
|
||
|
#print "graph_width 550\n";
|
||
|
|
||
|
for my $device (keys %{$hash{$vm}{'devices'}{'block'}}){
|
||
|
print $device . "_rd_bytes.label " . $device . "_rd\n";
|
||
|
print $device . "_rd_bytes.type COUNTER\n";
|
||
|
print $device . "_rd_bytes.info The number of bytes read by " . $hash{$vm}{'name'} . "\n";
|
||
|
print $device . "_rd_bytes.min 0\n";
|
||
|
print $device . "_rd_bytes.graph no\n";
|
||
|
|
||
|
print $device . "_wr_bytes.label " . $device . "\n";
|
||
|
print $device . "_wr_bytes.type COUNTER\n";
|
||
|
print $device . "_wr_bytes.info The number of bytes written by " . $hash{$vm}{'name'} . "\n";
|
||
|
print $device . "_wr_bytes.min 0\n";
|
||
|
print $device . "_wr_bytes.draw LINE2\n";
|
||
|
print $device . "_wr_bytes.negative " . $device . "_rd_bytes\n";
|
||
|
}
|
||
|
print "\n";
|
||
|
|
||
|
} elsif($type eq "fetch"){
|
||
|
print "multigraph libvirt_disk.bytes_" . $hash{$vm}{'label'} . "\n";
|
||
|
if(defined($hash{$vm}{'devices'}{'block'})){
|
||
|
for my $device (keys %{$hash{$vm}{'devices'}{'block'}}){
|
||
|
print $device . "_rd_bytes.value " . $hash{$vm}{'devices'}{'block'}{$device}{'rd_bytes'} . "\n";
|
||
|
print $device . "_wr_bytes.value " . $hash{$vm}{'devices'}{'block'}{$device}{'wr_bytes'} . "\n";
|
||
|
}
|
||
|
}
|
||
|
print "\n";
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#
|
||
|
# Disk errors
|
||
|
#
|
||
|
# errs -> Some kind of error count
|
||
|
|
||
|
|
||
|
if($show{'disk_errors'} == 1){
|
||
|
|
||
|
#
|
||
|
# Disk errors, top level
|
||
|
#
|
||
|
|
||
|
if($type eq "config"){
|
||
|
print "multigraph libvirt_disk_errs\n";
|
||
|
print "graph_title Disk errors per domain\n";
|
||
|
print "graph_args --base 1000\n";
|
||
|
print "graph_category Virtualization\n";
|
||
|
|
||
|
for my $vm (sort keys %hash) {
|
||
|
if(defined($hash{$vm}{'devices'}{'block'})){
|
||
|
my $devices=0;
|
||
|
if(defined($hash{$vm}{'devices'}{'block'})){
|
||
|
for my $device (keys %{$hash{$vm}{'devices'}{'block'}}){
|
||
|
$devices++;
|
||
|
}
|
||
|
}
|
||
|
if($devices > 0){
|
||
|
print $hash{$vm}{'label'} . "_errs.label " . $hash{$vm}{'name'} . "\n";
|
||
|
print $hash{$vm}{'label'} . "_errs.type COUNTER\n";
|
||
|
print $hash{$vm}{'label'} . "_errs.info The number of errors by " . $hash{$vm}{'name'} . "\n";
|
||
|
print $hash{$vm}{'label'} . "_errs.min 0\n";
|
||
|
print $hash{$vm}{'label'} . "_errs.draw LINE2\n";
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
print "\n";
|
||
|
|
||
|
} elsif($type eq "fetch"){
|
||
|
print "multigraph libvirt_disk_errs\n";
|
||
|
for my $vm (sort keys %hash) {
|
||
|
if(defined($hash{$vm}{'devices'}{'block'})){
|
||
|
my $errs=0;
|
||
|
for my $device (keys %{$hash{$vm}{'devices'}{'block'}}){
|
||
|
$errs+=$hash{$vm}{'devices'}{'block'}{$device}{'errs'};
|
||
|
}
|
||
|
print $hash{$vm}{'label'} . "_errs.value " . $errs . "\n";
|
||
|
}
|
||
|
}
|
||
|
print "\n";
|
||
|
}
|
||
|
|
||
|
#
|
||
|
# Disk errors, second level
|
||
|
#
|
||
|
|
||
|
for my $vm (sort keys %hash) {
|
||
|
my $devices=0;
|
||
|
if(defined($hash{$vm}{'devices'}{'block'})){
|
||
|
for my $device (keys %{$hash{$vm}{'devices'}{'block'}}){
|
||
|
$devices++;
|
||
|
}
|
||
|
}
|
||
|
if($devices > 0){
|
||
|
if(defined($hash{$vm}{'devices'}{'block'})){
|
||
|
if($type eq "config"){
|
||
|
print "multigraph libvirt_disk_errs." . $hash{$vm}{'label'} . "\n";
|
||
|
print "graph_title Disk errors for " . $hash{$vm}{'name'} . "\n";
|
||
|
print "graph_args --base 1000\n";
|
||
|
print "graph_category Virtualization\n";
|
||
|
|
||
|
for my $device (keys %{$hash{$vm}{'devices'}{'block'}}){
|
||
|
|
||
|
print $device . "_errs.label " . $device . "\n";
|
||
|
print $device . "_errs.type COUNTER\n";
|
||
|
print $device . "_errs.info The number of errors by " . $hash{$vm}{'name'} . " on defice " . $device . "\n";
|
||
|
print $device . "_errs.min 0\n";
|
||
|
print $device . "_errs.draw LINE2\n";
|
||
|
}
|
||
|
print "\n";
|
||
|
|
||
|
} elsif($type eq "fetch"){
|
||
|
print "multigraph libvirt_disk_errs." . $hash{$vm}{'label'} . "\n";
|
||
|
if(defined($hash{$vm}{'devices'}{'block'})){
|
||
|
for my $device (keys %{$hash{$vm}{'devices'}{'block'}}){
|
||
|
print $device . "_errs.value " . $hash{$vm}{'devices'}{'block'}{$device}{'errs'} . "\n";
|
||
|
}
|
||
|
}
|
||
|
print "\n";
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#
|
||
|
# Network used
|
||
|
#
|
||
|
|
||
|
if($show{'network_traffic'} == 1){
|
||
|
|
||
|
#
|
||
|
# Network used, top level
|
||
|
#
|
||
|
|
||
|
if($type eq "config"){
|
||
|
print "multigraph libvirt_network\n";
|
||
|
print "graph_title Network traffic per domain in bytes\n";
|
||
|
print "graph_args --base 1000\n";
|
||
|
print "graph_vlabel Bytes in (-) / out (+) per \${graph_period}\n";
|
||
|
print "graph_category Virtualization\n";
|
||
|
#print "graph_width 550\n";
|
||
|
|
||
|
for my $vm (sort keys %hash) {
|
||
|
if(defined($hash{$vm}{'devices'}{'network'})){
|
||
|
|
||
|
print $hash{$vm}{'label'} . "_rx_bytes.label " . $hash{$vm}{'name'} . "_rx\n";
|
||
|
print $hash{$vm}{'label'} . "_rx_bytes.type DERIVE\n";
|
||
|
print $hash{$vm}{'label'} . "_rx_bytes.info The number of bytes read by " . $hash{$vm}{'name'} . " in total.\n";
|
||
|
print $hash{$vm}{'label'} . "_rx_bytes.min 0\n";
|
||
|
print $hash{$vm}{'label'} . "_rx_bytes.draw LINE2\n";
|
||
|
print $hash{$vm}{'label'} . "_rx_bytes.graph no\n";
|
||
|
#print $hash{$vm}{'label'} . "_rx_bytes.cdef " . $hash{$vm}{'label'} . "_rx_bytes,8,*\n";
|
||
|
|
||
|
print $hash{$vm}{'label'} . "_tx_bytes.label " . $hash{$vm}{'name'} . "\n";
|
||
|
print $hash{$vm}{'label'} . "_tx_bytes.type DERIVE\n";
|
||
|
print $hash{$vm}{'label'} . "_tx_bytes.info The number of bytes written by " . $hash{$vm}{'name'} . " in total.\n";
|
||
|
print $hash{$vm}{'label'} . "_tx_bytes.min 0\n";
|
||
|
print $hash{$vm}{'label'} . "_tx_bytes.draw LINE2\n";
|
||
|
print $hash{$vm}{'label'} . "_tx_bytes.negative " . $hash{$vm}{'label'} . "_rx_bytes\n";
|
||
|
#print $hash{$vm}{'label'} . "_tx_bytes.cdef " . $hash{$vm}{'label'} . "_tx_bytes,8,*\n";
|
||
|
}
|
||
|
}
|
||
|
print "\n";
|
||
|
|
||
|
} elsif($type eq "fetch"){
|
||
|
print "multigraph libvirt_network\n";
|
||
|
for my $vm (sort keys %hash) {
|
||
|
if(defined($hash{$vm}{'devices'}{'network'})){
|
||
|
my $read=0;
|
||
|
my $write=0;
|
||
|
for my $vif (keys %{$hash{$vm}{'devices'}{'network'}}){
|
||
|
$read+=$hash{$vm}{'devices'}{'network'}{$vif}{'rx_bytes'};
|
||
|
$write+=$hash{$vm}{'devices'}{'network'}{$vif}{'tx_bytes'};
|
||
|
}
|
||
|
print $hash{$vm}{'label'} . "_rx_bytes.value " . $read . "\n";
|
||
|
print $hash{$vm}{'label'} . "_tx_bytes.value " . $write . "\n";
|
||
|
}
|
||
|
}
|
||
|
print "\n";
|
||
|
}
|
||
|
|
||
|
#
|
||
|
# Network used, second level
|
||
|
#
|
||
|
|
||
|
for my $vm (sort keys %hash) {
|
||
|
if(defined($hash{$vm}{'devices'}{'network'})){
|
||
|
if($type eq "config"){
|
||
|
print "multigraph libvirt_network.bytes_" . $hash{$vm}{'label'} . "\n";
|
||
|
print "graph_title Network traffic for " . $vm . "\n";
|
||
|
print "graph_args --base 1000\n";
|
||
|
print "graph_vlabel Bits in (-) / out (+) per \${graph_period}\n";
|
||
|
print "graph_category Virtualization\n";
|
||
|
#print "graph_width 550\n";
|
||
|
|
||
|
for my $vif (keys %{$hash{$vm}{'devices'}{'network'}}){
|
||
|
my $vif_id=$hash{$vm}{'devices'}{'network'}{$vif}{'vif_id'};
|
||
|
|
||
|
print "rx_bytes_" . $vif_id . ".label " . $vif . "_rx\n";
|
||
|
print "rx_bytes_" . $vif_id . ".type DERIVE\n";
|
||
|
print "rx_bytes_" . $vif_id . ".info The number of bytes read by " . $hash{$vm}{'name'} . "\n";
|
||
|
print "rx_bytes_" . $vif_id . ".min 0\n";
|
||
|
print "rx_bytes_" . $vif_id . ".graph no\n";
|
||
|
print "rx_bytes_" . $vif_id . ".cdef rx_bytes_" . $vif_id . ",8,*\n";
|
||
|
|
||
|
print "tx_bytes_" . $vif_id . ".label " . $vif . "\n";
|
||
|
print "tx_bytes_" . $vif_id . ".type DERIVE\n";
|
||
|
print "tx_bytes_" . $vif_id . ".info The number of bits written by " . $hash{$vm}{'name'} . "\n";
|
||
|
print "tx_bytes_" . $vif_id . ".min 0\n";
|
||
|
print "tx_bytes_" . $vif_id . ".draw LINE2\n";
|
||
|
print "tx_bytes_" . $vif_id . ".negative rx_bytes_" . $vif_id . "\n";
|
||
|
print "tx_bytes_" . $vif_id . ".cdef tx_bytes_" . $vif_id . ",8,*\n";
|
||
|
}
|
||
|
print "\n";
|
||
|
|
||
|
} elsif($type eq "fetch"){
|
||
|
print "multigraph libvirt_network.bytes_" . $hash{$vm}{'label'} . "\n";
|
||
|
for my $vif (keys %{$hash{$vm}{'devices'}{'network'}}){
|
||
|
my $vif_id=$hash{$vm}{'devices'}{'network'}{$vif}{'vif_id'};
|
||
|
print "rx_bytes_" . $vif_id . ".value " . $hash{$vm}{'devices'}{'network'}{$vif}{'rx_bytes'} . "\n";
|
||
|
print "tx_bytes_" . $vif_id . ".value " . $hash{$vm}{'devices'}{'network'}{$vif}{'tx_bytes'} . "\n";
|
||
|
}
|
||
|
print "\n";
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#
|
||
|
# Network drops and errors
|
||
|
#
|
||
|
# rx_drop -> Total packets drop at reception
|
||
|
# tx_drop -> Total packets dropped at transmission.
|
||
|
|
||
|
if($show{'network_drops'} == 1){
|
||
|
|
||
|
#
|
||
|
# Network drops, top level
|
||
|
#
|
||
|
|
||
|
if($type eq "config"){
|
||
|
print "multigraph libvirt_network_drop\n";
|
||
|
print "graph_title Network packets dropped per domain\n";
|
||
|
print "graph_args --base 1000\n";
|
||
|
print "graph_vlabel Count in (-) / out (+) per \${graph_period}\n";
|
||
|
print "graph_category Virtualization\n";
|
||
|
#print "graph_width 550\n";
|
||
|
|
||
|
for my $vm (sort keys %hash) {
|
||
|
if(defined($hash{$vm}{'devices'}{'network'})){
|
||
|
|
||
|
print $hash{$vm}{'label'} . "_rx_drop.label " . $hash{$vm}{'name'} . "_rx\n";
|
||
|
print $hash{$vm}{'label'} . "_rx_drop.type DERIVE\n";
|
||
|
print $hash{$vm}{'label'} . "_rx_drop.info The number of packets dropped at reception by " . $hash{$vm}{'name'} . "\n";
|
||
|
print $hash{$vm}{'label'} . "_rx_drop.min 0\n";
|
||
|
print $hash{$vm}{'label'} . "_rx_drop.draw LINE2\n";
|
||
|
print $hash{$vm}{'label'} . "_rx_drop.graph no\n";
|
||
|
|
||
|
print $hash{$vm}{'label'} . "_tx_drop.label " . $hash{$vm}{'name'} . "\n";
|
||
|
print $hash{$vm}{'label'} . "_tx_drop.type DERIVE\n";
|
||
|
print $hash{$vm}{'label'} . "_tx_drop.info The number of packets dropped at transmission by " . $hash{$vm}{'name'} . "\n";
|
||
|
print $hash{$vm}{'label'} . "_tx_drop.min 0\n";
|
||
|
print $hash{$vm}{'label'} . "_tx_drop.draw LINE2\n";
|
||
|
print $hash{$vm}{'label'} . "_tx_drop.negative " . $hash{$vm}{'label'} . "_rx_drop\n";
|
||
|
}
|
||
|
}
|
||
|
print "\n";
|
||
|
|
||
|
} elsif($type eq "fetch"){
|
||
|
print "multigraph libvirt_network_drop\n";
|
||
|
for my $vm (sort keys %hash) {
|
||
|
if(defined($hash{$vm}{'devices'}{'network'})){
|
||
|
my $rx_drop=0;
|
||
|
my $tx_drop=0;
|
||
|
for my $vif (keys %{$hash{$vm}{'devices'}{'network'}}){
|
||
|
$rx_drop+=$hash{$vm}{'devices'}{'network'}{$vif}{'rx_drop'};
|
||
|
$tx_drop+=$hash{$vm}{'devices'}{'network'}{$vif}{'tx_drop'};
|
||
|
}
|
||
|
|
||
|
print $hash{$vm}{'label'} . "_rx_drop.value " . $rx_drop . "\n";
|
||
|
print $hash{$vm}{'label'} . "_tx_drop.value " . $tx_drop . "\n";
|
||
|
|
||
|
}
|
||
|
}
|
||
|
print "\n";
|
||
|
}
|
||
|
|
||
|
#
|
||
|
# Network drops, second level
|
||
|
#
|
||
|
|
||
|
for my $vm (sort keys %hash) {
|
||
|
if(defined($hash{$vm}{'devices'}{'network'})){
|
||
|
if($type eq "config"){
|
||
|
print "multigraph libvirt_network_drop." . $hash{$vm}{'label'} . "\n";
|
||
|
print "graph_title Network packeds dropped by " . $vm . "\n";
|
||
|
print "graph_args --base 1000\n";
|
||
|
print "graph_vlabel Count in (-) / out (+) per \${graph_period}\n";
|
||
|
print "graph_category Virtualization\n";
|
||
|
#print "graph_width 550\n";
|
||
|
|
||
|
for my $vif (keys %{$hash{$vm}{'devices'}{'network'}}){
|
||
|
my $vif_id=$hash{$vm}{'devices'}{'network'}{$vif}{'vif_id'};
|
||
|
|
||
|
print "rx_drop_" . $vif_id . ".label " . $vif . "_rx\n";
|
||
|
print "rx_drop_" . $vif_id . ".type DERIVE\n";
|
||
|
print "rx_drop_" . $vif_id . ".info The number of packets dropped by " . $hash{$vm}{'name'} . ", nic " . $vif_id . "\n";
|
||
|
print "rx_drop_" . $vif_id . ".min 0\n";
|
||
|
print "rx_drop_" . $vif_id . ".graph no\n";
|
||
|
|
||
|
print "tx_drop_" . $vif_id . ".label " . $vif . "\n";
|
||
|
print "tx_drop_" . $vif_id . ".type DERIVE\n";
|
||
|
print "tx_drop_" . $vif_id . ".info The number of packets dropped by " . $hash{$vm}{'name'} . ", nic " . $vif_id . "\n";
|
||
|
print "tx_drop_" . $vif_id . ".min 0\n";
|
||
|
print "tx_drop_" . $vif_id . ".draw LINE2\n";
|
||
|
print "tx_drop_" . $vif_id . ".negative rx_drop_" . $vif_id . "\n";
|
||
|
}
|
||
|
print "\n";
|
||
|
|
||
|
} elsif($type eq "fetch"){
|
||
|
print "multigraph libvirt_network_drop." . $hash{$vm}{'label'} . "\n";
|
||
|
for my $vif (keys %{$hash{$vm}{'devices'}{'network'}}){
|
||
|
my $vif_id=$hash{$vm}{'devices'}{'network'}{$vif}{'vif_id'};
|
||
|
print "rx_drop_" . $vif_id . ".value " . $hash{$vm}{'devices'}{'network'}{$vif}{'rx_drop'} . "\n";
|
||
|
print "tx_drop_" . $vif_id . ".value " . $hash{$vm}{'devices'}{'network'}{$vif}{'tx_drop'} . "\n";
|
||
|
}
|
||
|
print "\n";
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#
|
||
|
# CPU used
|
||
|
#
|
||
|
|
||
|
if($show{'cpu_used'} == 1){
|
||
|
|
||
|
#
|
||
|
# CPU used, top level
|
||
|
#
|
||
|
|
||
|
if($type eq "config"){
|
||
|
print "multigraph libvirt_cpu\n";
|
||
|
print "graph_title Cpu time used per domain in percent\n";
|
||
|
print "graph_args --base 1000 -r --lower-limit 0 --upper-limit 100\n";
|
||
|
print "graph_category Virtualization\n";
|
||
|
#print "graph_width 550\n";
|
||
|
|
||
|
my $draw="AREA";
|
||
|
for my $vm (sort keys %hash) {
|
||
|
print $hash{$vm}{'label'} . "_time.label " . $hash{$vm}{'name'} . "\n";
|
||
|
print $hash{$vm}{'label'} . "_time.type DERIVE\n";
|
||
|
print $hash{$vm}{'label'} . "_time.info The cpu time used by " . $hash{$vm}{'name'} . " in percent of the total available cpu time on the physical node.\n";
|
||
|
print $hash{$vm}{'label'} . "_time.min 0\n";
|
||
|
print $hash{$vm}{'label'} . "_time.draw $draw\n";
|
||
|
$draw="STACK" if $draw eq "AREA";
|
||
|
}
|
||
|
print "\n";
|
||
|
|
||
|
} elsif($type eq "fetch"){
|
||
|
print "multigraph libvirt_cpu\n";
|
||
|
for my $vm (sort keys %hash) {
|
||
|
print $hash{$vm}{'label'} . "_time.value " . $hash{$vm}{'info'}{'cpuPercentage'} . "\n";
|
||
|
}
|
||
|
print "\n";
|
||
|
}
|
||
|
|
||
|
#
|
||
|
# CPU used, second level (pr virtual machine)
|
||
|
#
|
||
|
|
||
|
if($type eq "config"){
|
||
|
for my $vm (sort keys %hash) {
|
||
|
print "multigraph libvirt_cpu.vm_" . $hash{$vm}{'label'} . "\n";
|
||
|
print "graph_title Cpu time used by " . $hash{$vm}{'name'} . " in percent\n";
|
||
|
print "graph_args --base 1000\n";
|
||
|
print "graph_category Virtualization\n";
|
||
|
#print "graph_width 550\n";
|
||
|
|
||
|
print "time.label " . $hash{$vm}{'name'} . " (" . $hash{$vm}{'type'} . ")\n";
|
||
|
print "time.type DERIVE\n";
|
||
|
print "time.info The cpu time used by " . $hash{$vm}{'name'} . " in percent of the total available cpu time on the physical node. This domain has access to " . $hash{$vm}{'info'}{'nrVirtCpu'} . " VCPU(s) now, and $hash{$vm}{'maxvcpus'} at maximum. The scheduler for this domain is " . $hash{$vm}{'scheduler'} . ".\n";
|
||
|
print "time.min 0\n";
|
||
|
print "time.draw AREA\n";
|
||
|
print "\n";
|
||
|
}
|
||
|
|
||
|
} elsif($type eq "fetch"){
|
||
|
for my $vm (sort keys %hash) {
|
||
|
print "multigraph libvirt_cpu.vm_" . $hash{$vm}{'label'} . "\n";
|
||
|
print "time.value " . $hash{$vm}{'info'}{'cpuPercentage'} . "\n";
|
||
|
print "\n";
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#
|
||
|
# Memory allocation
|
||
|
#
|
||
|
|
||
|
if($show{'memory_allocated'} == 1){
|
||
|
|
||
|
#
|
||
|
# Memory allocation, top level
|
||
|
#
|
||
|
|
||
|
if($type eq "config"){
|
||
|
print "multigraph libvirt_mem\n";
|
||
|
print "graph_title Memory allocated per domain\n";
|
||
|
print "graph_args --base 1000\n";
|
||
|
print "graph_category Virtualization\n";
|
||
|
#print "graph_width 550\n";
|
||
|
|
||
|
my $draw="AREA";
|
||
|
for my $vm (sort keys %hash) {
|
||
|
print $hash{$vm}{'label'} . "_alloc.label " . $hash{$vm}{'name'} . "\n";
|
||
|
print $hash{$vm}{'label'} . "_alloc.type GAUGE\n";
|
||
|
print $hash{$vm}{'label'} . "_alloc.info Memory allocation per domain.\n";
|
||
|
print $hash{$vm}{'label'} . "_alloc.min 0\n";
|
||
|
print $hash{$vm}{'label'} . "_alloc.draw $draw\n";
|
||
|
$draw="STACK" if $draw eq "AREA";
|
||
|
}
|
||
|
print "\n";
|
||
|
|
||
|
} elsif($type eq "fetch"){
|
||
|
print "multigraph libvirt_mem\n";
|
||
|
for my $vm (sort keys %hash) {
|
||
|
print $hash{$vm}{'label'} . "_alloc.value " . $hash{$vm}{'info'}{'memory_bytes'} . "\n";
|
||
|
}
|
||
|
print "\n";
|
||
|
}
|
||
|
|
||
|
#
|
||
|
# Memory allocated, second level (pr virtual machine)
|
||
|
#
|
||
|
|
||
|
if($type eq "config"){
|
||
|
for my $vm (sort keys %hash) {
|
||
|
print "multigraph libvirt_mem.vm_" . $hash{$vm}{'label'} . "\n";
|
||
|
print "graph_title Memory allocated to " . $hash{$vm}{'name'} . "\n";
|
||
|
print "graph_args --base 1000\n";
|
||
|
print "graph_category Virtualization\n";
|
||
|
#print "graph_width 550\n";
|
||
|
|
||
|
print "mem.label " . $hash{$vm}{'name'} . " (" . $hash{$vm}{'type'} . ")\n";
|
||
|
print "mem.type GAUGE\n";
|
||
|
print "mem.info Amount of memory allocated to " . $hash{$vm}{'name'} . ". The maximum amount of memory for this domain is " . $hash{$vm}{'maxmem'}/1024 . " MB.\n";
|
||
|
print "mem.min 0\n";
|
||
|
print "mem.draw AREA\n";
|
||
|
print "\n";
|
||
|
}
|
||
|
|
||
|
} elsif($type eq "fetch"){
|
||
|
for my $vm (sort keys %hash) {
|
||
|
print "multigraph libvirt_mem.vm_" . $hash{$vm}{'label'} . "\n";
|
||
|
print "mem.value " . $hash{$vm}{'info'}{'memory_bytes'} . "\n";
|
||
|
print "\n";
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
sub clean_label() {
|
||
|
my $label=shift;
|
||
|
$label =~ s/^[^A-Za-z_]/_/;
|
||
|
$label =~ s/[^A-Za-z0-9_]/_/g;
|
||
|
return $label;
|
||
|
}
|
||
|
|
||
|
sub connect {
|
||
|
my $vmm = Sys::Virt->new(address => $address,
|
||
|
auth => 1,
|
||
|
credlist => [
|
||
|
Sys::Virt::CRED_AUTHNAME,
|
||
|
Sys::Virt::CRED_PASSPHRASE,
|
||
|
],
|
||
|
callback =>
|
||
|
sub {
|
||
|
my $creds = shift;
|
||
|
|
||
|
foreach my $cred (@{$creds}) {
|
||
|
if ($cred->{type} == Sys::Virt::CRED_AUTHNAME) {
|
||
|
$cred->{result} = $username;
|
||
|
}
|
||
|
if ($cred->{type} == Sys::Virt::CRED_PASSPHRASE) {
|
||
|
$cred->{result} = $password;
|
||
|
}
|
||
|
}
|
||
|
return 0;
|
||
|
});
|
||
|
return $vmm;
|
||
|
}
|
||
|
|
||
|
sub autoconf {
|
||
|
my $vmm=&connect();
|
||
|
if($vmm){
|
||
|
my $node = $vmm->get_node_info();
|
||
|
if($node){
|
||
|
print "yes\n";
|
||
|
exit(0);
|
||
|
} else {
|
||
|
print "no (Unable to fetch node info)\n";
|
||
|
exit(1);
|
||
|
}
|
||
|
} else {
|
||
|
print "no (Unable to connect to libvirt)\n";
|
||
|
exit(1);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
#
|
||
|
# Function to extract information from xml and return a hash with the necessary information.
|
||
|
# The logic is really ugly and should be improved.
|
||
|
#
|
||
|
sub parse_xml {
|
||
|
my $raw_xml=shift;
|
||
|
my %res=();
|
||
|
|
||
|
use XML::Simple qw(:strict);
|
||
|
my $xs=XML::Simple->new;
|
||
|
my @a=$xs->XMLin($raw_xml,ForceArray => 1, KeyAttr => 'target');
|
||
|
|
||
|
for (my $i=0 ; $i < scalar(@a) ; $i++){
|
||
|
# Hack to extract disk information and put it into the hash
|
||
|
# TODO: Improve
|
||
|
if(defined($a[$i]{'devices'}[0]{'disk'})){
|
||
|
|
||
|
my $teller = 0;
|
||
|
my $fortsette = 1;
|
||
|
|
||
|
while($fortsette){
|
||
|
if( $a[$i]{'devices'}[0]{'disk'}[$teller] ){
|
||
|
my $type=$a[$i]{'devices'}[0]{'disk'}[$teller]{'type'};
|
||
|
my $source_dev=$a[$i]{'devices'}[0]{'disk'}[$teller]{'source'}[0]{'dev'};
|
||
|
my $target_bus=$a[$i]{'devices'}[0]{'disk'}[$teller]{'target'}[0]{'bus'};
|
||
|
my $target_dev=$a[$i]{'devices'}[0]{'disk'}[$teller]{'target'}[0]{'dev'};
|
||
|
|
||
|
$res{'devices'}{'disk'}{$type}{$target_dev}{'source'}=$source_dev;
|
||
|
$res{'devices'}{'disk'}{$type}{$target_dev}{'bus'}=$target_bus;
|
||
|
$res{'devices'}{'disk'}{$type}{$target_dev}{'type'}=$type;
|
||
|
|
||
|
$teller++;
|
||
|
}
|
||
|
else{
|
||
|
$fortsette = 0;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
# Hack to extract network information and put it into the hash
|
||
|
# TODO: Improve
|
||
|
if(defined($a[$i]{'devices'}[0]{'interface'})){
|
||
|
|
||
|
my $teller = 0;
|
||
|
my $fortsette = 1;
|
||
|
|
||
|
while($fortsette){
|
||
|
if( $a[$i]{'devices'}[0]{'interface'}[$teller] ){
|
||
|
my $type=$a[$i]{'devices'}[0]{'interface'}[$teller]{'type'};
|
||
|
my $target=$a[$i]{'devices'}[0]{'interface'}[$teller]{'target'}[0]{'dev'};
|
||
|
my $bridge=$a[$i]{'devices'}[0]{'interface'}[$teller]{'source'}[0]{'bridge'};;
|
||
|
my $mac=$a[$i]{'devices'}[0]{'interface'}[$teller]{'mac'}[0]{'address'};;
|
||
|
|
||
|
$res{'devices'}{'interface'}{$type}{$target}{'target'}=$target;
|
||
|
$res{'devices'}{'interface'}{$type}{$target}{'mac'}=$mac;
|
||
|
$res{'devices'}{'interface'}{$type}{$target}{'bridge'}=$bridge;
|
||
|
$teller++;
|
||
|
}
|
||
|
else{
|
||
|
$fortsette = 0;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return \%res;
|
||
|
}
|
||
|
|
||
|
sub read_diskstats{
|
||
|
my $dev=shift;
|
||
|
|
||
|
my %res=();
|
||
|
|
||
|
# Verify that $dev is a block device.
|
||
|
if(-b $dev){
|
||
|
# Read minor and major number
|
||
|
my $rdev = stat($dev)->rdev;
|
||
|
$res{'major'} = $rdev >> 8;
|
||
|
$res{'minor'} = $rdev & 0xff;
|
||
|
|
||
|
# If major numer is 253, then proceed as dm-device
|
||
|
if($res{'major'} == 253){
|
||
|
|
||
|
# check that the directory /sys/block/dm-$minor/ exists with a /slaves/ sub directory
|
||
|
if(-d "/sys/block/dm-" . $res{'minor'} . "/"){
|
||
|
if(-d "/sys/block/dm-" . $res{'minor'} . "/slaves/"){
|
||
|
|
||
|
# see if /sys/block/dm-$minor/slaves/ has any slaves
|
||
|
opendir(DIR, "/sys/block/dm-" . $res{'minor'} . "/slaves/");
|
||
|
while(my $slave = readdir(DIR)){
|
||
|
|
||
|
# Exclude directories (. and ..)
|
||
|
if($slave !~ m/^\.+$/){
|
||
|
|
||
|
# Check if we have /sys/block/dm-$minor/slaves/$slave/stat
|
||
|
if(-f "/sys/block/dm-" . $res{'minor'} . "/slaves/" . $slave . "/stat"){
|
||
|
# Read the stat-file
|
||
|
open(FILE, "</sys/block/dm-" . $res{'minor'} . "/slaves/" . $slave . "/stat");
|
||
|
while (my $line = <FILE>) {
|
||
|
# 1 2 3 4 5 6 7 8 9 10 11
|
||
|
if($line =~ m/(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)/){
|
||
|
|
||
|
# Name units description
|
||
|
# ---- ----- -----------
|
||
|
# read I/Os requests number of read I/Os processed
|
||
|
# read merges requests number of read I/Os merged with in-queue I/O
|
||
|
# read sectors sectors number of sectors read
|
||
|
# read ticks milliseconds total wait time for read requests
|
||
|
# write I/Os requests number of write I/Os processed
|
||
|
# write merges requests number of write I/Os merged with in-queue I/O
|
||
|
# write sectors sectors number of sectors written
|
||
|
# write ticks milliseconds total wait time for write requests
|
||
|
# in_flight requests number of I/Os currently in flight
|
||
|
# io_ticks milliseconds total time this block device has been active
|
||
|
# time_in_queue milliseconds total wait time for all requests
|
||
|
#
|
||
|
# Documentation fetched from http://www.mjmwired.net/kernel/Documentation/block/stat.txt
|
||
|
|
||
|
# store the output in the hash
|
||
|
$res{'slaves'}{$slave}{'read_ios'}=$1;
|
||
|
$res{'slaves'}{$slave}{'read_merges'}=$2;
|
||
|
$res{'slaves'}{$slave}{'read_sectors'}=$3;
|
||
|
$res{'slaves'}{$slave}{'read_ticks'}=$4;
|
||
|
$res{'slaves'}{$slave}{'write_ios'}=$5;
|
||
|
$res{'slaves'}{$slave}{'write_merges'}=$6;
|
||
|
$res{'slaves'}{$slave}{'write_sectors'}=$7;
|
||
|
$res{'slaves'}{$slave}{'write_ticks'}=$8;
|
||
|
$res{'slaves'}{$slave}{'in_flight'}=$9;
|
||
|
$res{'slaves'}{$slave}{'io_ticks'}=$10;
|
||
|
$res{'slaves'}{$slave}{'time_in_queue'}=$11;
|
||
|
}
|
||
|
}
|
||
|
close(FILE);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
close(DIR);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return \%res;
|
||
|
}
|
||
|
|
||
|
# Return the timestamp of a file
|
||
|
sub get_prev_time(){
|
||
|
my $tmpfile=shift;
|
||
|
|
||
|
my $time=-1;
|
||
|
|
||
|
if(-r $tmpfile){
|
||
|
$time = stat($tmpfile)->mtime;
|
||
|
}
|
||
|
|
||
|
return $time;
|
||
|
}
|
||
|
|
||
|
init();
|
||
|
|
||
|
# vim:syntax=perl
|