在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下载镜像
libvirt 中的image cache
最新推荐文章于 2022-09-22 18:25:50 发布