Update
[virt-tools.git] / tools / virt-uname.pl
1 #!/usr/bin/perl -w
2 # virt-tools
3 # Copyright (C) 2009 Red Hat Inc.
4 #
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 2 of the License, or
8 # (at your option) any later version.
9 #
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 # GNU General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18
19 use strict;
20
21 use Net::SNMP;
22 use Sys::Virt;
23 use Pod::Usage;
24 use Getopt::Long;
25 use Locale::TextDomain 'virt-tools';
26
27 =encoding utf8
28
29 =head1 NAME
30
31 virt-uname, virt-ps, virt-ping - virtual machine information and statistics
32
33 =head1 SYNOPSIS
34
35  virt-uname [--options] [domname]
36
37  virt-ps [--options] [domname]
38
39  virt-ping [--options] [domname]
40
41  virt-ifconfig [--options] [domname]
42
43 =head1 COMMON OPTIONS
44
45 All the tools take either a single C<domname> parameter, which is the
46 name of the virtual machine as known to libvirt (C<virsh list>), or no
47 parameter in which case they operate on all currently running guests.
48
49 I<Note:> You must install the C<virt-tools-guest> package in each
50 Linux guest, otherwise these programs will not work.
51
52 There are some common options which can be supplied to any tool:
53
54 =over 4
55
56 =cut
57
58 my $help;
59
60 =item B<--help>
61
62 Display brief help.
63
64 =cut
65
66 my $version;
67
68 =item B<--version>
69
70 Display version number and exit.
71
72 =cut
73
74 my $uri;
75
76 =item B<--connect URI> | B<-c URI>
77
78 If using libvirt, connect to the given I<URI>.  If omitted, then we
79 connect to the default libvirt hypervisor.
80
81 =cut
82
83 my $csv;
84
85 =item B<--csv>
86
87 Write out the results in CSV format (comma-separated values).  This
88 format can be imported easily into databases and spreadsheets, but
89 read L</NOTE ABOUT CSV FORMAT> below.
90
91 =cut
92
93 my $verbose;
94
95 =item B<--verbose> | B<-v>
96
97 Enable verbose messages, useful for debugging.
98
99 =back
100
101 =cut
102
103 GetOptions ("help|?" => \$help,
104             "version" => \$version,
105             "connect|c=s" => \$uri,
106             "csv" => \$csv,
107             "verbose|v" => \$verbose,
108     ) or pod2usage (2);
109 pod2usage (1) if $help;
110 if ($version) {
111     print "@PACKAGE_STRING@\n";
112     exit
113 }
114
115 my %subcommands = (
116     "virt-uname" => [ \&do_uname, \&title_uname ],
117     "virt-ps" => [ \&do_ps, \&title_ps ],
118     "virt-ping" => [ \&do_ping, \&title_ping ],
119 );
120
121 # Which subcommand?
122 my ($do_it, $title_it);
123 foreach (keys %subcommands) {
124     if ($0 =~ /$_/) {
125         print STDERR "subcommand = $_\n" if $verbose;
126         $do_it = $subcommands{$_}->[0];
127         $title_it = $subcommands{$_}->[1];
128         last;
129     }
130 }
131 die "$0: cannot determine which sub-command to run\n" unless $do_it;
132
133 # If we are being run from a local directory, add that directory to
134 # the path, so we can be run from the source directory without being
135 # installed.
136 if (substr ($0, 0, 1) ne "/") {
137     $_ = $0;
138     s{/[^/]+$}{};
139     $ENV{PATH} = "$_:$ENV{PATH}"; # XXX Windows?
140     print STDERR "PATH set to $ENV{PATH}\n" if $verbose;
141 }
142
143 our $errors = 0;
144
145 # Do we have named guests?
146 if (@ARGV == 0) {
147     my $conn;
148
149     if ($uri) {
150         $conn = Sys::Virt->new (readonly => 1, address => $uri);
151     } else {
152         $conn = Sys::Virt->new (readonly => 1);
153     }
154
155     # Ignore inactive domains.
156     my @doms = $conn->list_domains ();
157
158     my @domnames = map { $_->get_name () } @doms;
159
160     if (@domnames) {
161         &$title_it ();
162         foreach (@domnames) {
163             get_and_do_it ($_);
164         }
165     }
166 } else {
167     &$title_it ();
168     foreach (@ARGV) {
169         get_and_do_it ($_);
170     }
171 }
172
173 sub get_and_do_it
174 {
175     # Turn any errors into warnings.
176     eval {
177         my ($key, $transport);
178         $key = get_key ($_);
179         $transport = get_transport ($_);
180         &$do_it ($_, $key, $transport);
181     };
182     if ($@) {
183         $errors++;
184         warn "$@";
185     }
186 }
187
188 print STDERR "errors = $errors\n" if $verbose;
189
190 exit ($errors == 0 ? 0 : 1);
191
192 =head1 virt-uname
193
194 C<virt-uname> displays the system information (kernel version etc) of
195 the guest.
196
197 =cut
198
199 sub title_uname
200 {
201     print_row (__"Guest");
202 }
203
204 sub do_uname
205 {
206     my $domname = shift;
207     my $key = shift;
208     my $transport = shift;
209
210
211
212 }
213
214 =head1 virt-ps
215
216 C<virt-ps> displays the process list of the guest.
217
218 =cut
219
220 sub title_ps
221 {
222     print_row (__"Guest");
223 }
224
225 sub do_ps
226 {
227     my $domname = shift;
228     my $key = shift;
229     my $transport = shift;
230
231
232
233 }
234
235 =head1 virt-ping
236
237 C<virt-ping> pings the guest by making an empty virt-tools request,
238 and checking that it replies.  This can be used as a simple test that
239 virt-tools is available and working inside the guest.
240
241 =cut
242
243 sub title_ping
244 {
245     print_row (__"Guest");
246 }
247
248 sub do_ping
249 {
250     my $domname = shift;
251     my $key = shift;
252     my $transport = shift;
253
254
255
256 }
257
258 # virt-ifconfig is implemented separately.
259
260 =head1 virt-ifconfig
261
262 C<virt-ifconfig> displays the IP address of the guest.
263
264 =cut
265
266 sub print_row
267 {
268     my @fields = @_;
269
270     local $_;
271     my $comma = 0;
272
273     foreach (@fields) {
274         print "," if $comma;
275         $comma = 1;
276
277         if (!$csv) {
278             printf "%-16s ", $_
279         } else {
280             # XXX Use Text::CSV here.
281             if ($_ =~ /"/) {
282                 s/"/""/;
283                 printf "\"%s\"", $_;
284             } elsif ($_ =~ /,/ || $_ =~ /\n/) {
285                 printf "\"%s\"", $_;
286             } else {
287                 print $_;
288             }
289         }
290     }
291     print "\n";
292 }
293
294 =head1 OVERVIEW
295
296 Virt-tools are a set of tools that you can install in your virtual
297 machines (host and guests) to get enhanced information about the
298 guests.
299
300 Unlike VMWare Tools, virt-tools is hypervisor agnostic.  Also
301 virt-tools is just about collecting statistics and does not include
302 any performance or functionality enhancements for guests (see virtio
303 if you want that).
304
305 There are two parts to any virt-tools installation: some client
306 programs like C<virt-uname> and C<virt-ps> that you run on the host,
307 to query guest information.  On the guest, you have to install and run
308 a virt-tools service.  Between the host and guest is a transport which
309 should be secured.
310
311 The L</GUEST ARCHITECTURE> section describes how virt-tools appears
312 from the guest side.
313
314 The L</HOST ARCHITECTURE> section describes the architecture of
315 virt-tools on the host side.
316
317 =head1 GUEST ARCHITECTURE
318
319 In most cases, you can just install the C<virt-tools-guest> package in
320 your Linux guests, or the Windows virt-tools guest package in your
321 Windows guests, and everything should just work.  In this section we
322 describe more about how it works (or is supposed to work) from the
323 guest side.
324
325 =head2 COMMUNICATIONS DIRECTORY
326
327 The guest writes various static, mostly unchanging, information into
328 its own directory.  On Linux the directory is
329 C<@localstatedir@/lib/virt-tools/> and under Windows it is
330 C<%systemroot%\virttool\>.  In the discussion below, this
331 communications directory is referred to as C<$GUESTCOMMSDIR>.
332
333 The host is able to read files out of this directory using
334 L<libguestfs(3)> (without any cooperation needed by the guest).
335
336 =head2 IP ADDRESSES
337
338 The host can't easily see the guest's IP address.  The host provides
339 the guest with a network interface connected to a bridge, but the
340 guest can use any IP address it likes (although well-behaved guests
341 will usually have some static IPs or are allocated one by DHCP).
342
343 So when the guest starts up, or its IP address changes (usually these
344 are rare events) the guest writes a file
345 C<$GUESTCOMMSDIR/ip-E<lt>ifaceE<gt>> which contains details of the IP
346 address of the interface E<lt>ifaceE<gt> (eg. the file might be called
347 C<ip-eth0> under Linux).
348
349 C<virt-ifconfig> reads this file directly using L<libguestfs(3)>.
350
351 =head2 KEYS
352
353 When the guest is first installed (or more precisely, when the
354 virt-tools-guest package is first installed in the guest), a random
355 secret key is generated.  This is used to encrypt communications with
356 the guest, and it is described in more detail below.
357
358 The key is written to C<$GUESTCOMMSDIR/key>.
359
360 =head2 SNMP DAEMON
361
362 For process listings, and just about every other piece of data except
363 for IP address, guests run a completely standard SNMP (Simple Network
364 Management Protocol) server.  The host client tools access this server
365 in order to query information about the guest.  They query this using
366 standard SNMP calls.
367
368 The protocol used is SNMPv3 (RFC 2571) which addresses security
369 concerns in earlier versions of the protocol.  In order to ensure that
370 only the host can access the SNMP server and see the results, all
371 communications are encrypted and authenticated using the guest's key.
372
373 =head2 TRANSPORT
374
375 There is not necessarily a network connection between the host and the
376 guest.  There are many configurations of virtualization in which the
377 host has no network access to the guest: for example, if the host
378 firewalls itself off from the guest (or vice versa), or if the guest
379 has a physically separate network card from the host.
380
381 Therefore the guest to host SNMP transport is not necessarily over an
382 IP network.  Other transports are possible, including "vmchannel"
383 (where "vmchannel" is the generic name for a collection of specialized
384 host-guest communication channels implemented in different ways by
385 different hypervisors).
386
387 The transport is written to C<$GUESTCOMMSDIR/transport>.
388
389 =head1 HOST ARCHITECTURE
390
391 On the host side, the host uses L<libguestfs(3)> to read the guest's
392 IP address and key, and uses some heuristics to determine the
393 transport to use.
394
395 Once the key and the transport to the guest are worked out, programs
396 like C<virt-ps>, C<virt-uname> and so on are just making
397 straightforward SNMP calls:
398
399  +-----------------+      +-----------------+
400  | host            |      | guest           |
401  |  virt-ps --- request ---> snmpd          |
402  |         <---- reply -----                |
403  +-----------------+      +-----------------+
404
405 The difficulty is in determining the key and the transport to use,
406 which is what this section covers.  You can also use this knowledge to
407 diagnose problems or to create non-standard configurations.
408
409 =head2 DETERMINE KEY
410
411 All the host tools use an external helper program called
412 C<virt-tools-get-key> to get the key of the guest.  (See
413 L<virt-tools-get-key(8)> for the precise usage of this program).
414
415 The key is generated by the guest once -- when the virt-tools-guest
416 package is installed in the guest.  The key is written to a file
417 C<$GUESTCOMMSDIR/key> (in the guest) which is readable only by root.
418
419 Using L<libguestfs(3)> the host can read any file in the guest, so it
420 can read this key out directly.  This is what the
421 C<virt-tools-get-key> program does, and you can run it by hand to
422 verify its operation:
423
424  # virt-tools-get-key -v domname
425  abcdef1234567890
426
427 =head3 KEY CACHE
428
429 C<virt-tools-get-key> caches the keys of guests that it has seen
430 before so it doesn't have to read them each time.  The cache is in
431 C<@localstatedir@/lib/virt-tools/keys/> (in the host).
432
433 You can just delete the files in this directory at any time, I<or> you
434 can drop a file in here which contains the key of a guest.
435
436 To do this, create a file
437 C<@localstatedir@/lib/virt-tools/keys/E<lt>UUIDE<gt>> where
438 E<lt>UUIDE<gt> is the guest's UUID as displayed by this command:
439
440  virsh domuuid <name>
441
442 The contents of the file should be the key.
443
444 You can test this works by running C<virt-tools-get-key> by hand.
445
446 This cache never expires, unless you remove the files by hand.
447
448 =cut
449
450 sub get_key
451 {
452     my $domname = shift;
453
454     my $cmd = "virt-tools-get-key";
455     $cmd .= " -v" if $verbose;
456     # XXX quoting
457     $cmd .= " -c '$uri'" if $uri;
458     $cmd .= " '$domname'";
459
460     print STDERR "$cmd\n" if $verbose;
461
462     open PIPE, "$cmd |" or die "$cmd: $!";
463     my $line = <PIPE>;
464     die __"no response from virt-tools-get-key\n" unless $line;
465     chomp $line;
466     close PIPE;
467
468     $line
469 }
470
471 =head2 DETERMINE TRANSPORT
472
473 All the host tools use a second helper program called
474 C<virt-tools-get-transport> to get the transport and address to use
475 for a guest.  (See L<virt-tools-get-transport(8)> for the precise
476 usage of this program).
477
478 This program tries a series of methods to determine how to access a
479 guest, be it through a direct network connection or over some
480 hypervisor-specific vmchannel.
481
482  # virt-tools-get-transport -v domname
483  udp:192.168.122.33
484
485 You can diagnose problems with the transport by trying to run this
486 command by hand.
487
488 =head3 TRANSPORT CACHE
489
490 C<virt-tools-get-transport> caches the transports of guests that it
491 has seen before so it doesn't have to determine them each time.  The
492 cache is in C<@localstatedir@/lib/virt-tools/transports/> (in the
493 host).
494
495 As for the L</KEY CACHE>, this directory is just some files that are
496 named after the UUID of the guest, containing the transport.
497
498 Unlike the key cache, C<virt-tools-get-transport> will check that a
499 transport is still valid, and will expire (ie. delete) the
500 corresponding entry in the transport cache if it is not valid.
501
502 =cut
503
504 sub get_transport
505 {
506     my $domname = shift;
507
508     my $cmd = "virt-tools-get-transport";
509     $cmd .= " -v" if $verbose;
510     # XXX quoting
511     $cmd .= " -c '$uri'" if $uri;
512     $cmd .= " '$domname'";
513
514     print STDERR "$cmd\n" if $verbose;
515
516     open PIPE, "$cmd |" or die "$cmd: $!";
517     my $line = <PIPE>;
518     die __"no response from virt-tools-get-transport\n" unless $line;
519     chomp $line;
520     close PIPE;
521
522     $line
523 }
524
525 =head2 SNMP QUERIES
526
527 Standard SNMP queries are used between the host and guest.
528
529 SNMP already supports many of the features we are trying to query
530 (eg. the UCD SNMP MIB provides a way to query the process list of a
531 machine in a form which is a de facto standard).
532
533 To determine what precise queries are sent, run the tools in verbose
534 mode or examine the source.
535
536 =head2 RUNNING YOUR OWN SNMP SERVER IN A GUEST
537
538 I<(To be written)>
539
540 =head1 NOTE ABOUT CSV FORMAT
541
542 Comma-separated values (CSV) is a deceptive format.  It I<seems> like
543 it should be easy to parse, but it is definitely not easy to parse.
544
545 Myth: Just split fields at commas.  Reality: This does I<not> work
546 reliably.  This example has two columns:
547
548  "foo,bar",baz
549
550 Myth: Read the file one line at a time.  Reality: This does I<not>
551 work reliably.  This example has one row:
552
553  "foo
554  bar",baz
555
556 For shell scripts, use C<csvtool> (L<http://merjis.com/developers/csv>
557 also packaged in major Linux distributions).
558
559 For other languages, use a CSV processing library (eg. C<Text::CSV>
560 for Perl or Python's built-in csv library).
561
562 Most spreadsheets and databases can import CSV directly.
563
564 =head1 SEE ALSO
565
566 L<virt-ifconfig(8)>,
567 L<guestfs(3)>,
568 L<guestfish(1)>,
569 L<Sys::Guestfs(3)>,
570 L<Sys::Guestfs::Lib(3)>,
571 L<Sys::Virt(3)>,
572 L<http://libguestfs.org/>.
573
574 =head1 AUTHORS
575
576 =over 4
577
578 =item *
579
580 Richard W.M. Jones (C<rjones at redhat dot com>)
581
582 =item *
583
584 Matthew Booth (C<mbooth at redhat dot com>)
585
586 =back
587
588 =head1 COPYRIGHT
589
590 Copyright (C) 2009 Red Hat Inc.
591
592 This program is free software; you can redistribute it and/or modify
593 it under the terms of the GNU General Public License as published by
594 the Free Software Foundation; either version 2 of the License, or
595 (at your option) any later version.
596
597 This program is distributed in the hope that it will be useful,
598 but WITHOUT ANY WARRANTY; without even the implied warranty of
599 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
600 GNU General Public License for more details.
601
602 You should have received a copy of the GNU General Public License
603 along with this program; if not, write to the Free Software
604 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.