一、Horizon介绍
Horizon是OpenStack的一个子项目,用于提供一个Web前端控制台(称为Dashboard),以此来展示OpenStack的功能。实际上,Horizon并不会为OpenStack添加任何新的功能,它只是使用了OpenStack部分API功能,因此,我们可以扩展Dashboard。
Horizon是基于 python Django webframework开发的标准的python wsgi程序。
Horizon将页面上所有元素模块化,网页中一些常见元素,表单,表格,标签页,全部封装成Python类,每个组件有自己对应的一小块html模板,当渲染整个页面的时候,Horizon先找到当前页面有多少组件,将各个组件分别进行渲染变成一小段片段,最后拼接成一个完整的html页面,返回浏览器。
总结Horizon的特点:
- 页面元素模块化
- 子面板可插拔
- All in One(从部署上说,Horizon只有它自己一个组件)
二、Horizon项目结构
2.1 整体结构
Horizon这套面板的设计分为三层:Dashboard -> PanelGroup -> Panel
1 | (1) project 普通用户登录后看到的项目面板 |
每一个dashboard都是Django 中的一个 app ,Django中的app可以理解为对业务逻辑化的一种手段,里面可以包含自己独有的url设定,模板,和业务逻辑代码。每个dashboard下定义了一系列的PanelGroup,虚拟机管理对应到界面就是一个PanelGroup(ManageComputer),里面有一系列的子Panel(Overview、Instances、Volumes)。Swift,Heat,Neutron的管理面板各自都是一个PanelGroup,底下有各自的子panel。
2.2项目结构
Horizon的源码中,包含两个主要代码文件夹:horizon 和 openstack_dashboard
horizon:这个包是在django 基础上写的通用组件,表格(table),标签页(tab),表单(form),面包屑导航(browser),工作流(workflow)。horizon/base.py 中还实现了一套dashboard/panel机制,使得Horizon面板上所有的dashboard都是 可插拔 的,所有的panel都是 动态加载 的
openstack_dashboard:horizon各个面板的具体实现代码
以下对各个目录做一个介绍,有些目录目前还不知道具体的作用:
1 | horizon |
三、Horizon 注册机制源码解析
3.1 horizon导入
openstack_dashboard/settings.py 导入 horizon 应用
1 | INSTALLED_APPS = [ |
python中在导包时,会自动导入它的init.py文件,当我们导入Horizon这个包的时候,init.py文件自动运行,在init.py 文件中再导入其他的包,或者模块。其中在horizon包的init.py文件中
1 | # horizon/__init__.py |
1 | # horizon/base.py |
注 :horizon采用单例的设计模式
1
2
3
4
5
6
7
8
9
10
11
12
13class HorizonSite(Site):
"""A singleton implementation of Site such that all dealings with horizon
get the same instance no matter what. There can be only one.
"""
_instance = None
def __new__(cls, *args, **kwargs):
if not cls._instance:
cls._instance = super(Site, cls).__new__(cls, *args, **kwargs)
return cls._instance
# The one true Horizon
Horizon = HorizonSite()
3.2 request请求
当用户通过浏览器发起request请求,根据Django的框架结构,使用URLconf进行连接请求和后端处理(view)的绑定,使用view进行后端处理,使用template进行页面渲染。
1 | # openstack_dashboard/urls.py |
request –>> url(r’’, include(horizon.urls)) : horizon.urls 对应的是 horizon.base._lazy_urls() ,
–>> horizon.base.Site.urls(),完成所有Dashboard和Panel的注册编译URLconf
1 | # horizon.base.Site.urls() |
- 标记(1)从“settings.INSTALLED_APPS发现模块,包含dashboard.py、panel.py的模块注册,添加到注册表中self._registry,没有的抛出异常。
1 | def _autodiscover(self): |
- 标记(2)发现每个Dashboards里的Panels,从注册表self._registry 取出注册dashboard,注册每个dashboard中的panel
1 | # horizon.base.Dashboard._autodiscover(): |
四、Horizon 用户登录流程
用户请求过来,首先到openstack_dashboard/urls.py,查找url对应的视图函数。
1 | urlpatterns = patterns( |
进入openstack.views.splash函数。如果用户已经验证过,则直接进入主页面,否则转到登录验证模块;
1 |
|
如未登录,则需要转到Horizon项目的验证插件openstack_auth,然后从这个插件中加载urls.py;
1 | urlpatterns = [ |
1 |
|
django的认证 views.login函数如下:
1 |
|
openstack_auth 中 form.py 继承 django_auth_forms.AuthticationForm 类,也就意味着openstack_auth的form.py会与django中的form类中的验证函数相结合,其中django_auth_forms.AuthticationForm类有一个钩子函数clean()函数,它将抛出所有的验证异常,而此钩子函数的具体实现则在子类openstack_auth中form.py中。
1 | def clean(self): |
keystone 验证用户名和密码的详细过程,其主要流程大概是先加载openstack_auth中的 backend.py 中的认证函数authenticate()来完成keystone的认证
1 | def authenticate(self, auth_url=None, **kwargs): |