Make snapshots with qemu-img instead of libvirt

* snapshot is only supposed to snapshot the root drive, whereas
   libvirt snapshots snapshot the memory and all attached disks
 * removes silly qemu_img flag
 * fixes bug 946830

Change-Id: I6afc9dbaa855f06864cd5a37f89ad63555e35d23
This commit is contained in:
Vishvananda Ishaya 2012-03-08 16:26:13 -08:00
parent f936594d9e
commit 7dbf9c7de2
5 changed files with 74 additions and 31 deletions

View File

@ -179,6 +179,10 @@ filterlist = [
# nova/virt/xenapi/vm_utils.py: 'mkfs' # nova/virt/xenapi/vm_utils.py: 'mkfs'
filters.CommandFilter("/sbin/mkfs", "root"), filters.CommandFilter("/sbin/mkfs", "root"),
# nova/virt/libvirt/utils.py: 'qemu-img'
filters.CommandFilter("/usr/bin/qemu-img", "root"),
# nova/virt/libvirt/connection.py: # nova/virt/libvirt/connection.py:
filters.ReadFileFilter("/etc/iscsi/initiatorname.iscsi"), filters.ReadFileFilter("/etc/iscsi/initiatorname.iscsi"),
] ]

View File

@ -61,6 +61,14 @@ def chown(path, owner):
pass pass
def create_snapshot(disk_path, snapshot_name):
pass
def delete_snapshot(disk_path, snapshot_name):
pass
def extract_snapshot(disk_path, source_fmt, snapshot_name, out_path, dest_fmt): def extract_snapshot(disk_path, source_fmt, snapshot_name, out_path, dest_fmt):
files[out_path] = '' files[out_path] = ''

View File

@ -96,8 +96,14 @@ class FakeVirtDomain(object):
def name(self): def name(self):
return "fake-domain %s" % self return "fake-domain %s" % self
def snapshotCreateXML(self, *args): def info(self):
return FakeVirDomainSnapshot(self) return [power_state.RUNNING, None, None, None, None]
def create(self):
pass
def managedSave(self, *args):
pass
def createWithFlags(self, launch_flags): def createWithFlags(self, launch_flags):
pass pass

View File

@ -616,21 +616,20 @@ class LibvirtConnection(driver.ComputeDriver):
if 'container_format' in base: if 'container_format' in base:
metadata['container_format'] = base['container_format'] metadata['container_format'] = base['container_format']
# Make the snapshot
snapshot_name = uuid.uuid4().hex
snapshot_xml = """
<domainsnapshot>
<name>%s</name>
</domainsnapshot>
""" % snapshot_name
snapshot_ptr = virt_dom.snapshotCreateXML(snapshot_xml, 0)
# Find the disk # Find the disk
xml_desc = virt_dom.XMLDesc(0) xml_desc = virt_dom.XMLDesc(0)
domain = ElementTree.fromstring(xml_desc) domain = ElementTree.fromstring(xml_desc)
source = domain.find('devices/disk/source') source = domain.find('devices/disk/source')
disk_path = source.get('file') disk_path = source.get('file')
snapshot_name = uuid.uuid4().hex
(state, _max_mem, _mem, _cpus, _t) = virt_dom.info()
if state == power_state.RUNNING:
virt_dom.managedSave(0)
# Make the snapshot
libvirt_utils.create_snapshot(disk_path, snapshot_name)
# Export the snapshot to a raw image # Export the snapshot to a raw image
with utils.tempdir() as tmpdir: with utils.tempdir() as tmpdir:
try: try:
@ -638,6 +637,11 @@ class LibvirtConnection(driver.ComputeDriver):
libvirt_utils.extract_snapshot(disk_path, source_format, libvirt_utils.extract_snapshot(disk_path, source_format,
snapshot_name, out_path, snapshot_name, out_path,
image_format) image_format)
finally:
libvirt_utils.delete_snapshot(disk_path, snapshot_name)
if state == power_state.RUNNING:
virt_dom.create()
# Upload that image to the image service # Upload that image to the image service
with libvirt_utils.file_open(out_path) as image_file: with libvirt_utils.file_open(out_path) as image_file:
image_service.update(context, image_service.update(context,
@ -645,9 +649,6 @@ class LibvirtConnection(driver.ComputeDriver):
metadata, metadata,
image_file) image_file)
finally:
snapshot_ptr.delete(0)
@exception.wrap_exception() @exception.wrap_exception()
def reboot(self, instance, network_info, reboot_type='SOFT'): def reboot(self, instance, network_info, reboot_type='SOFT'):
"""Reboot a virtual machine, given an instance reference.""" """Reboot a virtual machine, given an instance reference."""

View File

@ -24,17 +24,11 @@ import random
from nova import exception from nova import exception
from nova import flags from nova import flags
from nova.openstack.common import cfg
from nova import utils from nova import utils
from nova.virt import images from nova.virt import images
qemu_img_opt = cfg.StrOpt('qemu_img',
default='qemu-img',
help='binary to use for qemu-img commands')
FLAGS = flags.FLAGS FLAGS = flags.FLAGS
FLAGS.register_opt(qemu_img_opt)
def execute(*args, **kwargs): def execute(*args, **kwargs):
@ -63,7 +57,7 @@ def create_image(disk_format, path, size):
for megabytes, 'g' for gigabytes, 't' for terabytes). If no for megabytes, 'g' for gigabytes, 't' for terabytes). If no
prefix is given, it will be interpreted as bytes. prefix is given, it will be interpreted as bytes.
""" """
execute(FLAGS.qemu_img, 'create', '-f', disk_format, path, size) execute('qemu-img', 'create', '-f', disk_format, path, size)
def create_cow_image(backing_file, path): def create_cow_image(backing_file, path):
@ -74,7 +68,7 @@ def create_cow_image(backing_file, path):
:param backing_file: Existing image on which to base the COW image :param backing_file: Existing image on which to base the COW image
:param path: Desired location of the COW image :param path: Desired location of the COW image
""" """
execute(FLAGS.qemu_img, 'create', '-f', 'qcow2', '-o', execute('qemu-img', 'create', '-f', 'qcow2', '-o',
'cluster_size=2M,backing_file=%s' % backing_file, path) 'cluster_size=2M,backing_file=%s' % backing_file, path)
@ -85,7 +79,7 @@ def get_disk_size(path):
:returns: Size (in bytes) of the given disk image as it would be seen :returns: Size (in bytes) of the given disk image as it would be seen
by a virtual machine. by a virtual machine.
""" """
out, err = execute(FLAGS.qemu_img, 'info', path) out, err = execute('qemu-img', 'info', path)
size = [i.split('(')[1].split()[0] for i in out.split('\n') size = [i.split('(')[1].split()[0] for i in out.split('\n')
if i.strip().find('virtual size') >= 0] if i.strip().find('virtual size') >= 0]
return int(size[0]) return int(size[0])
@ -97,7 +91,7 @@ def get_disk_backing_file(path):
:param path: Path to the disk image :param path: Path to the disk image
:returns: a path to the image's backing store :returns: a path to the image's backing store
""" """
out, err = execute(FLAGS.qemu_img, 'info', path) out, err = execute('qemu-img', 'info', path)
backing_file = [i.split('actual path:')[1].strip()[:-1] backing_file = [i.split('actual path:')[1].strip()[:-1]
for i in out.split('\n') if 0 <= i.find('backing file')] for i in out.split('\n') if 0 <= i.find('backing file')]
if backing_file: if backing_file:
@ -168,7 +162,37 @@ def chown(path, owner):
:param path: File or directory whose ownership to change :param path: File or directory whose ownership to change
:param owner: Desired new owner (given as uid or username) :param owner: Desired new owner (given as uid or username)
""" """
utils.execute('chown', owner, path, run_as_root=True) execute('chown', owner, path, run_as_root=True)
def create_snapshot(disk_path, snapshot_name):
"""Create a snapshot in a disk image
:param disk_path: Path to disk image
:param snapshot_name: Name of snapshot in disk image
"""
qemu_img_cmd = ('qemu-img',
'snapshot',
'-c',
snapshot_name,
disk_path)
# NOTE(vish): libvirt changes ownership of images
execute(*qemu_img_cmd, run_as_root=True)
def delete_snapshot(disk_path, snapshot_name):
"""Create a snapshot in a disk image
:param disk_path: Path to disk image
:param snapshot_name: Name of snapshot in disk image
"""
qemu_img_cmd = ('qemu-img',
'snapshot',
'-d',
snapshot_name,
disk_path)
# NOTE(vish): libvirt changes ownership of images
execute(*qemu_img_cmd, run_as_root=True)
def extract_snapshot(disk_path, source_fmt, snapshot_name, out_path, dest_fmt): def extract_snapshot(disk_path, source_fmt, snapshot_name, out_path, dest_fmt):
@ -178,7 +202,7 @@ def extract_snapshot(disk_path, source_fmt, snapshot_name, out_path, dest_fmt):
:param snapshot_name: Name of snapshot in disk image :param snapshot_name: Name of snapshot in disk image
:param out_path: Desired path of extracted snapshot :param out_path: Desired path of extracted snapshot
""" """
qemu_img_cmd = (FLAGS.qemu_img, qemu_img_cmd = ('qemu-img',
'convert', 'convert',
'-f', '-f',
source_fmt, source_fmt,