博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Nova创建虚拟机的底层代码分析
阅读量:7236 次
发布时间:2019-06-29

本文共 9919 字,大约阅读时间需要 33 分钟。

作为个人学习笔记分享。有不论什么问题欢迎交流!

在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) #以下是错误处理。不表

你可能感兴趣的文章
装饰者模式
查看>>
集成计算引擎在大型企业绩效考核系统的应用方案
查看>>
150. Evaluate Reverse Polish Notation
查看>>
SpringBoot 实战 (十一) | 整合数据缓存 Cache
查看>>
css实现三栏布局的几种方法及优缺点
查看>>
proxychains是怎么工作的
查看>>
React16性能改善的原理一
查看>>
网页水印SDK的实现
查看>>
js的观察者模式
查看>>
函数柯里化
查看>>
手把手教你搭建智能合约测试环境、开发、编译、部署以及如何通过JS调用合约方法...
查看>>
Flex 布局教程
查看>>
固定宽度布局开发WebApp如何实现多终端下自适应?
查看>>
伟大的Scrum团队的特征
查看>>
2019春节防坑指南之抢票陷阱(文末有彩蛋)
查看>>
深入node.js-浏览器缓存机制
查看>>
解决IOS中input失焦后,页面上移,点击不了问题
查看>>
【C】 23_#error 和 #line 使用分析
查看>>
浅谈 Java 10 ,你可能不知道的五件事
查看>>
IT 人能在一线城市里生活一辈子吗?
查看>>