mirror of
https://github.com/libguestfs/libguestfs.git
synced 2026-03-21 22:53:37 +00:00
Move miscellaneous documentation from examples/ to docs/.
Wasn't very logical putting these doc files in the examples directory.
This commit is contained in:
86
docs/Makefile.am
Normal file
86
docs/Makefile.am
Normal file
@@ -0,0 +1,86 @@
|
||||
# libguestfs documentation
|
||||
# Copyright (C) 2010-2015 Red Hat Inc.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
include $(top_srcdir)/subdir-rules.mk
|
||||
|
||||
EXTRA_DIST = \
|
||||
guestfs-faq.pod \
|
||||
guestfs-performance.pod \
|
||||
guestfs-recipes.pod \
|
||||
guestfs-testing.pod \
|
||||
README
|
||||
|
||||
CLEANFILES = \
|
||||
stamp-guestfs-faq.pod \
|
||||
stamp-guestfs-performance.pod \
|
||||
stamp-guestfs-recipes.pod \
|
||||
stamp-guestfs-testing.pod
|
||||
|
||||
man_MANS = \
|
||||
guestfs-faq.1 \
|
||||
guestfs-performance.1 \
|
||||
guestfs-recipes.1 \
|
||||
guestfs-testing.1
|
||||
noinst_DATA = \
|
||||
$(top_builddir)/html/guestfs-faq.1.html \
|
||||
$(top_builddir)/html/guestfs-performance.1.html \
|
||||
$(top_builddir)/html/guestfs-recipes.1.html \
|
||||
$(top_builddir)/html/guestfs-testing.1.html
|
||||
|
||||
guestfs-faq.1 $(top_builddir)/html/guestfs-faq.1.html: stamp-guestfs-faq.pod
|
||||
|
||||
stamp-guestfs-faq.pod: guestfs-faq.pod
|
||||
$(PODWRAPPER) \
|
||||
--section 1 \
|
||||
--man guestfs-faq.1 \
|
||||
--html $(top_builddir)/html/guestfs-faq.1.html \
|
||||
--license LGPLv2+ \
|
||||
$<
|
||||
touch $@
|
||||
|
||||
guestfs-performance.1 $(top_builddir)/html/guestfs-performance.1.html: stamp-guestfs-performance.pod
|
||||
|
||||
stamp-guestfs-performance.pod: guestfs-performance.pod
|
||||
$(PODWRAPPER) \
|
||||
--section 1 \
|
||||
--man guestfs-performance.1 \
|
||||
--html $(top_builddir)/html/guestfs-performance.1.html \
|
||||
--license LGPLv2+ \
|
||||
$<
|
||||
touch $@
|
||||
|
||||
guestfs-recipes.1 $(top_builddir)/html/guestfs-recipes.1.html: stamp-guestfs-recipes.pod
|
||||
|
||||
stamp-guestfs-recipes.pod: guestfs-recipes.pod
|
||||
$(PODWRAPPER) \
|
||||
--section 1 \
|
||||
--man guestfs-recipes.1 \
|
||||
--html $(top_builddir)/html/guestfs-recipes.1.html \
|
||||
--license examples \
|
||||
$<
|
||||
touch $@
|
||||
|
||||
guestfs-testing.1 $(top_builddir)/html/guestfs-testing.1.html: stamp-guestfs-testing.pod
|
||||
|
||||
stamp-guestfs-testing.pod: guestfs-testing.pod
|
||||
$(PODWRAPPER) \
|
||||
--section 1 \
|
||||
--man guestfs-testing.1 \
|
||||
--html $(top_builddir)/html/guestfs-testing.1.html \
|
||||
--license LGPLv2+ \
|
||||
$<
|
||||
touch $@
|
||||
11
docs/README
Normal file
11
docs/README
Normal file
@@ -0,0 +1,11 @@
|
||||
This directory contains miscellaneous manual pages which don't fit
|
||||
elsewhere.
|
||||
|
||||
Most libguestfs documentation is in manual pages. The source for
|
||||
those manual pages are POD files (*.pod), and they are normally
|
||||
located next to the source files they relate to (eg. guestfish
|
||||
documentation is in fish/guestfish.pod).
|
||||
|
||||
All manual pages are available online at http://libguestfs.org/
|
||||
|
||||
The main API documentation is: http://libguestfs.org/guestfs.3.html
|
||||
1382
docs/guestfs-faq.pod
Normal file
1382
docs/guestfs-faq.pod
Normal file
File diff suppressed because it is too large
Load Diff
585
docs/guestfs-performance.pod
Normal file
585
docs/guestfs-performance.pod
Normal file
@@ -0,0 +1,585 @@
|
||||
=head1 NAME
|
||||
|
||||
guestfs-performance - engineering libguestfs for greatest performance
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This page documents how to get the greatest performance out of
|
||||
libguestfs, especially when you expect to use libguestfs to manipulate
|
||||
thousands of virtual machines or disk images.
|
||||
|
||||
Three main areas are covered. Libguestfs runs an appliance (a small
|
||||
Linux distribution) inside qemu/KVM. The first two areas are:
|
||||
minimizing the time taken to start this appliance, and the number of
|
||||
times the appliance has to be started. The third area is shortening
|
||||
the time taken for inspection of VMs.
|
||||
|
||||
=head1 BASELINE MEASUREMENTS
|
||||
|
||||
Before making changes to how you use libguestfs, take baseline
|
||||
measurements.
|
||||
|
||||
=head2 Baseline: Starting the appliance
|
||||
|
||||
On an unloaded machine, time how long it takes to start up the
|
||||
appliance:
|
||||
|
||||
time guestfish -a /dev/null run
|
||||
|
||||
Run this command several times in a row and discard the first few
|
||||
runs, so that you are measuring a typical "hot cache" case.
|
||||
|
||||
=head3 Explanation
|
||||
|
||||
This command starts up the libguestfs appliance on a null disk, and
|
||||
then immediately shuts it down. The first time you run the command,
|
||||
it will create an appliance and cache it (usually under
|
||||
F</var/tmp/.guestfs-*>). Subsequent runs should reuse the cached
|
||||
appliance.
|
||||
|
||||
=head3 Expected results
|
||||
|
||||
You should expect to be getting times under 6 seconds. If the times
|
||||
you see on an unloaded machine are above this, then see the section
|
||||
L</TROUBLESHOOTING POOR PERFORMANCE> below.
|
||||
|
||||
=head2 Baseline: Performing inspection of a guest
|
||||
|
||||
For this test you will need an unloaded machine and at least one real
|
||||
guest or disk image. If you are planning to use libguestfs against
|
||||
only X guests (eg. X = Windows), then using an X guest here would be
|
||||
most appropriate. If you are planning to run libguestfs against a mix
|
||||
of guests, then use a mix of guests for testing here.
|
||||
|
||||
Time how long it takes to perform inspection and mount the disks of
|
||||
the guest. Use the first command if you will be using disk images,
|
||||
and the second command if you will be using libvirt.
|
||||
|
||||
time guestfish --ro -a disk.img -i exit
|
||||
|
||||
time guestfish --ro -d GuestName -i exit
|
||||
|
||||
Run the command several times in a row and discard the first few runs,
|
||||
so that you are measuring a typical "hot cache" case.
|
||||
|
||||
=head3 Explanation
|
||||
|
||||
This command starts up the libguestfs appliance on the named disk
|
||||
image or libvirt guest, performs libguestfs inspection on it (see
|
||||
L<guestfs(3)/INSPECTION>), mounts the guest's disks, then discards all
|
||||
these results and shuts down.
|
||||
|
||||
The first time you run the command, it will create an appliance and
|
||||
cache it (usually under F</var/tmp/.guestfs-*>). Subsequent runs
|
||||
should reuse the cached appliance.
|
||||
|
||||
=head3 Expected results
|
||||
|
||||
You should expect times which are E<le> 5 seconds greater than
|
||||
measured in the first baseline test above. (For example, if the first
|
||||
baseline test ran in 5 seconds, then this test should run in E<le> 10
|
||||
seconds).
|
||||
|
||||
=head1 UNDERSTANDING THE APPLIANCE AND WHEN IT IS BUILT/CACHED
|
||||
|
||||
The first time you use libguestfs, it will build and cache an
|
||||
appliance. This is usually in F</var/tmp/.guestfs-*>, unless you have
|
||||
set C<$TMPDIR> or C<$LIBGUESTFS_CACHEDIR> in which case it will be
|
||||
under that temporary directory.
|
||||
|
||||
For more information about how the appliance is constructed, see
|
||||
L<supermin(1)/SUPERMIN APPLIANCES>.
|
||||
|
||||
Every time libguestfs runs it will check that no host files used by
|
||||
the appliance have changed. If any have, then the appliance is
|
||||
rebuilt. This usually happens when a package is installed or updated
|
||||
on the host (eg. using programs like C<yum> or C<apt-get>). The
|
||||
reason for reconstructing the appliance is security: the new program
|
||||
that has been installed might contain a security fix, and so we want
|
||||
to include the fixed program in the appliance automatically.
|
||||
|
||||
These are the performance implications:
|
||||
|
||||
=over 4
|
||||
|
||||
=item *
|
||||
|
||||
The process of building (or rebuilding) the cached appliance is slow,
|
||||
and you can avoid this happening by using a fixed appliance (see
|
||||
below).
|
||||
|
||||
=item *
|
||||
|
||||
If not using a fixed appliance, be aware that updating software on the
|
||||
host will cause a one time rebuild of the appliance.
|
||||
|
||||
=item *
|
||||
|
||||
F</var/tmp> (or C<$TMPDIR>, C<$LIBGUESTFS_CACHEDIR>) should be on a
|
||||
fast disk, and have plenty of space for the appliance.
|
||||
|
||||
=back
|
||||
|
||||
=head1 USING A FIXED APPLIANCE
|
||||
|
||||
To fully control when the appliance is built, you can build a fixed
|
||||
appliance. This appliance should be stored on a fast local disk.
|
||||
|
||||
To build the appliance, run the command:
|
||||
|
||||
libguestfs-make-fixed-appliance <directory>
|
||||
|
||||
replacing C<E<lt>directoryE<gt>> with the name of a directory where
|
||||
the appliance will be stored (normally you would name a subdirectory,
|
||||
for example: F</usr/local/lib/guestfs/appliance> or
|
||||
F</dev/shm/appliance>).
|
||||
|
||||
Then set C<$LIBGUESTFS_PATH> (and ensure this environment variable is
|
||||
set in your libguestfs program), or modify your program so it calls
|
||||
C<guestfs_set_path>. For example:
|
||||
|
||||
export LIBGUESTFS_PATH=/usr/local/lib/guestfs/appliance
|
||||
|
||||
Now you can run libguestfs programs, virt tools, guestfish etc. as
|
||||
normal. The programs will use your fixed appliance, and will not ever
|
||||
build, rebuild, or cache their own appliance.
|
||||
|
||||
(For detailed information on this subject, see:
|
||||
L<libguestfs-make-fixed-appliance(1)>).
|
||||
|
||||
=head2 Performance of the fixed appliance
|
||||
|
||||
In our testing we did not find that using a fixed appliance gave any
|
||||
measurable performance benefit, even when the appliance was located in
|
||||
memory (ie. on F</dev/shm>). However there are two points to
|
||||
consider:
|
||||
|
||||
=over 4
|
||||
|
||||
=item 1.
|
||||
|
||||
Using a fixed appliance stops libguestfs from ever rebuilding the
|
||||
appliance, meaning that libguestfs will have more predictable start-up
|
||||
times.
|
||||
|
||||
=item 2.
|
||||
|
||||
The appliance is loaded on demand. A simple test such as:
|
||||
|
||||
time guestfish -a /dev/null run
|
||||
|
||||
does not load very much of the appliance. A real libguestfs program
|
||||
using complicated API calls would demand-load a lot more of the
|
||||
appliance. Being able to store the appliance in a specified location
|
||||
makes the performance more predictable.
|
||||
|
||||
=back
|
||||
|
||||
=head1 REDUCING THE NUMBER OF TIMES THE APPLIANCE IS LAUNCHED
|
||||
|
||||
By far the most effective, though not always the simplest way to get
|
||||
good performance is to ensure that the appliance is launched the
|
||||
minimum number of times. This will probably involve changing your
|
||||
libguestfs application.
|
||||
|
||||
Try to call C<guestfs_launch> at most once per target virtual machine
|
||||
or disk image.
|
||||
|
||||
Instead of using a separate instance of L<guestfish(1)> to make a
|
||||
series of changes to the same guest, use a single instance of
|
||||
guestfish and/or use the guestfish I<--listen> option.
|
||||
|
||||
Consider writing your program as a daemon which holds a guest open
|
||||
while making a series of changes. Or marshal all the operations you
|
||||
want to perform before opening the guest.
|
||||
|
||||
You can also try adding disks from multiple guests to a single
|
||||
appliance. Before trying this, note the following points:
|
||||
|
||||
=over 4
|
||||
|
||||
=item 1.
|
||||
|
||||
Adding multiple guests to one appliance is a security problem because
|
||||
it may allow one guest to interfere with the disks of another guest.
|
||||
Only do it if you trust all the guests, or if you can group guests by
|
||||
trust.
|
||||
|
||||
=item 2.
|
||||
|
||||
There is a hard limit to the number of disks you can add to a single
|
||||
appliance. Call L<guestfs(3)/guestfs_max_disks> to get this limit.
|
||||
For further information see L<guestfs(3)/LIMITS>.
|
||||
|
||||
=item 3.
|
||||
|
||||
Using libguestfs this way is complicated. Disks can have unexpected
|
||||
interactions: for example, if two guests use the same UUID for a
|
||||
filesystem (because they were cloned), or have volume groups with the
|
||||
same name (but see C<guestfs_lvm_set_filter>).
|
||||
|
||||
=back
|
||||
|
||||
L<virt-df(1)> adds multiple disks by default, so the source code for
|
||||
this program would be a good place to start.
|
||||
|
||||
=head1 SHORTENING THE TIME TAKEN FOR INSPECTION OF VMs
|
||||
|
||||
The main advice is obvious: Do not perform inspection (which is
|
||||
expensive) unless you need the results.
|
||||
|
||||
If you previously performed inspection on the guest, then it may be
|
||||
safe to cache and reuse the results from last time.
|
||||
|
||||
Some disks don't need to be inspected at all: for example, if you are
|
||||
creating a disk image, or if the disk image is not a VM, or if the
|
||||
disk image has a known layout.
|
||||
|
||||
Even when basic inspection (C<guestfs_inspect_os>) is required,
|
||||
auxiliary inspection operations may be avoided:
|
||||
|
||||
=over 4
|
||||
|
||||
=item *
|
||||
|
||||
Mounting disks is only necessary to get further filesystem
|
||||
information.
|
||||
|
||||
=item *
|
||||
|
||||
Listing applications (C<guestfs_inspect_list_applications>) is an
|
||||
expensive operation on Linux, but almost free on Windows.
|
||||
|
||||
=item *
|
||||
|
||||
Generating a guest icon (C<guestfs_inspect_get_icon>) is cheap on
|
||||
Linux but expensive on Windows.
|
||||
|
||||
=back
|
||||
|
||||
=head1 PARALLEL APPLIANCES
|
||||
|
||||
Libguestfs appliances are mostly I/O bound and you can launch multiple
|
||||
appliances in parallel. Provided there is enough free memory, there
|
||||
should be little difference in launching 1 appliance vs N appliances
|
||||
in parallel.
|
||||
|
||||
On a 2-core (4-thread) laptop with 16 GB of RAM, using the (not
|
||||
especially realistic) test Perl script below, the following plot shows
|
||||
excellent scalability when running between 1 and 20 appliances in
|
||||
parallel:
|
||||
|
||||
12 ++---+----+----+----+-----+----+----+----+----+---++
|
||||
+ + + + + + + + + + *
|
||||
| |
|
||||
| * |
|
||||
11 ++ ++
|
||||
| |
|
||||
| |
|
||||
| * * |
|
||||
10 ++ ++
|
||||
| * |
|
||||
| |
|
||||
s | |
|
||||
9 ++ ++
|
||||
e | |
|
||||
| * |
|
||||
c | |
|
||||
8 ++ * ++
|
||||
o | * |
|
||||
| |
|
||||
n 7 ++ ++
|
||||
| * |
|
||||
d | * |
|
||||
| |
|
||||
s 6 ++ ++
|
||||
| * * |
|
||||
| * |
|
||||
| |
|
||||
5 ++ ++
|
||||
| |
|
||||
| * |
|
||||
| * * |
|
||||
4 ++ ++
|
||||
| |
|
||||
| |
|
||||
+ * * * + + + + + + + +
|
||||
3 ++-*-+----+----+----+-----+----+----+----+----+---++
|
||||
0 2 4 6 8 10 12 14 16 18 20
|
||||
number of parallel appliances
|
||||
|
||||
It is possible to run many more than 20 appliances in parallel, but if
|
||||
you are using the libvirt backend then you should be aware that out of
|
||||
the box libvirt limits the number of client connections to 20.
|
||||
|
||||
The simple Perl script below was used to collect the data for the plot
|
||||
above, but there is much more information on this subject, including
|
||||
more advanced test scripts and graphs, available in the following blog
|
||||
postings:
|
||||
|
||||
L<http://rwmj.wordpress.com/2013/02/25/multiple-libguestfs-appliances-in-parallel-part-1/>
|
||||
L<http://rwmj.wordpress.com/2013/02/25/multiple-libguestfs-appliances-in-parallel-part-2/>
|
||||
L<http://rwmj.wordpress.com/2013/02/25/multiple-libguestfs-appliances-in-parallel-part-3/>
|
||||
L<http://rwmj.wordpress.com/2013/02/25/multiple-libguestfs-appliances-in-parallel-part-4/>
|
||||
|
||||
#!/usr/bin/env perl
|
||||
|
||||
use strict;
|
||||
use threads;
|
||||
use warnings;
|
||||
use Sys::Guestfs;
|
||||
use Time::HiRes qw(time);
|
||||
|
||||
sub test {
|
||||
my $g = Sys::Guestfs->new;
|
||||
$g->add_drive_ro ("/dev/null");
|
||||
$g->launch ();
|
||||
|
||||
# You could add some work for libguestfs to do here.
|
||||
|
||||
$g->close ();
|
||||
}
|
||||
|
||||
# Get everything into cache.
|
||||
test (); test (); test ();
|
||||
|
||||
for my $nr_threads (1..20) {
|
||||
my $start_t = time ();
|
||||
my @threads;
|
||||
foreach (1..$nr_threads) {
|
||||
push @threads, threads->create (\&test)
|
||||
}
|
||||
foreach (@threads) {
|
||||
$_->join ();
|
||||
if (my $err = $_->error ()) {
|
||||
die "launch failed with $nr_threads threads: $err"
|
||||
}
|
||||
}
|
||||
my $end_t = time ();
|
||||
printf ("%d %.2f\n", $nr_threads, $end_t - $start_t);
|
||||
}
|
||||
|
||||
=head1 USING USER-MODE LINUX
|
||||
|
||||
Since libguestfs 1.24, it has been possible to use the User-Mode Linux
|
||||
(uml) backend instead of KVM
|
||||
(see L<guestfs(3)/USER-MODE LINUX BACKEND>). This section makes some
|
||||
general remarks about this backend, but it is B<highly advisable> to
|
||||
measure your own workload under UML rather than trusting comments or
|
||||
intuition.
|
||||
|
||||
=over 4
|
||||
|
||||
=item *
|
||||
|
||||
UML usually performs the same or slightly slower than KVM, on baremetal.
|
||||
|
||||
=item *
|
||||
|
||||
However UML often performs the same under virtualization as it does on
|
||||
baremetal, whereas KVM can run much slower under virtualization (since
|
||||
hardware virt acceleration is not available).
|
||||
|
||||
=item *
|
||||
|
||||
Upload and download is as much as 10 times slower on UML than KVM.
|
||||
Libguestfs sends this data over the UML emulated serial port, which is
|
||||
far less efficient than KVM's virtio-serial.
|
||||
|
||||
=item *
|
||||
|
||||
UML lacks some features (eg. qcow2 support), so it may not be
|
||||
applicable at all.
|
||||
|
||||
=back
|
||||
|
||||
For some actual figures, see:
|
||||
L<http://rwmj.wordpress.com/2013/08/14/performance-of-user-mode-linux-as-a-libguestfs-backend/#content>
|
||||
|
||||
=head1 TROUBLESHOOTING POOR PERFORMANCE
|
||||
|
||||
=head2 Ensure hardware virtualization is available
|
||||
|
||||
Use F</proc/cpuinfo> and this page:
|
||||
|
||||
http://virt-tools.org/learning/check-hardware-virt/
|
||||
|
||||
to ensure that hardware virtualization is available. Note that you
|
||||
may need to enable it in your BIOS.
|
||||
|
||||
Hardware virt is not usually available inside VMs, and libguestfs will
|
||||
run slowly inside another virtual machine whatever you do. Nested
|
||||
virtualization does not work well in our experience, and is certainly
|
||||
no substitute for running libguestfs on baremetal.
|
||||
|
||||
=head2 Ensure KVM is available
|
||||
|
||||
Ensure that KVM is enabled and available to the user that will run
|
||||
libguestfs. It should be safe to set 0666 permissions on F</dev/kvm>
|
||||
and most distributions now do this.
|
||||
|
||||
=head2 Processors to avoid
|
||||
|
||||
Avoid processors that don't have hardware virtualization, and some
|
||||
processors which are simply very slow (AMD Geode being a great
|
||||
example).
|
||||
|
||||
=head2 Xen dom0
|
||||
|
||||
In Xen, dom0 is a virtual machine, and so hardware virtualization is
|
||||
not available.
|
||||
|
||||
=head1 DETAILED TIMINGS USING TS
|
||||
|
||||
Use the L<ts(1)> command (from moreutils) to show detailed
|
||||
timings:
|
||||
|
||||
$ guestfish -a /dev/null run -v |& ts -i '%.s'
|
||||
0.000022 libguestfs: launch: program=guestfish
|
||||
0.000134 libguestfs: launch: version=1.29.31fedora=23,release=2.fc23,libvirt
|
||||
0.000044 libguestfs: launch: backend registered: unix
|
||||
0.000035 libguestfs: launch: backend registered: uml
|
||||
0.000035 libguestfs: launch: backend registered: libvirt
|
||||
0.000032 libguestfs: launch: backend registered: direct
|
||||
0.000030 libguestfs: launch: backend=libvirt
|
||||
0.000031 libguestfs: launch: tmpdir=/tmp/libguestfsw18rBQ
|
||||
0.000029 libguestfs: launch: umask=0002
|
||||
0.000031 libguestfs: launch: euid=1000
|
||||
0.000030 libguestfs: libvirt version = 1002012 (1.2.12)
|
||||
[etc]
|
||||
|
||||
The timestamps are seconds (incrementally since the previous line).
|
||||
|
||||
=head1 DETAILED TIMINGS USING SYSTEMTAP
|
||||
|
||||
You can use SystemTap (L<stap(1)>) to get detailed timings from
|
||||
libguestfs programs.
|
||||
|
||||
Save the following script as F<time.stap>:
|
||||
|
||||
global last;
|
||||
|
||||
function display_time () {
|
||||
now = gettimeofday_us ();
|
||||
delta = 0;
|
||||
if (last > 0)
|
||||
delta = now - last;
|
||||
last = now;
|
||||
|
||||
printf ("%d (+%d):", now, delta);
|
||||
}
|
||||
|
||||
probe begin {
|
||||
last = 0;
|
||||
printf ("ready\n");
|
||||
}
|
||||
|
||||
/* Display all calls to static markers. */
|
||||
probe process("/usr/lib*/libguestfs.so.0")
|
||||
.provider("guestfs").mark("*") ? {
|
||||
display_time();
|
||||
printf ("\t%s %s\n", $$name, $$parms);
|
||||
}
|
||||
|
||||
/* Display all calls to guestfs_* functions. */
|
||||
probe process("/usr/lib*/libguestfs.so.0")
|
||||
.function("guestfs_[a-z]*") ? {
|
||||
display_time();
|
||||
printf ("\t%s %s\n", probefunc(), $$parms);
|
||||
}
|
||||
|
||||
Run it as root in one window:
|
||||
|
||||
# stap time.stap
|
||||
ready
|
||||
|
||||
It prints "ready" when SystemTap has loaded the program. Run your
|
||||
libguestfs program, guestfish or a virt tool in another window. For
|
||||
example:
|
||||
|
||||
$ guestfish -a /dev/null run
|
||||
|
||||
In the stap window you will see a large amount of output, with the
|
||||
time taken for each step shown (microseconds in parenthesis). For
|
||||
example:
|
||||
|
||||
xxxx (+0): guestfs_create
|
||||
xxxx (+29): guestfs_set_pgroup g=0x17a9de0 pgroup=0x1
|
||||
xxxx (+9): guestfs_add_drive_opts_argv g=0x17a9de0 [...]
|
||||
xxxx (+8): guestfs_int_safe_strdup g=0x17a9de0 str=0x7f8a153bed5d
|
||||
xxxx (+19): guestfs_int_safe_malloc g=0x17a9de0 nbytes=0x38
|
||||
xxxx (+5): guestfs_int_safe_strdup g=0x17a9de0 str=0x17a9f60
|
||||
xxxx (+10): guestfs_launch g=0x17a9de0
|
||||
xxxx (+4): launch_start
|
||||
[etc]
|
||||
|
||||
You will need to consult, and even modify, the source to libguestfs to
|
||||
fully understand the output.
|
||||
|
||||
=head1 DETAILED DEBUGGING USING GDB
|
||||
|
||||
You can attach to the appliance BIOS/kernel using gdb. If you know
|
||||
what you're doing, this can be a useful way to diagnose boot
|
||||
regressions.
|
||||
|
||||
Firstly, you have to change qemu so it runs with the C<-S> and C<-s>
|
||||
options. These options cause qemu to pause at boot and allow you to
|
||||
attach a debugger. Read L<qemu(1)> for further information.
|
||||
Libguestfs invokes qemu several times (to scan the help output and so
|
||||
on) and you only want the final invocation of qemu to use these
|
||||
options, so use a qemu wrapper script like this:
|
||||
|
||||
#!/bin/bash -
|
||||
|
||||
# Set this to point to the real qemu binary.
|
||||
qemu=/usr/bin/qemu-kvm
|
||||
|
||||
if [ "$1" != "-global" ]; then
|
||||
# Scanning help output etc.
|
||||
exec $qemu "$@"
|
||||
else
|
||||
# Really running qemu.
|
||||
exec $qemu -S -s "$@"
|
||||
fi
|
||||
|
||||
Now run guestfish or another libguestfs tool with the qemu wrapper
|
||||
(see L<guestfs(3)/QEMU WRAPPERS> to understand what this is doing):
|
||||
|
||||
LIBGUESTFS_HV=/path/to/qemu-wrapper guestfish -a /dev/null -v run
|
||||
|
||||
This should pause just after qemu launches. In another window, attach
|
||||
to qemu using gdb:
|
||||
|
||||
$ gdb
|
||||
(gdb) set architecture i8086
|
||||
The target architecture is assumed to be i8086
|
||||
(gdb) target remote :1234
|
||||
Remote debugging using :1234
|
||||
0x0000fff0 in ?? ()
|
||||
(gdb) cont
|
||||
|
||||
At this point you can use standard gdb techniques, eg. hitting C<^C>
|
||||
to interrupt the boot and C<bt> get a stack trace, setting
|
||||
breakpoints, etc. Note that when you are past the BIOS and into the
|
||||
Linux kernel, you'll want to change the architecture back to 32 or 64
|
||||
bit.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<supermin(1)>,
|
||||
L<guestfish(1)>,
|
||||
L<guestfs(3)>,
|
||||
L<guestfs-examples(3)>,
|
||||
L<libguestfs-make-fixed-appliance(1)>,
|
||||
L<stap(1)>,
|
||||
L<qemu(1)>,
|
||||
L<gdb(1)>,
|
||||
L<http://libguestfs.org/>.
|
||||
|
||||
=head1 AUTHORS
|
||||
|
||||
Richard W.M. Jones (C<rjones at redhat dot com>)
|
||||
|
||||
=head1 COPYRIGHT
|
||||
|
||||
Copyright (C) 2012-2015 Red Hat Inc.
|
||||
689
docs/guestfs-recipes.pod
Normal file
689
docs/guestfs-recipes.pod
Normal file
@@ -0,0 +1,689 @@
|
||||
=begin comment
|
||||
|
||||
We break with tradition here and don't use ALL CAPS for the section
|
||||
headings, as this makes them much easier to read.
|
||||
|
||||
=end comment
|
||||
|
||||
=head1 NAME
|
||||
|
||||
guestfs-recipes - libguestfs, guestfish and virt tools recipes
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This page contains recipes for and links to things you can do using
|
||||
libguestfs, L<guestfish(1)> and the virt tools.
|
||||
|
||||
=head1 Access a remote disk image using guestfish
|
||||
|
||||
If the disk image is on a remote server which is accessible using SSH,
|
||||
HTTP, FTP, NBD, iSCSI, or similar, then you can open it directly. See
|
||||
L<guestfish(1)/ADDING REMOTE STORAGE> for several examples. This
|
||||
requires libguestfs E<ge> 1.22 and qemu E<ge> 1.5.
|
||||
|
||||
=head1 Audit a virtual machine for setuid files
|
||||
|
||||
See: L<virt-ls(1)/EXAMPLES>.
|
||||
|
||||
=head1 Audit a virtual machine for vulnerabilities and security problems
|
||||
|
||||
See:
|
||||
L<https://rwmj.wordpress.com/2013/05/16/scanning-offline-guests-using-openscap-and-guestmount/#content>
|
||||
|
||||
=head1 Change the background image in a Windows XP VM
|
||||
|
||||
The links below explain how to use L<guestfish(1)> to change the
|
||||
background image for a user of a Windows XP VM. Unfortunately the
|
||||
technique appears to be substantially different for each version of
|
||||
Windows.
|
||||
|
||||
L<https://lists.fedoraproject.org/pipermail/virt/2011-May/002655.html>
|
||||
L<https://lists.fedoraproject.org/pipermail/virt/2011-May/002658.html>
|
||||
|
||||
=head1 Checksum a file or device within a disk image
|
||||
|
||||
To checksum a whole device, or a partition, LV etc within a disk image:
|
||||
|
||||
guestfish --ro -a disk.img run : checksum-device md5 /dev/sda1
|
||||
|
||||
Replace C<md5> with the type of checksum you want. See
|
||||
L<guestfs(3)/guestfs_checksum_device> for a list of supported types.
|
||||
|
||||
F</dev/sda1> means "the first partition". You could use F</dev/sda>
|
||||
to checksum the whole disk image, or the name of a logical volume or
|
||||
RAID device.
|
||||
|
||||
To checksum a single file:
|
||||
|
||||
guestfish --ro -a disk.img -i checksum sha256 /etc/passwd
|
||||
|
||||
or for a Windows guest:
|
||||
|
||||
guestfish --ro -a disk.img -i \
|
||||
checksum sha256 'win:\windows\system32\config\SOFTWARE'
|
||||
|
||||
=head1 Cloning a virtual machine
|
||||
|
||||
Use a combination of tools like L<cp(1)>, L<dd(1)>, and
|
||||
virt tools like L<virt-sysprep(1)>, L<virt-sparsify(1)>
|
||||
and L<virt-resize(1)>.
|
||||
|
||||
For more details, see: L<virt-sysprep(1)/COPYING AND CLONING>.
|
||||
|
||||
=head1 Convert a CD-ROM / DVD / ISO to a tarball
|
||||
|
||||
This converts input F<cd.iso> to output F<cd.tar.gz>:
|
||||
|
||||
guestfish --ro -a cd.iso -m /dev/sda tgz-out / cd.tar.gz
|
||||
|
||||
To export just a subdirectory, eg. F</files>, do:
|
||||
|
||||
guestfish --ro -a cd.iso -m /dev/sda tgz-out /files cd.tar.gz
|
||||
|
||||
=head1 Convert from one format/filesystem to another
|
||||
|
||||
If you have a data disk in one format / filesystem / partition /
|
||||
volume manager, you can convert it another using this technique.
|
||||
|
||||
In this example, we start with a data disk that has a single partition
|
||||
containing a filesystem, and we want to create another disk that
|
||||
contains the same files but on an ext3 filesystem embedded in a
|
||||
logical volume on a sparse raw-format disk.
|
||||
|
||||
First create the formatted-but-empty target disk:
|
||||
|
||||
truncate -s 10G target.img
|
||||
virt-format -a target.img --partition=mbr --lvm --filesystem=ext3
|
||||
|
||||
Now, pipe two guestfish instances together to transfer the old data to
|
||||
the new disk:
|
||||
|
||||
guestfish --ro -a source.img -m /dev/sda1 -- tar-out / - | \
|
||||
guestfish --rw -a target.img -m /dev/VG/LV -- tar-in - /
|
||||
|
||||
To browse the final disk image, do:
|
||||
|
||||
guestfish --ro -a target.img -m /dev/VG/LV
|
||||
><fs> ll /
|
||||
|
||||
This technique is quite powerful, allowing you for example to split up
|
||||
source directories over the target filesystems.
|
||||
|
||||
Note this won't work (at least, not directly) for bootable virtual
|
||||
machine disks because it doesn't copy over the boot loader.
|
||||
|
||||
=head1 Convert Windows DVD to bootable USB key
|
||||
|
||||
L<http://rwmj.wordpress.com/2013/05/09/tip-convert-a-windows-dvd-iso-to-a-bootable-usb-key-using-guestfish/#content>
|
||||
|
||||
=head1 Convert Xen-style partitionless image to partitioned disk image
|
||||
|
||||
Xen disk images are often partitionless, meaning that the filesystem
|
||||
starts directly at the beginning of the disk with no partition table.
|
||||
You can in fact use these directly in KVM (provided the guest isn't
|
||||
Windows), but some people like to convert them to regular partitioned
|
||||
disk images, and this is required for Windows guests. Here is how to
|
||||
use guestfish to do this:
|
||||
|
||||
guestfish
|
||||
><fs> add-ro input.img
|
||||
><fs> sparse output.img 10G # adjust the output size
|
||||
><fs> run
|
||||
# Create a partition table on the output disk:
|
||||
><fs> part-init /dev/sdb mbr
|
||||
><fs> part-add /dev/sdb p 2048 -2048
|
||||
# Copy the data to the target partition:
|
||||
><fs> copy-device-to-device /dev/sda /dev/sdb1 sparse:true
|
||||
# Optionally resize the target filesystem. Use ntfsresize
|
||||
# for Windows guests:
|
||||
><fs> resize2fs /dev/sdb1
|
||||
|
||||
Such a disk image won't be directly bootable. You may need to boot it
|
||||
with an external kernel and initramfs (see below). Or you can use the
|
||||
guestfish commands C<syslinux> or C<extlinux> to install a SYSLINUX
|
||||
bootloader.
|
||||
|
||||
=head1 Create empty disk images
|
||||
|
||||
The L<virt-format(1)> tool can do this directly.
|
||||
|
||||
Use L<virt-make-fs(1)> to create a disk image with content. This can
|
||||
also create some standard disk images such as virtual floppy devices
|
||||
(VFDs).
|
||||
|
||||
You can also use the L<guestfish(1)> I<-N> option to create empty disk
|
||||
images. The useful guide below explains the options available.
|
||||
|
||||
L<https://rwmj.wordpress.com/2010/09/08/new-guestfish-n-options-in-1-5-9/#content>
|
||||
|
||||
L<virt-builder(1)> can create minimal guests.
|
||||
|
||||
=head1 Delete a file (or other simple file operations)
|
||||
|
||||
Use guestfish. To delete a file:
|
||||
|
||||
guestfish -a disk.img -i rm /file/to/delete
|
||||
|
||||
To touch a file (bring it up to date or create it):
|
||||
|
||||
guestfish -a disk.img -i touch /file/to/touch
|
||||
|
||||
To stat a file. Since this is a read-only operation, we can make it
|
||||
safer by adding the I<--ro> flag.
|
||||
|
||||
guestfish --ro -a disk.img -i stat /file/to/stat
|
||||
|
||||
There are dozens of these commands. See L<guestfish(1)> or the output
|
||||
of C<guestfish -h>
|
||||
|
||||
=head1 Diff two guests; compare a snapshot to the current version
|
||||
|
||||
Since libguestfs E<ge> 1.26, use L<virt-diff(1)> to look for
|
||||
differences between two guests (for example if they were originally
|
||||
cloned from the same source), or between two snapshots from the same
|
||||
guest. In earlier versions of libguestfs, use L<virt-ls(1)>.
|
||||
|
||||
=head1 Disable a systemd service
|
||||
|
||||
The following is the equivalent of C<systemctl mask ...>. To disable
|
||||
the C<cloud-init> service so it doesn't start at next boot:
|
||||
|
||||
guestfish -a disk.img -i \
|
||||
ln-sf /dev/null /etc/systemd/system/cloud-init.service
|
||||
|
||||
To disable tmp-on-tmpfs:
|
||||
|
||||
guestfish -a disk.img -i \
|
||||
ln-sf /dev/null /etc/systemd/system/tmp.mount
|
||||
|
||||
One problem with the commands above is there is no feedback if you get
|
||||
the name of the service you are trying to mask wrong. But you can use
|
||||
L<virt-ls(1)> to list the available systemd services like this:
|
||||
|
||||
virt-ls -a /tmp/fedora-19.img -R /lib/systemd/system
|
||||
|
||||
=head1 Dump raw filesystem content from inside a disk image or VM
|
||||
|
||||
You can use the L<guestfish(1)> C<download> command to extract the raw
|
||||
filesystem content from any filesystem in a disk image or a VM (even
|
||||
one which is encrypted or buried inside an LV or RAID device):
|
||||
|
||||
guestfish --ro -a disk.img run : download /dev/sda1 sda1.img
|
||||
|
||||
guestfish --ro -d Guest run : download /dev/vg_guest/lv_root lv.img
|
||||
|
||||
To download to stdout, replace the filename with a C<-> character:
|
||||
|
||||
guestfish --ro -a disk.img run : download /dev/sda1 - | gzip > sda1.gz
|
||||
|
||||
To list the filesystems in a disk image, use L<virt-filesystems(1)>.
|
||||
|
||||
See also L</Uploading raw filesystem content>.
|
||||
|
||||
=head1 Edit grub configuration in a VM
|
||||
|
||||
You can use this to:
|
||||
|
||||
=over 4
|
||||
|
||||
=item *
|
||||
|
||||
Fix a virtual machine that does not boot.
|
||||
|
||||
=item *
|
||||
|
||||
Change which kernel is used to boot the VM.
|
||||
|
||||
=item *
|
||||
|
||||
Change kernel command line options.
|
||||
|
||||
=back
|
||||
|
||||
Use L<virt-edit(1)> to edit the grub configuration:
|
||||
|
||||
virt-edit -d BrokenGuest /boot/grub2/grub.cfg
|
||||
|
||||
or for general tinkering inside an unbootable VM use L<virt-rescue(1)>
|
||||
like this:
|
||||
|
||||
virt-rescue -d BrokenGuest
|
||||
|
||||
=head1 Export any directory from a VM
|
||||
|
||||
To export F</home> from a VM into a local directory use
|
||||
L<virt-copy-out(1)>:
|
||||
|
||||
virt-copy-out -d Guest /home .
|
||||
|
||||
Notes:
|
||||
|
||||
=over 4
|
||||
|
||||
=item *
|
||||
|
||||
The final dot of the command is not a printing error. It means we
|
||||
want to copy out to the current directory.
|
||||
|
||||
=item *
|
||||
|
||||
This creates a directory called C<home> under the current directory.
|
||||
|
||||
=back
|
||||
|
||||
If the guest is a Windows guest then you can use drive letters and
|
||||
backslashes, but you must prefix the path with C<win:> and quote it to
|
||||
protect it from the shell, like this:
|
||||
|
||||
virt-copy-out -d WinGuest 'win:c:\windows\system32\config' .
|
||||
|
||||
To get the output as a compressed tarball, do:
|
||||
|
||||
virt-tar-out -d Guest /home - | gzip --best > home.tar.gz
|
||||
|
||||
Although it sounds tempting, this is usually not a reliable way to get
|
||||
a backup from a running guest. See the entry in the FAQ:
|
||||
L<http://libguestfs.org/FAQ.html#backup>
|
||||
|
||||
=head1 Find out which user is using the most space
|
||||
|
||||
This simple script examines a Linux guest to find out which user is
|
||||
using the most space in their home directory:
|
||||
|
||||
#!/bin/sh -
|
||||
|
||||
set -e
|
||||
|
||||
vm="$1"
|
||||
dir=/home
|
||||
|
||||
eval $(guestfish --ro -d "$vm" -i --listen)
|
||||
|
||||
for d in $(guestfish --remote ls "$dir"); do
|
||||
echo -n "$dir/$d"
|
||||
echo -ne '\t'
|
||||
guestfish --remote du "$dir/$d";
|
||||
done | sort -nr -k 2
|
||||
|
||||
guestfish --remote exit
|
||||
|
||||
=head1 Export external kernel and initramfs (initrd)
|
||||
|
||||
If a Linux guest doesn't have a boot loader or it is broken, then you
|
||||
can usually boot it using an external kernel and initramfs. In this
|
||||
configuration, the hypervisor acts like a bootloader, loading the
|
||||
kernel from the host disk into guest memory and jumping straight into
|
||||
the kernel.
|
||||
|
||||
However you may wonder how to get the right kernel corresponding to
|
||||
the disk image you have. Since libguestfs E<ge> 1.24
|
||||
L<virt-builder(1)> can get the latest kernel and corresponding
|
||||
initramfs for you:
|
||||
|
||||
mkdir outputdir
|
||||
virt-builder --get-kernel disk.img -o outputdir
|
||||
ls -lh outputdir
|
||||
|
||||
=head1 Get DHCP address from a VM
|
||||
|
||||
The link below explains the many different possible techniques for
|
||||
getting the last assigned DHCP address of a virtual machine.
|
||||
|
||||
L<https://rwmj.wordpress.com/2011/03/31/tip-code-for-getting-dhcp-address-from-a-virtual-machine-disk-image/#content>
|
||||
|
||||
In the libguestfs source examples directory you will find the latest
|
||||
version of the F<virt-dhcp-address.c> program.
|
||||
|
||||
=head1 Get the operating system product name string
|
||||
|
||||
Save the following script into a file called F<product-name.sh>:
|
||||
|
||||
#!/bin/sh -
|
||||
set -e
|
||||
eval "$(guestfish --ro -d "$1" --i --listen)"
|
||||
root="$(guestfish --remote inspect-get-roots)"
|
||||
guestfish --remote inspect-get-product-name "$root"
|
||||
guestfish --remote exit
|
||||
|
||||
Make the script executable and run it on a named guest:
|
||||
|
||||
# product-name.sh RHEL60x64
|
||||
Red Hat Enterprise Linux Server release 6.0 (Santiago)
|
||||
|
||||
You can also use an XPath query on the L<virt-inspector(1)> XML using
|
||||
the C<xpath> command line tool or from your favourite programming
|
||||
language:
|
||||
|
||||
# virt-inspector RHEL60x64 > xml
|
||||
# xpath '//product_name' < xml
|
||||
Found 1 nodes:
|
||||
-- NODE --
|
||||
<product_name>Red Hat Enterprise Linux Server release 6.0 (Santiago)</product_name>
|
||||
|
||||
=head1 Get the default boot kernel for a Linux VM
|
||||
|
||||
The link below contains a program to print the default boot kernel for
|
||||
a Linux VM.
|
||||
|
||||
L<https://rwmj.wordpress.com/2010/10/30/tip-use-augeas-to-get-the-default-boot-kernel-for-a-vm/#content>
|
||||
|
||||
It uses Augeas, and the technique is generally applicable for many
|
||||
different tasks, such as:
|
||||
|
||||
=over 4
|
||||
|
||||
=item *
|
||||
|
||||
listing the user accounts in the guest
|
||||
|
||||
=item *
|
||||
|
||||
what repositories is it configured to use
|
||||
|
||||
=item *
|
||||
|
||||
what NTP servers does it connect to
|
||||
|
||||
=item *
|
||||
|
||||
what were the boot messages last time it booted
|
||||
|
||||
=item *
|
||||
|
||||
listing who was logged in recently
|
||||
|
||||
=back
|
||||
|
||||
L<http://augeas.net/>
|
||||
|
||||
=head1 Hanging guests
|
||||
|
||||
There are various ways to use libguestfs to find out why a guest
|
||||
is hanging or unresponsive:
|
||||
|
||||
=over 4
|
||||
|
||||
=item 1.
|
||||
|
||||
Read the log files using virt-cat:
|
||||
|
||||
virt-cat Guest /var/log/messages | less
|
||||
|
||||
=item 2.
|
||||
|
||||
Read the Windows Event Log (Windows Vista or later only):
|
||||
|
||||
L<https://rwmj.wordpress.com/2011/04/17/decoding-the-windows-event-log-using-guestfish/#content>
|
||||
|
||||
=item 3.
|
||||
|
||||
Find out which files were last updated in a guest:
|
||||
|
||||
L<https://rwmj.wordpress.com/2012/02/27/using-libguestfs-to-find-out-why-a-windows-guest-was-hanging/#content>
|
||||
|
||||
This might give you a clue as to what program is running.
|
||||
|
||||
=back
|
||||
|
||||
=head1 Hex-dumping sectors from the guest
|
||||
|
||||
Hex-dump the boot partition (Master Boot Record / first sector):
|
||||
|
||||
guestfish --ro -a disk.img run : pread-device /dev/sda 0x200 0 |
|
||||
hexdump -C
|
||||
|
||||
(C<0x200> = 512 bytes which is the size of traditional PC sectors)
|
||||
|
||||
To hexdump the N'th partition, substitute a number for C<N> in the
|
||||
following command:
|
||||
|
||||
guestfish --ro -a disk.img \
|
||||
run : pread-device /dev/sda 0x200 $((N*0x200)) |
|
||||
hexdump -C
|
||||
|
||||
=head1 Hex-editing sectors in the guest
|
||||
|
||||
Hex-edit the boot partition (Master Boot Record / first sector):
|
||||
|
||||
guestfish --rw -a disk.img run : hexedit /dev/sda 0x200
|
||||
|
||||
=head1 Install packages (RPMs, Debian packages) in a guest
|
||||
|
||||
Since libguestfs 1.26, L<virt-builder(1)>, L<virt-customize(1)> and
|
||||
L<virt-sysprep(1)> have an I<--install> option for installing packages
|
||||
in Linux guests. (Use virt-customize if you have an existing guest,
|
||||
or virt-builder if you want to create a guest from scratch).
|
||||
|
||||
For example:
|
||||
|
||||
virt-builder fedora-20 --install emacs
|
||||
|
||||
=head1 Install packages from an alternate repository
|
||||
|
||||
Since libguestfs 1.26, you can use L<virt-builder(1)>,
|
||||
L<virt-customize(1)> or L<virt-sysprep(1)> I<--edit> option to edit
|
||||
repository metadata before installing packages
|
||||
|
||||
For example this would install packages from the updates-testing
|
||||
repository in Fedora:
|
||||
|
||||
virt-builder fedora-20 \
|
||||
--edit '/etc/yum.repos.d/fedora-updates-testing.repo:
|
||||
s/enabled=0/enabled=1/' \
|
||||
--install emacs
|
||||
|
||||
=head1 Install SYSLINUX bootloader in a guest
|
||||
|
||||
SYSLINUX is a small, easy to configure bootloader for Linux and
|
||||
Windows guests. If your guest is not bootable, you can install the
|
||||
SYSLINUX bootloader using either the guestfish commands C<syslinux>
|
||||
(for FAT-based guests) or C<extlinux> (for ext2/3/4 and btrfs-based
|
||||
guests).
|
||||
|
||||
This guide assumes a Linux guest where F</dev/sda1> is F</boot>,
|
||||
F</boot/vmlinuz> is the guest kernel, and F</dev/sda3> is the root
|
||||
partition. For a Windows guest you would need a FAT-formatted boot
|
||||
partition and you would need to use the C<syslinux> command instead.
|
||||
|
||||
Create a F<syslinux.cfg> configuration file. You should check the
|
||||
SYSLINUX documentation at L<http://www.syslinux.org> but it may look
|
||||
something like this:
|
||||
|
||||
DEFAULT linux
|
||||
LABEL linux
|
||||
SAY Booting the kernel
|
||||
KERNEL vmlinuz
|
||||
INITRD initrd
|
||||
APPEND ro root=/dev/sda3
|
||||
|
||||
Locate the syslinux master boot record (a file called something like
|
||||
F</usr/share/syslinux/mbr.bin>).
|
||||
|
||||
guestfish -a disk.img -i
|
||||
# Upload the master boot record and configuration file:
|
||||
><fs> upload ..../mbr.bin /boot/mbr.bin
|
||||
><fs> upload ..../syslinux.cfg /boot/syslinux.cfg
|
||||
# Put the MBR into the boot sector:
|
||||
><fs> copy-file-to-device /boot/mbr.bin /dev/sda size:440
|
||||
# Install syslinux on the first partition:
|
||||
><fs> extlinux /boot
|
||||
# Set the first partition as bootable:
|
||||
><fs> part-set-bootable /dev/sda 1 true
|
||||
|
||||
See also:
|
||||
L<http://rwmj.wordpress.com/2013/04/04/new-in-libguestfs-use-syslinux-or-extlinux-to-make-bootable-guests/#content>
|
||||
|
||||
=head1 List applications installed in a VM
|
||||
|
||||
Save the following to a file F<list-apps.sh>:
|
||||
|
||||
#!/bin/sh -
|
||||
set -e
|
||||
eval "$(guestfish --ro -d "$1" --i --listen)"
|
||||
root="$(guestfish --remote inspect-get-roots)"
|
||||
guestfish --remote inspect-list-applications "$root"
|
||||
guestfish --remote exit
|
||||
|
||||
Make the file executable and then you can run it on any named
|
||||
virtual machine:
|
||||
|
||||
# list-apps.sh WinGuest
|
||||
[0] = {
|
||||
app_name: Mozilla Firefox (3.6.12)
|
||||
app_display_name: Mozilla Firefox (3.6.12)
|
||||
app_epoch: 0
|
||||
app_version: 3.6.12 (en-GB)
|
||||
app_release:
|
||||
app_install_path: C:\Program Files\Mozilla Firefox
|
||||
app_trans_path:
|
||||
app_publisher: Mozilla
|
||||
app_url: http://www.mozilla.com/en-GB/
|
||||
app_source_package:
|
||||
app_summary:
|
||||
app_description: Mozilla Firefox
|
||||
}
|
||||
[1] = {
|
||||
app_name: VLC media player
|
||||
app_display_name: VLC media player 1.1.5
|
||||
app_epoch: 0
|
||||
app_version: 1.1.5
|
||||
app_release:
|
||||
app_install_path: C:\Program Files\VideoLAN\VLC
|
||||
app_trans_path:
|
||||
app_publisher: VideoLAN
|
||||
app_url: http://www.videolan.org/
|
||||
app_source_package:
|
||||
app_summary:
|
||||
app_description:
|
||||
}
|
||||
|
||||
If you want to run the script on disk images (instead of libvirt
|
||||
virtual machines), change C<-d "$1"> to C<-a "$1">. See also
|
||||
L<virt-inspector(1)>.
|
||||
|
||||
=head1 List files and directories in a VM
|
||||
|
||||
Use L<virt-ls(1)>.
|
||||
|
||||
=head1 List services in a Windows VM
|
||||
|
||||
The link below contains a script that can be used to list out the
|
||||
services from a Windows VM, and whether those services run at boot
|
||||
time or are loaded on demand.
|
||||
|
||||
L<https://rwmj.wordpress.com/2010/12/10/tip-list-services-in-a-windows-guest/#content>
|
||||
|
||||
=head1 Make a disk image sparse
|
||||
|
||||
Use L<virt-sparsify(1)>.
|
||||
|
||||
=head1 Monitor disk usage over time
|
||||
|
||||
You can use L<virt-df(1)> to monitor disk usage of your guests over
|
||||
time. The link below contains a guide.
|
||||
|
||||
L<http://virt-tools.org/learning/advanced-virt-df/>
|
||||
|
||||
=head1 Reading the Windows Event Log from Windows Vista (or later)
|
||||
|
||||
L<guestfish(1)> plus the tools described in the link below can be used
|
||||
to read out the Windows Event Log from any virtual machine running
|
||||
Windows Vista or a later version.
|
||||
|
||||
L<https://rwmj.wordpress.com/2011/04/17/decoding-the-windows-event-log-using-guestfish/#content>
|
||||
|
||||
=head1 Remove root password (Linux)
|
||||
|
||||
Using the L<virt-edit(1)> I<-e> option you can do simple replacements
|
||||
on files. One use is to remove the root password from a Linux guest:
|
||||
|
||||
virt-edit -d domname /etc/passwd -e 's/^root:.*?:/root::/'
|
||||
|
||||
virt-edit -a disk.img /etc/passwd -e 's/^root:.*?:/root::/'
|
||||
|
||||
=head1 Remove Administrator password (Windows)
|
||||
|
||||
The link below contains one technique for removing the Administrator
|
||||
password from a Windows VM, or to be more precise, it gives you a
|
||||
command prompt the next time you log in which you can use to bypass
|
||||
any security:
|
||||
|
||||
L<https://mdbooth.wordpress.com/2010/10/18/resetting-a-windows-guests-administrator-password-with-guestfish/>
|
||||
|
||||
=head1 Sysprepping a virtual machine (Windows)
|
||||
|
||||
It is possible to do a "sysprep" using libguestfs alone, although not
|
||||
straightforward. Currently there is code in the Aeolus Oz project
|
||||
which does this (using libguestfs). It is likely we will add this to
|
||||
L<virt-sysprep(1)> in future.
|
||||
|
||||
L<https://github.com/clalancette/oz>
|
||||
L<https://www.redhat.com/archives/virt-tools-list/2011-May/msg00019.html>
|
||||
|
||||
=head1 Unpack a live CD
|
||||
|
||||
Linux live CDs often contain multiple layers of disk images wrapped
|
||||
like a Russian doll. You can use L<guestfish(1)> to look inside these
|
||||
multiple layers, as outlined in the guide below.
|
||||
|
||||
L<https://rwmj.wordpress.com/2009/07/15/unpack-the-russian-doll-of-a-f11-live-cd/#content>
|
||||
|
||||
=head1 Uploading and downloading files
|
||||
|
||||
The link below contains general tips on uploading (copying in)
|
||||
and downloading (copying out) files from VMs.
|
||||
|
||||
L<https://rwmj.wordpress.com/2010/12/02/tip-uploading-and-downloading/#content>
|
||||
|
||||
=head1 Uploading raw filesystem content
|
||||
|
||||
You can use L<guestfish(1)> to upload whole filesystems into a VM,
|
||||
even into a filesystem which is encrypted or buried inside an LV or
|
||||
RAID device:
|
||||
|
||||
guestfish --rw -a disk.img run : upload sda1.img /dev/sda1
|
||||
|
||||
guestfish --rw -d Guest run : upload lv.img /dev/vg_guest/lv_root
|
||||
|
||||
One common problem is that the filesystem isn't the right size for the
|
||||
target. If it is too large, there's not much you can do with
|
||||
libguestfs - you have to prepare the filesystem differently. But if
|
||||
the filesystem needs to expand into the target, you can use guestfish
|
||||
to resize it to the right size:
|
||||
|
||||
guestfish --rw -d Guest run : \
|
||||
upload lv.img /dev/vg_guest/lv_root : \
|
||||
resize2fs /dev/vg_guest/lv_root
|
||||
|
||||
(or use C<ntfsresize> if the filesystem is NTFS).
|
||||
|
||||
=head1 Use libguestfs tools on VMware ESX guests
|
||||
|
||||
The link below explains how to use libguestfs, L<guestfish(1)> and the
|
||||
virt tools on any VMware ESX guests, by first sharing the VMware VMFS
|
||||
over sshfs.
|
||||
|
||||
L<https://rwmj.wordpress.com/2011/05/10/tip-use-libguestfs-on-vmware-esx-guests/#content>
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<guestfs(3)>,
|
||||
L<guestfish(1)>,
|
||||
L<guestfs-examples(3)>,
|
||||
L<guestfs-erlang(3)>,
|
||||
L<guestfs-golang(3)>,
|
||||
L<guestfs-java(3)>,
|
||||
L<guestfs-lua(3)>,
|
||||
L<guestfs-ocaml(3)>,
|
||||
L<guestfs-perl(3)>,
|
||||
L<guestfs-python(3)>,
|
||||
L<guestfs-ruby(3)>,
|
||||
L<http://libguestfs.org/>.
|
||||
|
||||
=head1 AUTHORS
|
||||
|
||||
Richard W.M. Jones (C<rjones at redhat dot com>)
|
||||
|
||||
=head1 COPYRIGHT
|
||||
|
||||
Copyright (C) 2009-2015 Red Hat Inc.
|
||||
397
docs/guestfs-testing.pod
Normal file
397
docs/guestfs-testing.pod
Normal file
@@ -0,0 +1,397 @@
|
||||
=head1 NAME
|
||||
|
||||
guestfs-testing - manual testing of libguestfs, you can help!
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This page has manual tests you can try on libguestfs. Everyone has a
|
||||
slightly different combination of platform, hardware and guests, so
|
||||
this testing is very valuable. Thanks for helping out!
|
||||
|
||||
Tests marked with a B<*> (asterisk) can B<destroy data> if you're not
|
||||
careful. The others are safe and won't modify anything.
|
||||
|
||||
Most of these tests will work with any libguestfs E<ge> 1.14. Some of
|
||||
these tests (marked) require libguestfs E<ge> 1.22.
|
||||
|
||||
You can report bugs you find through this link:
|
||||
|
||||
L<https://bugzilla.redhat.com/enter_bug.cgi?component=libguestfs&product=Virtualization+Tools>
|
||||
|
||||
or post on the mailing list (registration is B<not> required, but if
|
||||
you're not registered then you'll have to wait for a moderator to
|
||||
manually approve your message):
|
||||
|
||||
L<https://www.redhat.com/mailman/listinfo/libguestfs>
|
||||
|
||||
=head1 TESTS
|
||||
|
||||
=head2 Run libguestfs-test-tool
|
||||
|
||||
Run:
|
||||
|
||||
libguestfs-test-tool
|
||||
|
||||
This command does a very simple, non-destructive test that basic
|
||||
libguestfs is functioning. You don't need to run it as root.
|
||||
|
||||
If it I<doesn't> print C<===== TEST FINISHED OK =====>, report it as a
|
||||
bug. It is very important that you include the B<complete, unedited>
|
||||
output of C<libguestfs-test-tool> in your bug report. See the
|
||||
L</BUGS> section at the end of this page.
|
||||
|
||||
=head2 Check KVM acceleration is being used.
|
||||
|
||||
If your host has hardware virt acceleration, then with a hot cache
|
||||
libguestfs should be able to start up in a few seconds. Run the
|
||||
following command a few times:
|
||||
|
||||
time guestfish -a /dev/null run
|
||||
|
||||
After a few runs, the time should settle down to a few seconds (under
|
||||
5 seconds on fast 64 bit hardware).
|
||||
|
||||
How to check for hardware virt:
|
||||
|
||||
L<http://virt-tools.org/learning/check-hardware-virt/>
|
||||
|
||||
If the command above does not work at all, use
|
||||
L<libguestfs-test-tool(1)>.
|
||||
|
||||
=head2 Check which version of libguestfs, qemu, libvirt, etc is being used.
|
||||
|
||||
Look at the output of C<libguestfs-test-tool> and check:
|
||||
|
||||
=over 4
|
||||
|
||||
=item *
|
||||
|
||||
Which version of libguestfs is being used? Near the beginning of the
|
||||
output you'll see a line like:
|
||||
|
||||
library version: 1.22.0fedora=19,release=1.fc19,libvirt
|
||||
|
||||
=item *
|
||||
|
||||
Is libvirt being used? You can tell the difference by looking
|
||||
for the backend:
|
||||
|
||||
guestfs_get_backend: direct
|
||||
|
||||
or:
|
||||
|
||||
guestfs_get_backend: libvirt
|
||||
|
||||
=item *
|
||||
|
||||
Which version of qemu is being used? It may be printed out:
|
||||
|
||||
libguestfs: qemu version 1.5
|
||||
|
||||
but note that if you're using libvirt then libguestfs doesn't have
|
||||
this information.
|
||||
|
||||
=item *
|
||||
|
||||
Which kernel is being used? L<supermin(1)> will try to pick the
|
||||
latest kernel installed on your machine. You can see the version in
|
||||
the appliance output, eg:
|
||||
|
||||
[ 0.000000] Linux version 3.9.2-200.fc18.x86_64 [...]
|
||||
|
||||
=back
|
||||
|
||||
=head2 Try to open a local guest image with guestfish.
|
||||
|
||||
You can use any guest disk image for this test. Make sure you use the
|
||||
C<--ro> flag so that L<guestfish(1)> will open the disk image
|
||||
read-only.
|
||||
|
||||
guestfish --ro -a /path/to/disk.img -i
|
||||
|
||||
If the command is successful, it should print out the guest operating
|
||||
system name and put you at the guestfish C<E<gt>E<lt>fsE<gt>> prompt.
|
||||
You can use guestfish commands like S<C<ll />> to look inside the disk
|
||||
image. To exit, type C<exit>.
|
||||
|
||||
If you get an error, try enabling debugging (add C<-v> to the command
|
||||
line). Also make sure that L<libguestfs-test-tool(1)> succeeds.
|
||||
|
||||
=head2 Try to open a remote guest image with guestfish.
|
||||
|
||||
B<Note> this test requires S<libguestfs E<ge> 1.22> and S<qemu E<ge> 1.5>.
|
||||
You may also have to disable libvirt by setting this:
|
||||
|
||||
export LIBGUESTFS_BACKEND=direct
|
||||
|
||||
If you have a disk image available over HTTP/FTP, try to open it.
|
||||
|
||||
guestfish --ro -i --format=raw -a http://www.example.com/disk.img
|
||||
|
||||
For SSH you will need to make sure that ssh-agent is set up so you
|
||||
don't need a password to log in to the remote machine. Then a command
|
||||
similar to this should work:
|
||||
|
||||
guestfish --ro -i --format=raw \
|
||||
-a ssh://remote.example.com/path/to/disk.img
|
||||
|
||||
If you get an error, try enabling debugging (add C<-v> to the command
|
||||
line). Also make sure that L<libguestfs-test-tool(1)> succeeds.
|
||||
|
||||
=head2 Run virt-alignment-scan on all your guests.
|
||||
|
||||
Run L<virt-alignment-scan(1)> on guests or disk images:
|
||||
|
||||
virt-alignment-scan -a /path/to/disk.img
|
||||
|
||||
or:
|
||||
|
||||
virt-alignment-scan -d Guest
|
||||
|
||||
Does the alignment report match how the guest partitions are aligned?
|
||||
|
||||
=head2 Run virt-cat on some files in guests.
|
||||
|
||||
L<virt-cat(1)> can display files from guests. For a Linux guest, try:
|
||||
|
||||
virt-cat LinuxGuest /etc/passwd
|
||||
|
||||
A recent feature is support for Windows paths, for example:
|
||||
|
||||
virt-cat WindowsGuest 'c:\windows\win.ini'
|
||||
|
||||
An even better test is if you have a Windows guest with multiple
|
||||
drives. Do C<D:>, C<E:> etc paths work correctly?
|
||||
|
||||
=head2 B<*> Copy some files into a B<shut off> guest.
|
||||
|
||||
L<virt-copy-in(1)> can recursively copy files and directories
|
||||
into a guest or disk image.
|
||||
|
||||
virt-copy-in -d Guest /etc /tmp
|
||||
|
||||
This should copy local directory F</etc> to F</tmp/etc> in the guest
|
||||
(recursively). If you boot the guest, can you see all of the copied
|
||||
files and directories?
|
||||
|
||||
Shut the guest down and try copying multiple files and directories:
|
||||
|
||||
virt-copy-in -d Guest /home /etc/issue /tmp
|
||||
|
||||
=head2 Copy some files out of a guest.
|
||||
|
||||
L<virt-copy-out(1)> can recursively copy files and directories
|
||||
out of a guest or disk image.
|
||||
|
||||
virt-copy-out -d Guest /home .
|
||||
|
||||
Note the final space and period in the command is not a typo.
|
||||
|
||||
This should copy F</home> from the guest into the current directory.
|
||||
|
||||
=head2 Run virt-df.
|
||||
|
||||
L<virt-df(1)> lists disk space. Run:
|
||||
|
||||
virt-df
|
||||
|
||||
You can try comparing this to the results from L<df(1)> inside the
|
||||
guest, but there are some provisos:
|
||||
|
||||
=over 4
|
||||
|
||||
=item *
|
||||
|
||||
The guest must be idle.
|
||||
|
||||
=item *
|
||||
|
||||
The guest disks must be synched using L<sync(1)>.
|
||||
|
||||
=item *
|
||||
|
||||
Any action such as booting the guest will write log files causing the
|
||||
numbers to change.
|
||||
|
||||
=back
|
||||
|
||||
We don't guarantee that the numbers will be identical even under these
|
||||
circumstances. They should be similar. It would indicate a bug if
|
||||
you saw greatly differing numbers.
|
||||
|
||||
=head2 Try importing virt-df CSV output into a spreadsheet or database.
|
||||
|
||||
Run:
|
||||
|
||||
virt-df --csv > /tmp/report.csv
|
||||
|
||||
Now try to load this into your favorite spreadsheet or database. Are
|
||||
the results reproduced faithfully in the spreadsheet/database?
|
||||
|
||||
L<http://www.postgresql.org/docs/8.1/static/sql-copy.html>
|
||||
L<http://dev.mysql.com/doc/refman/5.1/en/load-data.html>
|
||||
|
||||
=head2 B<*> Edit a file in a B<shut off> guest.
|
||||
|
||||
L<virt-edit(1)> can edit files in guests. Try this command on
|
||||
a RHEL or Fedora guest:
|
||||
|
||||
virt-edit LinuxGuest /etc/sysconfig/network
|
||||
|
||||
On other Linux guests try editing other files such as:
|
||||
|
||||
virt-edit LinuxGuest /etc/motd
|
||||
|
||||
Are the changes seen inside the guest when it is booted?
|
||||
|
||||
=head2 Display the filesystems / partitions / LVs in a guest.
|
||||
|
||||
L<virt-filesystems(1)> can be used to display filesystems in
|
||||
a guest. Try this command on any disk image or guest:
|
||||
|
||||
virt-filesystems -a /path/to/disk.img --all --long -h
|
||||
|
||||
or:
|
||||
|
||||
virt-filesystems -d Guest --all --long -h
|
||||
|
||||
Do the results match what is seen in the guest?
|
||||
|
||||
=head2 Run virt-inspector on all your guests.
|
||||
|
||||
Use L<virt-inspector(1)> to get a report on all of your guests or disk
|
||||
images:
|
||||
|
||||
virt-inspector -a /path/to/disk.img | less
|
||||
|
||||
or:
|
||||
|
||||
virt-inspector -d Guest | less
|
||||
|
||||
Do the results match what is actually in the guest?
|
||||
|
||||
=head2 Try the auditing features of virt-ls on all your guests.
|
||||
|
||||
List all setuid or setgid programs in a Linux virtual machine:
|
||||
|
||||
virt-ls -lR -d Guest / | grep '^- [42]'
|
||||
|
||||
List all public-writable directories in a Linux virtual machine:
|
||||
|
||||
virt-ls -lR -d Guest / | grep '^d ...7'
|
||||
|
||||
List all Unix domain sockets in a Linux virtual machine:
|
||||
|
||||
virt-ls -lR -d Guest / | grep '^s'
|
||||
|
||||
List all regular files with filenames ending in '.png':
|
||||
|
||||
virt-ls -lR -d Guest / | grep -i '^-.*\.png$'
|
||||
|
||||
Display files larger than 10MB in home directories:
|
||||
|
||||
virt-ls -lR -d Guest /home | awk '$3 > 10*1024*1024'
|
||||
|
||||
Find everything modified in the last 7 days:
|
||||
|
||||
virt-ls -lR -d Guest --time-days / | awk '$6 <= 7'
|
||||
|
||||
Find regular files modified in the last 24 hours:
|
||||
|
||||
virt-ls -lR -d Guest --time-days / | grep '^-' | awk '$6 < 1'
|
||||
|
||||
Do the results match what is in the guest?
|
||||
|
||||
=head2 Create a disk image from a tarball.
|
||||
|
||||
Use L<virt-make-fs(1)> to create a disk image from any tarball
|
||||
that you happen to have:
|
||||
|
||||
virt-make-fs --partition=mbr --type=vfat /any/tarball.tar.gz output.img
|
||||
|
||||
Add 'output.img' as a raw disk to an existing guest. Check the guest
|
||||
can see the files. This test is particularly useful if you try it
|
||||
with a Windows guest.
|
||||
|
||||
Try other partitioning schemes, eg. I<--partition=gpt>.
|
||||
|
||||
Try other filesystem formats, eg. I<--type=ntfs>, I<--type=ext2>.
|
||||
|
||||
=head2 B<*> Run virt-rescue on a B<shut off> disk image or guest.
|
||||
|
||||
Use L<virt-rescue(1)> to examine, rescue or repair a B<shut off> guest
|
||||
or disk image:
|
||||
|
||||
virt-rescue -a /path/to/disk.img
|
||||
|
||||
or:
|
||||
|
||||
virt-rescue -d Guest
|
||||
|
||||
Can you use ordinary shell commands to examine the guest?
|
||||
|
||||
=head2 B<*> Resize your guests.
|
||||
|
||||
Use L<virt-resize(1)> to give a guest some more disk space. For
|
||||
example, if you have a disk image that is smaller than 30G, increase
|
||||
it to 30G by doing:
|
||||
|
||||
truncate -s 30G newdisk.img
|
||||
virt-filesystems -a /path/to/olddisk.img --all --long -h
|
||||
virt-resize /path/to/olddisk.img newdisk.img --expand /dev/sda1
|
||||
qemu-kvm -m 1024 -hda newdisk.img
|
||||
|
||||
Does the guest still boot? Try expanding other partitions.
|
||||
|
||||
=head2 B<*> Sparsify a guest disk.
|
||||
|
||||
Using L<virt-sparsify(1)>, make a disk image more sparse:
|
||||
|
||||
virt-sparsify /path/to/olddisk.img newdisk.img
|
||||
|
||||
Is F<newdisk.img> still bootable after sparsifying? Is the resulting
|
||||
disk image smaller (use C<du> to check)?
|
||||
|
||||
=head2 B<*> "sysprep" a B<shut off> Linux guest.
|
||||
|
||||
B<Note> that this really will mess up an existing guest, so it's
|
||||
better to clone the guest before trying this.
|
||||
|
||||
virt-sysprep --hostname newhost.example.com -a /path/to/disk.img
|
||||
|
||||
Was the sysprep successful? After booting, what changes were made and
|
||||
were they successful?
|
||||
|
||||
=head2 Dump the Windows Registry from your Windows guests.
|
||||
|
||||
Use L<virt-win-reg(1)> to dump out the Windows Registry from
|
||||
any Windows guests that you have.
|
||||
|
||||
virt-win-reg --unsafe-printable-strings WindowsGuest 'HKLM\Software' |
|
||||
less
|
||||
|
||||
virt-win-reg --unsafe-printable-strings WindowsGuest 'HKLM\System' |
|
||||
less
|
||||
|
||||
Does the output match running C<regedit> inside the guest?
|
||||
|
||||
A recent feature is the ability to dump user registries, so try this,
|
||||
replacing I<username> with the name of a local user in the guest:
|
||||
|
||||
virt-win-reg --unsafe-printable-strings WindowsGuest 'HKEY_USERS\username' |
|
||||
less
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<guestfs(3)>,
|
||||
L<guestfish(1)>,
|
||||
L<guestfs-examples(3)>,
|
||||
L<http://libguestfs.org/>.
|
||||
|
||||
=head1 AUTHORS
|
||||
|
||||
Richard W.M. Jones (C<rjones at redhat dot com>)
|
||||
|
||||
=head1 COPYRIGHT
|
||||
|
||||
Copyright (C) 2011-2012 Red Hat Inc.
|
||||
Reference in New Issue
Block a user