3 # Copyright (C) 2009 Red Hat Inc.
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.
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.
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.
21 use Sys::Guestfs::Lib qw(open_guest get_partitions);
29 use Locale::TextDomain 'virt-tools';
35 virt-tools-get-transport - virt-tools helper to get the guest's transport
39 virt-tools-get-transport [--options] domname
43 This helper program is used by L<virt-tools(8)> to get the transport
44 that should be used to connect to the SNMP daemon inside the guest.
45 If you don't know anything about this, you probably want to start by
46 reading L<virt-tools(8)>. Otherwise read on.
48 The single command line argument should be a libvirt domain name (see
53 Transports look somewhat like a URL, with a transport schema followed
54 by some specific details. Currently we have defined these transports:
58 =item udp:ip-address[:port]
60 Connect via UDP to C<ip-address>, optionally on the non-default port
61 C<port> (the usual SNMP port 161 is used otherwise).
63 =item tcp:ip-address[:port]
65 Connect via TCP to C<ip-address>, optionally on the non-default port
66 C<port> (the usual SNMP port 161 is used otherwise).
70 Connect via Unix domain socket C<path>. This would be used in future
71 for vmchannel implementations, but it is not used at the moment.
75 =head2 TRANSPORT CACHE
77 The cache is described in detail in L<virt-tools(8)>. In brief, if
78 C<@localstatedir@/lib/virt-tools/transports/E<lt>UUIDE<gt>> exists
79 (where E<lt>UUIDE<gt> is the guest's UUID), then the contents of that
80 file are returned directly. Otherwise we will try to create this file
81 after reading the transport so that we don't have to determine the
82 guest's transport each time.
102 Display version number and exit.
108 =item B<--connect URI> | B<-c URI>
110 If using libvirt, connect to the given I<URI>. If omitted, then we
111 connect to the default libvirt hypervisor.
117 =item B<--verbose> | B<-v>
119 Enable verbose messages, useful for debugging.
125 =item B<--no-ping> | B<-n>
127 Do not try to check that the transport is working by pinging the
130 If this option is I<not> given, then this program will expire the
131 cache entry for the guest if the transport from the cache doesn't
132 work, then it will try to determine the new transport, test that, and
133 fail if it still doesn't work.
139 GetOptions ("help|?" => \$help,
140 "version" => \$version,
141 "connect|c=s" => \$uri,
142 "verbose|v" => \$verbose,
143 "no-ping|n" => \$no_ping,
145 pod2usage (1) if $help;
147 print "@PACKAGE_STRING@\n";
151 die __"no domain name listed on the command line\n" unless @ARGV == 1;
153 my ($g, $conn, $dom);
156 ($g, $conn, $dom) = open_guest (\@ARGV, address => $uri);
158 ($g, $conn, $dom) = open_guest (\@ARGV);
161 my $uuid = $dom->get_uuid_string ();
162 my $domname = $dom->get_name ();
164 # See if the UUID exists in the cache already.
165 print STDERR "checking for UUID $uuid in the cache directory\n" if $verbose;
167 my $cachedir = "@localstatedir@/lib/virt-tools/transports";
168 if (-r "$cachedir/$uuid") {
169 print STDERR "$cachedir/$uuid exists\n" if $verbose;
170 open FILE, "$cachedir/$uuid" or die "$cachedir/$uuid: $!";
171 my $transport = <FILE>;
177 if (!test_transport ($transport)) {
178 unlink "$cachedir/$uuid"; # allow this to fail
183 print $transport, "\n";
188 print STDERR "$cachedir/$uuid not found, looking inside guest\n" if $verbose;
193 # Do not care about mountpoints. Instead, just look for a
194 # directory with one of a selection of names on one of the
195 # partitions that we found.
196 my @partitions = get_partitions ($g);
198 my ($transport, $key, $ip);
200 foreach my $partition (@partitions) {
202 $g->mount_ro ($partition, "/");
204 my @dirs = ("/var/lib/virt-tools", "/lib/virt-tools");
205 foreach $dir (@dirs) {
206 if ($g->is_dir ($dir)) {
207 if ($g->is_file ("$dir/transport")) {
208 $transport = $g->cat ("$dir/transport");
210 if ($g->is_file ("$dir/key")) {
211 $key = $g->cat ("$dir/key");
213 if ($g->is_file ("$dir/ip-eth0")) {
214 $ip = $g->cat ("$dir/ip-eth0");
220 last if $transport || $key;
225 die __x("{n}: no transport or key found in guest.\nDoes it have the virt-tool-guest package installed?\n",
227 unless $transport && $key;
230 if ($ip =~ m{inet (\S+)/}) {
232 } elsif ($ip =~ m{inet6 (\S+)/}) {
235 die __"could not parse the content of ip-eth0 file from the guest";
239 if ($transport =~ /^udp:(\d+)/) {
240 die __"UDP transport, but no IP address in guest" unless $ip;
241 $transport = "udp:$ip:$1";
243 elsif ($transport =~ /^udp/) {
244 die __"UDP transport, but no IP address in guest" unless $ip;
245 $transport = "udp:$ip:161";
247 elsif ($transport =~ /^tcp:(\d+)/) {
248 die __"TCP transport, but no IP address in guest" unless $ip;
249 $transport = "tcp:$ip:$1";
251 elsif ($transport =~ /^tcp/) {
252 die __"TCP transport, but no IP address in guest" unless $ip;
253 $transport = "tcp:$ip:161";
256 die __x("unknown transport type: {t}", t => $transport);
259 # Test the transport works.
260 die __x("transport {t} does not work", t => $transport)
261 unless test_transport ($transport, $key);
263 print STDERR "try to write $transport to $cachedir/$uuid\n" if $verbose;
265 if (open FILE, ">$cachedir/$uuid") {
266 print FILE $transport;
276 my $transport = shift;
280 my $cmd = "virt-tools-get-key";
281 $cmd .= " -v" if $verbose;
283 $cmd .= " -c '$uri'" if $uri;
284 $cmd .= " '$domname'";
286 print STDERR "$cmd\n" if $verbose;
288 open PIPE, "$cmd |" or die "$cmd: $!";
290 die __"no response from virt-tools-get-key\n" unless $key;
295 my ($hostname, $port, $domain);
296 if ($transport =~ /^udp:(.*):(.*)/) {
300 } elsif ($transport =~ /^tcp:(.*):(.*)/) {
305 die __x("unknown transport type: {t}", t => $transport);
309 print STDERR "creating Net::SNMP session to $domain:$hostname:$port with key $key\n"
312 my ($session, $error) = Net::SNMP->session (
314 -username => "virttools",
315 -authpassword => $key,
316 -authprotocol => "sha",
317 -privpassword => $key,
318 -privprotocol => "aes",
319 -hostname => $hostname,
323 return 0 unless $session;
325 my $sysUpTime = "1.3.6.1.2.1.1.3.0";
326 my $r = $session->get_request (-varbindlist => [$sysUpTime])
328 print STDERR "test_transport: sysUpTime = $r->{$sysUpTime}\n" if $verbose;
341 L<Sys::Guestfs::Lib(3)>,
343 L<http://libguestfs.org/>.
351 Richard W.M. Jones (C<rjones at redhat dot com>)
355 Matthew Booth (C<mbooth at redhat dot com>)
361 Copyright (C) 2009 Red Hat Inc.
363 This program is free software; you can redistribute it and/or modify
364 it under the terms of the GNU General Public License as published by
365 the Free Software Foundation; either version 2 of the License, or
366 (at your option) any later version.
368 This program is distributed in the hope that it will be useful,
369 but WITHOUT ANY WARRANTY; without even the implied warranty of
370 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
371 GNU General Public License for more details.
373 You should have received a copy of the GNU General Public License
374 along with this program; if not, write to the Free Software
375 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.