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:
parent
82d9f08dc8
commit
5d12a4e317
@ -16932,6 +16932,62 @@ class LibvirtSnapshotTests(_BaseSnapshotTests):
|
|||||||
rbd.remove_snap.assert_called_with('c', 'd', ignore_errors=True,
|
rbd.remove_snap.assert_called_with('c', 'd', ignore_errors=True,
|
||||||
pool='b', force=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):
|
class LXCSnapshotTests(LibvirtSnapshotTests):
|
||||||
"""Repeat all of the Libvirt snapshot tests, but with LXC enabled"""
|
"""Repeat all of the Libvirt snapshot tests, but with LXC enabled"""
|
||||||
@ -16939,6 +16995,9 @@ class LXCSnapshotTests(LibvirtSnapshotTests):
|
|||||||
super(LXCSnapshotTests, self).setUp()
|
super(LXCSnapshotTests, self).setUp()
|
||||||
self.flags(virt_type='lxc', group='libvirt')
|
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):
|
class LVMSnapshotTests(_BaseSnapshotTests):
|
||||||
@mock.patch.object(fake_libvirt_utils, 'disk_type', new='lvm')
|
@mock.patch.object(fake_libvirt_utils, 'disk_type', new='lvm')
|
||||||
|
@ -1638,7 +1638,7 @@ class LibvirtDriver(driver.ComputeDriver):
|
|||||||
if (self._host.has_min_version(MIN_LIBVIRT_LIVESNAPSHOT_VERSION,
|
if (self._host.has_min_version(MIN_LIBVIRT_LIVESNAPSHOT_VERSION,
|
||||||
MIN_QEMU_LIVESNAPSHOT_VERSION,
|
MIN_QEMU_LIVESNAPSHOT_VERSION,
|
||||||
host.HV_DRIVER_QEMU)
|
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.ephemeral_storage_encryption.enabled
|
||||||
and not CONF.workarounds.disable_libvirt_livesnapshot):
|
and not CONF.workarounds.disable_libvirt_livesnapshot):
|
||||||
live_snapshot = True
|
live_snapshot = True
|
||||||
@ -1703,6 +1703,15 @@ class LibvirtDriver(driver.ComputeDriver):
|
|||||||
update_task_state(task_state=task_states.IMAGE_PENDING_UPLOAD,
|
update_task_state(task_state=task_states.IMAGE_PENDING_UPLOAD,
|
||||||
expected_state=task_states.IMAGE_UPLOADING)
|
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
|
snapshot_directory = CONF.libvirt.snapshots_directory
|
||||||
fileutils.ensure_tree(snapshot_directory)
|
fileutils.ensure_tree(snapshot_directory)
|
||||||
with utils.tempdir(dir=snapshot_directory) as tmpdir:
|
with utils.tempdir(dir=snapshot_directory) as tmpdir:
|
||||||
|
Loading…
Reference in New Issue
Block a user