We now always copy a guest during conversion, meaning this tool is no longer
required.
---
Build.PL | 2 +-
MANIFEST | 2 -
lib/Sys/VirtV2V.pm | 9 +-
lib/Sys/VirtV2V/Connection.pm | 1 -
po/POTFILES.in | 1 -
snapshot/run-snapshot-locally | 43 --
snapshot/v2v-snapshot.pl | 931 -----------------------------------------
7 files changed, 3 insertions(+), 986 deletions(-)
delete mode 100755 snapshot/run-snapshot-locally
delete mode 100755 snapshot/v2v-snapshot.pl
diff --git a/Build.PL b/Build.PL
index 51afae8..f5e6e7c 100644
--- a/Build.PL
+++ b/Build.PL
@@ -217,7 +217,7 @@ my $build = $class->new (
dist_version_from => 'lib/Sys/VirtV2V.pm',
confdoc_files => [ 'v2v/virt-v2v.conf.pod' ],
install_path => { 'locale' => '/usr/local/share/locale' },
- script_files => [ 'snapshot/v2v-snapshot.pl', 'v2v/virt-v2v.pl'
],
+ script_files => [ 'v2v/virt-v2v.pl' ],
meta_add => {
resources => {
license => "http://www.gnu.org/licenses/gpl.html",
diff --git a/MANIFEST b/MANIFEST
index d5debe1..d200497 100644
--- a/MANIFEST
+++ b/MANIFEST
@@ -31,8 +31,6 @@ po/te.po
po/virt-v2v.pot
po/zh_CN.po
README-NLS
-snapshot/run-snapshot-locally
-snapshot/v2v-snapshot.pl
t/001-pod.t
t/002-pod-coverage.t
t/003-syntax.t
diff --git a/lib/Sys/VirtV2V.pm b/lib/Sys/VirtV2V.pm
index a831972..3e39d64 100644
--- a/lib/Sys/VirtV2V.pm
+++ b/lib/Sys/VirtV2V.pm
@@ -30,8 +30,8 @@ Sys::VirtV2V - Convert a virtual guest to use KVM
=head1 DESCRIPTION
-Modules under Sys::VirtV2V are used by the L<virt-v2v(1)> and
L<v2v-snapshot(1)>
-tools. See the documentation for those tools for a more detailed description.
+Modules under Sys::VirtV2V are used by the L<virt-v2v(1)> tool. See the
+virt-v2v documentation for a more detailed description.
The Sys::VirtV2V module provides package information for virt-v2v.
@@ -60,11 +60,6 @@ Please see the file COPYING.LIB for the full license.
=head1 SEE ALSO
L<virt-v2v(1)>,
-L<v2v-snapshot(1)>,
-L<Sys::VirtV2V::GuestOS(3pm)>,
-L<Sys::VirtV2V::HVSource(3pm)>,
-L<Sys::VirtV2V::Converter(3pm)>,
-L<Sys::VirtV2V::Connection(3pm)>,
L<http://libguestfs.org/>
=cut
diff --git a/lib/Sys/VirtV2V/Connection.pm b/lib/Sys/VirtV2V/Connection.pm
index 5b4ed8d..a211662 100644
--- a/lib/Sys/VirtV2V/Connection.pm
+++ b/lib/Sys/VirtV2V/Connection.pm
@@ -195,7 +195,6 @@ Please see the file COPYING.LIB for the full license.
L<Sys::VirtV2V::Connection::LibVirt(3pm)>,
L<Sys::VirtV2V::Connection::LibVirtXML(3pm)>,
L<virt-v2v(1)>,
-L<v2v-snapshot(1)>,
L<http://libguestfs.org/>.
=cut
diff --git a/po/POTFILES.in b/po/POTFILES.in
index ffdf250..d5c774a 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -10,5 +10,4 @@
../lib/Sys/VirtV2V/Target/LibVirt.pm
../lib/Sys/VirtV2V/Transfer/ESX.pm
../lib/Sys/VirtV2V/UserMessage.pm
-../snapshot/v2v-snapshot.pl
../v2v/virt-v2v.pl
diff --git a/snapshot/run-snapshot-locally b/snapshot/run-snapshot-locally
deleted file mode 100755
index 9fd1c06..0000000
--- a/snapshot/run-snapshot-locally
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/bin/sh
-# v2v-snapshot
-# Copyright (C) 2009 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.
-
-# This script sets up the environment so you can run v2v-snapshot in place
-# without needing to do 'make install' first.
-#
-# Use it like this:
-# ./run-snapshot-locally [usual v2v-snapshot args ...]
-#
-# It requires the environment variable VIRTV2V_ROOT to be set. If using
-# libguestfs from source, LIBGUESTFS_ROOT must also be set.
-
-if [ -z "$VIRTV2V_ROOT" ]; then
- echo "VIRTV2V_ROOT must be set"
- exit 1
-fi
-
-PERL5LIB="$VIRTV2V_ROOT/blib/lib"
-
-if [ ! -z "$LIBGUESTFS_ROOT" ]; then
- LD_LIBRARY_PATH="$LIBGUESTFS_ROOT/src/.libs"
- LIBGUESTFS_PATH="$LIBGUESTFS_ROOT/appliance"
-
PERL5LIB="$PERL5LIB:$LIBGUESTFS_ROOT/perl/blib/lib:$LIBGUESTFS_ROOT/perl/blib/arch"
-fi
-
-export PERL5LIB LD_LIBRARY_PATH LIBGUESTFS_PATH
-
-exec perl "$VIRTV2V_ROOT/snapshot/v2v-snapshot.pl" "$@"
diff --git a/snapshot/v2v-snapshot.pl b/snapshot/v2v-snapshot.pl
deleted file mode 100755
index ccbc907..0000000
--- a/snapshot/v2v-snapshot.pl
+++ /dev/null
@@ -1,931 +0,0 @@
-#!/usr/bin/perl
-# v2v-snapshot
-# Copyright (C) 2009 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.
-
-use warnings;
-use strict;
-
-use English;
-
-use File::Temp qw(tempfile);
-use Getopt::Long;
-use Pod::Usage;
-
-use Locale::TextDomain 'virt-v2v';
-
-use Sys::Virt;
-
-use Sys::VirtV2V;
-use Sys::VirtV2V::ExecHelper;
-use Sys::VirtV2V::Connection;
-use Sys::VirtV2V::UserMessage qw(user_message);
-
-=encoding utf8
-
-=head1 NAME
-
-v2v-snapshot - Convert a guest to use a qcow2 snapshot for storage
-
-=head1 SYNOPSIS
-
- v2v-snapshot guest-domain
-
- v2v-snapshot --rollback guest-domain
-
- v2v-snapshot --commit guest-domain
-
-=head1 DESCRIPTION
-
-v2v-snapshot is a tool for creating a local snapshot of a guest's storage. It is
-suitable for use when making a change to a guest which might have to be rolled
-back. v2v-snapshot creates a qcow2 snapshot for all a guest's block devices and
-updates the guest's libvirt domain to use them.
-
-When a change has been tested, v2v-snapshot can either commit the change, which
-will update the original storage with the changes made to the snapshot, or
-rollback the change, which will remove the snapshot. In either case, the guest
-will be updated again to use its original storage.
-
-B<v2v-snapshot can only snapshot a guest which is shutdown. It is not intended
-as a long-term storage option, and is not a general snapshotting tool for
-guests.>
-
-=head1 OPTIONS
-
-=over 4
-
-=cut
-
-my $help;
-
-=item B<--help>
-
-Display brief help.
-
-=cut
-
-my $version;
-
-=item B<--version>
-
-Display version number and exit.
-
-=cut
-
-my $uri;
-
-=item B<--connect URI> | B<-c URI>
-
-Connect to libvirt using the given I<URI>. If omitted, then we connect to the
-default libvirt hypervisor.
-
-=cut
-
-my $input = "libvirt";
-
-=item B<--input input> | B<-i input>
-
-The specified guest description uses the given I<input format>. The default is
-C<libvirt>. Supported options are:
-
-=over
-
-=item I<libvirt>
-
-Guest argument is the name of a libvirt domain.
-
-=item I<libvirtxml>
-
-Guest argument is the path to an XML file describing a libvirt domain.
-
-=back
-
-=cut
-
-my $outputxml;
-
-=item B<--outputxml file> | B<-o file>
-
-Write the updated domain xml to I<file> instead of directly creating the domain.
-If I<file> is '-' output will be to standard out.
-
-This option can be useful when snapshotting or rolling back to domain XML which
-can't be created on the local hypervisor, for example because Xen is not
-available locally.
-
-=cut
-
-my $datadir;
-
-=item B<--datadir dir> | B<-d dir>
-
-The directory v2v-snapshot will store its data. 2 subdirectories will be created
-for holding snapshot images and XML backups. It defaults to
-I</var/lib/virt-v2v>, except for connections to qemu:///session, when it
-defaults to ~/.virt-v2v.
-
-=cut
-
-my $force = 0;
-
-=item B<--force> | B<-f>
-
-Force an action to complete which might not be safe. Force is required to:
-
-=over
-
-Create a snapshot of a guest which already has an active snapshot (overwrites
-the XML backup).
-
-Rollback a guest which has no XML backup (all guest metadata is lost).
-
-=back
-
-=cut
-
-my $commit = 0;
-
-=item B<--commit>
-
-Commit the existing snapshot to its backing store and update the guest to using
-the original storage.
-
-=cut
-
-my $rollback = 0;
-
-=item B<--rollback>
-
-Remove the snapshot and restore the guest to its previous, unmodified storage.
-
-=back
-
-=cut
-
-# Initialise the message output prefix
-Sys::VirtV2V::UserMessage->set_identifier('v2v-snapshot');
-
-GetOptions ("help|?" => \$help,
- "version" => \$version,
- "connect|c=s" => \$uri,
- "input|i=s" => \$input,
- "outputxml|o=s" => \$outputxml,
- "datadir|d=s" => \$datadir,
- "force|f" => \$force,
- "commit" => \$commit,
- "rollback" => \$rollback
- ) or pod2usage(2);
-pod2usage(0) if($help);
-pod2usage({
- -message => __"--commit and --rollback options are mutually exclusive",
- -exitval => 1
-}) if($commit && $rollback);
-
-if ($version) {
- print "$Sys::VirtV2V::VERSION\n";
- exit(0);
-}
-
-pod2usage(user_message(__"no guest argument given")) if @ARGV == 0;
-
-# Get a libvirt connection
-my @vmm_params = (auth => 1);
-push(@vmm_params, uri => $uri) if(defined($uri));
-my $vmm = Sys::Virt->new(@vmm_params);
-
-# Set the default datadir depending on the connection
-if (!defined($datadir)) {
- if ($vmm->get_uri() eq "qemu:///session") {
- # Get the current user's home directory
- my (undef, undef, undef, undef, undef, # name, passwd, uid, gid, quota
- undef, undef, $home, undef, undef # comment, gcos, dir, shell, expire
- ) = getpwuid($UID);
-
- unless (defined($home)) {
- print STDERR user_message(__x("Unable to get home directory ".
- "for current user"));
- exit(1);
- }
-
- $datadir = File::Spec->catdir($home, ".virt-v2v");
- }
-
- else {
- $datadir = "/var/lib/virt-v2v";
- }
-
- unless (-d $datadir) {
- unless(mkdir($datadir)) {
- print STDERR user_message(__x("Unable to create data ".
- "directory {dir}: {error}",
- dir => $datadir,
- error => $@));
- exit(1);
- }
- }
-}
-
-# Get an appropriate Connection
-my $mdr = Sys::VirtV2V::Connection->instantiate($input, {}, $vmm, @ARGV);
-if(!defined($mdr)) {
- print STDERR user_message(__x("{input} is not a valid input format",
- input => $input));
- exit(1);
-}
-
-exit(1) unless($mdr->is_configured());
-
-###############################################################################
-## Start of processing
-
-# Get a libvirt configuration for the guest
-my $dom = $mdr->get_dom();
-exit(1) unless(defined($dom));
-
-my $pool = _get_pool($vmm);
-
-if($commit) {
- _commit_guest($dom, $vmm, $pool) == 0 or exit(1);
-}
-
-elsif($rollback) {
- my $retval;
- ($retval, $dom) = _rollback_guest($dom, $vmm, $pool);
-
- exit(1) unless($retval == 0);
-}
-
-# No commit or rollback. Snapshot the guest
-else {
- _snapshot_guest($dom, $vmm, $pool) == 0 or exit(1);
-}
-
-# Don't try to output anything if the domain is no longer defined
-if(!defined($dom)) {
- print user_message(__"No domain has been created.");
- exit($force == 1 ? 0 : 1);
-}
-
-# If --outputxml was given, just write the xml instead of creating the domain
-if($outputxml) {
- my $out;
- my $error = 0;
-
- # Write output to a file
- if('-' ne $outputxml) {
- unless(open($out, '>', $outputxml)) {
- print STDERR user_message(__x("Unable to open {file}: {error}",
- file => $outputxml,
- error => $!));
- ($out, $outputxml) = tempfile(_get_guest_name($dom).'-XXXXXX',
- SUFFIX => '.xml');
- $error = 1;
- }
-
- print $out $dom->toString();
-
- close($out) or die(__x("Error closing {file}: {error}",
- file => $outputxml, error => $!));
-
- if($error) {
- print STDERR user_message(__x("Wrote output to {file}",
- file => $outputxml));
- exit(1);
- }
- }
-
- # Write output to STDOUT
- else {
- print $dom->toString();
- }
-}
-
-else {
- eval {
- $vmm->define_domain($dom->toString());
- };
-
- if($@) {
- print STDERR user_message(__x("Unable to create guest: {error}",
- error => $@->stringify()));
- print STDERR user_message(__"Consider using the --outputxml option");
-
- # Write the output to a temporary file
- my ($out, $outputxml) = tempfile(_get_guest_name($dom).'-XXXXXX',
- SUFFIX => '.xml');
-
- print $out $dom->toString();
-
- print STDERR user_message(__x("Wrote output to {file}",
- file => $outputxml));
-
- unless(close($out)) {
- print STDERR user_message(__x("Error closing {file}: {error}",
- file => $outputxml, error => $!));
- }
-
- exit(1);
- }
-}
-
-###############################################################################
-## Helper functions
-
-sub _get_pool
-{
- my ($vmm) = @_;
-
- # Look for the v2v-snapshot storage pool
- my $pool;
- eval {
- $pool = $vmm->get_storage_pool_by_name('v2v-snapshot');
- };
-
- # If it wasn't there, try creating it
- if($@) {
- my $snapshotdir = $datadir.'/snapshots';
-
- unless (-d $snapshotdir) {
- unless(mkdir($snapshotdir)) {
- print STDERR user_message(__x("Unable to create snapshot ".
- "directory {dir}: {error}",
- dir => $snapshotdir,
- error => $@));
- exit(1);
- }
- }
-
- eval {
- $pool = $vmm->create_storage_pool("
- <pool type='dir'>
- <name>v2v-snapshot</name>
- <target>
- <path>$snapshotdir</path>
- </target>
- </pool>
- ");
- };
-
- # If that didn't work, give up
- if($@) {
- print STDERR user_message(__x("Unable to create v2v-snapshot ".
- "storage pool: {error}",
- error => $@->stringify()))
- unless(defined($pool));
- exit(1);
- }
- }
-
- # Check that the pool is usable
- my $pool_info = $pool->get_info();
-
- # If it's inactive, start it
- if($pool_info->{state} == Sys::Virt::StoragePool::STATE_INACTIVE) {
- eval {
- $pool->create();
- };
-
- if($@) {
- print STDERR user_message(__x("Unable to start v2v-snapshot ".
- "storage pool: {error}",
- error => $@->stringify()))
- unless(defined($pool));
- exit(1);
- }
- }
-
- # If it's building, there's nothing to do but wait
- elsif($pool_info->{state} == Sys::Virt::StoragePool::STATE_BUILDING) {
- print STDERR user_message(__"v2v-snapshot storage pool is ".
- "temporarily unavailable");
- exit(1);
- }
-
- return $pool;
-}
-
-# Get a storage volume object for a given path
-sub _get_volume
-{
- my ($path, $pool) = @_;
-
- my $vol;
- my $refreshed = 0;
- do {
- # XXX: Shouldn't be using an undocumented API
- # See RHBZ 519647. Replace with lookupByPath when it's available.
- eval {
- $vol = Sys::Virt::StorageVol->_new(path => $path,
- connection => $vmm);
- };
-
- if($@) {
- if($refreshed) {
- my $pool_xml = $pool->get_xml_description();
- my $pool_dom = new XML::DOM::Parser->parse($pool_xml);
-
- die(user_message(__x("Unable to find {path} in the ".
- "v2v-snapshot storage pool.",
- path => $path)));
- } else {
- $pool->refresh(0);
- $refreshed = 1;
- }
- }
- } until(defined($vol));
-
- return $vol;
-}
-
-sub _commit_guest
-{
- my ($dom, $vmm, $pool) = @_;
-
- # First, get a list of existing disks
- foreach my $disk ($dom->findnodes('/domain/devices/disk')) {
- my ($source) = $disk->findnodes('source');
- my ($target) = $disk->findnodes('target/@dev');
-
- # Look for the source location
- my $path;
- my $src_attrs = $source->getAttributes();
- foreach my $attr qw(dev file) {
- my $item = $src_attrs->getNamedItem($attr);
- if(defined($item)) {
- $path = $item->getNodeValue();
-
- # Remove the attribute. We'll add a new one in below.
- $src_attrs->removeNamedItem($attr);
-
- last;
- }
- }
-
- # Find the storage volume, which will include information on the backing
- # store
- my $vol;
- eval {
- $vol = _get_volume($path, $pool);
- };
- if($@) {
- print STDERR $@;
- return -1;
- }
-
- # Get the volume's backing store
- my $vol_xml = $vol->get_xml_description();
- my $vol_dom = new XML::DOM::Parser->parse($vol_xml);
- my ($backing_store) = $vol_dom->findnodes('/volume/backingStore');
-
- # Skip it if it doesn't have a backing store
- unless($backing_store) {
- print STDERR user_message(__x("Skipping device {target} as it ".
- "doesn't have a backing store",
- target => $target->getNodeValue()));
- next;
- }
-
- my ($backing_path) = $backing_store->findnodes('path/text()');
- $backing_path = $backing_path->getNodeValue();
- my ($backing_format) = $backing_store->findnodes('format/@type');
- $backing_format = $backing_format->getNodeValue();
-
- # Try to work out if the backing store is a file or a block device by
- # interrogating its storage volume object
- my $backing_type;
- eval {
- # XXX: See comment above about this usage of _new
- my $backing_vol = Sys::Virt::StorageVol->_new(path => $path,
- connection => $vmm);
- $backing_type = $backing_vol->get_info()->{type};
- };
-
- # Backing store isn't in a storage pool
- if($@) {
- # Guess based on path name
- # N.B. We could stat it, but that wouldn't work for a remote
- # connection
- if($backing_path =~ m{^/dev/}) {
- $backing_type = Sys::Virt::StorageVol::TYPE_BLOCK;
- } else {
- $backing_type = Sys::Virt::StorageVol::TYPE_FILE;
- }
- }
-
- # Update the domain XML with the location of the backing store
- if($backing_type == Sys::Virt::StorageVol::TYPE_BLOCK) {
- $source->setAttribute('dev', $backing_path);
- $source->removeAttribute('file');
- } else {
- $source->setAttribute('file', $backing_path);
- $source->removeAttribute('dev');
- }
-
- # Update the domain XML with with a driver appropriate to the backing
- # store
- my ($driver) = $disk->findnodes('driver');
-
- # Initialise the driver if it's not set
- $driver ||= $disk->appendChild($dom->createElement('driver'));
-
- $driver->setAttribute('name', 'qemu');
- $driver->setAttribute('type', $backing_format);
-
- # Commit snapshot to its backing store
- # XXX: There should be a libvirt API to do this
- my $eh = Sys::VirtV2V::ExecHelper->run
- ('/usr/bin/qemu-img', 'commit', '-f',
'qcow2', $path);
-
- # Check commit succeeded
- if($eh->status != 0) {
- print STDERR user_message(__x("Failed to commit snapshot
'{path}' ".
- "to backing store
'{backingstore}'.".
- "\nCommand output was:\n{output}",
- path => $path,
- backingstore => $backing_path,
- output => $eh->output()));
-
- return -1;
- }
-
- # Delete the snapshot volume
- $vol->delete(0);
- }
-
- # Remove the XML backup if it exists
- my $xmlpath = _get_xml_path($dom);
- unlink($xmlpath) if(-e $xmlpath);
-
- return 0;
-}
-
-sub _snapshot_guest
-{
- my ($dom, $vmm, $pool) = @_;
-
- my $name = _get_guest_name($dom);
-
- # Store a backup of the domain XML before modification
- my $xmlpath = _get_xml_path($dom);
-
- # Error if the xml backup already exists and force not specified
- if(-e $xmlpath && !$force) {
- print STDERR
- user_message(__x("A snapshot already exists for {guest}. You must
".
- "commit it or roll it back back before creating
".
- "a new snapshot.", guest => $name));
- return -1;
- }
-
- # Keep a list files and volumes created by the snapshot process. We need to
- # clean all of these up in the event of an error.
- my @created_files = ();
- my @created_volumes = ();
-
- my $ret = eval {
- # Write the backup
- my $xmlbackup;
- open($xmlbackup, '>', $xmlpath)
- or die(__x("Unable to write to {path}: {error}",
- path => $xmlpath, error => $!));
- push(@created_files, $xmlpath);
-
- print $xmlbackup $dom->toString();
-
- close($xmlbackup)
- or die(__x("Error closing {path}: {error}",
- path => $xmlpath, error => $!));
-
- # Get a timestamp for use in naming snapshot volumes
- my $time = time();
-
- return _foreach_disk($dom, sub {
- my ($disk, $source, $target, $path) = @_;
-
- # Create a new qcow2 volume in the v2v-snapshot storage pool
- my $target_name = $target->getNodeValue();
- my $vol_name = "$name-$target_name-$time.qcow2";
- my $vol_xml = "
- <volume>
- <name>$vol_name</name>
- <capacity>0</capacity>
- <target>
- <format type='qcow2'/>
- </target>
- <backingStore>
- <path>$path</path>
- </backingStore>
- </volume>
- ";
-
- my $vol;
- eval {
- $vol = $pool->create_volume($vol_xml);
- };
-
- if($@) {
- print STDERR
- user_message(__x("Unable to create storage volume:
{error}",
- error => $@->stringify()));
- return -1;
- }
-
- push(@created_volumes, $vol);
-
- # Update the source to be a "file" with the new path
- $source->setAttribute("file", $vol->get_path());
-
- # Remove the dev attribute in case it was set
- $source->removeAttribute("dev");
-
- # Also update the disk element to be a "file"
- $source->getParentNode()->setAttribute('type',
'file');
-
- # Replace the driver element with one which describes the qcow2 file
- my ($driver) = $disk->findnodes('driver');
-
- # Initialise the driver if it's not set
- $driver ||= $disk->appendChild($dom->createElement('driver'));
-
- $driver->setAttribute('name', 'qemu');
- $driver->setAttribute('type', 'qcow2');
-
- return 0;
- });
- };
-
- if ($@ || $ret < 0) {
- foreach my $file (@created_files) {
- unlink($file); # Don't check for further errors
- }
-
- foreach my $vol (@created_volumes) {
- $vol->delete();
- }
-
- die($@) if ($@);
- }
-
- return $ret;
-}
-
-sub _rollback_guest
-{
- my ($dom, $vmm, $pool) = @_;
-
- my $name = _get_guest_name($dom);
- my $xmlpath = _get_xml_path($dom);
-
- # Only rollback a guest without stored XML if force was specified
- if(! -e $xmlpath && !$force) {
- print STDERR user_message(__x("Refusing to rollback guest {name} ".
- "without backed-up xml",
- name => _get_guest_name($dom)));
- return -1;
- }
-
- # Delete all snapshots
- _foreach_disk($dom, sub {
- my ($disk, $source, $target, $path) = @_;
-
- # Find the storage volume, which will include information on the backing
- # store
- my $vol;
- eval {
- $vol = _get_volume($path, $pool);
- };
- if($@) {
- print STDERR $@;
- return -1;
- }
-
- # Check that the volume has a backing store
- my $vol_xml = $vol->get_xml_description();
- my $vol_dom = new XML::DOM::Parser->parse($vol_xml);
- my ($backing_store) = $vol_dom->findnodes('/volume/backingStore');
-
- unless(defined($backing_store)) {
- print STDERR user_message(__x("{path} is not a snapshot volume",
- path => $path));
- return -1;
- }
-
- if(-e $path && unlink($path) != 1) {
- print STDERR user_message(__x("Failed to delete {file}: {error}",
- file => $path, error => $!));
- return -1;
- }
-
- return 0;
- }) == 0 or return -1;
-
- # Load the backed-up XML
- if(-e $xmlpath) {
- $dom = new XML::DOM::Parser->parsefile($xmlpath);
- if(unlink($xmlpath) != 1) {
- print STDERR user_message(__x("Unable to delete backup xml file ".
- "{file}: {error}",
- file => $xmlpath, error => $!));
- return -1;
- }
- }
-
- # Or there is no backed-up XML (force must have been given)
- else {
- $dom = undef;
- }
-
- # undefined the guest if it is defined
- my $domain;
- eval {
- $domain = $vmm->get_domain_by_name($name);
- };
-
- # Nothing to do if the guest isn't defined
- if(defined($domain)) {
- my $state = $domain->get_info()->{state};
-
- # Check the domain is shutoff
- unless($state == Sys::Virt::Domain::STATE_SHUTOFF) {
- $domain->destroy();
-
- # $domain is now undefined. Get it back again
- $domain = $vmm->get_domain_by_name($name);
- }
-
- $domain->undefine();
- }
-
- return (0, $dom);
-}
-
-sub _foreach_disk
-{
- my ($dom, $func) = @_;
-
- # Get a list of existing disks
- foreach my $disk ($dom->findnodes('/domain/devices/disk[@device =
\'disk\']'))
- {
- my ($source) = $disk->findnodes('source');
- my ($target) = $disk->findnodes('target/@dev');
-
- # Ignore disks with no source
- next if (!defined($source));
-
- # Look for the source location
- my $path;
- my $src_attrs = $source->getAttributes();
- foreach my $attr qw(dev file) {
- my $item = $src_attrs->getNamedItem($attr);
- if(defined($item)) {
- $path = $item->getNodeValue();
- last;
- }
- }
-
- # Warn and ignore this source if we didn't find either
- if(!defined($path)) {
- print STDERR user_message(__x("invalid source element: {element}",
- element => $source->toString()));
- next;
- }
-
- $func->($disk, $source, $target, $path) == 0 or return -1;
- }
-}
-
-sub _get_guest_name
-{
- my ($dom) = @_;
-
- # Get the name of the guest from the domain description
- my ($name_elem) = $dom->findnodes('/domain/name/text()');
- return $name_elem->toString();
-}
-
-sub _get_xml_path
-{
- my ($dom) = @_;
-
- my $xmldir = $datadir.'/xml';
-
- # Ensure it exists
- unless (-d $xmldir) {
- unless (mkdir($xmldir)) {
- print STDERR user_message(__x("Unable to create xml storage ".
- "directory {dir}: {error}",
- dir => $xmldir, error => $@));
- exit(1);
- }
- }
-
- return $xmldir.'/'._get_guest_name($dom).'.xml';
-}
-
-=head1 EXAMPLES
-
-=head2 Snapshot a local guest
-
-=over
-
-This example covers snapshotting a guest which is available through libvirt on
-the local machine. The guest domain's name is I<E<lt>guestE<gt>>.
-
-First ensure the guest is shutdown:
-
- # virsh destroy <guest>
-
-Snapshot the guest:
-
- # v2v-snapshot <guest>
-
-Start the guest, make some changes, modify hardware, test changes. To commit
-the changes:
-
- # v2v-snapshot --commit <guest>
-
-Alternatively, to rollback the changes:
-
- # v2v-snapshot --rollback <guest>
-
-=back
-
-=head2 Snapshot an imported guest
-
-=over
-
-This example covers snapshotting a guest which has been copied from another
-machine. For this to work you must have the domain XML exported from the origin
-machine:
-
- (Origin) # virsh dumpxml <guest> > guest.xml
-
-You must also present all of the guest's disk images to the local machine in the
-locations specified in guest.xml. If copying the images, the easiest
-way to achieve this is to copy it to the same path on the local machine as it
-had on the origin machine. If the storage can be remotely mounted, it should be
-presented to the local machine with the same paths as on the origin machine. If
-the location of the storage must change, you must manually edit guest.xml to
-reflect the new paths.
-
-If it is possible to create the domain on the local machine:
-
- # v2v-snapshot -i libvirtxml guest.xml
-
-This command will create the imported domain locally with snapshot storage.
-
-If it is not possible to create the domain locally, for example because it is a
-Xen domain and the local libvirt cannot manage Xen domains:
-
- # v2v-snapshot -o snapshot-guest.xml -i libvirtxml guest.xml
-
-This command does not attempt the create the domain locally, which would fail.
-Instead it writes updated domain XML to I<snapshot-guest.xml>. The disks in
-snapshot-guest.xml point to the newly created snapshot volumes.
-
-The latter method of import is intended for use when importing a Xen domain from
-a origin machine for conversion with L<virt-v2v(1)>. virt-v2v should be given
-I<snapshot-guest.xml> as the domain XML.
-
-=back
-
-=head1 SEE ALSO
-
-L<virt-v2v(1)>,
-L<http://libguestfs.org/>.
-
-=head1 AUTHOR
-
-Matthew Booth <mbooth(a)redhat.com>
-
-=head1 COPYRIGHT
-
-Copyright (C) 2009 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.
--
1.6.6.1