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