ia64/xen-unstable

changeset 15175:6145e5508d6b

Added xeninfo.pl, a script for collecting statistics from Xen hosts using the
Xen-API. This also serves as a good example of the use of XML::RPC::Client
with the Xen-API.

By Ingard Mev?g <ingard [at] mevaag [dot] no>.

Signed-off-by: Ewan Mellor <ewan@xensource.com>
author Ewan Mellor <ewan@xensource.com>
date Wed May 16 23:12:16 2007 +0100 (2007-05-16)
parents 711bfe07999b
children 11a97dca57aa
files tools/examples/xeninfo.pl
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/tools/examples/xeninfo.pl	Wed May 16 23:12:16 2007 +0100
     1.3 @@ -0,0 +1,284 @@
     1.4 +#!/usr/bin/perl -w
     1.5 +
     1.6 +#############################################################################################################
     1.7 +#                                                                                                           #
     1.8 +#  Developed by Ingard Mev├ąg @ Oslo University College, spring 2007                                         #
     1.9 +#  ingard [at] mevaag  [dot] no                                                                             #
    1.10 +#                                                                                                           #
    1.11 +#  This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 License.      #
    1.12 +#  To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter #
    1.13 +#  to Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA.                #
    1.14 +#                                                                                                           #
    1.15 +#############################################################################################################
    1.16 +
    1.17 +use strict;
    1.18 +# http://search.cpan.org/~rjray/RPC-XML-0.59/lib/RPC/XML/Client.pm
    1.19 +require RPC::XML;
    1.20 +require RPC::XML::Client;
    1.21 +
    1.22 +# for debug purposes
    1.23 +#use Data::Dumper;
    1.24 +
    1.25 +##### CONFIG ######
    1.26 +
    1.27 +my %xenhosts = ("192.168.0.10" => {"port" => "9363"}, 
    1.28 +					 "192.168.0.11" => {"port" => "9363"}, 
    1.29 +					 "192.168.0.12" => {"port" => "9363"}, 
    1.30 +					 "192.168.0.13" => {"port" => "9363"});
    1.31 +
    1.32 +##### CONFIG END ###
    1.33 +
    1.34 +##### STATIC VARS #####
    1.35 +my %host_info;
    1.36 +
    1.37 +#######################
    1.38 +sub apiconnect
    1.39 +{
    1.40 +	foreach my $xenhost (keys %xenhosts)
    1.41 +	{
    1.42 +		my $xen = RPC::XML::Client->new("http://$xenhost:$xenhosts{$xenhost}{'port'}");
    1.43 +		my $session = $xen->simple_request("session.login_with_password", "user","");
    1.44 +		if (! $session)
    1.45 +		{
    1.46 +			print "Can't connect to $xenhost :(\n";
    1.47 +			$xenhosts{$xenhost} = {'xen' => $xen, 'session' => ""};
    1.48 +		}
    1.49 +		else
    1.50 +		{
    1.51 +			$xenhosts{$xenhost} = {'xen' => $xen, 'session' => $session->{'Value'}};
    1.52 +			print "Connected successfully to $xenhost..\n";
    1.53 +		}
    1.54 +	}
    1.55 +}
    1.56 +
    1.57 +sub validate_response
    1.58 +{
    1.59 +	my ($result_ref) = @_;
    1.60 +	if ($result_ref->{'Status'} eq "Success")
    1.61 +	{
    1.62 +		return $result_ref->{'Value'};
    1.63 +	}
    1.64 +	else
    1.65 +	{
    1.66 +		# status = Failure !
    1.67 +#		die ("xmlrpc failed! ErrorDescription: $result_ref->{'ErrorDescription'}[1] -> $result_ref->{'ErrorDescription'}[0]");
    1.68 +		print "xmlrpc failed! ErrorDescription: $result_ref->{'ErrorDescription'}[1] -> $result_ref->{'ErrorDescription'}[0]\n";
    1.69 +	}
    1.70 +}
    1.71 +
    1.72 +sub get_host_cpu_utilisation
    1.73 +{
    1.74 +	my ($xen, $session, $host_name, $host_ref) = @_;
    1.75 +	my $host_cpu_ref = validate_response($xen->simple_request("host.get_host_CPUs", $session, $host_ref));
    1.76 +	foreach (@$host_cpu_ref)
    1.77 +	{
    1.78 +		my $host_cpu_utilisation = validate_response($xen->simple_request("host_cpu.get_utilisation", $session, $_));
    1.79 +		$host_info{$host_name}{'cpus'}{$_} = $host_cpu_utilisation;
    1.80 +		print "     CPUiNFO: $host_cpu_utilisation\n";
    1.81 +	}
    1.82 +}
    1.83 +
    1.84 +sub get_host_pif_utilisation
    1.85 +{
    1.86 +	my ($xen, $session, $host_name, $host_ref) = @_;
    1.87 +
    1.88 +# This method isnt implemented yet it seems so using PIF.get_all for now.. 
    1.89 +# This will break when xen is made cluster aware..
    1.90 +#	my $host_pif_ref = validate_response($xen->simple_request("host.get_PIFs", $session, $host_ref)); 
    1.91 +	my $host_pif_ref = validate_response($xen->simple_request("PIF.get_all", $session));
    1.92 +	foreach (@$host_pif_ref)
    1.93 +	{
    1.94 +		my $host_pif_device = validate_response($xen->simple_request("PIF.get_device", $session, $_));
    1.95 +		my $host_pif_metrics_ref = validate_response($xen->simple_request("PIF.get_metrics", $session, $_));
    1.96 +
    1.97 +# Whats the best solution performancewise?
    1.98 +# Collecting stats from get_records, or pulling individually?
    1.99 +
   1.100 +#		my $host_pif_record = validate_response($xen->simple_request("PIF_metrics.get_record", $session, $host_pif_metrics_ref));
   1.101 +#		my $host_pif_io_read = $host_pif_record->{'io_read_kbs'};
   1.102 +#		my $host_pif_io_write = $host_pif_record->{'io_write_kbs'};
   1.103 +		my $host_pif_io_read = validate_response($xen->simple_request("PIF_metrics.get_io_read_kbs", $session, $host_pif_metrics_ref));
   1.104 +		my $host_pif_io_write = validate_response($xen->simple_request("PIF_metrics.get_io_write_kbs", $session, $host_pif_metrics_ref));
   1.105 +
   1.106 +		$host_info{$host_name}{'pifs'}{$host_pif_device} = {'read' => $host_pif_io_read, 'write' => $host_pif_io_write};
   1.107 +		print "     PiFiNFO: $host_pif_device READ: $host_pif_io_read - WRITE: $host_pif_io_write\n";
   1.108 +#		$host_info{$host_name}{'pifs'}{$host_pif_device}{'read'} = $host_pif_io_read;
   1.109 +#		$host_info{$host_name}{'pifs'}{$host_pif_device}{'write'} = $host_pif_io_write;
   1.110 +	}
   1.111 +}
   1.112 +
   1.113 +sub get_host_mem_utilisation
   1.114 +{
   1.115 +	my ($xen, $session, $host_name, $host_ref) = @_;
   1.116 +	my $host_metrics_ref = validate_response($xen->simple_request("host.get_metrics", $session, $host_ref)); 
   1.117 +	my $host_mem_total =  validate_response($xen->simple_request("host_metrics.get_memory_total", $session, $host_metrics_ref)) / 1024 / 1024;
   1.118 +	my $host_mem_free =  validate_response($xen->simple_request("host_metrics.get_memory_free", $session, $host_metrics_ref)) / 1024 / 1024;
   1.119 +	$host_info{$host_name}{'memory'} = {'total' => $host_mem_total, 'free' => $host_mem_free};
   1.120 +	print "     MEMiNFO: Total: $host_mem_total MB - Free: $host_mem_free MB\n";
   1.121 +}
   1.122 +
   1.123 +sub get_vm_mem_info
   1.124 +{
   1.125 +	my ($xen, $session, $host_name, $vm_ref, $vm_name_label) = @_;
   1.126 +	my $vm_mem_stat_max = validate_response($xen->simple_request("VM.get_memory_static_max",$session,$vm_ref));
   1.127 +	my $vm_mem_stat_min = validate_response($xen->simple_request("VM.get_memory_static_min",$session,$vm_ref));
   1.128 +	my $vm_mem_dyn_max = validate_response($xen->simple_request("VM.get_memory_dynamic_max",$session,$vm_ref));
   1.129 +	my $vm_mem_dyn_min = validate_response($xen->simple_request("VM.get_memory_dynamic_min",$session,$vm_ref));
   1.130 +
   1.131 +	# not implemented yet.. We'll do this at the same time as getting cpu utilisation
   1.132 +	# in the get_vm_metrics sub instead..
   1.133 +	#my $vm_metrics_ref = validate_response($xen->simple_request("VM.get_metrics",$session,$vm_ref));
   1.134 +	#my $vm_mem_actual = validate_response($xen->simple_request("VM_metrics.get_memory_actual",$session,$vm_metrics_ref));
   1.135 +
   1.136 +	$host_info{$host_name}{'vms'}{$vm_name_label}{'memory'} = {'static_max' => $vm_mem_stat_max,
   1.137 +								  'static_min' => $vm_mem_stat_min,
   1.138 +								  'dynamic_max' => $vm_mem_dyn_max,
   1.139 +								  'dynamic_min' => $vm_mem_dyn_min};
   1.140 +
   1.141 +	# xm list uses the dynamic min var as far as i can tell.. or?
   1.142 +	# Lets print the memactual info instead of this... I'll do that in the get_vm_metrics sub instead..
   1.143 +	# print "  |- MEMiNFO: Dynamic Min: $vm_mem_dyn_min - Actually in use: $vm_mem_actual\n";
   1.144 +}
   1.145 +
   1.146 +sub get_vm_metrics
   1.147 +{
   1.148 +	my ($xen, $session, $host_name, $vm_ref, $vm_name_label) = @_;
   1.149 +	my $vm_metrics_ref = validate_response($xen->simple_request("VM.get_metrics",$session,$vm_ref));
   1.150 +	
   1.151 +	my %vm_vcpu_utilisation = %{validate_response($xen->simple_request("VM_metrics.get_vcpus_utilisation",$session,$vm_metrics_ref))};
   1.152 +	for my $tempcpu (keys %vm_vcpu_utilisation)
   1.153 +	{
   1.154 +		print "  |- CPUiNFO: $tempcpu - $vm_vcpu_utilisation{$tempcpu}\n";
   1.155 +		$host_info{$host_name}{'vms'}{$vm_name_label}{'vcpus'} = {$tempcpu => $vm_vcpu_utilisation{$tempcpu}};
   1.156 +	}
   1.157 +	my $vm_mem_actual = validate_response($xen->simple_request("VM_metrics.get_memory_actual",$session,$vm_metrics_ref)) / 1024 / 1024;
   1.158 +	$host_info{$host_name}{'vms'}{$vm_name_label}{'memory'}{'actual'} = "$vm_mem_actual";
   1.159 +	print "  |- MEMiNFO: Actually in use: $vm_mem_actual MB\n";
   1.160 +}
   1.161 +
   1.162 +sub get_vm_vif_utilisation
   1.163 +{
   1.164 +	my ($xen, $session, $host_name, $vm_ref, $vm_name_label) = @_;
   1.165 +	my $vm_vifs = validate_response($xen->simple_request("VM.get_VIFs",$session,$vm_ref));
   1.166 +	foreach (@$vm_vifs)
   1.167 +	{
   1.168 +		my $vif_device = validate_response($xen->simple_request("VIF.get_device",$session,$_));
   1.169 +		my $vif_io_read = validate_response($xen->simple_request("VIF_metrics.get_io_read_kbs", $session, $_));
   1.170 +		my $vif_io_write = validate_response($xen->simple_request("VIF_metrics.get_io_write_kbs", $session, $_));
   1.171 +		$host_info{$host_name}{'vms'}{$vm_name_label}{'vifs'}{$vif_device} = {'read' => $vif_io_read, 'write' => $vif_io_write};
   1.172 +		print "  |- ViFiNFO: $vif_device READ: $vif_io_read - WRITE: $vif_io_write\n";
   1.173 +	}
   1.174 +}
   1.175 +
   1.176 +sub get_vm_vbd_utilisation
   1.177 +{
   1.178 +	my ($xen, $session, $host_name, $vm_ref, $vm_name_label) = @_;
   1.179 +	my $vm_vbds = validate_response($xen->simple_request("VM.get_VBDs",$session,$vm_ref));
   1.180 +	foreach (@$vm_vbds)
   1.181 +	{
   1.182 +		my $vbd_device = validate_response($xen->simple_request("VBD.get_device",$session,$_));
   1.183 +		my $vbd_io_read = validate_response($xen->simple_request("VBD_metrics.get_io_read_kbs", $session, $_));
   1.184 +		my $vbd_io_write = validate_response($xen->simple_request("VBD_metrics.get_io_write_kbs", $session, $_));
   1.185 +		$host_info{$host_name}{'vms'}{$vm_name_label}{'vbds'}{$vbd_device} = {'read' => $vbd_io_read, 'write' => $vbd_io_write};
   1.186 +		print "  |- VBDiNFO: $vbd_device READ: $vbd_io_read - WRITE: $vbd_io_write\n";
   1.187 +	}
   1.188 +}
   1.189 +
   1.190 +
   1.191 +sub get_vm_type
   1.192 +{
   1.193 +	my ($xen, $session, $host_name, $vm_ref, $vm_name_label) = @_;
   1.194 +	# not running response through validate_response() here to stop it from crashing..
   1.195 +	#
   1.196 +	# api docs says if this (following) field is set, its a HVM domain.
   1.197 +	my $vm_bootloader_results = $xen->simple_request("VM.get_HVM_boot_policy",$session,$vm_ref);
   1.198 +	if ("$vm_bootloader_results->{'Status'}" eq "Success")
   1.199 +	{
   1.200 +		if ("$vm_bootloader_results->{'Value'}" ne "")
   1.201 +		{
   1.202 +			$host_info{$host_name}{'vms'}{$vm_name_label}{'type'} = "HVM";
   1.203 +		}
   1.204 +		else
   1.205 +		{
   1.206 +			$host_info{$host_name}{'vms'}{$vm_name_label}{'type'} = "PV";
   1.207 +		}
   1.208 +	}
   1.209 +	else
   1.210 +	{
   1.211 +		# However, xen 3.0.4 doest support this part of the api, so afaik I can get the difference with: 
   1.212 +		my $vm_pv_kernel_results = $xen->simple_request("VM.get_PV_kernel",$session,$vm_ref);
   1.213 +		# which is something like:
   1.214 +		# 'PV_kernel': '/boot/vmlinuz-2.6.18-xen',
   1.215 +		# or
   1.216 +		# 'PV_kernel': '/usr/lib/xen/boot/hvmloader',
   1.217 +		if ("$vm_pv_kernel_results->{'Value'}" =~ m/hvm/i)
   1.218 +		{
   1.219 +			$host_info{$host_name}{'vms'}{$vm_name_label}{'type'} = "HVM";
   1.220 +		}
   1.221 +		else
   1.222 +		{
   1.223 +			$host_info{$host_name}{'vms'}{$vm_name_label}{'type'} = "PV";
   1.224 +		}
   1.225 +	}
   1.226 +}
   1.227 +
   1.228 +sub get_complete_info
   1.229 +{	
   1.230 +	my %all_vms;
   1.231 +	foreach my $xenhost (sort keys %xenhosts)
   1.232 +	{
   1.233 +		next unless $xenhosts{$xenhost}{'session'};
   1.234 +		my $xen = $xenhosts{$xenhost}{'xen'};
   1.235 +		my $session = $xenhosts{$xenhost}{'session'};
   1.236 +		print "_______________________\n## $xenhost ##\n-----------------------\n";
   1.237 +	
   1.238 +		my $host_ref = validate_response($xen->simple_request("session.get_this_host", $session));
   1.239 +		
   1.240 +		my $host_name = validate_response($xen->simple_request("host.get_name_label", $session, $host_ref));
   1.241 +		$xenhosts{$xenhost}{'hostname'} = $host_name;
   1.242 +		$host_info{$host_name}{'ip'} = $xenhost;
   1.243 +		
   1.244 +		get_host_cpu_utilisation($xen, $session, $host_name, $host_ref);
   1.245 +
   1.246 +		get_host_mem_utilisation($xen, $session, $host_name, $host_ref);
   1.247 +	
   1.248 +		get_host_pif_utilisation($xen, $session, $host_name, $host_ref);
   1.249 +	
   1.250 +	
   1.251 +		my $all_vm_refs = validate_response($xen->simple_request("host.get_resident_VMs",$session, $host_ref));
   1.252 +		
   1.253 +		foreach my $vm_ref (@$all_vm_refs)
   1.254 +		{
   1.255 +			my $vm_name_label = validate_response($xen->simple_request("VM.get_name_label",$session,$vm_ref));
   1.256 +			get_vm_type($xen,$session,$host_name,$vm_ref,$vm_name_label);
   1.257 +			
   1.258 +			my $vm_id = validate_response($xen->simple_request("VM.get_domid",$session,$vm_ref));
   1.259 +
   1.260 +			print "vm: $vm_id\t$vm_name_label\ttype: $host_info{$host_name}{'vms'}->{$vm_name_label}{'type'}\n";
   1.261 +			
   1.262 +			# vm_metrics includes both mem_actual & cpu utilisation
   1.263 +			# So we'll add all stats found in that class in one go..
   1.264 +			get_vm_metrics($xen,$session,$host_name,$vm_ref,$vm_name_label);
   1.265 +#			get_vm_cpu_utilisation($xen,$session,$host_name,$vm_ref,$vm_name_label);
   1.266 +
   1.267 +			# all other mem stats are added seperately..
   1.268 +			# This might not be needed at all as xen doesnt have functionality to
   1.269 +			# resize mem for a VM atm (afaik)
   1.270 +			get_vm_mem_info($xen,$session,$host_name,$vm_ref,$vm_name_label);
   1.271 +	
   1.272 +			get_vm_vif_utilisation($xen,$session,$host_name,$vm_ref,$vm_name_label);
   1.273 +			
   1.274 +			get_vm_vbd_utilisation($xen,$session,$host_name,$vm_ref,$vm_name_label);
   1.275 +			
   1.276 +			$all_vms{$vm_name_label} = "" unless ("$vm_name_label" eq "Domain-0");
   1.277 +		}
   1.278 +		print "\n";
   1.279 +	}
   1.280 +	# Debug: Uncomment to see the nested datastructure..
   1.281 +	#print Dumper(%host_info);
   1.282 +}
   1.283 +
   1.284 +
   1.285 +
   1.286 +apiconnect();
   1.287 +get_complete_info();