Update documentation.
authorRichard Jones <rjones@trick.home.annexia.org>
Thu, 24 Sep 2009 15:35:24 +0000 (16:35 +0100)
committerRichard Jones <rjones@trick.home.annexia.org>
Thu, 24 Sep 2009 15:35:24 +0000 (16:35 +0100)
tools/virt-uname.pl

index 9bca435..4c7e253 100755 (executable)
@@ -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</NOTE ABOUT CSV FORMAT> 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<virt-ifconfig> 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<virt-uname> and C<virt-ps> 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</GUEST CONFIGURATION> section describes how
-to configure guests and secure the transport.
+should be secured.
+
+The L</GUEST ARCHITECTURE> section describes how virt-tools appears
+from the guest side.
+
+The L</HOST ARCHITECTURE> section describes the architecture of
+virt-tools on the host side.
 
-Finally the L</ARCHITECTURE> 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<virt-tools-guest> 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</var/lib/virt-tools/>
+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<libguestfs(3)> (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-E<lt>ifaceE<gt>> which contains details of the IP
+address of the interface E<lt>ifaceE<gt> (eg. the file might be called
+C<ip-eth0> under Linux).
 
+C<virt-ifconfig> reads this file directly using L<libguestfs(3)>.
 
+=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<libguestfs(3)> 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<virt-ps>, C<virt-uname> 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<virt-tools-get-key> to get the key of the guest.  (See
 L<virt-tools-get-key(8)> 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</var/lib/virt-tools/key> (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<libguestfs(3)> the host can read any file in the guest, so it
 can read this key out directly.  This is what the
 C<virt-tools-get-key> 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 = <PIPE>;
+    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 = <PIPE>;
+    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<seems> like