Nova创建虚拟机的底层代码分析
作为个人学习笔记分享。有不论什么问题欢迎交流!
在openstack中创建虚拟机的底层实现是nova使用了libvirt,代码在nova/virt/libvirt/driver.py。
#image_meta:镜像的相关内容,#injected_files:要注入到VM的文件
#network_info:网络相关信息。block_device_info:磁盘相关信息
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,
block_device_info,
image_meta)
#创建VM的磁盘文件
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)
#综合各方面的信息,拼装一个define VM的XML文件
xml = self.to_xml(context, instance, network_info,
disk_info, image_meta,
block_device_info=block_device_info,
write_to_disk=True)
#向neutron请求IP,然后使用xml创建domain
self._create_domain_and_network(context, xml, instance, network_info,
block_device_info)
以下将具体分析上述4个函数,比源码略有删减
#virt_type: cpu_mode,一般为kvm,具体可參见该选项的凝视
def get_disk_info(virt_type, instance, block_device_info=None,
image_meta=None, rescue=False):
#依据device_type和virt_type返回总线类型。如kvm和disk。则会返回virtio
#cdrom和kvm,则会返回ide
disk_bus = get_disk_bus_for_device_type(virt_type, image_meta, "disk")
cdrom_bus = get_disk_bus_for_device_type(virt_type, image_meta, "cdrom")
#确定如何映射默认的disks到VM中,如root挂到/dev/vda等。还有swap, local等
mapping = get_disk_mapping(virt_type, instance,
disk_bus, cdrom_bus,
block_device_info,
image_meta, rescue)
#准备磁盘文件
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):
#推断是否从volume启动VM
booted_from_volume = self._is_booted_from_volume(
instance, disk_mapping)
#依据images_type。如qcow2, RBD等,创建各种格式的镜像相应的类
def image(fname, image_type=CONF.libvirt.images_type):
return self.image_backend.image(instance,
fname + suffix, image_type)
#创建raw格式的镜像相应的类
def raw(fname):
return image(fname, image_type='raw') LOG.info(_('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')
#这里用到了上面定义的def raw()。其返回一个raw类型的类。cache()使用#fetch_image()完毕镜像文件的kernel下载,关于镜像的下载具体情况能够參#考:http://blog.csdn.net/epugv/article/details/27970625
raw('kernel').cache(fetch_func=libvirt_utils.fetch_image,
context=context,
filename=fname,
image_id=disk_images['kernel_id'],
user_id=instance['user_id'],
project_id=instance['project_id'])
if disk_images['ramdisk_id']:
fname = imagecache.get_cache_fname(disk_images, 'ramdisk_id')
#完毕ramdisk文件下载
raw('ramdisk').cache(fetch_func=libvirt_utils.fetch_image,
context=context,
filename=fname,
image_id=disk_images['ramdisk_id'],
user_id=instance['user_id'],
project_id=instance['project_id']) # 创建暂时磁盘,ephemeral disk指的是除了root disk和swap disk之外的ephemeral
#空间
ephemeral_gb = instance['ephemeral_gb']
if 'disk.local' in disk_mapping:
disk_image = image('disk.local')
fn = functools.partial(self._create_ephemeral,
fs_label='ephemeral0',
os_type=instance["os_type"],
is_block_dev=disk_image.is_block_dev)
fname = "ephemeral_%s_%s" % (ephemeral_gb, os_type_with_default)
size = ephemeral_gb * units.Gi
disk_image.cache(fetch_func=fn,
filename=fname,
size=size,
ephemeral_size=ephemeral_gb)
#假设还有ephemeral disk,继续创建。label为'ephemeral%d' % idx
for idx, eph in enumerate(driver.block_device_info_get_ephemerals(
block_device_info)):
disk_image = image(blockinfo.get_eph_disk(idx))
fn = functools.partial(self._create_ephemeral,
fs_label='ephemeral%d' % idx,
os_type=instance["os_type"],
is_block_dev=disk_image.is_block_dev)
size = eph['size'] * units.Gi
fname = "ephemeral_%s_%s" % (eph['size'], os_type_with_default)
disk_image.cache(
fetch_func=fn,
filename=fname,
size=size,
ephemeral_size=eph['size'])
#创建swap disk
if swap_mb > 0:
size = swap_mb * units.Mi
image('disk.swap').cache(fetch_func=self._create_swap,
filename="swap_%s" % swap_mb,
size=size,
swap_mb=swap_mb)
# OpenStack还能够使用Config Drive实现元数据的注入,可是在制作image时一
#定要安装cloud-init软件,否则无法实现元数据注入
# Config drive
if configdrive.required_by(instance):
LOG.info(_('Using config drive'), instance=instance)
extra_md = {}
if admin_pass:
extra_md['admin_pass'] = admin_pass
#提取instance matedata
inst_md = instance_metadata.InstanceMetadata(instance,
content=files, extra_md=extra_md, network_info=network_info)
with configdrive.ConfigDriveBuilder(instance_md=inst_md) as cdb:
configdrive_path = self._get_disk_config_path(instance)
LOG.info(_('Creating config drive at %(path)s'),
{'path': configdrive_path}, instance=instance)
#将metadata写入实例所在的目录下的一个disk.config文件里
try:
cdb.make_drive(configdrive_path)
except processutils.ProcessExecutionError as e:
with excutils.save_and_reraise_exception():
LOG.error(_('Creating config drive failed '
'with error: %s'),
e, instance=instance) #依据官方文档 -2 => disable, -1 => inspect (libguestfs only), 0 =>
#not partitioned, >0 => partition number
# File injection only if needed
elif inject_files and CONF.libvirt.inject_partition != -2:
if booted_from_volume:
LOG.warn(_('File injection into a boot from volume '
'instance is not supported'), instance=instance)
self._inject_data(
instance, network_info, admin_pass, files, suffix)
def to_xml(self, context, instance, network_info, disk_info,
image_meta=None, rescue=None,
block_device_info=None, write_to_disk=False):
# We should get image metadata every time for generating xml
if image_meta is None:
image_ref = instance['image_ref']
image_meta = compute_utils.get_image_metadata(
context, self._image_api, image_ref, instance) msg = ('Start to_xml '
'network_info=%(network_info)s '
'disk_info=%(disk_info)s '
'image_meta=%(image_meta)s rescue=%(rescue)s '
'block_device_info=%(block_device_info)s' %
{'network_info': network_info_str, 'disk_info': disk_info,
'image_meta': image_meta, 'rescue': rescue,
'block_device_info': block_device_info})
#返回guest的具体參数
conf = self.get_guest_config(instance, network_info, image_meta,
disk_info, rescue, block_device_info)
xml = conf.to_xml()#将具体參数使用etree.tostring()生产一个xml dom
def _create_domain_and_network(self, context, xml, instance, network_info,
block_device_info=None, power_on=True,
reboot=False, vifs_already_plugged=False): for vol in block_device_mapping:
connection_info = vol['connection_info']
disk_info = blockinfo.get_info_from_bdm(
CONF.libvirt.virt_type, vol)
#挂载volume前与volume建立连接,如iscsi中的discover
conf = self.volume_driver_method('connect_volume',
connection_info,
disk_info)
#。。。 。。。
launch_flags = events and libvirt.VIR_DOMAIN_START_PAUSED or 0
try:
with self.virtapi.wait_for_instance_event(
instance, events, deadline=timeout,
error_callback=self._neutron_failed_callback):
self.plug_vifs(instance, network_info)#向network注入VIF
self.firewall_driver.setup_basic_filtering(instance,
network_info)
self.firewall_driver.prepare_instance_filter(instance,
network_info)
domain = self._create_domain(#调用libvirt的#defineXML () and #createWithFlags()
xml, instance=instance,
launch_flags=launch_flags,
power_on=power_on)
#应用防火墙
self.firewall_driver.apply_instance_filter(instance,
network_info)
#以下是错误处理。不表
Nova创建虚拟机的底层代码分析的更多相关文章
- nova创建虚拟机源码系列分析之二 wsgi模型
openstack nova启动时首先通过命令行或者dashborad填写创建信息,然后通过restful api的方式调用openstack服务去创建虚拟机.数据信息从客户端到达openstack服 ...
- 虚拟机创建流程中neutron代码分析(一)
前言: 在openstack的学习当中有一说法就是网络占学习时间的百分之七十.这个说法或许有夸大的成分,但不可否认的是openstack中的 网络是及其重要的部分,并且难度也是相当大.试图通过nova ...
- nova创建虚拟机源码分析系列之六 api入口create方法
openstack 版本:Newton 注:博文图片采用了很多大牛博客图片,仅作为总结学习,非商用.该图全面的说明了nova创建虚机的过程,从逻辑的角度清晰的描述了前端请求创建虚拟机之后发生的一系列反 ...
- nova创建虚拟机源码分析系列之五 nova源码分发实现
前面讲了很多nova restful的功能,无非是为本篇博文分析做铺垫.本节说明nova创建虚拟机的请求发送到openstack之后,nova是如何处理该条URL的请求,分析到处理的类. nova对于 ...
- nova创建虚拟机源码分析系列之三 PasteDeploy
上一篇博文介绍WSGI在nova创建虚拟机过程的作用是解析URL,是以一个最简单的例子去给读者有一个印象.在openstack中URL复杂程度也大大超过上一个例子.所以openstack使用了Past ...
- 在Ceph创建虚拟机的过程改进分析
作为个人学习笔记分享.有不论什么问题欢迎交流! 近期在Gerrit中看到一个change:https://review.openstack.org/#/c/94295/ , 它主要是对当前在Ceph中 ...
- nova创建虚拟机的详细过程
Nova 创建虚拟机详细过程
- nova创建虚拟机源码分析系列之四 nova代码模拟
在前面的三篇博文中,介绍了restful和SWGI的实现.结合restful和WSGI配置就能够简单的实现nova服务模型的最简单的操作. 如下的内容是借鉴网上博文,因为写的很巧妙,将nova管理虚拟 ...
- 虚拟机创建流程中neutron代码分析(三)
前言: 当neutron-server创建了port信息,将port信息写入数据库中.流程返回到nova服务端,接着nova创建的流程继续走.在计算节点中neutron-agent同样要完成很多的工作 ...
随机推荐
- 经常使用vi编辑命令
进入 vi 该命令 vi filename :打开或新建文件.在第一行和第一光标 vi +n filename :打开文件,并将光标置于第 n 行首 vi + filename :打开文件,并将 ...
- Oracle 数据迁移(从Oracle11G迁移到更高的版本号Oracle10G低版本号)
1.数据库状况 生产环境是11G,linux系统,測试环境是10G,windows系统,须要从生产环境导出一个用户下全部的数据,导入測试环境中. 由于数据量比較小,准备採用EXP和IMP工具来做 ...
- apache cxf之 一个简单的JAX-WS服务程序
推荐一本apache cxf的书籍: apache cxf的配置,这边就不做介绍了.请参照我关于它配置的博文. 开发步骤: 1.新建Java project,build path引入cxf runti ...
- jquery 弹出登陆框,简单易懂!修改密码效果代码
在网上找了一大堆,看的眼花瞭乱,还是研究原码,自已搞出来了! ui原地址:http://jqueryui.com/dialog/#modal-form 可以把js,css下载到本地,要不然不联网的话, ...
- Just like normal variables,
Just like normal variables, pointers can be declared constant. There are two different ways that poi ...
- hdu1664 Different Digits
求出n的倍数m,要求m使用的不同数字最少,且最小. 一开始不知道怎么搜,因为不知道m由多少个不同的数字组成. 然后百度了一下,看到和数论有关. m可能使用的数字的个数可能为一个或者两个 a,aa,aa ...
- 【原创】纯OO:从设计到编码写一个FlappyBird (四)
第三部分请点这里 这里来实现Obstacle类.其实flappybird的本质就是小鸟原地掉,然后几根柱子在走.这也是在Game类里,用obs.move()来实现游戏逻辑的原因. 我们首先必须确定几个 ...
- iOS开展——全球应对MotionEvent
遇到这样的要求:无论在哪个应用程序view controller,摇动手机,我们可以启动的方法. 你可以认为这个想法是使用包装的苹果"MotionEvent".但是,假如简单地把代 ...
- Directx11学习笔记【十七】纹理贴图
本文由zhangbaochong原创,转载请注明出处http://www.cnblogs.com/zhangbaochong/p/5596180.html 在之前的例子中,我们实现了光照和材质使得场景 ...
- Android异步任务
本文主要探讨Android平台提供的各种异步载入机制,包括它们的适用场景.用法等. 1. AsynTask AsynTask适用于最长能够持续几秒钟的短时间的操作,对于长时间的操作,建议使用java. ...