libvirt 中的image cache


在nova/virt/libvirt/driver.py 中的_create_image 会生成instance的镜像,且会调用cache来进行缓存到本地
def _create_image(self, context, instance,
                      disk_mapping, injection_info=None, suffix='',
                      disk_images=None, block_device_info=None,
                      fallback_from_host=None,
                      ignore_bdi_for_swap=False):
        booted_from_volume = self._is_booted_from_volume(block_device_info)

        def image(fname, image_type=CONF.libvirt.images_type):
	//最终通过image_backend来缓存
            return self.image_backend.by_name(instance,
                                              fname + suffix, image_type)

        def raw(fname):
            return image(fname, image_type='raw')


        LOG.info('Creating image', instance=instance)

      
        if disk_images['kernel_id']:
            fname = imagecache.get_cache_fname(disk_images['kernel_id'])
		//进行缓存操作
            raw('kernel').cache(fetch_func=libvirt_utils.fetch_raw_image,
                                context=context,
                                filename=fname,
                                image_id=disk_images['kernel_id'])
这里的self.image_backend = imagebackend.Backend(CONF.use_cow_images)
imagebackend的实现在libvirt/Imagebackend.py 中的
class Backend(object):
    def __init__(self, use_cow):
        self.BACKEND = {
            'raw': Flat,
            'flat': Flat,
            'qcow2': Qcow2,
            'lvm': Lvm,
            'rbd': Rbd,
            'ploop': Ploop,
            'default': Qcow2 if use_cow else Flat
        }

    def backend(self, image_type=None):
        if not image_type:
            image_type = CONF.libvirt.images_type
        image = self.BACKEND.get(image_type)
        if not image:
            raise RuntimeError(_('Unknown image_type=%s') % image_type)
        return image
可见这里默认用的是Qcow2。而nova支持的image的格式在BACKEND 这个字典中
因此这里继续调用Qcow2的get函数来根据name找到image。这里的Qcow2也是定义在Imagebackend.py 中
回到raw('kernel').cache 这句,原来最终是调用Qcow2.cache
class Qcow2(Image):
Qcow2继承与Image 内,由于Qcow2没有实现cache函数,因此这里调用Image的cache函数
  def cache(self, fetch_func, filename, size=None, *args, **kwargs):
        """Creates image from template.

        Ensures that template and image not already exists.
        Ensures that base directory exists.
        Synchronizes on template fetching.

        :fetch_func: Function that creates the base image
                     Should accept `target` argument.
        :filename: Name of the file in the image directory
        :size: Size of created image in bytes (optional)
        """
		//获取缓存文件的目录
        base_dir = os.path.join(CONF.instances_path,
                                CONF.image_cache_subdirectory_name)
		// 如果目录不存在,则创建新的目录
        if not os.path.exists(base_dir):
            fileutils.ensure_tree(base_dir)
		// 获取要缓存的镜像文件名
        base = os.path.join(base_dir, filename)

        @utils.synchronized(filename, external=True, lock_path=self.lock_path)
        def fetch_func_sync(target, *args, **kwargs):
            # NOTE(mdbooth): This method is called as a callback by the
            # create_image() method of a specific backend. It assumes that
            # target will be in the image cache, which is why it holds a
            # lock, and does not overwrite an existing file. However,
            # this is not true for all backends. Specifically Lvm writes
            # directly to the target rather than to the image cache,
            # and additionally it creates the target in advance.
            # This guard is only relevant in the context of the lock if the
            # target is in the image cache. If it isn't, we should
            # call fetch_func. The lock we're holding is also unnecessary in
            # that case, but it will not result in incorrect behaviour.
            if target != base or not os.path.exists(target):
                fetch_func(target=target, *args, **kwargs)
	// 由于是第一次缓存,因此镜像文件是不存在的,
        if not self.exists() or not os.path.exists(base):
            self.create_image(fetch_func_sync, base, size,
                              *args, **kwargs)
因此这里会继续调用create_image,这里会调用Qcow2 类自己的函数
def create_image(self, prepare_template, base, size, *args, **kwargs):
        filename = self._get_lock_name(base)

        @utils.synchronized(filename, external=True, lock_path=self.lock_path)
        def copy_qcow2_image(base, target, size):
            # TODO(pbrady): Consider copying the cow image here
            # with preallocation=metadata set for performance reasons.
            # This would be keyed on a 'preallocate_images' setting.
            libvirt_utils.create_cow_image(base, target)
            if size:
                image = imgmodel.LocalFileImage(target, imgmodel.FORMAT_QCOW2)
                disk.extend(image, size)
		// 文件不存在,则调用prepare_template从glance下载
        # Download the unmodified base image unless we already have a copy.
        if not os.path.exists(base):
            prepare_template(target=base, *args, **kwargs)

        # NOTE(ankit): Update the mtime of the base file so the image
        # cache manager knows it is in use.
        nova.privsep.path.utime(base)
        self.verify_base_size(base, size)
// 如果glance上没有的话,就调用copy_qcow2_image 来创建Qcow2格式的镜像

        if not os.path.exists(self.path):
            with fileutils.remove_path_on_error(self.path):
                copy_qcow2_image(base, self.path, size)
				
先看看这里的prepare_template最终等于libvirt_utils.fetch_raw_image,因此这里会调用fetch_raw_image 来下载镜像
nova/virt/libvirt/utils.py 中实现了fetch_raw_image
def fetch_raw_image(context, target, image_id):
    """Grab initrd or kernel image.

    This function does not attempt raw conversion, as these images will
    already be in raw format.
    """
    images.fetch(context, image_id, target)
这里的image来自nova/virt/image.py
def fetch(context, image_href, path):
    with fileutils.remove_path_on_error(path):
        IMAGE_API.download(context, image_href, dest_path=path)
最终调用 download 从glance下载镜像



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值