summaryrefslogtreecommitdiffstats
path: root/nova/virt
diff options
context:
space:
mode:
Diffstat (limited to 'nova/virt')
-rw-r--r--nova/virt/driver.py4
-rw-r--r--nova/virt/libvirt_conn.py81
2 files changed, 76 insertions, 9 deletions
diff --git a/nova/virt/driver.py b/nova/virt/driver.py
index f9cf1b8aa..fcd31861d 100644
--- a/nova/virt/driver.py
+++ b/nova/virt/driver.py
@@ -232,3 +232,7 @@ class ComputeDriver(object):
def inject_network_info(self, instance):
"""inject network info for specified instance"""
raise NotImplementedError()
+
+ def poll_rescued_instances(self, timeout):
+ """Poll for rescued instances"""
+ raise NotImplementedError()
diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py
index 5962507d7..80eb64f3c 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,67 @@ 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 = {'disk_format': base['disk_format'],
+ 'container_format': base['container_format'],
+ 'is_public': False,
+ 'properties': {'architecture': base['architecture'],
+ 'type': base['type'],
+ 'name': '%s.%s' % (base['name'], image_id),
+ '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):
@@ -760,11 +822,12 @@ class LibvirtConnection(driver.ComputeDriver):
'dns': network_ref['dns'],
'address_v6': address_v6,
'gateway_v6': network_ref['gateway_v6'],
- 'netmask_v6': network_ref['netmask_v6'],
- 'use_ipv6': FLAGS.use_ipv6}
+ 'netmask_v6': network_ref['netmask_v6']}
nets.append(net_info)
- net = str(Template(ifc_template, searchList=[{'interfaces': nets}]))
+ net = str(Template(ifc_template,
+ searchList=[{'interfaces': nets,
+ 'use_ipv6': FLAGS.use_ipv6}]))
if key or net:
inst_name = inst['name']