Nova 源码分析
参考地址
https://www.processon.com/view/link/5ff434b51e08531de81d1ca0
https://jckling.github.io/2021/05/23/OpenStack/OpenStack%20Nova/
# 接口文档
https://docs.openstack.org/api-ref/compute/?expanded=list-images-detail
https://github.com/int32bit/openstack-workflow
Nova 文件结构
- nova 目录
accelerator/ # Cyborg 加速器
api/ # Nova API 服务
__init__.py
auth.py # 身份认证中间件
compute_req_id.py # x-compute-request-id 中间件(oslo_middleware)
metadata/ # Metadata API
openstack/ # Nova v2.1 API
__init__.py
api_version_request.py # 版本验证
auth.py # noauth 中间件
common.py # 信息查询的工具函数
compute/ # 每个 API 的入口点
from nova.api.openstack.compute.routes import APIRouterV21
routes.py # 路由文件
identity.py # 验证项目是否存在
requestlog.py # 请求日志中间件
urlmap.py # url 映射
versioned_method.py # 版本信息
wsgi.py # WSGI 相关抽象类
wsgi_app.py # WSGI 应用程序初始化方法
validation/ # 请求体验证
wsgi.py # WSGI 原语(请求、应用、中间件、路由、加载器)
cmd/ # 各个 Nova 服务的入口程序
compute/ # Nova Compute 服务
conductor/ # Nova Conductor 服务 *** 处理需要协调的请求(构建/调整)、充当数据库代理或处理对象转换。***
conf/ # 所有的配置选项
console/ # nova-console 服务
db/ # 封装数据库操作
hacking/ # 编码规范检查
image/ # 封装镜像操作,Glance 接口抽象
keymgr/ # 密钥管理器实现
locale/ # 国际化相关文件
network/ # nova-network 服务
notifications/ # 通知相关功能
objects/ # 封装实体对象的 CURD 操作
pci/ # PCI/SR-IOV 支持
policies/ # 所有 Policy 的默认规则
privsep/ # oslo_privsep 相关
scheduler/ # Nova Scheduler 服务
servicegroup/ # 成员服务(membership),服务组
storage/ # Ceph 存储支持
tests/ # 单元测试
virt/ # 支持的 hypervisor 驱动
volume/ # 封装卷访问接口,Cinder 接口抽象
# 文件
__init__.py
availability_zones.py # 区域设置的工具函数
baserpc.py # 基础 RPC 客户端/服务端实现
block_device.py # 块设备映射
cache_utils.py # oslo_cache 封装
config.py # 解析命令行参数
context.py # 贯穿 Nova 的所有请求的上下文
crypto.py # 包装标准加密数据元素
debugger.py # pydev 调试
exception.py # 基础异常类
exception_wrapper.py # 封装异常类
filters.py # 基础过滤器
i18n.py # 集成 oslo_i18n
loadables.py # 可加载类
manager.py # 基础 Manager 类
middleware.py # 更新 oslo_middleware 的默认配置选项
monkey_patch.py # eventlet 猴子补丁
policy.py # 策略引擎
profiler.py # 调用 OSProfiler
quota.py # 每个项目的资源配额
rpc.py # RPC 操作相关的工具函数
safe_utils.py # 不会导致循环导入的工具函数
service.py # 通用节点基类,用于在主机上运行的所有工作者
service_auth.py # 身份认证插件
test.py # 单元测试基础类
utils.py # 工具函数
version.py # 版本号管理
weights.py # 权重插件
wsgi.py # 管理 WSGI 应用的服务器类
组成部分
-
nova-api
接受和响应用户的计算 API 调用
-
nova-api-metadata
接受来自实例的元数据请求
-
nova-compute
通过 hypervisor API 创建和终止虚拟机实例的守护进程。例如 KVM/QEMU 的 libvirt、VMware 的 VMwareAPI 。
运行在它所管理的 hypervisor 机器上,管理与虚拟机管理程序和虚拟机的通信。
-
nova-scheduler
从消息队列中获取虚拟机实例请求,并决定在哪个服务器上运行。
-
nova-conductor
处理需要协调的请求(构建/调整)、充当数据库代理或处理对象转换。用于连接 nova-api、nova-scheduler、nova-compute 服务。
-
nova-novncproxy
协调 nova-compute 服务和数据库之间的交互。避免 nova-compute 直接访问数据库,为了提供更好的 API 兼容性。建议不要部署在 nova-compute 服务所在的节点上。
-
nova-spicehtml5proxy
提供通过 SPICE 连接访问运行实例的代理,支持基于浏览器的 HTML5 客户端。
-
The queue
在守护进程之间传递消息的中央消息队列,通常使用 RabbitMQ 。
-
SQL database
存储云基础设施的大多数构建时和运行时状态,包括:可用的实例类型、在使用的实例、可用的网络、项目。
代码分析
路由函数
- 文件位置:nova/openstack/compute/router.py
##### 路由列表 ######
# 这是路由列表 配置了接口得路由信息 省略了部分
ROUTE_LIST = (
# NOTE: This is a redirection from '' to '/'. The request to the '/v2.1'
# or '/2.0' without the ending '/' will get a response with status code
# '302' returned.
('', '/'),
('/', {
'GET': [version_controller, 'show']
}),
('/versions/{id}', {
'GET': [version_controller, 'show']
}),
('/images', {
'GET': [images_controller, 'index']
}),
('/images/detail', {
'GET': [images_controller, 'detail'],
}),
('/images/{id}', {
'GET': [images_controller, 'show'],
'DELETE': [images_controller, 'delete']
}),
('/images/{image_id}/metadata', {
'GET': [image_metadata_controller, 'index'],
'POST': [image_metadata_controller, 'create'],
'PUT': [image_metadata_controller, 'update_all']
}),
('/images/{image_id}/metadata/{id}', {
'GET': [image_metadata_controller, 'show'],
'PUT': [image_metadata_controller, 'update'],
'DELETE': [image_metadata_controller, 'delete']
}),
# 查看和创建虚拟机接口 index create 都是 servers.ServersController 类中的绑定方法
# 后续调用方法时 多半用 射的方法去调用的
# 人话:get 访问 http:localhost:port/servers 时,触发 index servers.ServersController类中的函数
# port 访问 http:localhost:port/servers 时, 触发 create servers.ServersController类中的函数
('/servers', {
'GET': [server_controller, 'index'],
'POST': [server_controller, 'create']
}),
('/servers/detail', {
'GET': [server_controller, 'detail']
}),
('/servers/{id}', {
'GET': [server_controller, 'show'],
'PUT': [server_controller, 'update'],
'DELETE': [server_controller, 'delete']
}),
('/servers/{id}/action', {
'POST': [server_controller, 'action']
}),
('/servers/{server_id}/consoles', {
'GET': [consoles_controller, 'index'],
'POST': [consoles_controller, 'create']
}),
('/servers/{server_id}/consoles/{id}', {
'GET': [consoles_controller, 'show'],
'DELETE': [consoles_controller, 'delete']
}),
('/servers/{server_id}/diagnostics', {
'GET': [server_diagnostics_controller, 'index']
}),
('/servers/{server_id}/ips', {
'GET': [ips_controller, 'index']
}),
('/servers/{server_id}/ips/{id}', {
'GET': [ips_controller, 'show']
}),
('/servers/{server_id}/metadata', {
'GET': [server_metadata_controller, 'index'],
'POST': [server_metadata_controller, 'create'],
'PUT': [server_metadata_controller, 'update_all'],
}),
('/servers/{server_id}/metadata/{id}', {
'GET': [server_metadata_controller, 'show'],
'PUT': [server_metadata_controller, 'update'],
'DELETE': [server_metadata_controller, 'delete'],
}),
('/servers/{server_id}/migrations', {
'GET': [server_migrations_controller, 'index']
}),
('/servers/{server_id}/migrations/{id}', {
'GET': [server_migrations_controller, 'show'],
'DELETE': [server_migrations_controller, 'delete']
}),
('/servers/{server_id}/migrations/{id}/action', {
'POST': [server_migrations_controller, 'action']
}),
('/servers/{server_id}/os-instance-actions', {
'GET': [instance_actions_controller, 'index']
}),
('/servers/{server_id}/os-instance-actions/{id}', {
'GET': [instance_actions_controller, 'show']
}),
('/servers/{server_id}/os-interface', {
'GET': [server_os_interface_controller, 'index'],
'POST': [server_os_interface_controller, 'create']
}),
('/servers/{server_id}/os-interface/{id}', {
'GET': [server_os_interface_controller, 'show'],
'DELETE': [server_os_interface_controller, 'delete']
}),
('/servers/{server_id}/os-server-password', {
'GET': [server_password_controller, 'index'],
'DELETE': [server_password_controller, 'clear']
}),
('/servers/{server_id}/os-virtual-interfaces', {
'GET': [virtual_interfaces_controller, 'index']
}),
('/servers/{server_id}/os-volume_attachments', {
'GET': [server_volume_attachments_controller, 'index'],
'POST': [server_volume_attachments_controller, 'create'],
}),
('/servers/{server_id}/os-volume_attachments/{id}', {
'GET': [server_volume_attachments_controller, 'show'],
'PUT': [server_volume_attachments_controller, 'update'],
'DELETE': [server_volume_attachments_controller, 'delete']
}),
('/servers/{server_id}/remote-consoles', {
'POST': [server_remote_consoles_controller, 'create']
}),
('/servers/{server_id}/os-security-groups', {
'GET': [server_security_groups_controller, 'index']
}),
('/servers/{server_id}/tags', {
'GET': [server_tags_controller, 'index'],
'PUT': [server_tags_controller, 'update_all'],
'DELETE': [server_tags_controller, 'delete_all'],
}),
('/servers/{server_id}/tags/{id}', {
'GET': [server_tags_controller, 'show'],
'PUT': [server_tags_controller, 'update'],
'DELETE': [server_tags_controller, 'delete']
}),
('/servers/{server_id}/topology', {
'GET': [server_topology_controller, 'index']
}),
)
# 路由中的函数
#### 路由中的函数调用此函数
def _create_controller(main_controller, action_controller_list):
# 相当于将 servers.ServersController 类初始化传入 wsgi.Resource() 类中
controller = wsgi.Resource(main_controller())
for ctl in action_controller_list:
# 遍历[ admin_actions.AdminActionsController,
# admin_password.AdminPasswordController,
# console_output.ConsoleOutputController,]
controller.register_actions(ctl())
return controller
# func = functools.partial("函数名","参数","参数") 暂时理解为将函数换一个名字
# func() 不用传参就会执行 partial 中的函数
# 以下代码相当于 server_controller = functools.partial("函数名","参数","参数")
# 当 server_controller 加()被调用时 (成为server_controller())时执行 _create_controller 函数
################################## 注意:_create_controller ###################################################
################################## 注意:servers.ServersController ############################################
from nova.api.openstack.compute import servers
server_controller = functools.partial(_create_controller,
servers.ServersController,
[
admin_actions.AdminActionsController,
admin_password.AdminPasswordController,
console_output.ConsoleOutputController,
create_backup.CreateBackupController,
deferred_delete.DeferredDeleteController,
evacuate.EvacuateController,
floating_ips.FloatingIPActionController,
lock_server.LockServerController,
migrate_server.MigrateServerController,
multinic.MultinicController,
pause_server.PauseServerController,
remote_consoles.RemoteConsolesController,
rescue.RescueController,
security_groups.SecurityGroupActionController,
shelve.ShelveController,
suspend_server.SuspendServerController
]
)
class Resource(wsgi.Application):
support_api_request_version = True
def __init__(self, controller):
self.controller = controller
self.wsgi_actions = {}
if controller:
self.register_actions(controller)
def register_actions(self, controller):
# 查看 controller 对象中是否有 wsgi_actions 成员
actions = getattr(controller, 'wsgi_actions', {})
for key, method_name in actions.items():
self.wsgi_actions[key] = getattr(controller, method_name)
##### 路由类 #####
###### 当此类被调用时 应该执行路由中相应的函数
# APIRouterV21 基于 ROUTE_LIST,使用 Routes 模块作为 URL 映射的工具,将各个模块所实现的 API 对应的 URL 注册到 mapper 中,并把每个资源都封装成
# nova.api.openstack.wsgi.Resource 对象,当解析 URL 请求时,可以通过 URL 映射找到 API 对应的 Resource 对象。
class APIRouterV21(base_wsgi.Router):
"""Routes requests on the OpenStack API to the appropriate controller
and method. The URL mapping based on the plain list `ROUTE_LIST` is built
at here.
OpenStack API 的路由请求到 appropriate controller and method,
在这里,基于 ROUTE_LIST 构建了URL映射;
"""
def __init__(self, custom_routes=None):
""":param custom_routes: the additional routes can be added by this
parameter. This parameter is used to test on some fake routes
primarily.
"""
super(APIRouterV21, self).__init__(nova.api.openstack.ProjectMapper())
if custom_routes is None:
custom_routes = tuple()
# 循环遍历 ROUTE_LIST, 获取路由字符串 和 请求方法的字典
# ('/servers', {
# 'GET': [server_controller, 'index'],
# 'POST': [server_controller, 'create']
# }),
for path, methods in ROUTE_LIST + custom_routes:
# 判断 methods 是否 str类 的对象
if isinstance(methods, str):
# 重定向
self.map.redirect(path, methods)
continue
for method, controller_info in methods.items():
# methdos.items() 将字典同时返回 key value => 'GET': [server_controller, 'index']
# 在此处执行 server_controller() -> _create_controller() -> controller() -> Resource()()
controller = controller_info[0]()
action = controller_info[1]
self.map.create_route(path, method, controller, action)
@classmethod
def factory(cls, global_config, **local_config):
"""Simple paste factory, :class:`nova.wsgi.Router` doesn't have one."""
return cls()