阅读源码的首要问题就是就要对代码的结构了然于胸,需要强调的是,OpenStack项目的目录结构并不是根据组件严格划分,而是根据功能划分,以Nova为例,compute目录并不是一定在nova-compute节点上运行,而主要是和compute相关(虚拟机操作相关)的功能实现,同样的,scheduler目录代码并不全在scheduler服务节点运行,但主要是和调度相关的代码。不过目录结构并不是完全没有规律,它遵循一定的套路。
通常一个服务的目录都会包含api.py、rpcapi.py、manager.py,这个三个是最重要的模块。
api.py: 通常是供其它组件调用的封装库。换句话说,该模块通常并不会由本模块调用。比如compute目录的api.py,通常由nova-api服务的controller调用。
rpcapi.py:这个是RPC请求的封装,或者说是RPC封装的client端,该模块封装了RPC请求调用。
manager.py: 这个才是真正服务的功能实现,也是RPC的服务端,即处理RPC请求的入口,实现的方法通常和rpcapi实现的方法一一对应。
比如对一个虚拟机执行关机操作:
API节点
nova-api接收用户请求 -> nova-api调用compute/api.py -> compute/api调用compute/rpcapi.py -> rpcapi.py向目标计算节点发起stop_instance()RPC请求
计算节点
收到stop_instance()请求 -> 调用compute/manager.py的callback方法stop_instance() -> 调用libvirt关机虚拟机
前面提到OpenStack项目的目录结构是按照功能划分的,而不是服务组件,因此并不是所有的目录都能有对应的组件。仍以Nova为例:
cmd:这是服务的启动脚本,即所有服务的main函数。看服务怎么初始化,就从这里开始。
db: 封装数据库访问,目前支持的driver为sqlalchemy。
conf:Nova的配置项声明都在这里。
locale: 本地化处理。
image: 封装Glance调用接口。
network: 封装网络服务接口,根据配置不同,可能调用nova-network或者neutron。
volume: 封装数据卷访问接口,通常是Cinder的client封装。
virt: 这是所有支持的hypervisor驱动,主流的如libvirt、xen等。
objects: 对象模型,封装了所有实体对象的CURD操作,相对以前直接调用db的model更安全,并且支持版本控制。
policies: policy校验实现。
tests: 单元测试和功能测试代码。
以上同样适用于其它服务,比如Cinder等。
另外需要了解的是,所有的API入口都是从xxx-api开始的,RESTFul API是OpenStack服务的唯一入口,也就是说,阅读源码就从api开始。而api组件也是根据实体划分的,不同的实体对应不同的controller,比如servers、flavors、keypairs等,controller的index方法对应list操作、show方法对应get操作、create创建、delete删除、update更新等。
根据进程阅读源码并不是什么好的实践,因为光理解服务如何初始化、如何通信、如何发送心跳等就不容易,各种高级封装太复杂了。我认为比较好的阅读源码方式是追踪一个任务的执行过程,比如看启动虚拟机的整个流程,因此接下来本文将以创建一台虚拟机为例,一步步分析其过程。
目前有 1 条留言 访客:0 条, 博主:0 条 ,引用: 1 条
外部的引用: 1 条
- 如何阅读OpenStack源码 | 求索阁