munin-contrib/plugins/libvirt/libvirt

1301 lines
50 KiB
Perl
Executable File

#!/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, "</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