summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authortermie <github@anarkystic.com>2011-03-28 10:47:08 -0700
committertermie <github@anarkystic.com>2011-03-28 10:47:08 -0700
commitdbf14e9b6cc337233ef95b03fd1c2fdba8ebf8a7 (patch)
tree5c56178dcbf1c57197efbd2b529746b9f3fc5b83
parentc3c86f994413792cf582df86cf5e16f788005bed (diff)
add snapshot support for libvirt
-rw-r--r--nova/virt/libvirt_conn.py71
1 files changed, 65 insertions, 6 deletions
diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py
index 36457ee87..4456ffc12 100644
--- a/nova/virt/libvirt_conn.py
+++ b/nova/virt/libvirt_conn.py
@@ -38,12 +38,15 @@ Supports KVM, QEMU, UML, and XEN.
import multiprocessing
import os
-import shutil
-import sys
import random
+import shutil
import subprocess
+import sys
+import tempfile
+import time
import uuid
from xml.dom import minidom
+from xml.etree import ElementTree
from eventlet import greenthread
from eventlet import tpool
@@ -111,6 +114,8 @@ flags.DEFINE_string('live_migration_flag',
'Define live migration behavior.')
flags.DEFINE_integer('live_migration_bandwidth', 0,
'Define live migration behavior')
+flags.DEFINE_string('qemu_img', 'qemu-img',
+ 'binary to use for qemu-img commands')
def get_connection(read_only):
@@ -397,10 +402,64 @@ class LibvirtConnection(driver.ComputeDriver):
@exception.wrap_exception
def snapshot(self, instance, image_id):
- """ Create snapshot from a running VM instance """
- raise NotImplementedError(
- _("Instance snapshotting is not supported for libvirt"
- "at this time"))
+ """Create snapshot from a running VM instance.
+
+ This command only works with qemu 0.14+, the qemu_img flag is
+ provided so that a locally compiled binary of qemu-img can be used
+ to support this command.
+
+ """
+ image_service = utils.import_object(FLAGS.image_service)
+ virt_dom = self._conn.lookupByName(instance['name'])
+ elevated = context.get_admin_context()
+
+ base = image_service.show(elevated, instance['image_id'])
+
+ metadata = {'type': 'machine',
+ 'is_public': False,
+ 'properties': {'architecture': base['architecture'],
+ 'kernel_id': instance['kernel_id'],
+ 'image_location': 'snapshot',
+ 'image_state': 'available',
+ 'owner_id': instance['project_id'],
+ 'ramdisk_id': instance['ramdisk_id'],
+ }
+ }
+
+ # 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
+ xml_desc = virt_dom.XMLDesc(0)
+ domain = ElementTree.fromstring(xml_desc)
+ source = domain.find('devices/disk/source')
+ disk_path = source.get('file')
+
+ # Export the snapshot to a raw image
+ temp_dir = tempfile.mkdtemp()
+ out_path = os.path.join(temp_dir, snapshot_name)
+ qemu_img_cmd = '%s convert -f qcow2 -O raw -s %s %s %s' % (
+ FLAGS.qemu_img,
+ snapshot_name,
+ disk_path,
+ out_path)
+ utils.execute(qemu_img_cmd)
+
+ # Upload that image to the image service
+ with open(out_path) as image_file:
+ image_service.update(elevated,
+ image_id,
+ metadata,
+ image_file)
+
+ # Clean up
+ shutil.rmtree(temp_dir)
@exception.wrap_exception
def reboot(self, instance):