convert images that are not 'raw' to 'raw' during caching to node This uses 'qemu-img' to convert images that are not 'raw' to be 'raw'. By doing so, it a.) refuses to run uploaded images that have a backing image reference (LP: #853330, CVE-2011-3147) b.) ensures that when FLAGS.use_cow_images is False, and the libvirt xml written specifies 'driver_type="raw"' that the disk referenced is also raw format. (LP: #837102) c.) removes compression that might be present to avoid cpu bottlenecks (LP: #837100) It does have the negative side affect of using more space in the case where the user uploaded a qcow2 (or other advanced image format) that could have been used directly by the hypervisor. That could, later, be remedied by another 'qemu-img convert' being done to the "preferred" format of the hypervisor. === modified file 'nova/virt/images.py' --- nova/virt/images.py 2011-09-10 17:56:54 +0000 +++ nova/virt/images.py 2011-09-20 00:39:22 +0000 @@ -21,6 +21,9 @@ Handling of VM disk images. """ +import os + +from nova import exception from nova import flags from nova.image import glance as glance_image_service import nova.image @@ -42,3 +45,56 @@ with open(path, "wb") as image_file: metadata = image_service.get(context, image_id, image_file) return metadata + + +def fetch_to_raw(context, image_href, path, _user_id, _project_id): + path_tmp = "%s.part" % path + metadata = fetch(context, image_href, path_tmp, _user_id, _project_id) + + def _qemu_img_info(path): + + out, err = utils.execute('qemu-img', 'info', path) + + # output of qemu-img is 'field: value' + # the fields of interest are 'file format' and 'backing file' + data = {} + for line in out.splitlines(): + (field, val) = line.split(':', 1) + if val[0] == " ": + val = val[1:] + data[field] = val + + return(data) + + data = _qemu_img_info(path_tmp) + + fmt = data.get("file format", None) + if fmt == None: + raise exception.ImageUnacceptable( + reason=_("'qemu-img info' parsing failed."), image_id=image_href) + + if fmt != "raw": + staged = "%s.converted" % path + if "backing file" in data: + backing_file = data['backing file'] + raise exception.ImageUnacceptable(image_id=image_href, + reason=_("fmt=%(fmt)s backed by: %(backing_file)s" % + locals())) + + LOG.debug("%s was %s, converting to raw" % (image_href, fmt)) + out, err = utils.execute('qemu-img', 'convert', '-O', 'raw', + path_tmp, staged) + os.unlink(path_tmp) + + data = _qemu_img_info(staged) + if data.get('file format', None) != "raw": + raise exception.ImageUnacceptable(image_id=image_href, + reason=_("Converted to raw, but format is now %s") % + data.get('file format', None)) + + os.rename(staged, path) + + else: + os.rename(path_tmp, path) + + return metadata === modified file 'nova/virt/libvirt/connection.py' --- nova/virt/libvirt/connection.py 2011-09-19 14:22:34 +0000 +++ nova/virt/libvirt/connection.py 2011-09-19 20:59:29 +0000 @@ -769,7 +769,7 @@ def _fetch_image(self, context, target, image_id, user_id, project_id, size=None): """Grab image and optionally attempt to resize it""" - images.fetch(context, image_id, target, user_id, project_id) + images.fetch_to_raw(context, image_id, target, user_id, project_id) if size: disk.extend(target, size)