1
0
Fork 0
mirror of https://github.com/munin-monitoring/contrib.git synced 2025-07-22 02:51:03 +00:00

More housekeeping.

This commit is contained in:
Diego Elio Pettenò 2012-08-06 22:20:20 -07:00
parent 038c3ce96b
commit e5ce74926d
43 changed files with 0 additions and 0 deletions

101
plugins/virtualization/kvm_cpu Executable file
View file

@ -0,0 +1,101 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# vim: set fileencoding=utf-8
#
# Munin plugin to show CPU used by vm
#
# Copyright Maxence Dunnewind, Rodolphe Quiédeville
#
# License : GPLv3
#
# parsed environment variables:
# vmsuffix: part of vm name to be removed
#
#%# capabilities=autoconf
#%# family=contrib
import re, os, sys
from subprocess import Popen, PIPE
def config(vm_names):
''' Print the plugin's config
@param vm_names : a list of "cleaned" vms' name
'''
percent = len(filter(lambda x: x[0:3] == 'cpu' and x[3] != ' ', open('/proc/stat', 'r').readlines())) * 100
base_config = """graph_title KVM Virtual Machine CPU usage
graph_vlabel %%
graph_category KVM
graph_scale no
graph_period second
graph_info This graph shows the current CPU used by virtual machines
graph_args --base 1000 -r --lower-limit 0 --upper-limit %d""" % percent
print base_config
draw = "AREA"
for vm in vm_names:
print "%s_cpu.label %s" % (vm, vm)
print "%s_cpu.min 0" % vm
print "%s_cpu.type DERIVE" % vm
print "%s_cpu.draw %s" % (vm, draw)
print "%s_cpu.info percent of cpu time used by virtual machine" % vm
draw = "STACK"
def clean_vm_name(vm_name):
''' Replace all special chars
@param vm_name : a vm's name
@return cleaned vm's name
'''
# suffix part defined in conf
suffix = os.getenv('vmsuffix')
if suffix:
vm_name = re.sub(suffix,'',vm_name)
return re.sub(r"[^a-zA-Z0-9_]", "_", vm_name)
def detect_kvm():
''' Check if kvm is installed
'''
kvm = Popen("which kvm", shell=True, stdout=PIPE)
kvm.communicate()
return not bool(kvm.returncode)
def find_vm_names(pids):
'''Find and clean vm names from pids
@return a dictionnary of {pids : cleaned vm name}
'''
result = {}
for pid in pids:
cmdline = open("/proc/%s/cmdline" % pid, "r")
result[pid] = clean_vm_name(re.sub(r"^.*-name\x00([a-zA-Z0-9.-]*)\x00\-.*$",r"\1", cmdline.readline()))
return result
def list_pids():
''' Find the pid of kvm processes
@return a list of pids from running kvm
'''
pid = Popen("pidof kvm", shell=True, stdout=PIPE)
return pid.communicate()[0].split()
def fetch(vms):
''' Fetch values for a list of pids
@param dictionnary {kvm_pid: cleaned vm name}
'''
for ( pid, name ) in vms.iteritems():
( user, system ) = open("/proc/%s/stat" % pid, 'r').readline().split(' ')[13:15]
print '%s_cpu.value %d' % ( name, int(user) + int(system) )
if __name__ == "__main__":
if len(sys.argv) > 1:
if sys.argv[1] in ['autoconf', 'detect']:
if detect_kvm():
print "yes"
else:
print "no"
elif sys.argv[1] == "config":
config(find_vm_names(list_pids()).values())
else:
fetch(find_vm_names(list_pids()))
else:
fetch(find_vm_names(list_pids()))

110
plugins/virtualization/kvm_io Executable file
View file

@ -0,0 +1,110 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# vim: set fileencoding=utf-8
#
# Munin plugin to show io by vm
#
# Copyright Maxence Dunnewind, Rodolphe Quiédeville
#
# License : GPLv3
#
# parsed environment variables:
# vmsuffix: part of vm name to be removed
#
#%# capabilities=autoconf
#%# family=contrib
import re, os, sys
from subprocess import Popen, PIPE
def config(vm_names):
''' Print the plugin's config
@param vm_names : a list of "cleaned" vms' name
'''
base_config = """graph_title KVM Virtual Machine IO usage
graph_vlabel Bytes read(-)/written(+) per second
graph_category KVM
graph_info This graph shows the block device I/O used of virtual machines
graph_args --base 1024
"""
print base_config
for vm in vm_names:
print "%s_read.label %s" % (vm, vm)
print "%s_read.type COUNTER" % vm
print "%s_read.min 0" % vm
print "%s_read.draw LINE1" % vm
print "%s_read.info I/O used by virtual machine %s" % (vm, vm)
print "%s_write.label %s" % (vm, vm)
print "%s_write.type COUNTER" % vm
print "%s_write.min 0" % vm
print "%s_write.draw LINE1" % vm
print "%s_write.negative %s_read" % (vm, vm)
print "%s_write.info I/O used by virtual machine %s" % (vm, vm)
def clean_vm_name(vm_name):
''' Replace all special chars
@param vm_name : a vm's name
@return cleaned vm's name
'''
# suffix part defined in conf
suffix = os.getenv('vmsuffix')
if suffix:
vm_name = re.sub(suffix,'',vm_name)
return re.sub(r"[^a-zA-Z0-9_]", "_", vm_name)
def fetch(vms):
''' Fetch values for a list of pids
@param dictionnary {kvm_pid: cleaned vm name}
'''
res = {}
for pid in vms:
f = open("/proc/%s/io" % pid, "r")
for line in f.readlines():
if "read_bytes" in line:
read = line.split()[1]
print "%s_read.value %s" % (vms[pid], read)
if "write_bytes" in line:
write = line.split()[1]
print "%s_write.value %s" % (vms[pid], write)
break
f.close()
def detect_kvm():
''' Check if kvm is installed
'''
kvm = Popen("which kvm", shell=True, stdout=PIPE)
kvm.communicate()
return not bool(kvm.returncode)
def find_vm_names(pids):
'''Find and clean vm names from pids
@return a dictionnary of {pids : cleaned vm name}
'''
result = {}
for pid in pids:
cmdline = open("/proc/%s/cmdline" % pid, "r")
result[pid] = clean_vm_name(re.sub(r"^.*-name\x00([a-zA-Z0-9.-]*)\x00\-.*$",r"\1", cmdline.readline()))
return result
def list_pids():
''' Find the pid of kvm processes
@return a list of pids from running kvm
'''
pid = Popen("pidof kvm", shell=True, stdout=PIPE)
return pid.communicate()[0].split()
if __name__ == "__main__":
if len(sys.argv) > 1:
if sys.argv[1] in ['autoconf', 'detect']:
if detect_kvm():
print "yes"
else:
print "no"
elif sys.argv[1] == "config":
config(find_vm_names(list_pids()).values())
else:
fetch(find_vm_names(list_pids()))
else:
fetch(find_vm_names(list_pids()))

107
plugins/virtualization/kvm_mem Executable file
View file

@ -0,0 +1,107 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# vim: set fileencoding=utf-8
#
# Munin plugin to show amount of memory used by vm
#
# Copyright Maxence Dunnewind, Rodolphe Quiédeville, Adrien Pujol
#
# License : GPLv3
#
# parsed environment variables:
# vmsuffix: part of vm name to be removed
#
#%# capabilities=autoconf
#%# family=contrib
import re, os, sys
from subprocess import Popen, PIPE
def config(vm_names):
''' Print the plugin's config
@param vm_names : a list of "cleaned" vms' name
'''
base_config = """graph_title KVM Virtual Machine Memory usage
graph_vlabel Bytes
graph_category KVM
graph_info This graph shows the current amount of memory used by virtual machines
graph_args --base 1024
"""
print base_config
draw = "AREA"
for vm in vm_names:
print "%s_mem.label %s" % (vm, vm)
print "%s_mem.type GAUGE" % vm
if draw == 'AREA':
print "%s_mem.min 0" % vm
print "%s_mem.draw %s" % (vm, draw)
print "%s_mem.info memory used by virtual machine %s" % (vm, vm)
draw = "STACK"
def clean_vm_name(vm_name):
''' Replace all special chars
@param vm_name : a vm's name
@return cleaned vm's name
'''
# suffix part defined in conf
suffix = os.getenv('vmsuffix')
if suffix:
vm_name = re.sub(suffix,'',vm_name)
return re.sub(r"[^a-zA-Z0-9_]", "_", vm_name)
def fetch(vms):
''' Fetch values for a list of pids
@param dictionnary {kvm_pid: cleaned vm name}
'''
res = {}
for pid in vms:
try:
cmdline = open("/proc/%s/cmdline" % pid, "r")
amount = re.sub(r"^.*-m\x00(.*)\x00-smp.*$",r"\1", cmdline.readline())
ammount = int(amount) * 1024 * 1024
print "%s_mem.value %s" % (vms[pid], ammount)
except:
cmdline = open("/proc/%s/cmdline" % pid, "r")
amount = re.sub(r"^.*-m\x00(\d+).*$",r"\1", cmdline.readline())
ammount = int(amount) * 1024 * 1024
print "%s_mem.value %s" % (vms[pid], ammount)
def detect_kvm():
''' Check if kvm is installed
'''
kvm = Popen("which kvm", shell=True, stdout=PIPE)
kvm.communicate()
return not bool(kvm.returncode)
def find_vm_names(pids):
'''Find and clean vm names from pids
@return a dictionnary of {pids : cleaned vm name}
'''
result = {}
for pid in pids:
cmdline = open("/proc/%s/cmdline" % pid, "r")
result[pid] = clean_vm_name(re.sub(r"^.*-name\x00([a-zA-Z0-9.-]*)\x00\-.*$",r"\1", cmdline.readline()))
return result
def list_pids():
''' Find the pid of kvm processes
@return a list of pids from running kvm
'''
pid = Popen("pidof kvm", shell=True, stdout=PIPE)
return pid.communicate()[0].split()
if __name__ == "__main__":
if len(sys.argv) > 1:
if sys.argv[1] in ['autoconf', 'detect']:
if detect_kvm():
print "yes"
else:
print "no"
elif sys.argv[1] == "config":
config(find_vm_names(list_pids()).values())
else:
fetch(find_vm_names(list_pids()))
else:
fetch(find_vm_names(list_pids()))

141
plugins/virtualization/kvm_net Executable file
View file

@ -0,0 +1,141 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# vim: set fileencoding=utf-8
#
# Munin plugin to show the network I/O per vm
#
# Copyright Igor Borodikhin
#
# License : GPLv3
#
#
# parsed environment variables:
# vmsuffix: part of vm name to be removed
#
#%# capabilities=autoconf
#%# family=contrib
import re, os, sys
from subprocess import Popen, PIPE
def config(vm_names):
''' Print the plugin's config
@param vm_names : a list of "cleaned" vms' name
'''
base_config = """graph_title KVM Network I/O
graph_vlabel Bytes rx(-)/tx(+) per second
graph_category KVM
graph_info This graph shows the network I/O of the virtual machines
graph_args --base 1024
"""
print base_config
for vm in vm_names:
print "%s_in.label %s" % (vm, vm)
print "%s_in.type COUNTER" % vm
print "%s_in.min 0" % vm
print "%s_in.draw LINE2" % vm
print "%s_out.negative %s_in" % (vm, vm)
print "%s_out.label %s" % (vm, vm)
print "%s_out.type COUNTER" % vm
print "%s_out.min 0" % vm
print "%s_out.draw LINE2" % vm
def clean_vm_name(vm_name):
''' Replace all special chars
@param vm_name : a vm's name
@return cleaned vm's name
'''
# suffix part defined in conf
suffix = os.getenv('vmsuffix')
if suffix:
vm_name = re.sub(suffix,'',vm_name)
return re.sub(r"[^a-zA-Z0-9_]", "_", vm_name)
def fetch(vms):
''' Fetch values for a list of pids
@param dictionnary {kvm_pid: cleaned vm name}
'''
res = {}
for pid in vms:
tap = get_vm_mac(pid)
try:
f = open("/proc/net/dev", "r")
for line in f.readlines():
if tap in line:
print "%s_in.value %s" % (vms[pid], re.sub(r"%s:"%tap, "", line.split()[0]))
print "%s_out.value %s" % (vms[pid], line.split()[8])
break
except Exception as inst:
print inst
continue
def detect_kvm():
''' Check if kvm is installed
'''
kvm = Popen("which kvm", shell=True, stdout=PIPE)
kvm.communicate()
return not bool(kvm.returncode)
def find_vm_names(pids):
'''Find and clean vm names from pids
@return a dictionnary of {pids : cleaned vm name}
'''
result = {}
for pid in pids:
cmdline = open("/proc/%s/cmdline" % pid, "r")
result[pid] = clean_vm_name(re.sub(r"^.*-name\x00([a-zA-Z0-9.-]*)\x00\-.*$",r"\1", cmdline.readline()))
return result
def get_vm_mac(pid):
'''Find and clean vm names from pids
@return the mac address for a specified pid
'''
cmdline = open("/proc/%s/cmdline" % pid, "r")
line = cmdline.readline()
mac = re.sub(r"^.*ifname=(tap[^,]+),.*$",r"\1", line)
return mac
def list_pids():
''' Find the pid of kvm processes
@return a list of pids from running kvm
'''
pid = Popen("pidof kvm", shell=True, stdout=PIPE)
return pid.communicate()[0].split()
def find_vms_tap():
''' Check if kvm is installed
@return a list of pids from running kvm
'''
result = []
tap = ""
mac = ""
kvm = Popen("ip a | grep -A 1 tap | awk '{print $2}' | grep -v '^$'", shell=True, stdout=PIPE)
res = kvm.communicate()[0].split('\n')
for line in res:
try:
if len(line) > 0:
if re.match(r"^tap.*", line):
tap = re.sub(r"(tap[^:]+):", r"\1", line)
else:
result.append(tap)
except Exception as inst:
continue
return result
if __name__ == "__main__":
if len(sys.argv) > 1:
if sys.argv[1] in ['autoconf', 'detect']:
if detect_kvm():
print "yes"
else:
print "no"
elif sys.argv[1] == "config":
config(find_vm_names(list_pids()).values())
else:
fetch(find_vm_names(list_pids()))
else:
fetch(find_vm_names(list_pids()))

View file

@ -0,0 +1,59 @@
#!/usr/bin/python
# Revision 1.0 2008/05/16 - Steven Wagner
# First functional release. Works for me.
#
# Revision 0.5 2008/05/01 - Julien Rottenberg
# initial display of variables from libvirt
#python-libvirt is required
import libvirt
import sys
conn = libvirt.openReadOnly("qemu:///system")
if conn == None:
print 'Failed to open connection to the hypervisor'
sys.exit(1)
try:
(model, memory, cpus, mhz, nodes, socket, cores, threads) = conn.getInfo()
except:
print 'getInfo failed'
sys.exit(1)
#print
#print "KVM running on %d %s %d mhz CPUs w/ %d MB RAM." % (cpus, model, mhz, memory)
#print
ids = conn.listDomainsID()
if ids == None or len(ids) == 0:
print 'No running domains found.'
sys.exit(1)
if len(sys.argv) == 2:
if sys.argv[1] == "config":
print "graph_title KVM Domain CPU Utilization"
print "graph_vlabel CPU use in seconds"
print "graph_args --base 1000"
print "graph_category kvm"
for id in ids:
dom = conn.lookupByID(id)
nodeName = dom.name()
print "%s.type COUNTER" %(nodeName)
print "%s.label %s" %(nodeName, nodeName)
sys.exit(1)
for id in ids:
dom = conn.lookupByID(id)
state, maxMem, memory, numVirtCpu, cpuTime = dom.info()
nodeName = dom.name()
# uuid = dom.UUID()
# ostype = dom.OSType()
# print """Domain: %s, %s state (%s), %d CPUs, %d seconds, %d milliseconds, mem/max (%d/%d) """ \
# % (nodeName, ostype, state, numVirtCpu, cpuTime/float(1000000000), cpuTime/float(1000000), memory, maxMem )
print "%s.value %d" % (nodeName, cpuTime/float(1000000))

View file

@ -0,0 +1,668 @@
#!/usr/bin/perl -w
=HEADER
-== Munin plugin for VMware ESXi/vSphere monitoring ==-
Copyright (c) 2012 - Stefan Seidel <munin@stefanseidel.info>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
This plugin uses the vSphere SDK for Perl available at
http://www.vmware.com/support/developer/viperltoolkit/
or included in the vSphere CLI available at
http://www.vmware.com/support/developer/vcli/
The use of the SDK is subject to the terms and condition
of VMware, Inc. to which you must agree upon installation.
=cut
=USAGE
-== Usage ==-
Put this file in /usr/share/munin/plugins, `chmod +x` it and
`ln -s` it to /etc/munin/plugins/esx_<hostname of server to monitor>
Add a file "esx_" /etc/munin/plugin-conf.d with content like this
(omit the "# " at the beginning of each line)
---- snip ----
[esx_*]
timeout 60
env.user <username on ESX server or vCenter>
env.password <password of user on ESX server or vCenter>
---- snip ----
Then you need to add this host to your munin.conf on the munin server
(often this is the same as your munin node, i.e. this host) and restart
munin-node, and wait for the data to populate.
-== Query all hosts of a vCenter ==-
An alternate way of using this plugin is to link it to
/etc/munin/plugins/vcenter_<hostname_of_vcenter>
In this mode, the vCenter server specified in the filename is queried
for a list of hosts it manages, and graphs are created for all these
hosts. The option "flatview" is implied in this mode, since one munin
plugin can only be assigned to one host. The option "vCenter" is ignored
since the vCenter server is given through the file name. You can, however
still use the option "flatview" to override the "host_name" under which
the results are reported. Make sure to read the section below about
this option!
-== Graphs don't render ==-
Munin 1.4 has a bug with complex multigraphs like this, see
http://munin-monitoring.org/ticket/1224 for details and a fix if
your graphs don't render!
-== Option flatview ==-
There is an option to render all VMs and Host Systems in a flat
structure, i.e. not rendering VMs as sub-items of their host.
This is useful if you frequently move VMs between hosts and want to
keep the VM graphs running. To activate this option, add
---- snip ----
env.flatview top_level_entry
---- snip ----
to the entry in your config file in /etc/munin/plugin-conf.d (see above).
Be aware that this has some drawbacks:
- you cannot have the same VM name in two hosts you monitor
(the VM name is the unique identifier for the graphs)
- you will only indirectly be able to see which VM is on which host
(running VMs will appear in the CPU graphs of their hosts)
- it's a flat structure, so it can become quite a long list
- because of the way Munin works, all hosts will be queried serially,
not in parallel as it would be the case without "flat view" - this
MAY lead to timing problems if you have a large number of hosts or VMs
-== Option vCenter ==-
If you wish to access the host system indirectly through a vCenter, just
specify this parameter:
---- snip ----
env.vCenter <address or hostname of the vCenter>
---- snip ----
This option can be used with or without the "flatview" option. Make sure your
password and username are valid on the vCenter. The plugin name will still have
to contain the hostname of the host you want to monitor - be aware that you have
to use the hostname exactly as it is registered in the vCenter, so IPs and
hostnames are NOT interchangeable.
=cut
=ACK
-== Ackknowledgements ==-
I would like to thank VMware for their SDK and the good documentation.
Special thanks go to MEGABIT Informationstechnik GmbH (www.megabit.net)
who graciously sponsored the development of the "flat view" option
and the ability to access hosts via vCenter as well as the feature to
query all hosts on the vCenter.
=cut
use strict;
use sort 'stable'; # guarantee stability
no warnings; # don't want warnings in output
use VMware::VIRuntime; # need to install VIM SDK (vSphere CLI/SDK 4.1 or newer)
use VMware::VILib;
use VMware::VIExt;
use Data::Dumper;
use DateTime::Format::ISO8601; # may need to install "libdatetime-format-iso8601-perl" on Debian-based systems
use List::Util qw(sum max);
use List::MoreUtils qw(all);
use Munin::Plugin;
use Time::HiRes qw(time);
my $DEBUG = ${Munin::Plugin::DEBUG};
# Important: this is needed if you do not use a "proper" SSL certificate
# on your vSphere/vCenter/ESX(i) server (which is the default)
$ENV{PERL_LWP_SSL_VERIFY_HOSTNAME} = 0;
# for datetime parsing later on
my $iso8601 = DateTime::Format::ISO8601->new;
my @host_names = ();
my $host_name;
my $host_view;
my $dtsys;
my $perfMan;
my %perfCounter;
# IDs/UUIDs to human readable names
my $resolveNames;
if ($0 =~ /vcenter_(.+)$/) {
$ENV{vCenter} = $1;
$ENV{flatview} = $ENV{flatview} || $ENV{vCenter};
my $vpid = open(FH, "-|");
if ($vpid == 0) {
Opts::set_option ('username', $ENV{user} || 'root');
Opts::set_option ('password', $ENV{password} || '');
Opts::set_option ('server', $ENV{vCenter});
Util::connect();
foreach (@{Vim::find_entity_views(view_type => 'HostSystem', properties => ['name'])}) {
print $_->{name}, "\n";
}
Util::disconnect();
exit 0;
} else {
while (<FH>) {
push @host_names, trim($_);
print "# found host ",trim($_)," on vCenter\n" if $DEBUG;
}
close FH;
}
} else {
# get hostname from filename and blurt it out immediately
# so that when something goes wrong, at least the plugin
# output is linked with the right host
$0 =~ /esx_(.+)$/;
push @host_names, $1;
}
my @returns = ();
foreach $host_name (@host_names) {
# make sure we only print one host_name statement per plugin
if ((@returns == 0) and (defined $ARGV[0]) and ($ARGV[0] eq "config")) {
if ($ENV{flatview}) {
print "host_name $ENV{flatview}\n";
print "# for host $host_name\n" if $DEBUG;
} else {
print "host_name $host_name\n";
}
}
local *FH;
my $pid = open(FH, "-|");
if ($pid == 0) {
# CHILD
# env.user and env.password need to be set in plugin-conf.d
Opts::set_option ('username', $ENV{user} || 'root');
Opts::set_option ('password', $ENV{password} || '');
if ($ENV{vCenter}) {
print "# vCenter: $ENV{vCenter} - host $host_name\n" if $DEBUG;
Opts::add_options ( (vihost => { alias => "h", type => "=s", required => 0 }) );
Opts::set_option ('vihost',$host_name);
Opts::set_option ('server',$ENV{vCenter});
} else {
Opts::set_option ('server',$host_name);
}
# plugin needs Munin 1.4 or later
need_multigraph();
my $sstarttime = time();
# connect to vSphere host
Util::connect();
# central object host_view holds all relevant items (VMs, network, etc.)
$host_view = VIExt::get_host_view(1, ['summary', 'network', 'datastore', 'vm', 'runtime', 'configManager.networkSystem', 'configManager.dateTimeSystem']);
Opts::assert_usage(defined($host_view), "Invalid host.");
my $serviceInst = Vim::get_view (mo_ref => ManagedObjectReference->new(type => 'ServiceInstance', value => 'ServiceInstance'));
# Performance Manager for getting the actual values
$perfMan = Vim::get_view (mo_ref => $serviceInst->content->perfManager);
Opts::assert_usage(defined($perfMan), "No PerformanceManager.");
# may be needed later
#my $netsys = Vim::get_view(mo_ref => ManagedObjectReference->new(type => 'HostNetworkSystem', value => 'networkSystem'));
#Opts::assert_usage(defined($netsys), "No NetworkSystem.");
# used for getting the current vSphere server time and then
# defining the (now - 5minutes) interval
$dtsys = Vim::get_view(mo_ref => $host_view->{'configManager.dateTimeSystem'});
Opts::assert_usage(defined($dtsys), "No DateTimeSystem.");
print "# time to connect and get objects: ", time() - $sstarttime, "\n" if $DEBUG;
# enumerate all performance counters by their IDs
%perfCounter = map { $_->key => $_ } @{$perfMan->perfCounter};
# holds all performance data
my @all_perf_data = ();
# store VM ids for iteration later on
my @all_vms = ();
$host_view->update_view_data();
# retrieve performance counters for host
push @all_perf_data, get_perf_data($host_view);
# manually set UF name for host system
$resolveNames->{vm}->{""} = "Host System";
# only purpose of this loop is getting the UF network names
# network ManagedObjects do not have performance counters
for ($host_view->network) {
for (@$_) {
my $network = Vim::get_view (mo_ref => $_);
$resolveNames->{net}->{$_->{value}} = $_->{value}." (".$network->summary->name.")";
}
}
# purpose of this loop is getting the UF datastore names
# and retrieving capacity and free/uncommitted space
# datastore ManagedObjects do not have performance counters
for ($host_view->datastore) {
for (@$_) {
my $datastore = Vim::get_view (mo_ref => $_);
# update freeSpace values (doesn't work on free ESXi)
eval { $datastore->RefreshDatastore(); };
$datastore->update_view_data();
my $uuid =$datastore->summary->url;
$uuid =~ s!.+/!!;
$resolveNames->{datastore}->{$uuid} = $datastore->name;
push (@all_perf_data,
{ rollup => "latest",
group => "datastore",
name => "capacity",
value => $datastore->summary->capacity,
counter => PerfCounterInfo->new(nameInfo => ElementDescription->new(label => "Capacity", summary => "Maximum amount of storage space on this datastore")),
vm => "",
instance => $uuid,
unit => "Bytes" });
push (@all_perf_data,
{ rollup => "latest",
group => "datastore",
name => "freeSpace",
value => $datastore->summary->freeSpace,
counter => PerfCounterInfo->new(nameInfo => ElementDescription->new(label => "Free", summary => "Total amount of unused, available storage space on this datastore")),
vm => "",
instance => $uuid,
unit => "Bytes" });
push (@all_perf_data,
{ rollup => "latest",
group => "datastore",
name => "uncommitted",
value => $datastore->summary->uncommitted,
counter => PerfCounterInfo->new(nameInfo => ElementDescription->new(label => "Uncommitted", summary => "Total additional storage space, potentially used by all virtual machines on this datastore")),
vm => "",
instance => $uuid,
unit => "Bytes" });
}
}
# iterate over all vms
for ($host_view->vm) {
for (@$_) {
my $vm = Vim::get_view (mo_ref => $_);
$vm->update_view_data();
# store VM id for later iteration
my $vmId = $_->{value};
push @all_vms, $vmId;
# ID to VM name
$resolveNames->{vm}->{$vmId} = "VM ".$vm->summary->config->name;
$resolveNames->{vmuuid}->{$vmId} = $vm->summary->config->uuid;
# fetch disk space usage per datastore
for (@{$vm->storage->perDatastoreUsage}) {
my $uuid = Vim::get_view(mo_ref => $_->datastore)->summary->url;
$uuid =~ s!.+/!!;
push (@all_perf_data,
{ rollup => "latest",
group => "datastore",
name => "committed",
value => $_->committed,
counter => PerfCounterInfo->new(nameInfo => ElementDescription->new(label => "Comitted", summary => "Storage space, in bytes, on this datastore that is actually being used by the virtual machine.\n\nIt includes space actually occupied by disks, logs, snapshots, configuration files etc. Files of the virtual machine which are present on a different datastore (e.g. a virtual disk on another datastore) are not included here.\n\n")),
vm => $vmId,
instance => $uuid,
unit => "Bytes" });
push (@all_perf_data,
{ rollup => "latest",
group => "datastore",
name => "uncommitted",
value => $_->uncommitted,
counter => PerfCounterInfo->new(nameInfo => ElementDescription->new(label => "Uncomitted", summary => "Additional storage space, in bytes, potentially used by the virtual machine on this datastore.\n\nAdditional space may be needed for example when lazily allocated disks grow, or storage for swap is allocated when powering on the virtual machine.\n\nIf the virtual machine is running off delta disks (for example because a snapshot was taken), then only the potential growth of the currently used delta-disks is considered.\n\n")),
vm => $vmId,
instance => $uuid,
unit => "Bytes" });
push (@all_perf_data,
{ rollup => "latest",
group => "datastore",
name => "unshared",
value => $_->unshared,
counter => PerfCounterInfo->new(nameInfo => ElementDescription->new(label => "Unshared", summary => "Storage space, in bytes, occupied by the virtual machine on this datastore that is not shared with any other virtual machine.\n\n")),
vm => $vmId,
instance => $uuid,
unit => "Bytes" });
}
# retrieve performance counters for this VM
push @all_perf_data, get_perf_data ($_);
}
}
# keep track of how many sensors are in which state
my %sensorCount = ( green => 0, red => 0, unknown => 0, yellow => 0 );
# iterate over all sensor data
my $index = 0;
for (@{$host_view->runtime->healthSystemRuntime->systemHealthInfo->numericSensorInfo}) {
# update counters
$sensorCount{$_->healthState->key}++;
# do not create entries for unmonitorable things like software components
next unless ($_->baseUnits =~ /.+/);
# create entry with sensor data
push (@all_perf_data,
{ rollup => "latest",
group => "sensors",
name => "sensor_".($index++),
value => $_->currentReading,
counter => PerfCounterInfo->new(nameInfo => ElementDescription->new(label => $_->name, summary => "Sensor data for the ".$_->sensorType." sensor ".$_->name.". ".$_->healthState->summary." (".$_->healthState->label.")")),
vm => "",
instance => "",
unitModifier => $_->unitModifier,
unit => $_->baseUnits });
}
# we're finished querying the server, so we can disconnect now
Util::disconnect();
# create entries for the green/red/yellow/unknown counters
for (keys %sensorCount) {
push (@all_perf_data,
{ rollup => "latest",
group => "sensors",
name => $_."_sensors",
value => $sensorCount{$_},
counter => PerfCounterInfo->new(nameInfo => ElementDescription->new(label => ucfirst($_), summary => "Count of sensors in the $_ state")),
vm => "",
instance => "",
unit => "Numbers" });
}
if ($DEBUG) {
foreach (sort { $a->{group} cmp $b->{group} || $a->{instance} cmp $b->{instance} || $a->{name} cmp $b->{name} || $a->{rollup} cmp $b->{rollup} || $a->{vm} cmp $b->{vm} } @all_perf_data) {
print "# $_->{vm}\t$_->{rollup}\t$_->{group}\t$_->{instance}\t$_->{name}\t$_->{value}\t$_->{unit}\n";
}
}
# which graphs to draw
my @all_graphs = ();
# host system
push @all_graphs, (
{ selector => { group => qr/^cpu$/i, name => qr/^usagemhz$/i, instance => qr/^$/ },
config => { groupBy => "group", graphName => "host_cpu", graphTitle => "CPU usage per " }
},
{ selector => { group => qr/^disk$/i, name => qr/^(read|usage|write)$/i, instance => qr/.+/ },
config => { groupBy => "group", graphName => "host_disk_transfer", graphTitle => "Disk Transfer Rates per " }
},
{ selector => { group => qr/^disk$/i, name => qr/^.+Averaged$/i, instance => qr/.+/ },
config => { groupBy => "group", graphName => "host_disk_iops", graphTitle => "Disk I/O operations per " }
},
{ selector => { group => qr/^disk$/i, name => qr/^.+Latency$/i, instance => qr/.+/, vm => qr/^$/ },
config => { groupBy => "vm", graphName => "host_disk_latency", graphTitle => "Disk latency for " }
},
{ selector => { group => qr/^mem$/i, unit => qr/^KB$/i, rollup => qr/^none$/, vm => qr/^$/ },
config => { groupBy => "vm", graphName => "host_memory", graphTitle => "Memory usage for " }
},
{ selector => { group => qr/^datastore$/i, unit => qr/^Bytes$/i, vm => qr/^$/ },
config => { groupBy => "vm", graphName => "usage_datastore", graphTitle => "Disk space usage for ", graphArgs => "--lower-limit 10737418240 --logarithmic --alt-autoscale-min --units=si" }
},
{ selector => { group => qr/^net$/i, unit => qr/^KBps$/i, vm => qr/^$/ },
config => { groupBy => "vm", graphName => "host_traffic_net", graphTitle => "Network traffic for " }
},
{ selector => { group => qr/^net$/i, unit => qr/^Number$/i, vm => qr/^$/ },
config => { groupBy => "vm", graphName => "host_packets_net", graphTitle => "Network packets for " }
},
{ selector => { group => qr/^power$/i, name => qr/^power$/i },
config => { groupBy => "group", graphName => "power_usage", graphTitle => "Host System and VM " }
},
{ selector => { group => qr/^sys$/i, name => qr/^diskUsage$/i },
config => { groupBy => "name", graphName => "host_disk_usage", graphTitle => "Host System " }
},
{ selector => { group => qr/^sys$/i, name => qr/^uptime$/i },
config => { groupBy => "name", graphName => "uptimes", graphTitle => "Host System and VM ", graphArgs => "--lower-limit 1000 --logarithmic --alt-autoscale-min" }
}
);
# graphs per VM
foreach (@all_vms) {
my $vmName = clean_fieldname($resolveNames->{vm}->{$_});
push @all_graphs, (
{ selector => { group => qr/^cpu$/i, name => qr/^usagemhz$/i, vm => qr/^$_$/ },
config => { groupBy => "vm", graphName => "$vmName.vm_cpu", graphTitle => "CPU usage for " }
},
{ selector => { group => qr/^mem$/i, unit => qr/^KB$/i, rollup => qr/^none$/, vm => qr/^$_$/ },
config => { groupBy => "vm", graphName => "$vmName.vm_memory", graphTitle => "Memory usage for " }
},
{ selector => { group => qr/^datastore$/i, unit => qr/^Bytes$/i, vm => qr/^$_$/ },
config => { groupBy => "vm", graphName => "$vmName.vm_datastore", graphTitle => "Disk space usage for ", graphArgs => "--lower-limit 10485760 --logarithmic --alt-autoscale-min --units=si" }
},
{ selector => { group => qr/^virtualDisk$/i, unit => qr/^Millisecond$/i, vm => qr/^$_$/ },
config => { groupBy => "vm", graphName => "$vmName.vm_disklat", graphTitle => "Disk latency for " }
},
{ selector => { group => qr/^virtualDisk$/i, unit => qr/^Number$/i, vm => qr/^$_$/ },
config => { groupBy => "vm", graphName => "$vmName.vm_diskiops", graphTitle => "Disk I/O operations for " }
},
{ selector => { group => qr/^virtualDisk$/i, unit => qr/^KBps$/i, vm => qr/^$_$/ },
config => { groupBy => "vm", graphName => "$vmName.vm_disktrans", graphTitle => "Disk transfer rates for " }
},
{ selector => { group => qr/^net$/i, unit => qr/^KBps$/i, vm => qr/^$_$/ },
config => { groupBy => "vm", graphName => "$vmName.vm_traffic_net", graphTitle => "Network traffic for " }
},
{ selector => { group => qr/^net$/i, unit => qr/^Number$/i, vm => qr/^$_$/ },
config => { groupBy => "vm", graphName => "$vmName.vm_packets_net", graphTitle => "Network packets for " }
},
{ selector => { group => qr/^sys$/i, name => qr/^uptime$/i, vm => qr/^$_$/ },
config => { groupBy => "vm", graphName => "$vmName.vm_uptime", graphTitle => "VM uptime " }
}
);
}
# sensor graphs
push @all_graphs, (
{ selector => { group => qr/^sensors$/i },
config => { groupBy => "unit", graphName => "sensor_", graphTitle => "Sensors ", multiGraph => 1 }
});
print "# time to collect all data: ", time() - $sstarttime, "\n" if $DEBUG;
# actual processing
foreach (@all_graphs) {
if ((defined $ARGV[0]) and ($ARGV[0] eq "config")) {
munin_print("config", \@all_perf_data, $_);
munin_print("values", \@all_perf_data, $_) if $ENV{MUNIN_CAP_DIRTYCONFIG}; # this doesn't seem to work even on Munin 1.4.6
} else {
munin_print("values", \@all_perf_data, $_);
}
}
print "# time of the script: ", time() - $sstarttime, "\n" if $DEBUG;
exit 0;
} else {
# PARENT
push @returns, *FH;
}
}
# gather and print the output of the forked processes
foreach my $fh (@returns) {
while (<$fh>) {
print $_;
}
close ($fh);
}
exit 0;
####################################################################
# calculate sum, max or avg from performance data values
sub process_value_array {
my $arr = shift;
my $pd = shift;
my @vs = ();
if ($pd->unitInfo->key eq "percent") {
@vs = map { $_ / 100 } @$arr ;
} else {
@vs = @$arr;
}
return sum(@vs) if $pd->rollupType->val eq "summation";
return max(@vs) if $pd->nameInfo->key =~ /max/i;
return sum(@vs)/@$arr;
}
# query performance data for object
sub get_perf_data {
my $entity = shift;
my @ret = ();
my $gathstart = time();
# get the current server time
my $curtime = $iso8601->parse_datetime($dtsys->QueryDateTime());
# and subtract 5 minutes to get all values for the last period
my $oldtime = $curtime->clone->add(minutes => -5);
# actual query, intervalId is 20 because that's the default
my $perfQ = $perfMan->QueryPerf(querySpec => PerfQuerySpec->new(entity => $entity, intervalId => 20, startTime => $oldtime));
# loop over PerfEntityMetric
foreach (defined $perfQ ? @$perfQ : ()) {
my $vm = ($_->entity->type eq 'VirtualMachine')?$_->entity->value:"";
# loop over PerfMetricIntSeries
foreach (@{$_->{value}}) {
my $perfDesc = $perfCounter{$_->id->counterId};
next unless defined $perfDesc;
push @ret, { rollup => $perfDesc->rollupType->val,
group => $perfDesc->groupInfo->key,
name => $perfDesc->nameInfo->key,
value => process_value_array(\@{$_->{value}}, $perfDesc),
counter => $perfDesc,
vm => $vm,
instance => $_->id->instance,
unit => $perfDesc->unitInfo->label };
}
}
print "# time to gather info for $entity :", time() - $gathstart, "\n" if $DEBUG;
return @ret;
}
# generate a munin-friendly and unique field name
sub gen_dp_name {
my $fname = $_[0]->{name};
$fname .= "v".$resolveNames->{vmuuid}->{$_[0]->{vm}} unless $_[1] eq "vm" or $_[0]->{vm} eq "";
$fname .= "i$_[0]->{instance}" unless $_[1] eq "instance" or $_[0]->{instance} eq "";
return clean_fieldname($fname);
}
# trim white spaces
sub trim {
my $string = shift;
$string =~ s/^\s+//;
$string =~ s/\s+$//;
return $string;
}
# print values and configs for graphs
sub munin_print {
# action
my $act = shift || "";
# values
my $arr = shift || ();
# parameters
my $par = shift || {};
my $cfg = $par->{config};
$par = $par->{selector};
my $oldGroup = "_-_";
my $factor;
if ($ENV{flatview}) {
$cfg->{graphName} = clean_fieldname("Host_".$host_view->name).".".$cfg->{graphName} unless $cfg->{graphName} =~ m/\./;
}
# find values according to criteria in $par and sort by grouping parameter
#foreach (sort { $a->{$cfg->{groupBy}} cmp $b->{$cfg->{groupBy}} } grep { my $d = $_; all { (not exists $d->{$_}) || $d->{$_} =~ /$par->{$_}/ } keys %$par; } @$arr) {
foreach (sort { $a->{$cfg->{groupBy}} cmp $b->{$cfg->{groupBy}} } grep { my $d = $_; all { (not exists $d->{$_}) || $d->{$_} =~ /$par->{$_}/ } keys %$par; } @$arr) {
my $groupCrit = $cfg->{groupBy} || "";
my $curGroup = $_->{$groupCrit} || "";
if (!($curGroup eq $oldGroup)) {
# we're in a new group, meaning a new graph starts
$factor = 0;
# clean up group name for multigraph name
my $ccurGroup = $curGroup;
$ccurGroup =~ s/ |\./_/g;
print "multigraph ",$cfg->{graphName},(exists $cfg->{multiGraph}?$ccurGroup:""),"\n";
if ("config" eq $act) {
# want configuration
print "graph_title ",$cfg->{graphTitle},$resolveNames->{$groupCrit}->{$curGroup} || $curGroup,"\n";
#print "graph_order xxx yyy\n";
my $unit = $_->{unit};
my $base = 1000;
# since the y-axis markers are going to be wrong with source units like
# KB, MB, MHz etc., we define a correction factor via cdef later
# this way, if 1024 MB is reported, the graph shows 1G and not 1k
# (although 1k MB is technically also correct, but confusing)
if ($unit =~ /^Bytes$/i) {
$base = 1024;
} elsif ($unit =~ /^KBps$/i) {
$unit = "Bytes/s";
$factor = 1024;
$base = 1024;
} elsif ($unit =~ /^KB$/i) {
$unit = "Bytes";
$factor = 1024;
$base = 1024;
} elsif ($unit =~ /^MB$/i) {
$unit = "Bytes";
$factor = 1024*1024;
$base = 1024;
} elsif ($unit =~ /^MHz$/i) {
$unit = "Hz";
$factor = 1000000;
} elsif ($unit =~ /^Millisecond$/i) {
$unit = "Second";
$factor = 1/1000;
}
print "graph_vlabel $unit\n";
print "graph_category $_->{group}\n";
print "graph_args --base=$base --alt-autoscale-max ",(defined $cfg->{graphArgs})?$cfg->{graphArgs}:"","\n";
}
}
$oldGroup = $curGroup;
my $dpName = gen_dp_name($_, $groupCrit);
if ("config" eq $act) {
# want configuration
# get instance and VM names and UF names, if applicable
my $iName = $resolveNames->{$_->{group}}->{$_->{instance}} || (("" eq $_->{instance})?"":$_->{group}." ".$_->{instance});
$iName = " $iName" if $iName;
my $vmName = $resolveNames->{vm}->{$_->{vm}};
$vmName = " $vmName" if $vmName;
# all values are drawn as lines for now
print "$dpName.draw LINE2\n";
print "$dpName.label ",$_->{counter}->nameInfo->label,$iName,("vm" eq $groupCrit)?"":$vmName || "","\n";
my $summary = $_->{counter}->nameInfo->summary;
$summary =~ s!\n!\\n!g;
print "$dpName.info ",$summary,$iName?", instance$iName ($_->{instance})":"",$vmName?",$vmName":"","\n";
# declare CDEF if we want to apply a factor
if ($factor > 1) {
print "$dpName.cdef $dpName,$factor,*\n";
} elsif ($factor <= 0) {
if (defined $_->{unitModifier}) {
# sensor values have a unit modifier M attached to them so that REALVAL=VAL*10^M
# y,x,LOG,*,EXP is x^y, just in case this is not obvious to the reader
print "$dpName.cdef $dpName,",$_->{unitModifier},",10,LOG,*,EXP,*\n";
}
} elsif ($factor < 1) {
print "$dpName.cdef $dpName,",1/$factor,",/\n";
}
} else {
# just print value
print "$dpName.value $_->{value}\n";
}
}
}

View file

@ -0,0 +1,264 @@
#!/bin/bash
GREP="/bin/grep"
SED="/bin/sed"
TAIL="/usr/bin/tail"
SSH="/usr/bin/ssh"
BASENAME="/usr/bin/basename"
# script name must be like esx_cpu_machine.domain or esx_mem_machine.domain
temp="$(basename $0 | $SED 's/^esx_//g')"
which_info="${temp%%_*}"
HOST="${temp##*_}"
case "$which_info" in
"cpu" | "mem" | "hmem" | "gmem" ) ;;
* ) echo "Script name incorrect, should be esx_xxx_hostname where xxx in {cpu,mem,hmem,gmem}"
exit 1;;
esac
# ---------------
function get_infos () {
summary="$($SSH "$HOST" \
vim-cmd hostsvc/hostsummary \; \
vim-cmd vmsvc/getallvms)"
}
function get_vmlist () {
total_linenumber="$(echo "$summary" | wc -l)"
vmlist_linenumber="$(echo "$summary" | $GREP -n "^Vmid")"
vmlist_linenumber="${vmlist_linenumber/:*/}"
vmlist="$(echo "$summary" | $TAIL -n $(($total_linenumber - $vmlist_linenumber)) | tr -s " ")"
}
function overallCpuUsage () {
cpu="$(echo "$1" | $GREP "overallCpuUsage")"
cpu="${cpu/*overallCpuUsage = /}"
cpu="${cpu/,*/}"
}
function overallMemoryUsage () {
mem="$(echo "$1" | $GREP "overallMemoryUsage")"
mem="${mem/*overallMemoryUsage = /}"
mem="${mem/,*/}"
}
# ---------------
function get_vmsvcsummaries () {
n=0
cmd=""
# echo "$vmlist" | \
while read vmline ; do
id[$n]="${vmline%% *}"
temp="${vmline#${id[$n]} }"
name[$n]="${temp%% *}"
cmd="$cmd""vim-cmd vmsvc/get.summary ${id[$n]} \\\; "
(( n++ ))
done <<EOF
$vmlist
EOF
vmsummaries="$($SSH "$HOST" $cmd)"
}
# ---------------
function VMoverallCpuUsage () {
cpulist="$(echo "$1" | $GREP "overallCpuUsage")"
n=0
while read c ; do
temp="${c/*overallCpuUsage = /}"
vmcpu[$n]="${temp/,*/}"
if [ "${vmcpu[$n]}" == "<unset>" ]; then
vmcpu[$n]="0"
fi
(( n++ ))
done <<EOF
$cpulist
EOF
}
function VMoverallGuestMemUsage () {
memlist="$(echo "$1" | $GREP "guestMemoryUsage")"
n=0
while read m ; do
temp="${m/*guestMemoryUsage = /}"
vmmem[$n]="${temp/,*/}"
if [ "${vmmem[$n]}" == "<unset>" ]; then
vmmem[$n]="0"
fi
(( n++ ))
done <<EOF
$memlist
EOF
}
function VMoverallHostMemUsage () {
memlist="$(echo "$1" | $GREP "hostMemoryUsage")"
n=0
while read m ; do
temp="${m/*hostMemoryUsage = /}"
vmmem[$n]="${temp/,*/}"
if [ "${vmmem[$n]}" == "<unset>" ]; then
vmmem[$n]="0"
fi
(( n++ ))
done <<EOF
$memlist
EOF
}
# ---------------
if [ "$1" = "autoconf" ]; then
get_infos
if [ -n "$summary" ]; then
echo yes
exit 0
else
echo "Cannot connect to ESX server $HOST"
exit 1
fi
fi
if [ "$1" = "config" ]; then
get_infos
if [ -z "$summary" ]; then
echo "Cannot connect to ESX server $HOST"
exit 1
fi
case "$which_info" in
"cpu" )
echo 'graph_title ESXi Domain CPU Usage'
echo 'graph_args -l 0'
echo 'graph_scale no'
echo 'graph_vlabel CPU usage in MHz'
echo 'graph_category esx'
echo 'graph_info This graph shows the average CPU MHz used by each domain'
name="Domain_0"
echo "$name.label $name"
echo "$name.type GAUGE"
echo "$name.draw AREA"
echo "$name.min 0"
echo "$name.info CPU MHz used by $name"
get_vmlist
if [ -n "$vmlist" ]; then
n=0
cmd=""
while read vmline ; do
id="${vmline%% *}"
temp="${vmline#$id }"
name="${temp%% *}"
name=`echo $name | sed -e"s/[-\.]/_/g"`
echo "$name.label $name"
echo "$name.type GAUGE"
echo "$name.draw STACK"
echo "$name.min 0"
echo "$name.info CPU MHz used by $name"
(( n++ ))
done <<EOF
$vmlist
EOF
fi;;
"mem" | "hmem" | "gmem" )
echo 'graph_title ESXi Domain '"$which_info"' Usage'
echo 'graph_args -l 0'
echo 'graph_scale no'
echo 'graph_vlabel Memory usage in Megabytes'
echo 'graph_category esx'
echo 'graph_info This graph shows the average Memory used by each domain'
name="Domain_0"
echo "$name.label $name"
echo "$name.type GAUGE"
echo "$name.draw AREA"
echo "$name.min 0"
echo "$name.info Memory usage for $name"
get_vmlist
if [ -n "$vmlist" ]; then
n=0
cmd=""
while read vmline ; do
id="${vmline%% *}"
temp="${vmline#$id }"
name="${temp%% *}"
name=`echo $name | sed -e"s/[-\.]/_/g"`
echo "$name.label $name"
echo "$name.type GAUGE"
echo "$name.draw STACK"
echo "$name.min 0"
echo "$name.info Memory usage for $name"
(( n++ ))
done <<EOF
$vmlist
EOF
fi;;
esac
exit 0
fi
# ---------------
# Get the informations
get_infos
if [ -z "$summary" ]; then
echo "Cannot connect to ESX server $HOST"
exit 1
fi
case $which_info in
"cpu" ) overallCpuUsage "$summary" ;;
"mem" | "hmem" | "gmem" ) overallMemoryUsage "$summary" ;;
esac
get_vmlist
if [ -n "$vmlist" ]; then
get_vmsvcsummaries
case $which_info in
"cpu" ) VMoverallCpuUsage "$vmsummaries";;
"mem" | "hmem" ) VMoverallHostMemUsage "$vmsummaries";;
"gmem" ) VMoverallGuestMemUsage "$vmsummaries";;
esac
fi
# ---------------
# Print information Munin style
case $which_info in
"cpu" ) echo "Domain_0.value ""$cpu";;
"mem" | "gmem" | "hmem" ) echo "Domain_0.value ""$(($mem))";;
esac
if [ -n "$vmlist" ]; then
n=0
while [ -n "${id[$n]}" ]; do
#echo ${id[$n]} ${name[$n]} ${vmcpu[$n]} ${vmmem[$n]}
nicename=`echo ${name[$n]} | sed 's/[^a-z|A-Z|0-9]/\_/g'`
case $which_info in
"cpu" ) echo "$nicename".value "${vmcpu[$n]}";;
"mem" | "gmem" | "hmem" ) echo "$nicename".value "$((${vmmem[$n]}))";;
esac
(( n++ ))
done
fi

View file

@ -0,0 +1,47 @@
#!/bin/bash
i=0
VMX[0]='/var/lib/vmware/Virtual Machines/<VM Name>/Other Linux.vmx';
VMX[1]='another VM';
VMX[2]='and one more :)';
VMX[3]='add as much as you like!';
if [ "$1" = "autoconf" ]; then
echo yes
exit 0
fi
if [ "$1" = "config" ]; then
echo 'graph_title VMware CPU-Load'
echo 'graph_args --base 1000 -l 0'
echo 'graph_vlabel Load of VMware VMs'
echo 'graph_category VMware'
while [ $i -lt ${#VMX[*]} ]
do
NAME=`vmware-cmd "${VMX[i]}" getconfig displayName |sed 's!getconfig(displayName) = !!' | sed 's! !!g' | sed 's!-!_!g'`
echo $NAME.label $NAME
i=`expr $i + 1`
done
exit 0
fi
i=0
while [ $i -lt ${#VMX[*]} ]
do
PID=`vmware-cmd "${VMX[$i]}" getpid | sed 's!getpid() = !!'`
NAME=`vmware-cmd "${VMX[i]}" getconfig displayName |sed 's!getconfig(displayName) = !!' | sed 's! !!g' | sed 's!-!_!g'`
CPU=`ps -o %cpu -p $PID --no-header`
echo $NAME."value" $CPU
i=`expr $i + 1`
done

View file

@ -0,0 +1,77 @@
#!/bin/bash
#
# Created by Jan Rękorajski <baggins@pld-linux.org> based on vserver_cpu_ plugin.
#
# Graph Vserver cumulative cpu usage stats
#
# Configuration variables
# vservers - specify the vservers to include in the graph (default: all)
#
# NOTE: If no configuration variable is set, the default will be used
#
# see vserver_resources for example uses of configuration files
VSERVERS="$vservers"
INFO=(`sed 's/.*:\t//' /proc/virtual/info 2>/dev/null || echo '<none>'`)
KCIN="$[ 16#${INFO[2]} ]";
# If this is 1, then VCI_SPACES is present in the kernel (new in 2.6.19)
if [ $[ (KCIN >> 10) & 1 ] -eq 1 ]
then
NAMELOC="nsproxy"
else
NAMELOC="cvirt"
fi
if [ -z "$VSERVERS" ] ; then
XIDS=`find /proc/virtual/* -type d -exec basename {} \;`
else
# it's really more performant to specify vservers by ids or by linking but not in the configuration-file by name
XIDS=""
for i in $VSERVERS ; do
if [ -d /proc/virtual/$i ] ; then
XIDS="${XIDS}${i} "
else
for j in `find /proc/virtual/* -type d -exec basename {} \;` ; do
if [ "$i" = "`cat /proc/virtual/$j/$NAMELOC |grep NodeName |cut -f2`" ] ; then
XIDS="${XIDS}${j} "
fi
done
fi
done
fi
if [ "$1" = "config" ]; then
echo 'graph_category vserver'
echo 'graph_args --base 1000'
echo 'graph_title Vserver cpu usage'
echo 'graph_vlabel jiffies used per ${graph_period}'
echo 'graph_info Shows jiffies used on each vserver.'
for i in $XIDS ; do
LABEL=`grep NodeName /proc/virtual/$i/$NAMELOC | cut -f2`
NAME=`echo $LABEL | tr '-' '_'`
echo "${NAME}_hold.label on hold for cpu on $LABEL"
echo "${NAME}_hold.info on hold for cpu on $LABEL."
echo "${NAME}_hold.type COUNTER"
echo "${NAME}_scpu.label system cpu usage for $LABEL"
echo "${NAME}_scpu.info system cpu usage for $LABEL."
echo "${NAME}_scpu.type COUNTER"
echo "${NAME}_ucpu.label user cpu usage for $LABEL"
echo "${NAME}_ucpu.info user cpu usage for $LABEL."
echo "${NAME}_ucpu.type COUNTER"
done
exit 0
fi
for i in $XIDS ; do
NAME=`grep NodeName /proc/virtual/$i/$NAMELOC | cut -f2 | tr '-' '_'`
awk -v name=$NAME -v u=0 -v s=0 -v h=0 '
/^cpu [0-9]+:/ { u+=$3; s+=$4; h+=$5}
END {
print name "_hold.value " h
print name "_scpu.value " s
print name "_ucpu.value " u
}' /proc/virtual/$i/sched
done

View file

@ -0,0 +1,120 @@
#!/bin/sh
#
# Copyright (C) 2008 Chris Wilson
# Copyright (C) 2006 Holger Levsen
#
# 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.
#
# Configuration variables
# vservers - specify the vservers to include in the graph (default: all)
# limits - if true, turn on limit graphing (default: false)
#
# NOTE: If no configuration variables are set, the defaults will be used
# Example /etc/munin/plugin-conf.d/munin-node
#
# The first group monitors the vservers named "vserver1 vserver2
# vserver3 vserver4" and looks to see if the resource limit has been
# breached, if so it sends a message to nagios via send_nsca, and
# sends an email to notify that this has happened.
#
# The second monitors the vservers "vserver5 vserver6 vserver7" and
# has no limit notifications turned on.
#
# The third monitors all vservers on the system, in one graph, and it has
# no limit notifications defined.
#
# You can use any combination of these to fit your needs.
#
#
# [vsrmem_group1]
# user root
# env.vservers vserver1 vserver2 vserver3 vserver4
# env.limits 1
# contacts nagios email
# contact.nagios.command /usr/bin/send_nsca -H your.nagios-host.here -c /etc/send_nsca.cfg
# contact.email.command mail -s "Munin-notification for ${var:group} :: ${var:host}" your@email.address.here
#
# [vsrmem_group2]
# user root
# env.vservers vserver5 vserver6 vserver7
# env.limits 0
#
# [vserver_rmemory]
# user root
#
# Graph Vserver RSS usage and limits
#
# Changelog
# version 0.1 - 2006 April xx - Holger Levsen
# - initial author
# version 0.2 - 2006 April 24 - Micah Anderson <micah@riseup.net>
# - Add dynamic arch page size determination
# - Some cleanup and clarification
# version 0.3 - 2006 May 3 - Micah Anderson <micah@riseup.net>
# - Add ability to group vservers via environment vars
# - Fix missing close quotes and standardize indents
# - Add limit notification
# - Update documentation to include info on groups and limits
# version 0.4 - 2006 Jun 22 - Micah Anderson <micah@riseup.net>
# - Fix error that results if NodeName is set to include a domain name
# version 0.5 - 2008 Apr 12 - Chris Wilson <chris+munin@qwirx.com>
# - Changed to display limit hits instead of resource usage
# - Adapt to latest vserver kernel (lack of some variables in /proc/virtual)
# Note that your vserver names may change if the contents of
# /etc/vservers/* do not match the nodenames. Also you must specify
# the vservers variable with context IDs (XIDs) rather than names.
scriptname=`basename $0`
resource=`echo $scriptname | sed -e 's/.*_//'`
vservers="$vservers"
if [ -z "$vservers" ]; then
vservers=`ls -1 /proc/virtual | grep -v info | grep -v status`
fi
if [ "$1" = "config" ]; then
echo "graph_title Vserver $resource limit hits"
# echo 'graph_args --base 1024k -l 0'
echo "graph_vlabel $resource limit hits"
echo 'graph_category vserver'
echo "graph_info Shows number of hits on $resource limits by each vserver.'"
for vserver_xid in $vservers ; do
longname=`/usr/sbin/vuname --xid $vserver_xid NODENAME | cut -f2`
name=`echo $longname | cut -d. -f1`
echo "$vserver_xid.label $name"
echo "$vserver_xid.info $resource limit hits by $longname"
echo "$vserver_xid.critical 1"
echo "$vserver_xid.min 0"
echo "$vserver_xid.type DERIVE"
done
exit 0
elif [ "$1" = "suggest" ]; then
if [ -z "$vservers" ]; then
echo "No vservers running, cannot suggest!" >&2
exit 2
fi
vserver1=`echo $vservers | sed -e 's/ .*//'`
tail -n +2 /proc/virtual/$vserver1/limit | sed -e 's/:.*//'
else
for vserver_xid in $vservers; do
cat /proc/virtual/$vserver_xid/limit \
| awk -v xid="$vserver_xid" -v res="$resource:" \
'{ if ( $1 == res )
printf "%s.value %d\n", xid, $7 }'
done
fi

View file

@ -0,0 +1,96 @@
#!/bin/sh
#
# Copyright (C) 2008 Chris Wilson
# Copyright (C) 2006 Holger Levsen
#
# 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.
#
# Configuration variables
# vservers - specify the vservers to include in the graph (default: all)
# limits - if true, turn on limit graphing (default: false)
#
# NOTE: If no configuration variables are set, the defaults will be used
# Example /etc/munin/plugin-conf.d/munin-node
#
# [vserver_limits_RSS]
# user root
# env.vservers 7 18 20 42
#
# Graph Vserver resource limits. Useful to help you know when and how often
# you changed the limits of each vserver, e.g. because customer needed more
# RAM.
#
# Changelog
# version 0.1 - 2006 April xx - Holger Levsen
# - initial author
# version 0.2 - 2006 April 24 - Micah Anderson <micah@riseup.net>
# - Add dynamic arch page size determination
# - Some cleanup and clarification
# version 0.3 - 2006 May 3 - Micah Anderson <micah@riseup.net>
# - Add ability to group vservers via environment vars
# - Fix missing close quotes and standardize indents
# - Add limit notification
# - Update documentation to include info on groups and limits
# version 0.4 - 2006 Jun 22 - Micah Anderson <micah@riseup.net>
# - Fix error that results if NodeName is set to include a domain name
# version 0.5 - 2008 Apr 12 - Chris Wilson <chris+munin@qwirx.com>
# - Changed to display limits instead of resource usage
# - Adapt to latest vserver kernel (lack of some variables in /proc/virtual)
# Note that your vserver names may change if the contents of
# /etc/vservers/* do not match the nodenames. Also you must specify
# the vservers variable with context IDs (XIDs) rather than names.
scriptname=`basename $0`
resource=`echo $scriptname | sed -e 's/.*_//'`
vservers="$vservers"
if [ -z "$vservers" ]; then
vservers=`ls -1 /proc/virtual | grep -v info | grep -v status`
fi
if [ "$1" = "config" ]; then
echo "graph_title Vserver $resource limits"
# echo 'graph_args --base 1024k -l 0'
echo "graph_vlabel $resource limits"
echo 'graph_category vserver'
echo "graph_info Shows current $resource limits for each vserver.'"
for vserver_xid in $vservers ; do
longname=`/usr/sbin/vuname --xid $vserver_xid NODENAME | cut -f2`
name=`echo $longname | cut -d. -f1`
echo "$vserver_xid.label $name"
echo "$vserver_xid.info $resource limits for $longname"
echo "$vserver_xid.min 0"
echo "$vserver_xid.type GAUGE"
done
exit 0
elif [ "$1" = "suggest" ]; then
if [ -z "$vservers" ]; then
echo "No vservers running, cannot suggest!" >&2
exit 2
fi
vserver1=`echo $vservers | sed -e 's/ .*//'`
tail -n +2 /proc/virtual/$vserver1/limit | sed -e 's/:.*//'
else
for vserver_xid in $vservers; do
cat /proc/virtual/$vserver_xid/limit \
| awk -v xid="$vserver_xid" -v res="$resource:" \
'{ if ( $1 == res )
printf "%s.value %d\n", xid, $6 }'
done
fi

77
plugins/virtualization/xen Executable file
View file

@ -0,0 +1,77 @@
#!/bin/sh
#
# Script to monitor CPU usage of Xen domains
#
# Author: unknown
# Modifications: Matthias Pfafferodt, syntron@web.de, Roland Mohrbacher
# License: GPL v. 2
#
# Parameters understood:
#
# conifg (required)
# autoconf (optional - used by munin-config)
#
#%# family=auto
#%# capabilities=autoconf
# statefile: name of seen xen domains
statefile="/var/lib/munin/plugin-state/munin-plugin-xen.state"
if [ "$1" = "autoconf" ]; then
if which xm > /dev/null ; then
echo yes
exit 0
fi
echo "no (xm not found)"
exit 1
fi
if [ "$1" = "config" ]; then
if [ ! -e $statefile ]; then
touch $statefile
fi
echo 'graph_title Xen Domain Utilerisation'
echo 'graph_args --base 1000 -l 0 --upper-limit 100 --rigid'
echo 'graph_scale no'
echo 'graph_vlabel %'
echo 'graph_category xen'
echo 'graph_info This graph shows how many % of the CPU time where used by a domain'
xm list | grep -v "^Name .* Time(s)$" | \
while read name domid mem cpu state time console; do
name=`echo $name | sed -e"s/[-.]/_/g"`
TEST=`less $statefile | grep "^${name}$" | wc -l`
if [ $TEST -ne 1 ]; then
echo "$name" >> $statefile
fi
done
FIRST=1
cat $statefile | sort | \
while read name; do
echo "$name.label $name"
echo "$name.type COUNTER"
if [ $FIRST -eq 1 ]; then
echo "$name.draw AREA"
FIRST=0
else
echo "$name.draw STACK"
fi
echo "$name.min 0"
echo "$name.max 100"
echo "$name.info % of the CPU time spend for $name"
done
exit 0
fi
xm list | grep -v "^Name .* Time(s)$" | \
while read name domid mem cpu state time console; do
name=`echo $name | sed -e "s/[-.]/_/g"`
# only seconds
time=`echo $time | sed -e "s/\..//"`
# scale 60s/60s => 100%/60s
time=`echo "$time*100/60" | bc`
echo "$name.value $time"
done

129
plugins/virtualization/xen-cpu Executable file
View file

@ -0,0 +1,129 @@
#!/usr/bin/perl -wT
#
# Script to minitor the cpu usage of Xen domains
#
# Author: Adam Crews <doo <at> shroom <dot> com>
#
# License: GPL
# Based on the origional xen script from Matthias Pfafferodt, syntron at web.de
#
# Note: Your munin config must run this as root.
#
# Parameters
# config (required)
# autoconf (optional - used by munin-config)
#
# Changelog:
# Properly ignore the xentop output header line.
# Ward Vandewege (ward@gnu.org), 2011-04-20
#
#%# family=auto
#%# capabilities=autoconf
# Define where to find xm tools
my $XM = '/usr/sbin/xm';
my $XMTOP = '/usr/sbin/xentop';
##############
# You should not need to edit anything below here
#
use strict;
$ENV{PATH} = '/bin:/usr/bin:/usr/sbin';
my $arg; undef($arg);
if (defined($ARGV[0])) {
$arg = 'config' if ($ARGV[0] eq 'config');
$arg = 'autoconf' if ($ARGV[0] eq 'autoconf');
if ( "$arg" eq 'autoconf') {
if ( -e $XM && -e $XMTOP ) {
print "yes\n";
exit 0;
} else {
print "no ($XM and/or $XMTOP not found\n";
exit 1;
}
}
if ( "$arg" eq 'config') {
my %cnf; undef(%cnf);
%cnf = (
'graph_title' => 'Xen Domain CPU Usage',
'graph_args' => '--base 1000 -l 0 --upper-limit 100 --rigid',
'graph_vlabel' => 'Percent (%)',
'graph_category' => 'xen',
'graph_info' => 'Display the % of CPU Usage for each domain',
);
my @domains = `$XM list`;
shift(@domains); # we dont need the header line
my $cnt = "0";
foreach my $domain ( @domains ) {
my ($dom,undef) = split(/\s/, $domain, 2);
# we need to change - and . to _ or things get weird with the graphs
# some decent quoting would probably fix this, but this works for now
$dom =~ s/[-.]/_/g;
$cnf{ "$dom" . '.label' } = "$dom";
$cnf{ "$dom" . '.draw' } = 'STACK';
$cnf{ "$dom" . '.min' } = '0';
$cnf{ "$dom" . '.max' } = '100';
$cnf{ "$dom" . '.info' } = '% CPU used for ' . "$dom";
if ( "$cnt" == "0") { $cnf{$dom.'.draw'} = 'AREA'; }
$cnt++;
}
foreach my $key (sort(keys(%cnf))) {
print "$key $cnf{$key}\n";
}
exit 0;
}
}
# Nothing was passed as an argument, so let's just return the proper values
my @chunks; undef(@chunks);
{
# run the xentop command a few times because the first reading is not always accurate
local $/ = undef;
@chunks = split(/^xentop - .*$/m, `$XMTOP -b -i2 -d2`);
}
# Take only the last run of xentop
my @stats = split (/\n/,pop(@chunks));
# remove the first 4 items that are junk that we don't need.
shift(@stats);
shift(@stats);
shift(@stats);
shift(@stats);
my %vals; undef(%vals);
foreach my $domain (@stats) {
# trim the leading whitespace
$domain =~ s/^\s+//;
my @v_tmp = split(/\s+/, $domain);
next if ($v_tmp[0] eq 'NAME');
# we need to change - and . to _ or things get weird with the graphs
# some decent quoting would probably fix this, but this works for now
$v_tmp[0] =~ s/[-.]/_/g;
$vals{$v_tmp[0]}{'cpu_percent'} = $v_tmp[3];
$vals{$v_tmp[0]}{'vcpu'} = $v_tmp[8];
if ( $vals{$v_tmp[0]}{'vcpu'} =~ m/n\/a/ ) {
my $cpu = `grep -c "processor" < /proc/cpuinfo`;
if ( $cpu =~ m/^(\d+)$/ ) {
$vals{$v_tmp[0]}{'vcpu'} = $1;
}
}
}
foreach my $key (sort(keys(%vals))) {
print "$key.value " . ($vals{$key}{'cpu_percent'}/$vals{'Domain_0'}{'vcpu'}), "\n";
}

242
plugins/virtualization/xen-multi Executable file
View file

@ -0,0 +1,242 @@
#! /usr/bin/perl
# -*- perl -*-
=head1 NAME
xen_multi - Munin multigraph plugin to monitor Xen domains activity
=head1 APPLICABLE SYSTEMS
This plugin should work on any system running a Xen hypervisor and where xentop
is installed. It also needs Munin 1.4.0 or higher, since it uses AREASTACK
(available from 1.3.3) and multigraph (available from 1.4.0).
=head1 CONFIGURATION
xentop requires superuser privileges, so you need to include in your
configuration:
[xen-multi]
user root
Then restart munin-node and you're done.
=head1 INTERPRETATION
This plugin produces four different graphs: CPU usage, memory usage, disk IOs
and network traffic.
In each graph, all Xen domains (including dom0) have their data stacked, giving
an overall amount of ressources used.
NOTE: xentop always reports 0 for dom0's disk IOs and network traffic, but
both graphs show its entry all the same, so each domain can keep its own color
along the different graphs.
=head2 CPU usage
This graph shows a percentage of the CPU time used by each domain.
=head2 Memory usage
This graph shows the amount of memory (in bytes) used by each domain.
=head2 Disk IOs
This graph shows the number of disk read and write operations for each domain.
=head2 Network traffic
This graph shows the amount of bits received and transmitted for each domain.
=head1 ACKNOWLEDGEMENTS
Michael Renner for the C<diskstats> plugin which I borrowed some code from.
=head1 VERSION
0.90
=head1 MAGIC MARKERS
#%# family=auto
#%# capabilities=autoconf
=head1 AUTHOR
Raphael HALIMI <raphael.halimi@gmail.com>
=head1 LICENSE
GPLv2
=cut
use strict;
use Munin::Plugin;
# autoconf - quite simple
if ($ARGV[0] eq "autoconf") {
if (`which xentop`) {
print "yes\n";
} else {
print "no (xentop not found)\n";
}
exit 0;
}
#
# Common steps for both "config" and a normal run
#
#
# trim_label
#
# Trims a given label to it's non-wrapping size
# $type = 'pos' for normal graphs and 'neg' for mirror graphs
# pos: nnn.nnU_ times 4
# neg: nnn.nnU/nnn.nnU_ times 4
sub trim_label {
my ($type, $label) = @_; my $data_characters;
my ($graph_width, $graph_border_width, $padding_characters, $pixels_per_character) = (400,97,10,6);
if ($type eq 'pos') {$data_characters = 32;} elsif ($type eq 'neg') {$data_characters = 64;} else {return $label;}
my $available_characters = abs(($graph_width+$graph_border_width)/$pixels_per_character)-$padding_characters-$data_characters;
# If the label is longer than the available space, we write as many
# characters as we can on both left and right, and two dots in the middle
if ( $available_characters < length $label ) {
my $center = ($available_characters-2)/2;
$label = substr($label,0,($center)) . '..' . substr($label,-$center);
}
return $label;
}
# Global variables
my (%domains,$domain,$munindomain,$cpusecs,$memk,$nettxk,$netrxk,$vbdrd,$vbdwr);
open (XENTOP,"xentop -b -f -i1 |") or die "Could not execute xentop, $!";
# Now we build a hash of hashes to store information
while (<XENTOP>) {
# Some cleaning first
s/^\s+//; chomp;
# Skip the headers
next if /^NAME/;
# We define only what we need
($domain,undef,$cpusecs,undef,$memk,undef,undef,undef,undef,undef,$nettxk,$netrxk,undef,undef,$vbdrd,$vbdwr,undef,undef,undef) = split(/\s+/);
# We have to store the sanitised domain name in a separate variable
$domains{$domain}{'munindomain'} = clean_fieldname($domain);
# We need the remaining data only for a normal run
if ($ARGV[0] eq "") {
$domains{$domain}{'cpusecs'} = $cpusecs;
$domains{$domain}{'mem'} = $memk;
$domains{$domain}{'nettx'} = $nettxk;
$domains{$domain}{'netrx'} = $netrxk;
$domains{$domain}{'vbdrd'} = $vbdrd;
$domains{$domain}{'vbdwr'} = $vbdwr;
}
}
#
# config - quite simple, too
#
if ($ARGV[0] eq "config") {
print "multigraph xen_cpu_time\n";
print "graph_title Xen domains CPU time\n";
print "graph_args --base 1000 -l 0\n";
print "graph_vlabel %\n";
print "graph_scale no\n";
print "graph_category xen\n";
print "graph_info This graph shows CPU time for each Xen domain.\n";
for $domain (sort(keys(%domains))) {
print "$domains{$domain}{'munindomain'}_cpu_time.label ".trim_label('pos',$domain)."\n";
print "$domains{$domain}{'munindomain'}_cpu_time.type COUNTER\n";
print "$domains{$domain}{'munindomain'}_cpu_time.cdef $domains{$domain}{'munindomain'}_cpu_time,100,*\n";
print "$domains{$domain}{'munindomain'}_cpu_time.draw AREASTACK\n";
}
print "\nmultigraph xen_mem\n";
print "graph_title Xen domains memory usage\n";
print "graph_args --base 1024 -l 0\n";
print "graph_vlabel bytes\n";
print "graph_category xen\n";
print "graph_info This graph shows memory usage for each Xen domain.\n";
for $domain (sort(keys(%domains))) {
print "$domains{$domain}{'munindomain'}_mem.label ".trim_label('pos',$domain)."\n";
print "$domains{$domain}{'munindomain'}_mem.cdef $domains{$domain}{'munindomain'}_mem,1024,*\n";
print "$domains{$domain}{'munindomain'}_mem.draw AREASTACK\n";
}
print "\nmultigraph xen_net\n";
print "graph_title Xen domains network traffic\n";
print "graph_args --base 1000\n";
print "graph_vlabel bits per \${graph_period} in (-) / out (+)\n";
print "graph_category xen\n";
print "graph_info This graph shows network traffic for each Xen domain.\n";
for $domain (sort(keys(%domains))) {
print "$domains{$domain}{'munindomain'}_netrx.label none\n";
print "$domains{$domain}{'munindomain'}_netrx.cdef $domains{$domain}{'munindomain'}_netrx,8192,*\n";
print "$domains{$domain}{'munindomain'}_netrx.type COUNTER\n";
print "$domains{$domain}{'munindomain'}_netrx.graph no\n";
print "$domains{$domain}{'munindomain'}_nettx.label ".trim_label('neg',$domain)."\n";
print "$domains{$domain}{'munindomain'}_nettx.cdef $domains{$domain}{'munindomain'}_nettx,8192,*\n";
print "$domains{$domain}{'munindomain'}_nettx.type COUNTER\n";
print "$domains{$domain}{'munindomain'}_nettx.draw AREASTACK\n";
print "$domains{$domain}{'munindomain'}_nettx.negative $domains{$domain}{'munindomain'}_netrx\n";
}
print "\nmultigraph xen_disk\n";
print "graph_title Xen domains disk IOs\n";
print "graph_args --base 1000\n";
print "graph_vlabel IOs per \${graph_period} read (-) / write (+)\n";
print "graph_category xen\n";
print "graph_info This graph shows disk IOs for each Xen domain.\n";
for $domain (sort(keys(%domains))) {
print "$domains{$domain}{'munindomain'}_vbdrd.label none\n";
print "$domains{$domain}{'munindomain'}_vbdrd.type COUNTER\n";
print "$domains{$domain}{'munindomain'}_vbdrd.graph no\n";
print "$domains{$domain}{'munindomain'}_vbdwr.label ".trim_label('neg',$domain)."\n";
print "$domains{$domain}{'munindomain'}_vbdwr.type COUNTER\n";
print "$domains{$domain}{'munindomain'}_vbdwr.draw AREASTACK\n";
print "$domains{$domain}{'munindomain'}_vbdwr.negative $domains{$domain}{'munindomain'}_vbdrd\n";
}
exit 0;
}
#
# Normal run
#
print "multigraph xen_cpu_time\n";
for $domain (sort(keys(%domains))) {
print "$domains{$domain}{'munindomain'}_cpu_time.value $domains{$domain}{'cpusecs'}\n";
}
print "\nmultigraph xen_mem\n";
for $domain (sort(keys(%domains))) {
print "$domains{$domain}{'munindomain'}_mem.value $domains{$domain}{'mem'}\n";
}
print "\nmultigraph xen_net\n";
for $domain (sort(keys(%domains))) {
print "$domains{$domain}{'munindomain'}_nettx.value $domains{$domain}{'nettx'}\n";
print "$domains{$domain}{'munindomain'}_netrx.value $domains{$domain}{'netrx'}\n";
}
print "\nmultigraph xen_disk\n";
for $domain (sort(keys(%domains))) {
print "$domains{$domain}{'munindomain'}_vbdrd.value $domains{$domain}{'vbdrd'}\n";
print "$domains{$domain}{'munindomain'}_vbdwr.value $domains{$domain}{'vbdwr'}\n";
}

189
plugins/virtualization/xen_cpu_v2 Executable file
View file

@ -0,0 +1,189 @@
#!/usr/bin/perl -w
#
# xen_cpu_v2.pl 1.00
# Script to minitor the CPU usage of Xen domains
# Zoltan HERPAI (c) 2009, wigyori@uid0.hu
#
# Based loosely on Adam Crews' xen_cpu script
#
# This script tries to measure the CPU usage of the Xen guests
# accurately.
# The problem with the current monitoring script is that these
# scripts use the CPU output of xentop or xm list, which might be
# inaccurate due to the resources used up at the time of the query by
# the xm or xentop command.
#
# This script stores the previous value of the CPU sec value of the given
# guests in a tempfile, then does some simple calculations to get the real
# CPU usage percentage of the guests.
#
#%# family=auto
#%# capabilities=autoconf
use strict;
use POSIX;
# Define where to find xm tools
my $XM = '/usr/sbin/xm';
my $XMTOP = '/usr/sbin/xentop';
my $curtime = time();
my $basename = `/usr/bin/basename $0`; chop ($basename);
my $TEMPFILE = "/tmp/$basename";
my $debug = 0;
##############
# You should not need to edit anything below here
#
$ENV{PATH} = '/bin:/usr/bin:/usr/sbin';
my $arg;
if ( defined($ARGV[0]) )
{
if ( $ARGV[0] eq 'config' )
{
$arg = 'config';
}
if ( $ARGV[0] eq 'autoconf' )
{
$arg = 'autoconf';
}
if ( $arg eq 'autoconf')
{
if ( -e $XM && -e $XMTOP )
{
print "yes\n";
exit 0;
}
else
{
print "no ($XM and/or $XMTOP not found\n";
exit 1;
}
}
if ( $arg eq 'config' )
{
my %cnf;
%cnf = (
'graph_title' => 'Xen Domain CPU Usage v2',
'graph_args' => '--base 1000 -l 0 --upper-limit 100 --rigid',
'graph_vlabel' => 'Percent (%)',
'graph_category' => 'xen',
'graph_info' => 'Display the % of CPU Usage for each domain',
);
my @domains = `$XM list`;
my $cnt = 0;
shift(@domains); # we dont need the header line
foreach my $domain ( @domains )
{
my ($dom,undef) = split(/\s/, $domain, 2);
$dom =~ s/[-.]/_/g;
$cnf{ "$dom" . '.label' } = "$dom";
$cnf{ "$dom" . '.draw' } = 'STACK';
$cnf{ "$dom" . '.min' } = '0';
$cnf{ "$dom" . '.max' } = '100';
$cnf{ "$dom" . '.info' } = '% CPU used for ' . "$dom";
# $cnf{ "$dom" . '.draw' } = 'AREA';
if ( $cnt == 0 )
{
$cnf{ "$dom" . '.draw' } = 'AREA';
}
$cnt++;
}
foreach my $key (sort(keys(%cnf)))
{
print "$key $cnf{$key}\n";
}
exit 0;
}
}
my @xmlist = `$XM list`;
shift (@xmlist);
my %dom; my $name; my $oldtime;
# Read old data
if ( -e $TEMPFILE )
{
open(FH, "<", $TEMPFILE) or die $!;
$oldtime = <FH>;
if ( $debug )
{
print "Oldtime: $oldtime\n";
}
while (<FH>)
{
# Get the guest name and its CPU usage, and store it in $dom
$_ =~ /(\S+)\s+\S+\s+\S+\s+\d+\s+\S+\s+(\S+)/;
$dom{$1}->{'oldtime'} = $2;
}
close FH;
}
my $diff; my $cpusum = 0;
foreach my $domain ( @xmlist )
{
# Get the domains' name and current CPU usage, store it in $dom
$domain =~ /(\S+)\s+\S+\s+\S+\s+\d+\s+\S+\s+(\S+)/;
$dom{$1}->{'newtime'} = $2;
$diff = $dom{$1}->{'newtime'} - $dom{$1}->{'oldtime'};
$diff = sprintf("%.2f", $diff);
# Calc the diff between old and new cputime, or reset the counter
if ( $diff < 0 )
{
$diff = $dom{$1}->{'newtime'};
}
$dom{$1}->{'diff'} = $diff;
# Calc a sum CPU usage
$cpusum = $cpusum + $diff;
}
my $numcpus = `$XM info |grep nr_cpus |cut -d \: -f 2`;
my $timediff = $curtime - $oldtime;
my $tcpuavail = $numcpus * $timediff;
if ( $debug )
{
print "UsedCPUtime sum: $cpusum\n";
print "CPUs: $numcpus\n";
print "Timediff: $timediff\n";
print "Total CPU time available: $tcpuavail\n";
}
my $key; my $value;
while (($key, $value) = each %dom)
{
# Calc a percentage based on the used CPU time sum
my $tmp = 0;
$tmp = ( $dom{$key}->{'diff'} / $cpusum ) * 100;
$dom{$key}->{'pc_time'} = sprintf("%.2f", $tmp);
# Calc a percentage based on the _total_ available CPU time
$tmp = 0;
$tmp = ( $dom{$key}->{'diff'} / $tcpuavail ) * 100;
$dom{$key}->{'pc_tcpu'} = sprintf("%.2f", $tmp);
if ( $debug )
{
print "$key newtime: ".$dom{$key}->{'newtime'}.", oldtime: ".$dom{$key}->{'oldtime'}.", diff: ".$dom{$key}->{'diff'}.", pc_bytime ".$dom{$key}->{'pc_time'}.", pc_bytcpu ".$dom{$key}->{'pc_tcpu'}."\n";
}
print "$key.value ".$dom{$key}->{'pc_tcpu'}."\n";
}
# We'll need to log out the current "xm list" output, and the current time also.
open(FH, ">", $TEMPFILE) or die $!;
print FH $curtime."\n";
print FH @xmlist;
close FH;

View file

@ -0,0 +1,67 @@
#!/bin/sh
#
# Script to monitor memory status of the xen host
#
# Written by immerda project (admin(_at_)immerda.ch)
# 2007
# License: GPL
#
# Parameters understood:
#
# config (required)
# autoconf (optional - used by munin-config)
#
XM='/usr/sbin/xm'
if [ "$1" = "autoconf" ]; then
if [ -e $XM ]; then
echo yes
exit 0
fi
echo "no (xm not found)"
exit 1
fi
if [ "$1" = "config" ]; then
echo 'graph_title Xen Memory'
echo 'graph_args --base 1000 -l 0'
echo 'graph_scale no'
echo 'graph_vlabel MB'
echo 'graph_category xen'
echo 'graph_info This graph shows of many mS wall time where used by a domain'
# xm info | while read name bla value; do echo "$name $value"; done
$XM info | while read name bla value; do
#total_memory 2047
#free_memory 1476
name=`echo $name | sed -e"s/-/_/"`
if [ "$name" = "total_memory" ]; then
echo "$name.label $name"
echo "$name.type GAUGE"
echo "$name.min 0"
echo "$name.info total memory"
fi
if [ "$name" = "free_memory" ]; then
echo "$name.label $name"
echo "$name.type GAUGE"
echo "$name.draw AREA"
# echo "$name.draw STACK"
echo "$name.min 0"
echo "$name.info free memory"
fi
done
exit 0
fi
$XM info | while read name bla value; do
name=`echo $name | sed -e"s/-/_/"`
if [ "$name" = "total_memory" ]; then
echo "$name.value $value"
fi
if [ "$name" = "free_memory" ]; then
echo "$name.value $value"
fi
done

View file

@ -0,0 +1,59 @@
#!/bin/sh
# Author: mario manno <projects@manno.name>
# Description: measure traffic for one xen host
# Get xen host name from symlink
#
#%# family=auto
#%# capabilities=autoconf suggest
DOMAIN=$( basename $0 | sed 's/^xen_traffic_//g' )
NAME=$( echo $DOMAIN | sed -e's/-/_/g' )
if [ "$1" = "autoconf" ]; then
if which xm > /dev/null ; then
echo yes
else
echo "no (xm not found)"
exit 1
fi
if [ -r /proc/net/dev ]; then
echo yes
else
echo "no (/proc/net/dev not found)"
exit 1
fi
exit 0
fi
if [ "$1" = "suggest" ]; then
xm list | awk '{print $1}' | egrep -v "^(Name|Domain-0)"
exit 0
fi
if [ "$1" = "config" ]; then
echo "graph_title Xen Traffic for $NAME"
echo 'graph_vlabel bits in (-) / out (+) per ${graph_period}'
echo 'graph_args --base 1024 -l 0'
echo 'graph_category xen'
echo 'out.label sent'
echo 'out.type DERIVE'
echo 'out.min 0'
echo 'out.cdef out,8,*'
echo 'in.label received'
echo 'in.type DERIVE'
echo 'in.min 0'
echo 'in.cdef in,8,*'
exit 0
fi
dev=$( xm network-list $DOMAIN | egrep "^[0-9]+" | sed 's@^.*vif/\([0-9]*\)/\([0-9]*\).*$@vif\1.\2@')
awk -v interface="$dev" \
'BEGIN { gsub(/\./, "\\.", interface) } \
$1 ~ "^" interface ":" {
split($0, a, /: */); $0 = a[2]; \
print "in.value " $1 "\nout.value " $9 \
}' \
/proc/net/dev

View file

@ -0,0 +1,70 @@
#!/bin/sh
# Author: mario manno <projects@manno.name>
# Description: measure traffic for all xen hosts
#
# Changelog:
# Also handle domUs with named network interfaces.
# Ward Vandewege (ward@gnu.org), 2011-04-20
#
#%# family=auto
#%# capabilities=autoconf
if [ "$1" = "autoconf" ]; then
if which xm > /dev/null ; then
echo yes
else
echo "no (xm not found)"
exit 1
fi
if [ -r /proc/net/dev ]; then
echo yes
else
echo "no (/proc/net/dev not found)"
exit 1
fi
exit 0
fi
if [ "$1" = "config" ]; then
echo 'graph_title Xen Traffic'
echo 'graph_vlabel bits received (-) / sent (+) per ${graph_period}'
echo 'graph_args --base 1024 -l 0'
echo 'graph_category xen'
DOMAINS=$(xm list | awk '{print $1}' | egrep -v "^(Name|Domain-0)")
for dom in $DOMAINS; do
name=$( echo $dom | tr .- __ )
#echo $name"UP.label $name"
#echo $name"DOWN.label $name"
echo $name'Down.label received'
echo $name'Down.type COUNTER'
echo $name'Down.graph no'
echo "${name}Down.cdef ${name}Down,8,*"
echo "${name}Up.label ${name}"
echo $name'Up.type COUNTER'
echo "${name}Up.negative ${name}Down"
echo "${name}Up.cdef ${name}Up,8,*"
done
exit 0
fi
DOMAINS=$(xm list | awk '{print $1}' | egrep -v "^(Name|Domain-0)")
for dom in $DOMAINS; do
dev=$( xm list $dom --long | awk '/vifname / { print $2 }' | sed 's/)//' )
if [ "$dev" == "" ]; then
dev=$( xm network-list $dom |\
egrep "^[0-9]+" | sed 's@^.*vif/\([0-9]*\)/\([0-9]*\).*$@vif\1.\2@')
fi
name=$( echo $dom | tr .- __ )
#awk -v name="$name" -v interface="$dev" -F'[: \t]+' \
#'{ sub(/^ */,""); if ($1 == interface) \
#print name"DOWN.value "$2"\n"name"UP.value "$10; }' /proc/net/dev
awk -v name="$name" -v interface="$dev" \
'BEGIN { gsub(/\./, "\\.", interface) } \
$1 ~ "^" interface ":" {
split($0, a, /: */); $0 = a[2]; \
print name"Down.value " $1 "\n"name"Up.value " $9 \
}' \
/proc/net/dev
done

115
plugins/virtualization/xen_vbd Executable file
View file

@ -0,0 +1,115 @@
#!/usr/bin/perl
#
# 2007-06-01 Zoltan HERPAI <wigyori@uid0.hu>
#
# Credits goes for:
# Adam Crews for his xen_cpu plugin
# Mario Manno for his xen_traffic_all plugin
#
# Script to monitor the I/O usage of Xen domains
# Version 0.1
#
#%# family=auto
#%# capabilities=autoconf
# Location of xm tools
$XM = '/usr/sbin/xm';
$XMTOP = '/usr/sbin/xentop';
# ah, parameters coming in
if ( defined($ARGV[0]))
{
if ($ARGV[0] eq 'config') { $arg = 'config'; }
if ($ARGV[0] eq 'autoconf') { $arg = 'autoconf'; }
if ( $arg eq 'autoconf' )
{
if ( -e $XM && -e $XMTOP )
{
print "yes\n";
exit 0;
}
else
{
print "no ($XM and/or $XMTOP not found\n";
exit 0;
}
}
if ( $arg eq 'config' )
{
%cnf = (
'graph_title' => 'Xen Domain I/O usage',
'graph_args' => '--base 1024 -l 0',
'graph_vlabel' => 'read (-), write (+)',
'graph_category' => 'xen',
'graph_info' => 'Display the I/O operations for each domain',
);
@domains = `$XM list`;
shift(@domains); # we don't need the header line
foreach $domain ( @domains )
{
($dom, undef) = split(/\s/, $domain);
$dom =~ s/[-.]/_/g;
$cnf{ $dom.'RD' . '.label' } = 'read';
$cnf{ $dom.'RD' . '.type' } = 'COUNTER';
$cnf{ $dom.'RD' . '.graph' } = 'no';
$cnf{ $dom.'RD' . '.cdef' } = $dom.'RD,8,*';
$cnf{ $dom.'WR' . '.label' } = $dom;
$cnf{ $dom.'WR' . '.type' } = 'COUNTER';
$cnf{ $dom.'WR' . '.negative' } = $dom.'RD';
$cnf{ $dom.'WR' . '.cdef' } = $dom.'WR,8,*';
if ( "$cnt" == "0" )
{
$cnf { "$dom" . '.draw' } = 'AREA';
}
$cnt++;
}
foreach $key ( sort(keys(%cnf)) )
{
print "$key $cnf{$key}\n";
}
exit 0;
}
}
# No args, get rolling
{
local $/ = undef;
@chunks = split(/^xentop - .*$/m, `$XMTOP -b -i1`);
}
@stats = split (/\n/, pop(@chunks));
shift(@stats);
shift(@stats);
shift(@stats);
shift(@stats);
foreach $domain (@stats)
{
$domain =~ s/^\s+//;
@tmp = split(/\s+/, $domain);
$domname = $tmp[0];
$domname =~ s/[-.]/_/g;
$vbdrd = $tmp[14];
$vbdwr = $tmp[15];
$vals{$domname."RD"}{'value'} = $vbdrd;
$vals{$domname."WR"}{'value'} = $vbdwr;
}
foreach $key ( sort(keys(%vals)) )
{
print "$key.value " . ($vals{$key}{'value'}) . "\n";
}