libvirt: Allow use of live snapshots with RBD snapshot/clone

The recently merged functionality for making use of RBD snapshot/clone
when available is very valuable for the Ceph/RBD users out there.
The new method also makes it possible to do live instance snapshots
with Ceph/RBD.  However, the current code explicitly forbids it.

This patch allows the use of live instance snapshots when a RBD
snapshot/clone is performed directly, and reverts back to cold
instance snapshot when the old method is used.

Co-Authored-By: Nicolas Simonds <nic@metacloud.com>
Change-Id: Ic3a3c73898aa868d6c510639ab12d2401dcb5001
Closes-Bug: #1539179
(cherry picked from commit 2318323549)
This commit is contained in:
Nicolas Simonds 2016-03-07 14:46:32 -08:00 committed by Matt Riedemann
parent 82d9f08dc8
commit 5d12a4e317
2 changed files with 69 additions and 1 deletions

View File

@ -16932,6 +16932,62 @@ class LibvirtSnapshotTests(_BaseSnapshotTests):
rbd.remove_snap.assert_called_with('c', 'd', ignore_errors=True,
pool='b', force=True)
@mock.patch.object(imagebackend.Image, 'direct_snapshot')
@mock.patch.object(imagebackend.Image, 'resolve_driver_format')
@mock.patch.object(host.Host, 'has_min_version', return_value=True)
@mock.patch.object(host.Host, 'get_guest')
def test_raw_with_rbd_clone_is_live_snapshot(self,
mock_get_guest,
mock_version,
mock_resolve,
mock_snapshot):
self.flags(disable_libvirt_livesnapshot=False, group='workarounds')
self.flags(images_type='rbd', group='libvirt')
mock_guest = mock.Mock(spec=libvirt_guest.Guest)
mock_guest._domain = mock.Mock()
mock_get_guest.return_value = mock_guest
driver = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
recv_meta = self._create_image()
with mock.patch.object(driver, "suspend") as mock_suspend:
driver.snapshot(self.context, self.instance_ref, recv_meta['id'],
self.mock_update_task_state)
self.assertFalse(mock_suspend.called)
@mock.patch.object(libvirt_driver.imagebackend.images, 'convert_image',
side_effect=_fake_convert_image)
@mock.patch.object(fake_libvirt_utils, 'find_disk')
@mock.patch.object(imagebackend.Image, 'resolve_driver_format')
@mock.patch.object(host.Host, 'has_min_version', return_value=True)
@mock.patch.object(host.Host, 'get_guest')
@mock.patch.object(rbd_utils, 'RBDDriver')
@mock.patch.object(rbd_utils, 'rbd')
def test_raw_with_rbd_clone_failure_does_cold_snapshot(self,
mock_rbd,
mock_driver,
mock_get_guest,
mock_version,
mock_resolve,
mock_find_disk,
mock_convert):
self.flags(disable_libvirt_livesnapshot=False, group='workarounds')
self.flags(images_type='rbd', group='libvirt')
rbd = mock_driver.return_value
rbd.parent_info = mock.Mock(side_effect=exception.ImageUnacceptable(
image_id='fake_id', reason='rbd testing'))
mock_find_disk.return_value = ('rbd://some/fake/rbd/image', 'raw')
mock_guest = mock.Mock(spec=libvirt_guest.Guest)
mock_guest.get_power_state.return_value = power_state.RUNNING
mock_guest._domain = mock.Mock()
mock_get_guest.return_value = mock_guest
driver = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
recv_meta = self._create_image()
with mock.patch.object(fake_libvirt_utils, 'disk_type', new='rbd'):
with mock.patch.object(driver, "suspend") as mock_suspend:
driver.snapshot(self.context, self.instance_ref,
recv_meta['id'], self.mock_update_task_state)
self.assertTrue(mock_suspend.called)
class LXCSnapshotTests(LibvirtSnapshotTests):
"""Repeat all of the Libvirt snapshot tests, but with LXC enabled"""
@ -16939,6 +16995,9 @@ class LXCSnapshotTests(LibvirtSnapshotTests):
super(LXCSnapshotTests, self).setUp()
self.flags(virt_type='lxc', group='libvirt')
def test_raw_with_rbd_clone_failure_does_cold_snapshot(self):
self.skipTest("managedSave is not supported with LXC")
class LVMSnapshotTests(_BaseSnapshotTests):
@mock.patch.object(fake_libvirt_utils, 'disk_type', new='lvm')

View File

@ -1638,7 +1638,7 @@ class LibvirtDriver(driver.ComputeDriver):
if (self._host.has_min_version(MIN_LIBVIRT_LIVESNAPSHOT_VERSION,
MIN_QEMU_LIVESNAPSHOT_VERSION,
host.HV_DRIVER_QEMU)
and source_type not in ('lvm', 'rbd')
and source_type not in ('lvm')
and not CONF.ephemeral_storage_encryption.enabled
and not CONF.workarounds.disable_libvirt_livesnapshot):
live_snapshot = True
@ -1703,6 +1703,15 @@ class LibvirtDriver(driver.ComputeDriver):
update_task_state(task_state=task_states.IMAGE_PENDING_UPLOAD,
expected_state=task_states.IMAGE_UPLOADING)
# TODO(nic): possibly abstract this out to the snapshot_backend
if source_type == 'rbd' and live_snapshot:
# Standard snapshot uses qemu-img convert from RBD which is
# not safe to run with live_snapshot.
live_snapshot = False
# Suspend the guest, so this is no longer a live snapshot
self._prepare_domain_for_snapshot(context, live_snapshot,
state, instance)
snapshot_directory = CONF.libvirt.snapshots_directory
fileutils.ensure_tree(snapshot_directory)
with utils.tempdir(dir=snapshot_directory) as tmpdir: