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>
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();