From 964579f782379911b8c292a605acf2b49b1c288a Mon Sep 17 00:00:00 2001 From: Espen Braastad Date: Wed, 31 Mar 2010 13:39:50 +0200 Subject: [PATCH] Initial version --- plugins/other/libvirt | 1300 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1300 insertions(+) create mode 100755 plugins/other/libvirt diff --git a/plugins/other/libvirt b/plugins/other/libvirt new file mode 100755 index 00000000..62ada22d --- /dev/null +++ b/plugins/other/libvirt @@ -0,0 +1,1300 @@ +#!/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, ") { + # 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