#!/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} || "$ENV{MUNIN_PLUGSTATE}/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 device " . $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 number 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