virt-ping
[virt-tools.git] / tools / virt-ifconfig.pl
1 #!/usr/bin/perl -w
2 # virt-ifconfig
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 Sys::Guestfs;
22 use Sys::Guestfs::Lib qw(open_guest get_partitions);
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-ifconfig - Display IP address of a virtual machine
32
33 =head1 SYNOPSIS
34
35  virt-ifconfig [--options] domname
36
37  virt-ifconfig [--options]
38
39 =head1 DESCRIPTION
40
41 C<virt-ifconfig domname> displays the IP address of a virtual machine
42 named C<domname>, where C<domname> is the libvirt name.  If no
43 C<domname> is given, this lists out the IP addresses of all running
44 virtual machines known to libvirt.
45
46 For Linux guests, this only works if the C<virt-tools-guest> package
47 is installed in the guest.
48
49 =head1 OPTIONS
50
51 =over 4
52
53 =cut
54
55 my $help;
56
57 =item B<--help>
58
59 Display brief help.
60
61 =cut
62
63 my $version;
64
65 =item B<--version>
66
67 Display version number and exit.
68
69 =cut
70
71 my $uri;
72
73 =item B<--connect URI> | B<-c URI>
74
75 If using libvirt, connect to the given I<URI>.  If omitted, then we
76 connect to the default libvirt hypervisor.
77
78 =cut
79
80 my $csv;
81
82 =item B<--csv>
83
84 Write out the results in CSV format (comma-separated values).  This
85 format can be imported easily into databases and spreadsheets, but
86 read L</NOTE ABOUT CSV FORMAT> below.
87
88 =back
89
90 =cut
91
92 GetOptions ("help|?" => \$help,
93             "version" => \$version,
94             "connect|c=s" => \$uri,
95             "csv" => \$csv,
96     ) or pod2usage (2);
97 pod2usage (1) if $help;
98 if ($version) {
99     print "@PACKAGE_STRING@\n";
100     exit
101 }
102
103 # Open the guest handle.
104
105 if (@ARGV == 0) {
106     my $conn;
107
108     if ($uri) {
109         $conn = Sys::Virt->new (readonly => 1, address => $uri);
110     } else {
111         $conn = Sys::Virt->new (readonly => 1);
112     }
113
114     # Ignore inactive domains - who cares about their IP address?
115     my @doms = $conn->list_domains ();
116
117     my @domnames = map { $_->get_name () } @doms;
118
119     if (@domnames) {
120         print_title ();
121         foreach (@domnames) {
122             do_ifconfig ($_);
123         }
124     }
125 } else {
126     print_title ();
127     do_ifconfig (@ARGV);
128 }
129
130 sub print_title
131 {
132     print_row (__"Guest", __"Iface", __"Family", __"IP address");
133 }
134
135 sub print_row
136 {
137     my $domname = shift;
138     my $iface = shift;
139     my $family = shift;
140     my $ip = shift;
141
142     if (!$csv) {
143         printf ("%-20s %-7s %-7s %s\n", $domname, $iface, $family, $ip);
144     } else {
145         printf ("%s,%s,%s,%s\n", $domname, $iface, $family, $ip);
146     }
147 }
148
149 sub do_ifconfig
150 {
151     my @args = @_;
152     my $g;
153
154     if ($uri) {
155         $g = open_guest (\@args, address => $uri);
156     } else {
157         $g = open_guest (\@args);
158     }
159
160     $g->launch ();
161
162     # Don't care about mountpoints.  Instead, just look for a
163     # directory with one of a selection of names on one of the
164     # partitions that we found.
165     my @partitions = get_partitions ($g);
166
167     my %ips;
168     foreach my $partition (@partitions) {
169         eval {
170             $g->mount_ro ($partition, "/");
171             my $dir;
172             my @dirs = ("/var/lib/virt-tools", "/lib/virt-tools");
173             foreach $dir (@dirs) {
174                 if ($g->is_dir ($dir)) {
175                     my @names = $g->ls ($dir);
176                     @names = grep { /^ip-/ } @names;
177                     my $name;
178                     foreach $name (@names) {
179                         my $iface = $name;
180                         $iface =~ s/^ip-//;
181                         eval {
182                             my @lines = $g->read_lines ("$dir/$name");
183                             foreach (@lines) {
184                                 if (m{^\s*inet (\S+)/\d+ }) {
185                                     $ips{$iface}{inet} = []
186                                         unless exists $ips{$iface}{inet};
187                                     push @{$ips{$iface}{inet}}, $1;
188                                 } elsif (m{^\s*inet6 (\S+)/\d+ }) {
189                                     $ips{$iface}{inet6} = []
190                                         unless exists $ips{$iface}{inet6};
191                                     push @{$ips{$iface}{inet6}}, $1;
192                                 }
193                             }
194                         }
195                     }
196                 }
197             }
198         };
199         $g->umount_all ();
200     }
201
202     my @ifaces = sort keys %ips;
203     if (@ifaces) {
204         my $iface;
205         foreach $iface (@ifaces) {
206             my @families = sort keys %{$ips{$iface}};
207             my $family;
208             foreach $family (@families) {
209                 foreach (@{$ips{$iface}{$family}}) {
210                     print_row ($args[0], $iface, $family, $_);
211                 }
212             }
213         }
214     } else {
215         print STDERR
216             __x("{n}: no IP address found (is it running virt-tools-guest?)\n",
217                 n => $args[0]);
218     }
219 }
220
221 exit 0;
222
223 =head1 NOTE ABOUT CSV FORMAT
224
225 Comma-separated values (CSV) is a deceptive format.  It I<seems> like
226 it should be easy to parse, but it is definitely not easy to parse.
227
228 Myth: Just split fields at commas.  Reality: This does I<not> work
229 reliably.  This example has two columns:
230
231  "foo,bar",baz
232
233 Myth: Read the file one line at a time.  Reality: This does I<not>
234 work reliably.  This example has one row:
235
236  "foo
237  bar",baz
238
239 For shell scripts, use C<csvtool> (L<http://merjis.com/developers/csv>
240 also packaged in major Linux distributions).
241
242 For other languages, use a CSV processing library (eg. C<Text::CSV>
243 for Perl or Python's built-in csv library).
244
245 Most spreadsheets and databases can import CSV directly.
246
247 =head1 SEE ALSO
248
249 L<virt-tools(8)>,
250 L<guestfs(3)>,
251 L<guestfish(1)>,
252 L<Sys::Guestfs(3)>,
253 L<Sys::Guestfs::Lib(3)>,
254 L<Sys::Virt(3)>,
255 L<http://libguestfs.org/>.
256
257 =head1 AUTHOR
258
259 Richard W.M. Jones L<http://et.redhat.com/~rjones/>
260
261 =head1 COPYRIGHT
262
263 Copyright (C) 2009 Red Hat Inc.
264
265 This program is free software; you can redistribute it and/or modify
266 it under the terms of the GNU General Public License as published by
267 the Free Software Foundation; either version 2 of the License, or
268 (at your option) any later version.
269
270 This program is distributed in the hope that it will be useful,
271 but WITHOUT ANY WARRANTY; without even the implied warranty of
272 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
273 GNU General Public License for more details.
274
275 You should have received a copy of the GNU General Public License
276 along with this program; if not, write to the Free Software
277 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.