From 757afc8b34358ccf2dc93fb4ad309014d0536f66 Mon Sep 17 00:00:00 2001 From: Richard Jones Date: Thu, 24 Sep 2009 16:35:24 +0100 Subject: [PATCH] Update documentation. --- tools/virt-uname.pl | 243 ++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 200 insertions(+), 43 deletions(-) diff --git a/tools/virt-uname.pl b/tools/virt-uname.pl index 9bca435..4c7e253 100755 --- a/tools/virt-uname.pl +++ b/tools/virt-uname.pl @@ -19,6 +19,7 @@ use strict; use Net::SNMP; +use Sys::Virt; use Pod::Usage; use Getopt::Long; use Locale::TextDomain 'virt-tools'; @@ -87,6 +88,14 @@ Write out the results in CSV format (comma-separated values). This format can be imported easily into databases and spreadsheets, but read L below. +=cut + +my $verbose; + +=item B<--verbose> | B<-v> + +Enable verbose messages, useful for debugging. + =back =cut @@ -95,6 +104,7 @@ GetOptions ("help|?" => \$help, "version" => \$version, "connect|c=s" => \$uri, "csv" => \$csv, + "verbose|v" => \$verbose, ) or pod2usage (2); pod2usage (1) if $help; if ($version) { @@ -103,15 +113,16 @@ if ($version) { } my %subcommands = ( - "virt-uname" => [ &do_uname, &title_uname ], - "virt-ps" => [ &do_ps, &title_ps ], - "virt-ping" => [ &do_ping, &title_ping ], + "virt-uname" => [ \&do_uname, \&title_uname ], + "virt-ps" => [ \&do_ps, \&title_ps ], + "virt-ping" => [ \&do_ping, \&title_ping ], ); # Which subcommand? my ($do_it, $title_it); foreach (keys %subcommands) { if ($0 =~ /$_/) { + print STDERR "subcommand = $_\n" if $verbose; $do_it = $subcommands{$_}->[0]; $title_it = $subcommands{$_}->[1]; last; @@ -119,6 +130,18 @@ foreach (keys %subcommands) { } die "$0: cannot determine which sub-command to run\n" unless $do_it; +# If we are being run from a local directory, add that directory to +# the path, so we can be run from the source directory without being +# installed. +if (substr ($0, 0, 1) ne "/") { + $_ = $0; + s{/[^/]+$}{}; + $ENV{PATH} = "$_:$ENV{PATH}"; # XXX Windows? + print STDERR "PATH set to $ENV{PATH}\n" if $verbose; +} + +our $errors = 0; + # Do we have named guests? if (@ARGV == 0) { my $conn; @@ -135,29 +158,36 @@ if (@ARGV == 0) { my @domnames = map { $_->get_name () } @doms; if (@domnames) { - title_it (); + &$title_it (); foreach (@domnames) { - my ($key, $transport); - eval { - $key = get_key ($_); - $transport = get_transport ($_); - }; - if (!$@) { do_it ($_, $key, $transport) } + get_and_do_it ($_); } } } else { - title_it (); + &$title_it (); foreach (@ARGV) { - my ($key, $transport); - eval { - $key = get_key ($_); - $transport = get_transport ($_); - }; - if (!$@) { do_it ($_, $key, $transport) } + get_and_do_it ($_); } } -exit 0; +sub get_and_do_it +{ + # Turn any errors into warnings. + eval { + my ($key, $transport); + $key = get_key ($_); + $transport = get_transport ($_); + &$do_it ($_, $key, $transport); + }; + if ($@) { + $errors++; + warn "$@"; + } +} + +print STDERR "errors = $errors\n" if $verbose; + +exit ($errors == 0 ? 0 : 1); =head1 virt-uname @@ -233,6 +263,34 @@ C displays the IP address of the guest. =cut +sub print_row +{ + my @fields = @_; + + local $_; + my $comma = 0; + + foreach (@fields) { + print "," if $comma; + $comma = 1; + + if (!$csv) { + printf "%-16s ", $_ + } else { + # XXX Use Text::CSV here. + if ($_ =~ /"/) { + s/"/""/; + printf "\"%s\"", $_; + } elsif ($_ =~ /,/ || $_ =~ /\n/) { + printf "\"%s\"", $_; + } else { + print $_; + } + } + } + print "\n"; +} + =head1 OVERVIEW Virt-tools are a set of tools that you can install in your virtual @@ -248,39 +306,93 @@ There are two parts to any virt-tools installation: some client programs like C and C that you run on the host, to query guest information. On the guest, you have to install and run a virt-tools service. Between the host and guest is a transport which -should be secured. The L section describes how -to configure guests and secure the transport. +should be secured. + +The L section describes how virt-tools appears +from the guest side. + +The L section describes the architecture of +virt-tools on the host side. -Finally the L section describes the architecture of -virt-tools and provides information about diagnosing problems. +=head1 GUEST ARCHITECTURE -=head1 GUEST CONFIGURATION +In most cases, you can just install the C package in +your Linux guests, or the Windows virt-tools guest package in your +Windows guests, and everything should just work. In this section we +describe more about how it works (or is supposed to work) from the +guest side. +=head2 COMMUNICATIONS DIRECTORY +The guest writes various static, mostly unchanging, information into +its own directory. On Linux the directory is C +and under Windows it is C<%systemroot%\virttool\>. In the discussion +below, this communications directory is referred to as +C<$GUESTCOMMSDIR>. +The host is able to read files out of this directory using +L (without any cooperation needed by the guest). +=head2 IP ADDRESSES +The host can't easily see the guest's IP address. The host provides +the guest with a network interface connected to a bridge, but the +guest can use any IP address it likes (although well-behaved guests +will usually have some static IPs or are allocated one by DHCP). +So when the guest starts up, or its IP address changes (usually these +are rare events) the guest writes a file +C<$GUESTCOMMSDIR/ip-EifaceE> which contains details of the IP +address of the interface EifaceE (eg. the file might be called +C under Linux). +C reads this file directly using L. +=head2 KEYS +When the guest is first installed (or more precisely, when the +virt-tools-guest package is first installed in the guest), a random +secret key is generated. This is used to encrypt communications with +the guest, and it is described in more detail below. +The key is written to C<$GUESTCOMMSDIR/key>. -=head1 ARCHITECTURE +=head2 SNMP DAEMON -Guests run an SNMP (Simple Network Management Protocol) server. The -host client tools access this server in order to query information -about the guest. They query this using standard SNMP calls. +For process listings, and just about every other piece of data except +for IP address, guests run a completely standard SNMP (Simple Network +Management Protocol) server. The host client tools access this server +in order to query information about the guest. They query this using +standard SNMP calls. The protocol used is SNMPv3 (RFC 2571) which addresses security concerns in earlier versions of the protocol. In order to ensure that -only the host can access the SNMP server, the guest generates a random -secret key which the host must find out. Also the host must find a -suitable transport to connect to the SNMP server (eg. by finding the -IP address of the guest or using another transport into the guest). +only the host can access the SNMP server and see the results, all +communications are encrypted and authenticated using the guest's key. + +=head2 TRANSPORT + +There is not necessarily a network connection between the host and the +guest. There are many configurations of virtualization in which the +host has no network access to the guest: for example, if the host +firewalls itself off from the guest (or vice versa), or if the guest +has a physically separate network card from the host. -Once the key and the transport to the guest are worked out, the query -is a straightforward SNMP call: +Therefore the guest to host SNMP transport is not necessarily over an +IP network. Other transports are possible, including "vmchannel" +(where "vmchannel" is the generic name for a collection of specialized +host-guest communication channels implemented in different ways by +different hypervisors). + +=head1 HOST ARCHITECTURE + +On the host side, the host uses L to read the guest's +IP address and key, and uses some heuristics to determine the +transport to use. + +Once the key and the transport to the guest are worked out, programs +like C, C and so on are just making +straightforward SNMP calls: +-----------------+ +-----------------+ | host | | guest | @@ -290,7 +402,7 @@ is a straightforward SNMP call: The difficulty is in determining the key and the transport to use, which is what this section covers. You can also use this knowledge to -diagnose problems, and to create non-standard configurations. +diagnose problems or to create non-standard configurations. =head2 DETERMINE KEY @@ -298,20 +410,16 @@ All the host tools use an external helper program called C to get the key of the guest. (See L for the precise usage of this program). -The key is generated by the guest once -- when the virt-tools package -is installed in the guest. The key is written to a file -C (in the guest) which is readable only by -root. - -On Windows guests the key is written to -C<%systemroot%\virttools.key> +The key is generated by the guest once -- when the virt-tools-guest +package is installed in the guest. The key is written to a file +C<$GUESTCOMMSDIR/key> (in the guest) which is readable only by root. Using L the host can read any file in the guest, so it can read this key out directly. This is what the C program does, and you can run it by hand to verify its operation: - # virt-tools-get-key -v domname|uuid + # virt-tools-get-key -v domname abcdef1234567890 =head3 KEY CACHE @@ -338,6 +446,23 @@ This cache never expires, unless you remove the files by hand. sub get_key { + my $domname = shift; + + my $cmd = "virt-tools-get-key"; + $cmd .= " -v" if $verbose; + # XXX quoting + $cmd .= " -c '$uri'" if $uri; + $cmd .= " '$domname'"; + + print STDERR "$cmd\n" if $verbose; + + open PIPE, "$cmd |" or die "$cmd: $!"; + my $line = ; + die "no response from virt-tools-get-key\n" unless $line; + chomp $line; + close PIPE; + + $line } =head2 DETERMINE TRANSPORT @@ -351,7 +476,7 @@ This program tries a series of methods to determine how to access a guest, be it through a direct network connection or over some hypervisor-specific vmchannel. - # virt-tools-get-transport -v domname|uuid + # virt-tools-get-transport -v domname udp:192.168.122.33 You can diagnose problems with the transport by trying to run this @@ -374,8 +499,40 @@ corresponding entry in the transport cache if it is not valid. sub get_transport { + my $domname = shift; + + my $cmd = "virt-tools-get-transport"; + $cmd .= " -v" if $verbose; + # XXX quoting + $cmd .= " -c '$uri'" if $uri; + $cmd .= " '$domname'"; + + print STDERR "$cmd\n" if $verbose; + + open PIPE, "$cmd |" or die "$cmd: $!"; + my $line = ; + die "no response from virt-tools-get-transport\n" unless $line; + chomp $line; + close PIPE; + + $line } +=head2 SNMP QUERIES + +Standard SNMP queries are used between the host and guest. + +SNMP already supports many of the features we are trying to query +(eg. the UCD SNMP MIB provides a way to query the process list of a +machine in a form which is a de facto standard). + +To determine what precise queries are sent, run the tools in verbose +mode or examine the source. + +=head2 RUNNING YOUR OWN SNMP SERVER IN A GUEST + +I<(To be written)> + =head1 NOTE ABOUT CSV FORMAT Comma-separated values (CSV) is a deceptive format. It I like -- 1.8.3.1