openstack虚拟机创建快照源码分析超详细(Queen版本)

这是openStack请求应答模型(源自could man)

 

 

一.nova-api接收到外部请求,并处理转发请求

代码路径 :nova-stable-queens ——> nova ——> compute——> api.py

然后 snapshot 函数开始接收请求,并进行处理(函数很长,分步解释)

1.准备处理请求

    #创建快照
    def snapshot(self, context, instance, name, extra_properties=None):
        """Snapshot the given instance.

 

2.先创建新的镜像。这个新的镜像将保留给compute manager用来上载快照或备份

image_meta = self._create_image(context, instance, name,
                                        'snapshot',
                                        extra_properties=extra_properties)

 

3.将instance.task_state的状态设置为penddging状态(这个状态码后面要用到,它标志着操作进行到什么程度,完成各个子操作状态码会变更,方便判断以及异常处理)

instance.task_state = task_states.IMAGE_SNAPSHOT_PENDING

 

4.调用 nova-stable-queens ——> nova ——> compute ——> rpcapi.py 里的snapshot_instance函数,(并且将刚才创建的那个新镜像的id,也就是 image_meta['id'] 作为参数传入)

self.compute_rpcapi.snapshot_instance(context, instance,
                                              image_meta['id'])

 

5.打开 rpcapi.py找到 snapshot_instance 函数,snapshot_instance 函数被api.py的snapshot函数调用,用于创建快照

 def snapshot_instance(self, ctxt, instance, image_id):
        version = self._ver(ctxt, '4.0')

 

6.实例化一个router用来传递消息(正如文首的模型图所示,nova-api是通过消息队列来异步发消息的),向compute发出具体需要执行的操作

        cctxt = self.router.client(ctxt).prepare(
                server=_compute_host(None, instance), version=version)

 

7.通过名为cctxt的router,调用cast,发送message

        cctxt.cast(ctxt, 'snapshot_instance',
                   instance=instance,
                   image_id=image_id)

 

8.cast函数调用proxy_rpc_to_manager函数,通知manager

    def cast(self, ctxt, method, **kwargs):
        msg = self._make_msg(method, **kwargs)
        topic = self._get_topic()
        self.cells_rpcapi.proxy_rpc_to_manager(ctxt, msg, topic)

 

9.proxy_rpc_to_manager函数

 def proxy_rpc_to_manager(self, message, host_name, rpc_message,
                             topic, timeout):
        """Proxy RPC to the given compute topic."""
        # Check that the host exists.
        objects.Service.get_by_compute_host(message.ctxt, host_name)

        topic, _sep, server = topic.partition('.')

        cctxt = rpc.get_client(messaging.Target(topic=topic,
                                                server=server or None))

补充:

           1.真正的snapshot操作是需要在nova-compute节点上执行的,所以nova-api需要向nova-compute发送message,由于OpenStack环境中会有很多个nova-compute,所以需要通过server=_compute_host(None, instance)来获取虚拟机所在的host,并向其发送message。

           2.proxy_rpc_to_manager函数会通知manager,所以之后应该去该目录下的manager.py去找。由于前面都是函数调用的关系去串联的,刚开始学习看源码的时候就在这里断掉了不明白为什么就直接到driver.py了,实际上就是这样来的。

          3.进行函数追踪的时候,点进去会有很多函数都是同名的不知道是哪一个,可以通过(1.对参数 2.看实例化它的类是那个,选择该类里面的那个方法)去辅助找

怎么通知的需要深究rpc原理,有兴趣可以单独看

 

10. 打开nova-stable-queens ——> nova ——> compute ——>manager.py 里面_snapshot_instance函数,可以看到调用dirver的代码

def _snapshot_instance(self, context, image_id, instance,
                           expected_task_state):

            ……此处省略一堆堆,下面是调用dirver的代码,将在snapshot函数中真正执行创建
    self.driver.snapshot(context, instance, image_id,update_task_state)

 

二.向compute节点执行

11.打开nova-stable-queens ——> nova——> virt ——> libvirt ——> driver.py,找到 snapshot函数,从这里才真的开始创建快照

    def snapshot(self, context, instance, image_id, update_task_state):
        """Create snapshot from a running VM instance.

 

12. 检测libvirt版本,看使用live snapshot 热快照 还是cold snapshot 冷快照(取决于最后得出的 live_snapshot 是否等于 False,社区目前认为live snapshot不稳定,libvirt版本小于1.3.0的都只能用cold snapshot )

 if (self._host.has_min_version(hv_type=host.HV_DRIVER_QEMU)
                and source_type not in ('lvm')
                and not CONF.ephemeral_storage_encryption.enabled
                and not CONF.workarounds.disable_libvirt_livesnapshot
            try:
                guest.get_block_device(disk_path).abort_job()
            except libvirt.libvirtError as ex:
                error_code = ex.get_error_code()
                if error_code == libvirt.VIR_ERR_CONFIG_UNSUPPORTED:
                    live_snapshot = False
                else:
                    pass
        else:
            live_snapshot = False

 

13.调用image_backend函数判断后端存储

        root_disk = self.image_backend.by_libvirt_path(
            instance, disk_path, image_type=source_type)

 

14.这些判断都搞完之后更新一下task状态码

update_task_state(task_state=task_states.IMAGE_PENDING_UPLOAD)

update_task_state(task_state=task_states.IMAGE_UPLOADING,expected_state=task_states.IMAGE_PENDING_UPLOAD)

 

15.挂起客户机

 self._prepare_domain_for_snapshot(context, live_snapshot, state, instance)

 

16.然后执行创建快照(到底执行哪一种,取决于live_snapshot 的值)

    16.1 冷创建

 #冷创建快照
 root_disk.snapshot_extract(out_path, image_format)

    16.2 热创建

self._live_snapshot(context, instance, guest,disk_path, out_path, source_format,image_format, instance.image_meta)

 

17.创建完快照,调用_snapshot_domain函数,恢复虚拟机状态

self._snapshot_domain(context, live_snapshot, virt_dom, state, instance)

_snapshot_domain会调用_attach_pci_devices和_attach_direct_passthrough_ports

 if guest is not None:
    self._attach_pci_devices(guest, pci_manager.get_instance_pci_devs(instance))
    self._attach_direct_passthrough_ports(context, instance, guest)

_attach_pci_devices又会调用attach_device函数,最后在attach_device中将客户机连接到设备

def attach_device(self, conf, persistent=False, live=False):
        """Attaches device to the guest.

 

18.调用update函数,上传快照到glance

self._image_api.update(context,image_id,metadata,image_file)

结束

 

 

 

 

 

 

 

 

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值