New tool: virt-sysprep: system preparation for guests.
authorRichard W.M. Jones <rjones@redhat.com>
Fri, 7 Oct 2011 18:22:11 +0000 (19:22 +0100)
committerRichard W.M. Jones <rjones@redhat.com>
Sat, 8 Oct 2011 12:38:30 +0000 (13:38 +0100)
12 files changed:
.gitignore
Makefile.am
clone/Makefile.am [new file with mode: 0644]
clone/test-virt-sysprep.sh [new file with mode: 0755]
clone/virt-sysprep.in [new file with mode: 0644]
clone/virt-sysprep.pod [new file with mode: 0755]
configure.ac
fish/guestfish.pod
po-docs/ja/Makefile.am
po-docs/podfiles
po-docs/uk/Makefile.am
src/guestfs.pod

index 4f1438f..8980fd0 100644 (file)
@@ -37,6 +37,9 @@ cat/virt-ls
 cat/virt-ls.1
 ChangeLog
 *.class
+clone/stamp-virt-sysprep.pod
+clone/virt-sysprep
+clone/virt-sysprep.1
 *.cma
 *.cmi
 *.cmo
@@ -151,6 +154,7 @@ html/virt-make-fs.1.html
 html/virt-rescue.1.html
 html/virt-resize.1.html
 html/virt-sparsify.1.html
+html/virt-sysprep.1.html
 html/virt-tar.1.html
 html/virt-tar-in.1.html
 html/virt-tar-out.1.html
index 308a1f3..3d44c76 100644 (file)
@@ -38,6 +38,9 @@ SUBDIRS += fish
 # virt-tools in C.
 SUBDIRS += align cat df edit inspector rescue
 
+# virt-tools in shell.
+SUBDIRS += clone
+
 # Language bindings.
 if HAVE_PERL
 SUBDIRS += perl perl/examples
@@ -160,6 +163,7 @@ HTMLFILES = \
        html/virt-rescue.1.html \
        html/virt-resize.1.html \
        html/virt-sparsify.1.html \
+       html/virt-sysprep.1.html \
        html/virt-tar.1.html \
        html/virt-tar-in.1.html \
        html/virt-tar-out.1.html \
diff --git a/clone/Makefile.am b/clone/Makefile.am
new file mode 100644 (file)
index 0000000..20e1d52
--- /dev/null
@@ -0,0 +1,51 @@
+# libguestfs cloning tools
+# Copyright (C) 2011 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+include $(top_srcdir)/subdir-rules.mk
+
+EXTRA_DIST = \
+       test-virt-sysprep.sh \
+       virt-sysprep.pod
+
+CLEANFILES = stamp-virt-sysprep.pod
+
+bin_SCRIPTS = virt-sysprep
+
+# Manual pages and HTML files for the website.
+man_MANS = virt-sysprep.1
+noinst_DATA = $(top_builddir)/html/virt-sysprep.1.html
+
+virt-sysprep.1 $(top_builddir)/html/virt-sysprep.1.html: stamp-virt-sysprep.pod
+
+stamp-virt-sysprep.pod: virt-sysprep.pod
+       $(top_builddir)/podwrapper.sh \
+         --man virt-sysprep.1 \
+         --html $(top_builddir)/html/virt-sysprep.1.html \
+         $<
+       touch $@
+
+# Tests.
+
+random_val := $(shell awk 'BEGIN{srand(); print 1+int(255*rand())}' < /dev/null)
+
+TESTS_ENVIRONMENT = \
+       MALLOC_PERTURB_=$(random_val) \
+       LD_LIBRARY_PATH=$(top_builddir)/src/.libs \
+       LIBGUESTFS_PATH=$(top_builddir)/appliance \
+       TMPDIR=$(top_builddir)
+
+TESTS = test-virt-sysprep.sh
diff --git a/clone/test-virt-sysprep.sh b/clone/test-virt-sysprep.sh
new file mode 100755 (executable)
index 0000000..897afb7
--- /dev/null
@@ -0,0 +1,35 @@
+#!/bin/bash -
+# libguestfs virt-sysprep test script
+# Copyright (C) 2011 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+export LANG=C
+set -e
+
+rm -f test.img guestfish
+
+qemu-img create -f qcow2 -o backing_file=../images/fedora.img test.img
+
+cat <<'EOF' > guestfish
+#!/bin/sh -
+../run ../fish/guestfish "$@"
+EOF
+chmod +x guestfish
+PATH=.:$PATH
+
+./virt-sysprep -a test.img
+
+rm -f test.img guestfish
diff --git a/clone/virt-sysprep.in b/clone/virt-sysprep.in
new file mode 100644 (file)
index 0000000..b73acfb
--- /dev/null
@@ -0,0 +1,289 @@
+#!/bin/bash -
+# @configure_input@
+# libguestfs virt-sysprep tool
+# Copyright (C) 2011 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+unset CDPATH
+program="virt-sysprep"
+version="@PACKAGE_VERSION@"
+
+TEMP=`getopt \
+        -o a:c:d:vVx \
+        --long help,add:,connect:,domain:,enable:,format::,hostname:,list-operations,verbose,version \
+        -n $program -- "$@"`
+if [ $? != 0 ]; then
+    echo "$program: problem parsing the command line arguments"
+    exit 1
+fi
+eval set -- "$TEMP"
+
+# This array accumulates the arguments we pass through to guestfish.
+declare -a guestfish
+guestfish[0]="guestfish"
+guestfish[1]="--rw"
+guestfish[2]="--listen"
+guestfish[3]="-i"
+i=4
+
+verbose=
+add_params=0
+enable=
+hostname_param=localhost.localdomain
+
+usage ()
+{
+    echo "Usage:"
+    echo "  $program [--options] -d domname"
+    echo "  $program [--options] -a disk.img [-a disk.img ...]"
+    echo
+    echo "Read $program(1) man page for more information."
+    echo
+    echo "NOTE: $program modifies the guest or disk image *in place*."
+    exit $1
+}
+
+while true; do
+    case "$1" in
+        -a|--add)
+            guestfish[i++]="-a"
+            guestfish[i++]="$2"
+            ((add_params++))
+            shift 2;;
+        -c|--connect)
+            guestfish[i++]="-c"
+            guestfish[i++]="$2"
+            shift 2;;
+        -d|--domain)
+            guestfish[i++]="-d"
+            guestfish[i++]="$2"
+            ((add_params++))
+            shift 2;;
+        --enable)
+            if [ -n "$enable" ]; then
+                echo "error: --enable option can only be given once"
+                exit 1
+            fi
+            enable="$2"
+            shift 2;;
+        --format)
+            if [ -n "$2" ]; then
+                guestfish[i++]="--format=$2"
+            else
+                guestfish[i++]="--format"
+            fi
+            shift 2;;
+        --help)
+            usage 0;;
+        --hostname)
+            hostname_param="$2"
+            shift 2;;
+        --list-operations)
+            enable=list
+            shift;;
+        -v|--verbose)
+            guestfish[i++]="-v"
+            verbose=yes
+            shift;;
+        -V|--version)
+            echo "$program $version"
+            exit 0;;
+        -x)
+            guestfish[i++]="-x"
+            shift;;
+        --)
+            shift
+            break;;
+        *)
+            echo "Internal error!"
+            exit 1;;
+    esac
+done
+
+# Different sysprep operations that can be enabled.  Default is to
+# enable all of these, although some of them are only done on certain
+# guest types (see details below).
+if [ -z "$enable" ]; then
+    hostname=yes
+    net_hwaddr=yes
+    ssh_hostkeys=yes
+    udev_persistent_net=yes
+elif [ "$enable" = "list" ]; then
+    echo "hostname"
+    echo "net-hwaddr"
+    echo "ssh-hostkeys"
+    echo "udev-persistent-net"
+    exit 0
+else
+    for opt in $(echo "$enable" | sed 's/,/ /g'); do
+        case "$opt" in
+            hostname)              hostname=yes ;;
+            net-hwaddr)            net_hwaddr=yes ;;
+            ssh-hostkeys)          ssh_hostkeys=yes ;;
+            udev-persistent-net)   udev_persistent_net=yes ;;
+            *)
+                echo "error: unknown --enable feature: $opt"
+                exit 1
+        esac
+    done
+fi
+
+# Make sure there were no extra parameters on the command line.
+if [ $# -gt 0 ]; then
+    echo "error: $program: extra parameters on the command line"
+    echo
+    usage 1
+fi
+
+# Did the user specify at least one -a or -d option?
+if [ $add_params -eq 0 ]; then
+    echo "error: $program: you need at least one -a or -d option"
+    echo
+    usage 1
+fi
+
+# end of command line parsing
+#----------------------------------------------------------------------
+
+set -e
+
+if [ "$verbose" = "yes" ]; then
+    echo command: "${guestfish[@]}"
+fi
+
+# Create a temporary directory for general purpose use during operations.
+tmpdir="$(mktemp -d)"
+
+# Call guestfish.
+GUESTFISH_PID=
+eval $("${guestfish[@]}")
+if [ -z "$GUESTFISH_PID" ]; then
+    echo "$program: guestfish didn't start up, see error messages above"
+    exit 1
+fi
+
+cleanup ()
+{
+    kill $GUESTFISH_PID >/dev/null 2>&1 ||:
+    rm -rf "$tmpdir" ||:
+}
+trap cleanup EXIT
+
+# Launch back-end, inspect for operating systems, and get the guest
+# root disk.
+root=$(guestfish --remote inspect-get-roots)
+
+if [ "$root" = "" ]; then
+    echo "$program: no operating system was found on this disk"
+    exit 1
+fi
+
+if [ "$verbose" = "yes" ]; then
+    echo root: "$root"
+fi
+
+# Get the guest type.
+type="$(guestfish --remote -- -inspect-get-type $root)"
+
+if [ "$type" = "linux" ]; then
+    distro="$(guestfish --remote -- -inspect-get-distro $root)"
+fi
+
+if [ "$type" = "windows" ]; then
+    systemroot="$(guestfish --remote -- -inspect-get-windows-systemroot $root)"
+fi
+
+#----------------------------------------------------------------------
+# Useful functions.
+
+# erase_line filename regex
+#
+# Erase line(s) in a file that match the given regex.
+erase_line ()
+{
+    guestfish --remote -- download "$1" "$tmpdir/file"
+    sed "/$2/d" < "$tmpdir/file" > "$tmpdir/file.1"
+    guestfish --remote -- upload "$tmpdir/file.1" "$1"
+}
+
+# rm_files wildcard
+#
+# Remove files.  Doesn't fail if no files exist.  Note the wildcard
+# parameter cannot contain spaces or characters that need special
+# quoting.
+rm_files ()
+{
+    files=$(guestfish --remote -- glob-expand "$1")
+    for f in $files; do
+        guestfish --remote -- rm "$f"
+    done
+}
+
+# rm_file filename
+#
+# Remove a single file.  No error if the file doesn't exist or is not
+# a file.
+rm_file ()
+{
+    t=$(guestfish --remote -- is-file "$1")
+    if [ "$t" = "true" ]; then
+        guestfish --remote -- rm "$1"
+    fi
+}
+
+#----------------------------------------------------------------------
+# The sysprep operations.
+
+if [ "$hostname" = "yes" ]; then
+    case "$type/$distro" in
+        linux/fedora)
+            guestfish --remote -- \
+                download /etc/sysconfig/network "$tmpdir/network"
+            echo "HOSTNAME=$hostname_param" > "$tmpdir/network.1"
+            sed '/^HOSTNAME=/d' < "$tmpdir/network" >> "$tmpdir/network.1"
+            guestfish --remote -- \
+                upload "$tmpdir/network.1" /etc/sysconfig/network ;;
+        linux/debian|linux/ubuntu)
+            guestfish --remote -- write /etc/hostname "$hostname_param"
+    esac
+fi
+
+if [ "$net_hwaddr" = "yes" ]; then
+    case "$type/$distro" in
+        linux/fedora)
+            # XXX these filenames can have spaces and untrusted chars in them!
+            files=$(guestfish --remote -- glob-expand '/etc/sysconfig/network-scripts/ifcfg-*')
+            for f in $files; do
+                erase_line "$f" "^HWADDR="
+            done
+    esac
+fi
+
+if [ "$ssh_hostkeys" = "yes" -a "$type" != "windows" ]; then
+    rm_files "/etc/ssh/*_host_*"
+fi
+
+if [ "$udev_persistent_net" = "yes" -a "$type" = "linux" ]; then
+    rm_file /etc/udev/rules.d/70-persistent-net.rules
+fi
+
+# Clean up and close down.
+
+guestfish --remote umount-all
+guestfish --remote sync
+guestfish --remote exit
+
+exit 0
diff --git a/clone/virt-sysprep.pod b/clone/virt-sysprep.pod
new file mode 100755 (executable)
index 0000000..cc8e44f
--- /dev/null
@@ -0,0 +1,404 @@
+=encoding utf8
+
+=head1 NAME
+
+virt-sysprep - Reset or unconfigure a virtual machine so clones can be made
+
+=head1 SYNOPSIS
+
+ virt-sysprep [--options] -d domname
+
+ virt-sysprep [--options] -a disk.img [-a disk.img ...]
+
+=head1 DESCRIPTION
+
+Virt-sysprep "resets" or "unconfigures" a virtual machine so that
+clones can be made from it.  Steps in this process include removing
+SSH host keys, removing persistent network MAC configuration, and
+removing user accounts.  Each step can be enabled or disabled as
+required.
+
+Virt-sysprep is a simple shell script, allowing easy inspection or
+customization by the system administrator.
+
+Virt-sysprep modifies the guest or disk image I<in place>.  The guest
+must be shut down.  If you want to preserve the existing contents of
+the guest, you I<must copy or clone the disk first>.
+See L</COPYING AND CLONING> below.
+
+"Sysprep" stands for "system preparation" tool.  The name comes from
+the Microsoft program C<sysprep.exe> which is used to unconfigure
+Windows machines in preparation for cloning them.  Having said that,
+virt-sysprep does I<not> currently work on Microsoft Windows guests.
+We plan to support Windows sysprepping in a future version, and we
+already have code to do it.
+
+=head1 OPTIONS
+
+=over 4
+
+=item B<--help>
+
+Display brief help.
+
+=item B<-a> file
+
+=item B<--add> file
+
+Add I<file> which should be a disk image from a virtual machine.
+
+The format of the disk image is auto-detected.  To override this and
+force a particular format use the I<--format=..> option.
+
+=item B<-c> URI
+
+=item B<--connect> URI
+
+If using libvirt, connect to the given I<URI>.  If omitted, then we
+connect to the default libvirt hypervisor.
+
+If you specify guest block devices directly (I<-a>), then libvirt is
+not used at all.
+
+=item B<-d> guest
+
+=item B<--domain> guest
+
+Add all the disks from the named libvirt guest.  Domain UUIDs can be
+used instead of names.
+
+=item B<--enable=...>
+
+Choose which sysprep operations to perform.  Give a comma-separated
+list of operations, for example:
+
+ --enable=ssh-hostkeys,udev-persistent-net
+
+would enable ONLY C<ssh-hostkeys> and C<udev-persistent-net> operations.
+
+If the I<--enable> option is not given, then we default to trying all
+possible sysprep operations.  But some sysprep operations are skipped
+for some guest types.
+
+Use I<--list-operations> to list operations supported by a particular
+version of virt-sysprep.
+
+See L</OPERATIONS> below for a list and an explanation of each
+operation.
+
+=item B<--format=raw|qcow2|..>
+
+=item B<--format>
+
+The default for the I<-a> option is to auto-detect the format of the
+disk image.  Using this forces the disk format for I<-a> options which
+follow on the command line.  Using I<--format> with no argument
+switches back to auto-detection for subsequent I<-a> options.
+
+For example:
+
+ virt-sysprep --format=raw -a disk.img
+
+forces raw format (no auto-detection) for C<disk.img>.
+
+ virt-sysprep --format=raw -a disk.img --format -a another.img
+
+forces raw format (no auto-detection) for C<disk.img> and reverts to
+auto-detection for C<another.img>.
+
+If you have untrusted raw-format guest disk images, you should use
+this option to specify the disk format.  This avoids a possible
+security problem with malicious guests (CVE-2010-3851).
+
+=item B<--hostname> newhostname
+
+Change the hostname.  See the L</hostname> operation below.
+If not given, defaults to C<localhost.localdomain>.
+
+=item B<--list-operations>
+
+List the operations supported by the virt-sysprep program.
+
+=item B<-v>
+
+=item B<--verbose>
+
+Enable verbose messages for debugging.
+
+=item B<-V>
+
+=item B<--version>
+
+Display version number and exit.
+
+=item B<-x>
+
+Enable tracing of libguestfs API calls.
+
+=back
+
+=head1 OPERATIONS
+
+If the I<--enable> option is I<not> given, then all sysprep operations
+in the list below are enabled, although some are skipped depending on
+the type of guest.
+
+Operations can be individually enabled using the I<--enable> option.
+Use a comma-separated list, for example:
+
+ virt-sysprep --enable=ssh-hostkeys,udev-persistent-net [etc..]
+
+To list the operations supported by the current version of
+virt-sysprep, use I<--list-operations>.
+
+=head2 hostname
+
+This changes the hostname of the guest to the value given in the
+I<--hostname> parameter.
+
+If the I<--hostname> parameter is not given, then the hostname is
+changed to C<localhost.localdomain>.
+
+=head2 net-hwaddr
+
+Remove HWADDR (hard-coded MAC address) configuration.  For Fedora and
+Red Hat Enterprise Linux, this is removed from C<ifcfg-*> files.
+
+=head2 ssh-hostkeys
+
+This erases the SSH host keys in the guest.
+
+The SSH host keys are regenerated (differently) next time the guest is
+booted.
+
+If, after cloning, the guest gets the same IP address, ssh will give
+you a stark warning about the host key changing:
+
+ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+ @    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
+ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+ IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
+
+=head2 udev-persistent-net
+
+This erases udev persistent net rules which map the guest's existing
+MAC address to a fixed ethernet device (eg. eth0).
+
+After a guest is cloned, the MAC address usually changes.  Since the
+old MAC address occupies the old name (eg. eth0), this means the fresh
+MAC address is assigned to a new name (eg. eth1) and this is usually
+undesirable.  Erasing the udev persistent net rules avoids this.
+
+=head1 COPYING AND CLONING
+
+Virt-sysprep can be used as part of a process of cloning guests, or to
+prepare a template from which guests can be cloned.  There are many
+different ways to achieve this using the virt tools, and this section
+is just an introduction.
+
+A virtual machine (when switched off) consists of two parts:
+
+=over 4
+
+=item I<configuration>
+
+The configuration or description of the guest.  eg. The libvirt
+XML (see C<virsh dumpxml>), the running configuration of the guest,
+or another external format like OVF.
+
+Some configuration items that might need to be changed:
+
+=over 4
+
+=item *
+
+name
+
+=item *
+
+UUID
+
+=item *
+
+path to block device(s)
+
+=item *
+
+network card MAC address
+
+=back
+
+=item I<block device(s)>
+
+One or more hard disk images, themselves containing files,
+directories, applications, kernels, configuration, etc.
+
+Some things inside the block devices that might need to be changed:
+
+=over 4
+
+=item *
+
+hostname and other net configuration
+
+=item *
+
+UUID
+
+=item *
+
+SSH host keys
+
+=item *
+
+Windows unique security ID (SID)
+
+=item *
+
+Puppet registration
+
+=back
+
+=back
+
+=head2 COPYING THE BLOCK DEVICE
+
+Starting with an original guest, you probably wish to copy the guest
+block device and its configuration to make a template.  Then once you
+are happy with the template, you will want to make many clones from
+it.
+
+                        virt-sysprep
+                             |
+                             v
+ original guest --------> template ---------->
+                                      \------> cloned
+                                       \-----> guests
+                                        \---->
+
+You can, of course, just copy the block device on the host using
+L<cp(1)> or L<dd(1)>.
+
+                   dd                 dd
+ original guest --------> template ---------->
+                                      \------> cloned
+                                       \-----> guests
+                                        \---->
+
+There are some smarter (and faster) ways too:
+
+=over 4
+
+=item *
+
+                          snapshot
+                template ---------->
+                            \------> cloned
+                             \-----> guests
+                              \---->
+
+Use the block device as a backing file and create a snapshot on top
+for each guest.  The advantage is that you don't need to copy the
+block device (very fast) and only changes are stored (less storage
+required).
+
+Note that writing to the backing file once you have created guests on
+top of it is not possible: you will corrupt the guests.
+
+Tools that can do this include:
+L<qemu-img(1)> (with the I<create -f qcow2 -o backing_file> option),
+L<lvcreate(8)> (I<--snapshot> option).  Some filesystems (such as
+btrfs) and most Network Attached Storage devices can also create cheap
+snapshots from files or LUNs.
+
+=item *
+
+Get your NAS to snapshot and/or duplicate the LUN.
+
+=item *
+
+Prepare your template using L<virt-sparsify(1)>.  See below.
+
+=back
+
+=head2 VIRT-CLONE
+
+A separate tool, L<virt-clone(1)>, can be used to duplicate the block
+device and/or modify the external libvirt configuration of a guest.
+It will reset the name, UUID and MAC address of the guest in the
+libvirt XML.
+
+L<virt-clone(1)> does not use libguestfs and cannot look inside the
+disk image.  This was the original motivation to write virt-sysprep.
+
+=head2 SPARSIFY
+
+              virt-sparsify
+ original guest --------> template
+
+L<virt-sparsify(1)> can be used to make the cloning template smaller,
+making it easier to compress and/or faster to copy.
+
+Notice that since virt-sparsify also copies the image, you can use it
+to make the initial copy (instead of C<dd>).
+
+=head2 RESIZE
+
+                         virt-resize
+                template ---------->
+                            \------> cloned
+                             \-----> guests
+                              \---->
+
+If you want to give people cloned guests, but let them pick the size
+of the guest themselves (eg. depending on how much they are prepared
+to pay for disk space), then instead of copying the template, you can
+run L<virt-resize(1)>.  Virt-resize performs a copy and resize, and
+thus is ideal for cloning guests from a template.
+
+=head1 SHELL QUOTING
+
+Libvirt guest names can contain arbitrary characters, some of which
+have meaning to the shell such as C<#> and space.  You may need to
+quote or escape these characters on the command line.  See the shell
+manual page L<sh(1)> for details.
+
+=head1 EXIT STATUS
+
+This program returns 0 on success, or 1 if there was an error.
+
+=head1 SEE ALSO
+
+L<guestfs(3)>,
+L<guestfish(1)>,
+L<virt-clone(1)>,
+L<virt-rescue(1)>,
+L<virt-resize(1)>,
+L<virt-sparsify(1)>,
+L<virsh(1)>,
+L<qemu-img(1)>,
+L<lvcreate(8)>,
+L<http://libguestfs.org/>,
+L<http://libvirt.org/>.
+
+=head1 AUTHOR
+
+Richard W.M. Jones L<http://people.redhat.com/~rjones/>
+
+=head1 COPYRIGHT
+
+Copyright (C) 2011 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., 675 Mass Ave, Cambridge, MA 02139, USA.
index ec02ff1..a2ea880 100644 (file)
@@ -936,6 +936,8 @@ AC_SUBST([LIBTOOL])
 dnl Produce output files.
 AC_CONFIG_HEADERS([config.h])
 dnl http://www.mail-archive.com/automake@gnu.org/msg10204.html
+AC_CONFIG_FILES([clone/virt-sysprep],
+                [chmod +x clone/virt-sysprep])
 AC_CONFIG_FILES([podwrapper.sh],
                 [chmod +x podwrapper.sh])
 AC_CONFIG_FILES([run],
@@ -946,6 +948,7 @@ AC_CONFIG_FILES([Makefile
                  capitests/Makefile
                  cat/Makefile
                  caution/Makefile
+                 clone/Makefile
                  csharp/Makefile
                  daemon/Makefile
                  debian/changelog
index 696d3b3..022e03e 100644 (file)
@@ -1283,6 +1283,7 @@ L<virt-make-fs(1)>,
 L<virt-rescue(1)>,
 L<virt-resize(1)>,
 L<virt-sparsify(1)>,
+L<virt-sysprep(1)>,
 L<virt-tar(1)>,
 L<virt-tar-in(1)>,
 L<virt-tar-out(1)>,
index d03fdb3..552d4fb 100644 (file)
@@ -42,7 +42,8 @@ MANPAGES = \
        virt-ls.1 \
        virt-rescue.1 \
        virt-resize.1 \
-       virt-sparsify.1
+       virt-sparsify.1 \
+       virt-sysprep.1
 
 # Ship the POD files and the translated manpages in the tarball.  This
 # just simplifies building from the tarball, at a small cost in extra
index 48732e7..c4e4d6b 100644 (file)
@@ -2,6 +2,7 @@
 ../cat/virt-cat.pod
 ../cat/virt-filesystems.pod
 ../cat/virt-ls.pod
+../clone/virt-sysprep.pod
 ../df/virt-df.pod
 ../edit/virt-edit.pod
 ../erlang/examples/guestfs-erlang.pod
index d03fdb3..552d4fb 100644 (file)
@@ -42,7 +42,8 @@ MANPAGES = \
        virt-ls.1 \
        virt-rescue.1 \
        virt-resize.1 \
-       virt-sparsify.1
+       virt-sparsify.1 \
+       virt-sysprep.1
 
 # Ship the POD files and the translated manpages in the tarball.  This
 # just simplifies building from the tarball, at a small cost in extra
index 25ca56d..1a5abc6 100644 (file)
@@ -2845,6 +2845,11 @@ and documentation.
 Safety and liveness tests of components that libguestfs depends upon
 (not of libguestfs itself).  Mainly this is for qemu and the kernel.
 
+=item C<clone>
+
+Tools for cloning virtual machines.  Currently contains
+L<virt-sysprep(1)> command and documentation.
+
 =item C<contrib>
 
 Outside contributions, experimental parts.
@@ -3202,6 +3207,7 @@ L<virt-make-fs(1)>,
 L<virt-rescue(1)>,
 L<virt-resize(1)>,
 L<virt-sparsify(1)>,
+L<virt-sysprep(1)>,
 L<virt-tar(1)>,
 L<virt-tar-in(1)>,
 L<virt-tar-out(1)>,