diff options
Diffstat (limited to 'nova/virt/libvirt/imagebackend.py')
-rw-r--r-- | nova/virt/libvirt/imagebackend.py | 111 |
1 files changed, 81 insertions, 30 deletions
diff --git a/nova/virt/libvirt/imagebackend.py b/nova/virt/libvirt/imagebackend.py index 08bad69489..0a64ef43dd 100644 --- a/nova/virt/libvirt/imagebackend.py +++ b/nova/virt/libvirt/imagebackend.py @@ -81,14 +81,24 @@ def _update_utime_ignore_eacces(path): class Image(metaclass=abc.ABCMeta): SUPPORTS_CLONE = False - - def __init__(self, path, source_type, driver_format, is_block_dev=False): + SUPPORTS_LUKS = False + + def __init__( + self, + path, + source_type, + driver_format, + is_block_dev=False, + disk_info_mapping=None + ): """Image initialization. :param path: libvirt's representation of the path of this disk. :param source_type: block or file :param driver_format: raw or qcow2 :param is_block_dev: + :param disk_info_mapping: disk_info['mapping'][device] metadata + specific to this image generated by nova.virt.libvirt.blockinfo. """ if (CONF.ephemeral_storage_encryption.enabled and not self._supports_encryption()): @@ -105,6 +115,8 @@ class Image(metaclass=abc.ABCMeta): self.is_block_dev = is_block_dev self.preallocate = False + self.disk_info_mapping = disk_info_mapping + # NOTE(dripton): We store lines of json (path, disk_format) in this # file, for some image types, to prevent attacks based on changing the # disk_format. @@ -145,22 +157,23 @@ class Image(metaclass=abc.ABCMeta): pass def libvirt_info( - self, disk_info, cache_mode, extra_specs, boot_order=None, - disk_unit=None, + self, cache_mode, extra_specs, boot_order=None, disk_unit=None, ): """Get `LibvirtConfigGuestDisk` filled for this image. - :disk_info: Metadata generated by libvirt.blockinfo.get_disk_mapping :cache_mode: Caching mode for this image :extra_specs: Instance type extra specs dict. :boot_order: Disk device boot order """ - disk_bus = disk_info['bus'] + if self.disk_info_mapping is None: + raise AttributeError( + 'Image must have disk_info_mapping to call libvirt_info()') + disk_bus = self.disk_info_mapping['bus'] info = vconfig.LibvirtConfigGuestDisk() info.source_type = self.source_type - info.source_device = disk_info['type'] + info.source_device = self.disk_info_mapping['type'] info.target_bus = disk_bus - info.target_dev = disk_info['dev'] + info.target_dev = self.disk_info_mapping['dev'] info.driver_cache = cache_mode info.driver_discard = self.discard_mode info.driver_io = self.driver_io @@ -522,11 +535,16 @@ class Flat(Image): when creating a disk from a qcow2 if force_raw_images is not set in config. """ - def __init__(self, instance=None, disk_name=None, path=None): + def __init__( + self, instance=None, disk_name=None, path=None, disk_info_mapping=None + ): self.disk_name = disk_name path = (path or os.path.join(libvirt_utils.get_instance_path(instance), disk_name)) - super(Flat, self).__init__(path, "file", "raw", is_block_dev=False) + super().__init__( + path, "file", "raw", is_block_dev=False, + disk_info_mapping=disk_info_mapping + ) self.preallocate = ( strutils.to_slug(CONF.preallocate_images) == 'space') @@ -568,15 +586,21 @@ class Flat(Image): def copy_raw_image(base, target, size): libvirt_utils.copy_image(base, target) if size: - image = imgmodel.LocalFileImage(target, - self.driver_format) - disk.extend(image, size) + self.resize_image(size) generating = 'image_id' not in kwargs if generating: if not self.exists(): # Generating image in place prepare_template(target=self.path, *args, **kwargs) + + # NOTE(plibeau): extend the disk in the case of image is not + # accessible anymore by the customer and the base image is + # available on source compute during the resize of the + # instance. + else: + if size: + self.resize_image(size) else: if not os.path.exists(base): prepare_template(target=base, *args, **kwargs) @@ -608,10 +632,15 @@ class Flat(Image): class Qcow2(Image): - def __init__(self, instance=None, disk_name=None, path=None): + def __init__( + self, instance=None, disk_name=None, path=None, disk_info_mapping=None + ): path = (path or os.path.join(libvirt_utils.get_instance_path(instance), disk_name)) - super(Qcow2, self).__init__(path, "file", "qcow2", is_block_dev=False) + super().__init__( + path, "file", "qcow2", is_block_dev=False, + disk_info_mapping=disk_info_mapping + ) self.preallocate = ( strutils.to_slug(CONF.preallocate_images) == 'space') @@ -625,7 +654,8 @@ class Qcow2(Image): @utils.synchronized(filename, external=True, lock_path=self.lock_path) def create_qcow2_image(base, target, size): - libvirt_utils.create_cow_image(base, target, size) + libvirt_utils.create_image( + target, 'qcow2', size, backing_file=base) # Download the unmodified base image unless we already have a copy. if not os.path.exists(base): @@ -689,7 +719,10 @@ class Lvm(Image): def escape(filename): return filename.replace('_', '__') - def __init__(self, instance=None, disk_name=None, path=None): + def __init__( + self, instance=None, disk_name=None, path=None, + disk_info_mapping=None + ): self.ephemeral_key_uuid = instance.get('ephemeral_key_uuid') if self.ephemeral_key_uuid is not None: @@ -718,7 +751,10 @@ class Lvm(Image): self.lv_path = os.path.join('/dev', self.vg, self.lv) path = '/dev/mapper/' + dmcrypt.volume_name(self.lv) - super(Lvm, self).__init__(path, "block", "raw", is_block_dev=True) + super(Lvm, self).__init__( + path, "block", "raw", is_block_dev=True, + disk_info_mapping=disk_info_mapping + ) # TODO(sbauza): Remove the config option usage and default the # LVM logical volume creation to preallocate the full size only. @@ -826,7 +862,9 @@ class Rbd(Image): SUPPORTS_CLONE = True - def __init__(self, instance=None, disk_name=None, path=None): + def __init__( + self, instance=None, disk_name=None, path=None, disk_info_mapping=None + ): if not CONF.libvirt.images_rbd_pool: raise RuntimeError(_('You should specify' ' images_rbd_pool' @@ -848,31 +886,32 @@ class Rbd(Image): if self.driver.ceph_conf: path += ':conf=' + self.driver.ceph_conf - super(Rbd, self).__init__(path, "block", "rbd", is_block_dev=False) + super().__init__( + path, "block", "rbd", is_block_dev=False, + disk_info_mapping=disk_info_mapping + ) self.discard_mode = CONF.libvirt.hw_disk_discard def libvirt_info( - self, disk_info, cache_mode, extra_specs, boot_order=None, - disk_unit=None, + self, cache_mode, extra_specs, boot_order=None, disk_unit=None ): """Get `LibvirtConfigGuestDisk` filled for this image. - :disk_info: Metadata generated by libvirt.blockinfo.get_disk_mapping :cache_mode: Caching mode for this image :extra_specs: Instance type extra specs dict. :boot_order: Disk device boot order """ info = vconfig.LibvirtConfigGuestDisk() - disk_bus = disk_info['bus'] + disk_bus = self.disk_info_mapping['bus'] hosts, ports = self.driver.get_mon_addrs() - info.source_device = disk_info['type'] + info.source_device = self.disk_info_mapping['type'] info.driver_format = 'raw' info.driver_cache = cache_mode info.driver_discard = self.discard_mode info.target_bus = disk_bus - info.target_dev = disk_info['dev'] + info.target_dev = self.disk_info_mapping['dev'] info.source_type = 'network' info.source_protocol = 'rbd' info.source_name = '%s/%s' % (self.driver.pool, self.rbd_name) @@ -1189,10 +1228,15 @@ class Rbd(Image): class Ploop(Image): - def __init__(self, instance=None, disk_name=None, path=None): + def __init__( + self, instance=None, disk_name=None, path=None, disk_info_mapping=None + ): path = (path or os.path.join(libvirt_utils.get_instance_path(instance), disk_name)) - super(Ploop, self).__init__(path, "file", "ploop", is_block_dev=False) + super().__init__( + path, "file", "ploop", is_block_dev=False, + disk_info_mapping=disk_info_mapping + ) self.resolve_driver_format() @@ -1295,18 +1339,25 @@ class Backend(object): raise RuntimeError(_('Unknown image_type=%s') % image_type) return image - def by_name(self, instance, name, image_type=None): + def by_name(self, instance, name, image_type=None, disk_info_mapping=None): """Return an Image object for a disk with the given name. :param instance: the instance which owns this disk :param name: The name of the disk :param image_type: (Optional) Image type. Default is CONF.libvirt.images_type. + :param disk_info_mapping: (Optional) Disk info mapping dict :return: An Image object for the disk with given name and instance. :rtype: Image """ + # NOTE(artom) To pass functional tests, wherein the code here is loaded + # *before* any config with self.flags() is done, we need to have the + # default inline in the method, and not in the kwarg declaration. + image_type = image_type or CONF.libvirt.images_type backend = self.backend(image_type) - return backend(instance=instance, disk_name=name) + return backend( + instance=instance, disk_name=name, + disk_info_mapping=disk_info_mapping) def by_libvirt_path(self, instance, path, image_type=None): """Return an Image object for a disk with the given libvirt path. |