openstack代码层面剖析虚拟机创建完整流程

前言

使用python-novaclient创建虚拟机,结合github上python-novaclient、nova源码分析创建虚拟机的整个流程。
由于代码涉及功能非常多,因此文章着重介绍整个链路,而不会去解释每个节点做了什么。

环境

openstack S版本

正文

调用novaclient创建虚拟机时,novaclient最后会去请求nova处理任务。因此这里将novaclient和nova分开介绍。

novaclient 部分:

python-novaclient代码仓库:
https://github.com/openstack/python-novaclient

SDK 创建虚拟机参考:
https://docs.openstack.org/ocata/user-guide/sdk-compute-apis.html#create-server-api-v2

image.png

如图,创建虚拟机调用了 nova_client.servers.create()

1. 首先寻找nova_client

from novaclient.client import Client
通过导包,可以看到 nova_client 是此处的 novaclient.client.Client

2. 寻找 novaclient.client.Client

novaclient.client.Client代码位置:
https://github.com/openstack/python-novaclient/blob/stable/stein/novaclient/client.py

image.png

已然找到了Client,在此Client方法中返回了client_class。对client_class定义的代码都在当前页面中,分析后可以发现Client导向 novaclient.v2.client.Client

3. 寻找 novaclient.v2.client.Client

novaclient.v2.client.Client代码位置:
https://github.com/openstack/python-novaclient/blob/stable/stein/novaclient/v2/client.py

image.png

如图,第一层nova_client至此结束,实际指向novaclient.v2.client.Client类。
接下来分析 nova_client.servers.create() 中的servers。
在当前Client类中 可以发现 servers指向 servers.ServerManager(self),结合导包得出这个servers 实际指向 novaclient.v2.servers.ServerManager

4. 寻找 novaclient.v2.servers.ServerManager

novaclient.v2.servers.ServerManager代码位置:
https://github.com/openstack/python-novaclient/blob/stable/stein/novaclient/v2/servers.py

image.png

如图,nova_client.servers.create() 中的servers也已找到。开始分析create()方法。

  1. 当前类的 create() 指向 self._boot()
  2. 当前类的 self._boot() 指向 self._create()
  3. self._create() 并没有在当前类中定义,这里可以通过基类寻找。
5. 寻找 self._create()
  1. 父类 BootingManagerWithFind 中并没有定义
  2. 再往上,ManagerWithFind 类中也没有定义
  3. 再往上, Manager 类中定义了 _create() 方法

self._create() 代码位置:
https://github.com/openstack/python-novaclient/blob/stable/stein/novaclient/base.py

image.png

在 _create() 中,可以看到调用了一个post方法。这里就是novaclient sdk的最底层。
分析可得知,novaclient 向nova 发送http post请求完成创建任务。
因此nova 势必实现了一个web server,接下来分析nova源码时,可以从此处切入。

nova 部分

nova 代码仓库:
https://github.com/openstack/nova

1. 寻找webserver的入口

根据webserver 编程经验,首先寻找路由部分。

路由代码:
https://github.com/openstack/nova/blob/stable/stein/nova/api/openstack/compute/routes.py

image.png

如图,结合 novalicent的url 以及post方式,可以看出:创建虚拟机通过 server_controller 的create方法实现。
通过当前页面的代码分析,可以得出 server_controller 指向 ServersController。
下一步寻找 ServersController

2. 寻找 ServersController

ServersController 代码位置:
https://github.com/openstack/nova/blob/stable/stein/nova/api/openstack/compute/servers.py

在当前类中,找到了create方法,如下图:


image.png

create方法最后调用了 self.compute_api.create()
在类初始化定义当中 compute_api 指向 compute.API()
接下来寻找 compute.API()

3. 寻找 compute.API()

compute.API() 代码位置:
https://github.com/openstack/nova/blob/stable/stein/nova/compute/init.py

image.png

当前页面分析代码,可得知 API() 指向 nova.compute.api.API

4. 寻找 nova.compute.api.API

nova.compute.api.API 代码位置:
https://github.com/openstack/nova/blob/stable/stein/nova/compute/api.py

image.png

self.compute_api.create() 中的compute_api已然找到,现在寻找对应的create()

  1. 当前类中实现了create()create()指向 self._create_instance()
  2. 当前类实现了 self._create_instance(),由于参数的配置不同,本人环境self._create_instance()指向 self.compute_task_api.schedule_and_build_instances()。这里指向的方法虽有不同,但是大体实现原理都是一致的。
  3. self.compute_task_api又指向 conductor.ComputeTaskAPI()
    接下来找到 conductor.ComputeTaskAPI()
5. 寻找 conductor.ComputeTaskAPI()

conductor.ComputeTaskAPI() 代码位置:
https://github.com/openstack/nova/blob/stable/stein/nova/conductor/init.py

image.png

如图,根据导包,conductor.ComputeTaskAPI() 又指向 nova.conductor.api.ComputeTaskAPI

6. 寻找 nova.conductor.api.ComputeTaskAPI

nova.conductor.api.ComputeTaskAPI 代码位置:
https://github.com/openstack/nova/blob/stable/stein/nova/conductor/api.py

image.png

至此,self.compute_task_api.schedule_and_build_instances()中的 compute_task_api 已然找到。接下来寻找 schedule_and_build_instances()

  1. 当前类实现了 schedule_and_build_instances()
  2. schedule_and_build_instances()又指向 self.conductor_compute_rpcapi.schedule_and_build_instances()
  3. self.conductor_compute_rpcapi指向 rpcapi.ComputeTaskAPI()

接下来寻找 rpcapi.ComputeTaskAPI()

7. 寻找 rpcapi.ComputeTaskAPI()

rpcapi.ComputeTaskAPI() 代码位置:
https://github.com/openstack/nova/blob/stable/stein/nova/conductor/rpcapi.py

image.png

如图 self.conductor_compute_rpcapi.schedule_and_build_instances() 中的 self.conductor_compute_rpcapi 已然找到,接下来就是寻找 schedule_and_build_instances()

当前类实现了 schedule_and_build_instances(),这个方法调用了 消息队列的 异步方法,代码如下:

cctxt.cast(context, 'schedule_and_build_instances', **kw)

这里说明,nova哪里还有一个消息的消费者,也就是实现 schedule_and_build_instances的服务端。
接下来去寻找这个 schedule_and_build_instances

8. 寻找消息队列的消费者 schedule_and_build_instances

schedule_and_build_instances 代码位置:
https://github.com/openstack/nova/blob/stable/stein/nova/conductor/manager.py

image.png

通过方法所在类的装饰器可以看出,这是消息队列的消费者。
当前方法又指向 self.compute_rpcapi.build_and_run_instance()
self.compute_rpcapi 指向 compute_rpcapi.ComputeAPI()
结合导包,最终指向为:nova.compute.rpcapi.ComputeAPI()
现在去寻找 nova.compute.rpcapi.ComputeAPI()

9. 寻找 nova.compute.rpcapi.ComputeAPI()

nova.compute.rpcapi.ComputeAPI() 代码位置:
https://github.com/openstack/nova/blob/stable/stein/nova/compute/rpcapi.py

image.png

self.compute_rpcapi.build_and_run_instance() 中的 self.compute_rpcapi已然找到,接下来寻找当前类的 build_and_run_instance()
当前类实现了build_and_run_instance()
build_and_run_instance() 调用了消息队列的异步方法,代码如下:

cctxt.cast(ctxt, 'build_and_run_instance', **kwargs)

接下来,就去寻找这个 build_and_run_instance

10. 寻找 build_and_run_instance

build_and_run_instance 代码位置:
https://github.com/openstack/nova/blob/stable/stein/nova/compute/manager.py

image.png

  1. 当前方法最后调用了一个协程,指向 _locked_do_build_and_run_instance
  2. 当前方法中定义了_locked_do_build_and_run_instance
  3. _locked_do_build_and_run_instance 指向self._do_build_and_run_instance
  4. 当前类定义了 self._do_build_and_run_instance
  5. self._do_build_and_run_instance 指向 self._build_and_run_instance()
  6. 当前类定义了 self._build_and_run_instance()
  7. self._build_and_run_instance() 数据库更新、调度都在这里有体现。指向 self.driver.spawn()
  8. 结合导包,self.driver 指向 nova.virt.driver.load_compute_driver
11. 寻找 nova.virt.driver.load_compute_driver

nova.virt.driver.load_compute_driver 代码位置:
https://github.com/openstack/nova/blob/stable/stein/nova/virt/driver.py

image.png

本环境的 driver是 libvirt.LibvirtDriver
当前方法返回 nova.virt.libvirt.LibvirtDriver
接下来寻找 nova.virt.libvirt.LibvirtDriver

12. 寻找 nova.virt.libvirt.LibvirtDriver

nova.virt.libvirt.LibvirtDriver 代码位置:
https://github.com/openstack/nova/blob/stable/stein/nova/virt/libvirt/init.py

image.png

这里又指向 nova.virt.libvirt.driver.LibvirtDriver
接下来寻找 nova.virt.libvirt.driver.LibvirtDriver

13. 寻找 nova.virt.libvirt.driver.LibvirtDriver

nova.virt.libvirt.driver.LibvirtDriver 代码位置:
https://github.com/openstack/nova/blob/stable/stein/nova/virt/libvirt/driver.py

image.png

  1. self.driver.spawn() 中的driver 已然找到,在当前类中寻找 spawn()
  2. 当前类实现了 spawn()
  3. spawn() 中实现了生成xml等,指向 self._create_domain_and_network()
  4. 当前类实现了 self._create_domain_and_network()
  5. self._create_domain_and_network() 指向 self._create_domain()
  6. 当前类实现了 host.write_instance_config(),这里需要注意传入了一个host参数,host取值于当前类的属性。
  7. 结合导包,self._create_domain() 指向 nova.virt.libvirt.guest.Guest.create()
    接下来寻找 nova.virt.libvirt.guest.Guest.create()
14. 寻找 nova.virt.libvirt.guest.Guest.create()

nova.virt.libvirt.guest.Guest.create() 代码位置:https://github.com/openstack/nova/blob/stable/stein/nova/virt/libvirt/guest.py

image.png

指向 host.write_instance_config()
接下来寻找 host.write_instance_config()。这里的host 是步骤【13】里的 host.write_instance_config() 传入的。

15. 寻找 host.write_instance_config()

host.write_instance_config() 代码位置:
https://github.com/openstack/nova/blob/stable/stein/nova/virt/libvirt/host.py

image.png

  1. 当前方法指向 self.get_connection().defineXML()
  2. self.get_connection() 指向 self._get_connection()
  3. self._get_connection() 指向 self._connect()
  4. self._connect() 指向 tpool.proxy_call(), 大致意思是返回一个libvirt 连接。
  5. defineXML() 就是创建一个虚拟机,但是还未启动。
  6. 回到步骤【13】中的 _create_domain(),这里实现了虚拟机是否开启

至此,openstack部分已全部走完。

你可能感兴趣的:(openstack代码层面剖析虚拟机创建完整流程)