最终调用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)
nova 创建qcow2的kernel image的过程
最新推荐文章于 2024-07-12 16:46:50 发布