b1d305b831e0cac93d2aedc486036e6915890292
[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", __"System name");
202 }
203
204 sub do_uname
205 {
206     my $domname = shift;
207     my $key = shift;
208     my $transport = shift;
209
210     my $session = get_snmp_session ($key, $transport);
211     my $sysDescr = "1.3.6.1.2.1.1.1.0";
212     my $r = $session->get_request (-varbindlist => [$sysDescr])
213         or die __x("SNMP error: {e}", $session->error);
214     print_row ($domname, $r->{$sysDescr});
215     $session->close;
216 }
217
218 =head1 virt-ps
219
220 C<virt-ps> displays the process list of the guest.
221
222 =cut
223
224 sub title_ps
225 {
226     print_row (__"Guest");
227 }
228
229 sub do_ps
230 {
231     my $domname = shift;
232     my $key = shift;
233     my $transport = shift;
234
235
236
237 }
238
239 =head1 virt-ping
240
241 C<virt-ping> pings the guest by making an empty virt-tools request,
242 and checking that it replies.  This can be used as a simple test that
243 virt-tools is available and working inside the guest.
244
245 =cut
246
247 sub title_ping
248 {
249     print_row (__"Guest");
250 }
251
252 sub do_ping
253 {
254     my $domname = shift;
255     my $key = shift;
256     my $transport = shift;
257
258
259
260 }
261
262 # virt-ifconfig is implemented separately.
263
264 =head1 virt-ifconfig
265
266 C<virt-ifconfig> displays the IP address of the guest.
267
268 =cut
269
270 sub print_row
271 {
272     my @fields = @_;
273
274     local $_;
275     my $comma = 0;
276
277     foreach (@fields) {
278         if (!$csv) {
279             printf "%-16s ", $_
280         } else {
281             print "," if $comma;
282             $comma = 1;
283
284             # XXX Use Text::CSV here.
285             if ($_ =~ /"/) {
286                 s/"/""/;
287                 printf "\"%s\"", $_;
288             } elsif ($_ =~ /,/ || $_ =~ /\n/) {
289                 printf "\"%s\"", $_;
290             } else {
291                 print $_;
292             }
293         }
294     }
295     print "\n";
296 }
297
298 =head1 OVERVIEW
299
300 Virt-tools are a set of tools that you can install in your virtual
301 machines (host and guests) to get enhanced information about the
302 guests.
303
304 Unlike VMWare Tools, virt-tools is hypervisor agnostic.  Also
305 virt-tools is just about collecting statistics and does not include
306 any performance or functionality enhancements for guests (see virtio
307 if you want that).
308
309 There are two parts to any virt-tools installation: some client
310 programs like C<virt-uname> and C<virt-ps> that you run on the host,
311 to query guest information.  On the guest, you have to install and run
312 a virt-tools service.  Between the host and guest is a transport which
313 should be secured.
314
315 The L</GUEST ARCHITECTURE> section describes how virt-tools appears
316 from the guest side.
317
318 The L</HOST ARCHITECTURE> section describes the architecture of
319 virt-tools on the host side.
320
321 =head1 GUEST ARCHITECTURE
322
323 In most cases, you can just install the C<virt-tools-guest> package in
324 your Linux guests, or the Windows virt-tools guest package in your
325 Windows guests, and everything should just work.  In this section we
326 describe more about how it works (or is supposed to work) from the
327 guest side.
328
329 =head2 COMMUNICATIONS DIRECTORY
330
331 The guest writes various static, mostly unchanging, information into
332 its own directory.  On Linux the directory is
333 C<@localstatedir@/lib/virt-tools/> and under Windows it is
334 C<%systemroot%\virttool\>.  In the discussion below, this
335 communications directory is referred to as C<$GUESTCOMMSDIR>.
336
337 The host is able to read files out of this directory using
338 L<libguestfs(3)> (without any cooperation needed by the guest).
339
340 =head2 IP ADDRESSES
341
342 The host can't easily see the guest's IP address.  The host provides
343 the guest with a network interface connected to a bridge, but the
344 guest can use any IP address it likes (although well-behaved guests
345 will usually have some static IPs or are allocated one by DHCP).
346
347 So when the guest starts up, or its IP address changes (usually these
348 are rare events) the guest writes a file
349 C<$GUESTCOMMSDIR/ip-E<lt>ifaceE<gt>> which contains details of the IP
350 address of the interface E<lt>ifaceE<gt> (eg. the file might be called
351 C<ip-eth0> under Linux).
352
353 C<virt-ifconfig> reads this file directly using L<libguestfs(3)>.
354
355 =head2 KEYS
356
357 When the guest is first installed (or more precisely, when the
358 virt-tools-guest package is first installed in the guest), a random
359 secret key is generated.  This is used to encrypt communications with
360 the guest, and it is described in more detail below.
361
362 The key is written to C<$GUESTCOMMSDIR/key>.
363
364 =head2 SNMP DAEMON
365
366 For process listings, and just about every other piece of data except
367 for IP address, guests run a completely standard SNMP (Simple Network
368 Management Protocol) server.  The host client tools access this server
369 in order to query information about the guest.  They query this using
370 standard SNMP calls.
371
372 The protocol used is SNMPv3 (RFC 2571) which addresses security
373 concerns in earlier versions of the protocol.  In order to ensure that
374 only the host can access the SNMP server and see the results, all
375 communications are encrypted and authenticated using the guest's key.
376
377 =head2 TRANSPORT
378
379 There is not necessarily a network connection between the host and the
380 guest.  There are many configurations of virtualization in which the
381 host has no network access to the guest: for example, if the host
382 firewalls itself off from the guest (or vice versa), or if the guest
383 has a physically separate network card from the host.
384
385 Therefore the guest to host SNMP transport is not necessarily over an
386 IP network.  Other transports are possible, including "vmchannel"
387 (where "vmchannel" is the generic name for a collection of specialized
388 host-guest communication channels implemented in different ways by
389 different hypervisors).
390
391 The transport is written to C<$GUESTCOMMSDIR/transport>.
392
393 =head1 HOST ARCHITECTURE
394
395 On the host side, the host uses L<libguestfs(3)> to read the guest's
396 IP address and key, and uses some heuristics to determine the
397 transport to use.
398
399 Once the key and the transport to the guest are worked out, programs
400 like C<virt-ps>, C<virt-uname> and so on are just making
401 straightforward SNMP calls:
402
403  +-----------------+      +-----------------+
404  | host            |      | guest           |
405  |  virt-ps --- request ---> snmpd          |
406  |         <---- reply -----                |
407  +-----------------+      +-----------------+
408
409 The difficulty is in determining the key and the transport to use,
410 which is what this section covers.  You can also use this knowledge to
411 diagnose problems or to create non-standard configurations.
412
413 =head2 DETERMINE KEY
414
415 All the host tools use an external helper program called
416 C<virt-tools-get-key> to get the key of the guest.  (See
417 L<virt-tools-get-key(8)> for the precise usage of this program).
418
419 The key is generated by the guest once -- when the virt-tools-guest
420 package is installed in the guest.  The key is written to a file
421 C<$GUESTCOMMSDIR/key> (in the guest) which is readable only by root.
422
423 Using L<libguestfs(3)> the host can read any file in the guest, so it
424 can read this key out directly.  This is what the
425 C<virt-tools-get-key> program does, and you can run it by hand to
426 verify its operation:
427
428  # virt-tools-get-key -v domname
429  abcdef1234567890
430
431 =head3 KEY CACHE
432
433 C<virt-tools-get-key> caches the keys of guests that it has seen
434 before so it doesn't have to read them each time.  The cache is in
435 C<@localstatedir@/lib/virt-tools/keys/> (in the host).
436
437 You can just delete the files in this directory at any time, I<or> you
438 can drop a file in here which contains the key of a guest.
439
440 To do this, create a file
441 C<@localstatedir@/lib/virt-tools/keys/E<lt>UUIDE<gt>> where
442 E<lt>UUIDE<gt> is the guest's UUID as displayed by this command:
443
444  virsh domuuid <name>
445
446 The contents of the file should be the key.
447
448 You can test this works by running C<virt-tools-get-key> by hand.
449
450 This cache never expires, unless you remove the files by hand.
451
452 =cut
453
454 sub get_key
455 {
456     my $domname = shift;
457
458     my $cmd = "virt-tools-get-key";
459     $cmd .= " -v" if $verbose;
460     # XXX quoting
461     $cmd .= " -c '$uri'" if $uri;
462     $cmd .= " '$domname'";
463
464     print STDERR "$cmd\n" if $verbose;
465
466     open PIPE, "$cmd |" or die "$cmd: $!";
467     my $line = <PIPE>;
468     die __"no response from virt-tools-get-key\n" unless $line;
469     chomp $line;
470     close PIPE;
471
472     $line
473 }
474
475 =head2 DETERMINE TRANSPORT
476
477 All the host tools use a second helper program called
478 C<virt-tools-get-transport> to get the transport and address to use
479 for a guest.  (See L<virt-tools-get-transport(8)> for the precise
480 usage of this program).
481
482 This program tries a series of methods to determine how to access a
483 guest, be it through a direct network connection or over some
484 hypervisor-specific vmchannel.
485
486  # virt-tools-get-transport -v domname
487  udp:192.168.122.33
488
489 You can diagnose problems with the transport by trying to run this
490 command by hand.
491
492 =head3 TRANSPORT CACHE
493
494 C<virt-tools-get-transport> caches the transports of guests that it
495 has seen before so it doesn't have to determine them each time.  The
496 cache is in C<@localstatedir@/lib/virt-tools/transports/> (in the
497 host).
498
499 As for the L</KEY CACHE>, this directory is just some files that are
500 named after the UUID of the guest, containing the transport.
501
502 Unlike the key cache, C<virt-tools-get-transport> will check that a
503 transport is still valid, and will expire (ie. delete) the
504 corresponding entry in the transport cache if it is not valid.
505
506 =cut
507
508 sub get_transport
509 {
510     my $domname = shift;
511
512     my $cmd = "virt-tools-get-transport";
513     $cmd .= " -v" if $verbose;
514     # XXX quoting
515     $cmd .= " -c '$uri'" if $uri;
516     $cmd .= " '$domname'";
517
518     print STDERR "$cmd\n" if $verbose;
519
520     open PIPE, "$cmd |" or die "$cmd: $!";
521     my $line = <PIPE>;
522     die __"no response from virt-tools-get-transport\n" unless $line;
523     chomp $line;
524     close PIPE;
525
526     $line
527 }
528
529 =head2 SNMP QUERIES
530
531 Standard SNMP queries are used between the host and guest.
532
533 SNMP already supports many of the features we are trying to query
534 (eg. the UCD SNMP MIB provides a way to query the process list of a
535 machine in a form which is a de facto standard).
536
537 To determine what precise queries are sent, run the tools in verbose
538 mode or examine the source.
539
540 =cut
541
542 sub get_snmp_session
543 {
544     my $key = shift;
545     my $transport = shift;
546
547     my ($hostname, $port, $domain);
548     if ($transport =~ /^udp:(.*):(.*)/) {
549         $domain = "udp";
550         $hostname = $1;
551         $port = $2;
552     } elsif ($transport =~ /^tcp:(.*):(.*)/) {
553         $domain = "tcp";
554         $hostname = $1;
555         $port = $2;
556     } else {
557         die __x("unknown transport type: {t}", t => $transport);
558     }
559
560     if ($verbose) {
561         print STDERR "creating Net::SNMP session to $domain:$hostname:$port with key $key\n"
562     }
563
564     my ($session, $error) = Net::SNMP->session (
565         -version => 3,
566         -username => "virttools",
567         -authpassword => $key,
568         -authprotocol => "sha",
569         -privpassword => $key,
570         -privprotocol => "aes",
571         -hostname => $hostname,
572         -port => $port,
573         -domain => $domain,
574         );
575     die __x("SNMP failure: {e}", e => $error) unless $session;
576
577     $session;
578 }
579
580 =head2 RUNNING YOUR OWN SNMP SERVER IN A GUEST
581
582 I<(To be written)>
583
584 =head1 NOTE ABOUT CSV FORMAT
585
586 Comma-separated values (CSV) is a deceptive format.  It I<seems> like
587 it should be easy to parse, but it is definitely not easy to parse.
588
589 Myth: Just split fields at commas.  Reality: This does I<not> work
590 reliably.  This example has two columns:
591
592  "foo,bar",baz
593
594 Myth: Read the file one line at a time.  Reality: This does I<not>
595 work reliably.  This example has one row:
596
597  "foo
598  bar",baz
599
600 For shell scripts, use C<csvtool> (L<http://merjis.com/developers/csv>
601 also packaged in major Linux distributions).
602
603 For other languages, use a CSV processing library (eg. C<Text::CSV>
604 for Perl or Python's built-in csv library).
605
606 Most spreadsheets and databases can import CSV directly.
607
608 =head1 SEE ALSO
609
610 L<virt-ifconfig(8)>,
611 L<guestfs(3)>,
612 L<guestfish(1)>,
613 L<Sys::Guestfs(3)>,
614 L<Sys::Guestfs::Lib(3)>,
615 L<Sys::Virt(3)>,
616 L<http://libguestfs.org/>.
617
618 =head1 AUTHORS
619
620 =over 4
621
622 =item *
623
624 Richard W.M. Jones (C<rjones at redhat dot com>)
625
626 =item *
627
628 Matthew Booth (C<mbooth at redhat dot com>)
629
630 =back
631
632 =head1 COPYRIGHT
633
634 Copyright (C) 2009 Red Hat Inc.
635
636 This program is free software; you can redistribute it and/or modify
637 it under the terms of the GNU General Public License as published by
638 the Free Software Foundation; either version 2 of the License, or
639 (at your option) any later version.
640
641 This program is distributed in the hope that it will be useful,
642 but WITHOUT ANY WARRANTY; without even the implied warranty of
643 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
644 GNU General Public License for more details.
645
646 You should have received a copy of the GNU General Public License
647 along with this program; if not, write to the Free Software
648 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.