这里只关注Nova virt的spawn函数,glance、nova后端为ceph
nova/virt/libvirt/driver.py
def spawn(self, context, instance, p_w_picpath_meta, injected_files,
admin_password, network_info=None, block_device_info=None):
p_w_picpath_meta = objects.ImageMeta.from_dict(p_w_picpath_meta)
disk_info = blockinfo.get_disk_info(CONF.libvirt.virt_type,
instance,
p_w_picpath_meta,
block_device_info)
self._create_p_w_picpath(context, instance, # 虚拟机拉取glance p_w_picpath
disk_info['mapping'],
network_info=network_info,
block_device_info=block_device_info,
files=injected_files,
admin_pass=admin_password)
xml = self._get_guest_xml(context, instance, network_info,
disk_info, p_w_picpath_meta,
block_device_info=block_device_info,
write_to_disk=True)
self._create_domain_and_network(context, xml, instance, network_info,
disk_info,
block_device_info=block_device_info)
LOG.debug("Instance is running", instance=instance)
def _wait_for_boot():
"""Called at an interval until the VM is running."""
state = self.get_info(instance).state
if state == power_state.RUNNING:
LOG.info(_LI("Instance spawned successfully."),
instance=instance)
raise loopingcall.LoopingCallDone()
timer = loopingcall.FixedIntervalLoopingCall(_wait_for_boot) # loopingcall等待虚拟机running的状态
timer.start(interval=0.5).wait()
nova/virt/libvirt/driver.py
def _create_p_w_picpath(self, context, instance,
disk_mapping, suffix='',
disk_p_w_picpaths=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( # 判断是不是boot_from_volume,boot_from_volume没有base p_w_picpath
instance)
if not booted_from_volume:
root_fname = p_w_picpathcache.get_cache_fname(disk_p_w_picpaths, 'p_w_picpath_id')
size = instance.root_gb * units.Gi
if size == 0 or suffix == '.rescue':
size = None
backend = p_w_picpath('disk')
if backend.SUPPORTS_CLONE: # 只有backend为rbd的才支持clone操作
def clone_fallback_to_fetch(*args, **kwargs):
try:
backend.clone(context, disk_p_w_picpaths['p_w_picpath_id']) # clone操作在nova/virt/libvirt/p_w_picpathbackend.py中class Rbd下
except exception.ImageUnacceptable: # 除p_w_picpath格式为raw和iso外的格式都抛异常
libvirt_utils.fetch_p_w_picpath(*args, **kwargs)
fetch_func = clone_fallback_to_fetch
else:
fetch_func = libvirt_utils.fetch_p_w_picpath
self._try_fetch_p_w_picpath_cache(backend, fetch_func, context, # 进入_try_fetch_p_w_picpath_cache函数
root_fname, disk_p_w_picpaths['p_w_picpath_id'],
instance, size, fallback_from_host)
。。。。。。。。
# File injection only if needed,
# 这里在OpenStack in Openstack环境下注入密码有坑,从nova-compute log中看到一直卡在create p_w_picpath过程,
# 实际上是卡在密码注入过程。。。
elif inject_files and CONF.libvirt.inject_partition != -2:
if booted_from_volume:
LOG.warn(_LW('File injection into a boot from volume '
'instance is not supported'), instance=instance)
self._inject_data( # 注入相关的操作
instance, network_info, admin_pass, files, suffix)
if CONF.libvirt.virt_type == 'uml':
libvirt_utils.chown(p_w_picpath('disk').path, 'root')
nova/virt/libvirt/p_w_picpathbackend.py
def clone(self, context, p_w_picpath_id_or_uri):
p_w_picpath_meta = IMAGE_API.get(context, p_w_picpath_id_or_uri,
include_locations=True)
locations = p_w_picpath_meta['locations']
LOG.debug('Image locations are: %(locs)s' % {'locs': locations})
if p_w_picpath_meta.get('disk_format') not in ['raw', 'iso']: # p_w_picpath格式判断, 所以ceph p_w_picpath格式最好是raw,这样走的ceph的clone
reason = _('Image is not raw format')
raise exception.ImageUnacceptable(p_w_picpath_id=p_w_picpath_id_or_uri,
reason=reason)
for location in locations:
if self.driver.is_cloneable(location, p_w_picpath_meta):
return self.driver.clone(location, self.rbd_name) # 调用nova/virt/libvirt/storage/rbd_utils.py
reason = _('No p_w_picpath locations are accessible')
raise exception.ImageUnacceptable(p_w_picpath_id=p_w_picpath_id_or_uri,
reason=reason)
nova/virt/libvirt/driver.py
def _try_fetch_p_w_picpath_cache(self, p_w_picpath, fetch_func, context, filename,
p_w_picpath_id, instance, size,
fallback_from_host=None):
try:
p_w_picpath.cache(fetch_func=fetch_func, # 进入cache函数
context=context,
filename=filename,
p_w_picpath_id=p_w_picpath_id,
user_id=instance.user_id,
project_id=instance.project_id,
size=size)
except exception.ImageNotFound:
if not fallback_from_host:
raise
LOG.debug("Image %(p_w_picpath_id)s doesn't exist anymore "
"on p_w_picpath service, attempting to copy "
"p_w_picpath from %(host)s",
{'p_w_picpath_id': p_w_picpath_id, 'host': fallback_from_host},
instance=instance)
def copy_from_host(target, max_size):
libvirt_utils.copy_p_w_picpath(src=target,
dest=target,
host=fallback_from_host,
receive=True)
p_w_picpath.cache(fetch_func=copy_from_host,
filename=filename)
nova/virt/libvirt/p_w_picpathbackend.py
def cache(self, fetch_func, filename, size=None, *args, **kwargs):
"""Creates p_w_picpath from template.
Ensures that template and p_w_picpath not already exists.
Ensures that base directory exists.
Synchronizes on template fetching.
:fetch_func: Function that creates the base p_w_picpath
Should accept `target` argument.
:filename: Name of the file in the p_w_picpath directory
:size: Size of created p_w_picpath in bytes (optional)
"""
@utils.synchronized(filename, external=True, lock_path=self.lock_path)
def fetch_func_sync(target, *args, **kwargs):
# The p_w_picpath may have been fetched while a subsequent
# call was waiting to obtain the lock.
if not os.path.exists(target): # 如果不存在base p_w_picpath的话
fetch_func(target=target, *args, **kwargs) # fetch_func是clone_fallback_to_fetch
base_dir = os.path.join(CONF.instances_path,
CONF.p_w_picpath_cache_subdirectory_name)
if not os.path.exists(base_dir):
fileutils.ensure_tree(base_dir)
base = os.path.join(base_dir, filename)
if not self.check_p_w_picpath_exists() or not os.path.exists(base):
self.create_p_w_picpath(fetch_func_sync, base, size, base p_w_picpath如果不存在的话,进入create_p_w_picpath
*args, **kwargs)
if (size and self.preallocate and self._can_fallocate() and
os.access(self.path, os.W_OK)):
utils.execute('fallocate', '-n', '-l', size, self.path)
nova/virt/libvirt/p_w_picpathbackend.py
def create_p_w_picpath(self, prepare_template, base, size, *args, **kwargs):
if not self.check_p_w_picpath_exists():
prepare_template(target=base, max_size=size, *args, **kwargs) # prepare_template这里是fetch_func_sync
# prepare_template() may have cloned the p_w_picpath into a new rbd
# p_w_picpath already instead of downloading it locally
if not self.check_p_w_picpath_exists(): # 如果走的是rbd clone操作,这里就不会用rbd import了
self.driver.import_p_w_picpath(base, self.rbd_name)
self.verify_base_size(base, size)
if size and size > self.get_disk_size(self.rbd_name):
self.driver.resize(self.rbd_name, size)
总结: nova、glance后端为ceph,raw格式的p_w_picpath没有base p_w_picpath, qcow2格式还是有base p_w_picpath的,不过rbd import base p_w_picpath到pool后,可以把缓存的base p_w_picpath删除
转载于:https://blog.51cto.com/iceyao/1838604