nova 创建qcow2的kernel image的过程

最终调用nova/virt/libvirt/driver.py 中的spawn来创建虚拟机
    def spawn(self, context, instance, image_meta, injected_files,
              admin_password, network_info=None, block_device_info=None):
        disk_info = blockinfo.get_disk_info(CONF.libvirt.virt_type,
                                            instance,
                                            image_meta,
                                            block_device_info)
        gen_confdrive = functools.partial(self._create_configdrive,
                                          context, instance,
                                          admin_pass=admin_password,
                                          files=injected_files,
                                          network_info=network_info)
这里有调用_create_image
        self._create_image(context, instance,
                           disk_info['mapping'],
                           network_info=network_info,
                           block_device_info=block_device_info,
                           files=injected_files,
                           admin_pass=admin_password)

_create_image 源码如下:
    def _create_image(self, context, instance,
                      disk_mapping, suffix='',
                      disk_images=None, network_info=None,
                      block_device_info=None, files=None,
                      admin_pass=None, inject_files=True,
                      fallback_from_host=None):
        booted_from_volume = self._is_booted_from_volume(
            instance, disk_mapping)

        def image(fname, image_type=CONF.libvirt.images_type):
            return self.image_backend.image(instance,
                                            fname + suffix, image_type)

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

        # ensure directories exist and are writable
        fileutils.ensure_tree(libvirt_utils.get_instance_path(instance))

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

        if not disk_images:
            disk_images = {'image_id': instance.image_ref,
                           'kernel_id': instance.kernel_id,
                           'ramdisk_id': instance.ramdisk_id}

        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'])
可以看到_create_image 中最终调用raw('kernel').cache 来创建kennel镜像,而raw函数调用image。所以最终调用image.cache 来创建kernel镜像,image定义如下:
def image(fname, image_type=CONF.libvirt.images_type):
            return self.image_backend.image(instance,
                                            fname + suffix, image_type)
可见最终调用mage_backend.image。其源码路径为nova/virt/libvirt/imagebackend.py 
  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)
        """
        @utils.synchronized(filename, external=True, lock_path=self.lock_path)
        def fetch_func_sync(target, *args, **kwargs):
            # The image may have been fetched while a subsequent
            # call was waiting to obtain the lock.
            if not os.path.exists(target):
                fetch_func(target=target, *args, **kwargs)

        base_dir = os.path.join(CONF.instances_path,
                                CONF.image_cache_subdirectory_name)
//获取kernel镜像
        if not os.path.exists(base_dir):
            fileutils.ensure_tree(base_dir)
        base = os.path.join(base_dir, filename)
//如果镜像不存在则调用create_image 来创建kernel镜像
        if not self.exists() or not os.path.exists(base):
            self.create_image(fetch_func_sync, base, size,
                              *args, **kwargs)
由于建立的kernel镜像为qcow2格式,因此create_image实现在qcow2中

class Qcow2(Image):
    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)

        # Download the unmodified base image unless we already have a copy.
//qcow2镜像的制作必须有个base,如果没有base的话,要通过prepare_template来下载base
        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.
        libvirt_utils.update_mtime(base)
        self.verify_base_size(base, size)

        legacy_backing_size = None
        legacy_base = base

        # Determine whether an existing qcow2 disk uses a legacy backing by
        # actually looking at the image itself and parsing the output of the
        # backing file it expects to be using.
有base后通过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是create_image的第二个参数,往上回溯可以发现这个函数其实为
            self.create_image(fetch_func_sync, base, size,
                              *args, **kwargs)
原来就是fetch_func_sync
        def fetch_func_sync(target, *args, **kwargs):
            # The image may have been fetched while a subsequent
            # call was waiting to obtain the lock.
            if not os.path.exists(target):
                fetch_func(target=target, *args, **kwargs)
这里有调用函数指针fetch_func,继续回溯
raw('kernel').cache(fetch_func=libvirt_utils.fetch_raw_image,
                                context=context,
                                filename=fname,
                                image_id=disk_images['kernel_id'])
原来最终调用libvirt_utils.fetch_raw_image 来下载base镜像,其源码在libvirt/utils.py 
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.fetch.其源码在virtt/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 的函数最终在nova/image/glance.py 中实现。重点是知道这里是通过glance下载的base镜像就行了
回到Qcow2类的create_image函数中,下载base镜像后还要通过copy_qcow2_image创建qcow2镜像.其源码在libvirt/utils.py中
def create_cow_image(backing_file, path, size=None):
    """Create COW image

    Creates a COW image with the given backing file
构建命令创建qcow2镜像
    :param backing_file: Existing image on which to base the COW image
    :param path: Desired location of the COW image
    """
    base_cmd = ['qemu-img', 'create', '-f', 'qcow2']
    cow_opts = []
    if backing_file:
        cow_opts += ['backing_file=%s' % backing_file]
        base_details = images.qemu_img_info(backing_file)
    else:
        base_details = None
    # Explicitly inherit the value of 'cluster_size' property of a qcow2
    # overlay image from its backing file. This can be useful in cases
    # when people create a base image with a non-default 'cluster_size'
    # value or cases when images were created with very old QEMU
    # versions which had a different default 'cluster_size'.
    if base_details and base_details.cluster_size is not None:
        cow_opts += ['cluster_size=%s' % base_details.cluster_size]
    if size is not None:
        cow_opts += ['size=%s' % size]
    if cow_opts:
        # Format as a comma separated list
        csv_opts = ",".join(cow_opts)
        cow_opts = ['-o', csv_opts]
    cmd = base_cmd + cow_opts + [path]
执行命令
    execute(*cmd)


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值