I. Source Code Analysis Environment:
I should have set up the horizon development environment to facilitate debugging. However, due to various errors, I did not build the environment successfully. This also caused many source code problems to be resolved. I can continue to add this part in the future.
Official build method reference website: http://docs.openstack.org/developer/horizon/quickstart.html
Openstack version: stable-Havana
Ii. Software Used in source code analysis:
Sourceinsight: this is of course the first powerful tool in source code analysis. It is very convenient to search for global keywords. However, I have found that python is not very well supported, but it can be used together.
OneNote: although this note-taking software is very similar to a whiteboard, it can analyze the call relationship of functions in it like drawing and writing on paper.
Snagit: a software that can be used in various places for convenience. It is pasted into OneNote for analysis.
Notepad ++: used to record notes during source code analysis without explanation
Visio: used to draw various charts
Iii. Brief Description
First of all, I think source code analysis is actually a kind of physical activity rather than a non-technical activity. Even if I don't understand it, it may be that the source code author has written obscure. Besides, the open-source community is becoming more and more mature, open-source software itself will also add instructions for implementation and use. Therefore, you can read the source code to learn and imitate it. To put it bluntly, you may flash your mind when you need it. You may have seen someone else do this or you can do this. The results of source code analysis still need to focus on implementation principles and usage skills. There is not much need to worry about the specific details, so the source code listed below is basically not complete, but only part of it is extracted!
This analysis is not purely about the source code. It mainly analyzes a bug where the front-end page request does not respond. With this problem, we will sort out the entire source code analysis process!
I am new to Python, Django, and horizon. I am not very familiar with many things. I also hope you can talk about them more. If you have any mistakes, please criticize and correct them!
Iv. Analysis of horizon source code
Let's talk about my analysis ideas. First, Horizon is implemented based on Django. Simply put, it is the website architecture, mainly analyzing front-end requests and backend processing. So the first step is to find the specific content of the page request. I am using the chrome developer tool. The second step is to find the binding between the front-end request and backend processing, specifically, which function is used to process the action. in step 3, it is expected that horizon will call the API interfaces of other components of openstack. Here, only the backend processing process is analyzed and the API call is stopped, the analysis is not detailed for the moment.
V. Horizon frontend request
The browser chrome developer tool is mainly used to analyze the specific requests sent by the page. This is to analyze the execution of a button on the front end.
Specific button elements:
Request link address:
Other related elements:
Summary:
Address:/dashboard/admin/instances/[1]
Method: Post
Parameters:
Instances_filter_q:
Action: instances _ soft_reboot _ 89a8849b-a3cd-4ce0-9158-c3dd69e8508e
Note: [1] The/dashboard/in the request address should be related to the Apache server configuration. You can check the installation and configuration process of horizon later.
6. Binding URL to backend
Based on Django's framework structure, the urlconf file (https://docs.djangoproject.com/en/1.4/topics/http/urls/) is used to bind the link request to the backend processing (view), the view is used for backend processing, and the template is used for page rendering.
1. directory structure:
Horizon ------------- component, which provides some functions
| --- _ Init _. py ----------- controls the horizon package import Behavior
| --- Base. py ----------- site class, dashboard class, and Panel class provided by horizon, responsible for the entire basic architecture
| --- Site_urls.py
Openstack_dashboard -------------- root directory of the website project
|
| --- Settings. py ------------ basic website settings [1]
| --- URLs. py ---------------- website basic URL settings
| --- Views. py --------------- basic website View
| --- Templates -------------- basic website template
|
| --- Dashboards
| --- Admin ------------- dashboard [2]
| --- Instances -------------- Panel [3]
| --- Panel. py ---------------------- registers the panel in the dashboard.
| --- URLs. py
| --- Views. py
...
| --- Dashboard. py ------------ registers dashboard in horizon
| --- Models. py
...
Note: Only some directories and files related to this analysis are listed here. [1] There is also an openstack_dashboard/local/local_settings.py, which seems to be a local setting, and it is still unclear how the settings. py and it are combined.
[2] [3] here the dashboard and panel are custom components of horizon, corresponding to the corresponding part of the page. As shown in:
2. url binding analysis:
Openstack_dashboard/settings. py
Root_urlconf = 'openstack _ dashboard. urls'
Openstack_dashboard/URLs. py
A small trick is used. When you import the horizon package
Horizon/_ init _. py
[Said Xiao Jieyu] control the package import behavior in package's _ init _. py, which makes the use of the package more concise and convenient.
Horizon/base. py
Basic class relationships:
Part1:
Part2:
Part3:
Site Class:
To sum up, the final include () import is the _ lazy_urls of the site class.
3. Describe the relationship among site, dashboard, and panel:
[Said Xiao Jieyu] Here, Horizon adopts the registration mechanism, that is, registering other components to the attributes of the root object with an object as the root object. This mechanism makes the software more scalable, and the organization is clear. It looks like a design pattern.
Horizon is a site object. When registering a dashboard class, a dashboard object is built and registered to its attribute _ registry dictionary. The Panel class is registered to the dashboard class, during registration, the Panel object will be built and registered to the _ registry Dictionary of the dashboard object. The details are as follows:
A dashboard registration process
For example, admin:
Openstack_dashboard/dashboards/admin/dashboard. py
Import horizon
Class systempanels (horizon. panelgroup ):
Slug = "admin"
Name = _ ("System Panel ")
Panels = ('overview', 'metering', 'hypervisors ', 'instances', 'volumes ',
'Flagors ', 'images', 'networks', 'routers', 'defaults', 'info ')
Class identitypanels (horizon. panelgroup ):
Slug = "Identity"
Name = _ ("Identity panel ")
Panels = ('domains', 'project', 'users', 'groups', 'roles ')
Class admin (horizon. Dashboard ):
Name = _ ("admin ")
Slug = "admin"
"Panels can be used to discover all panels related to the dashboard, so that you can register these panels in the dashboard later """
Panels = (systempanels, identitypanels)
Default_panel = 'overview'
Permissions = ('openstack. roles. admin ',)
Horizon. Register (Admin)
Horizon/base. py
Site Class:
Def register (self, dashboard ):
"Registers a: Class :'~ Horizon. Dashboard 'with horizon ."""
Return self. _ register (dashboard)
Registry class:
Def _ register (self, CLS ):
"Registers the given class.
If the specified class is already registered then it is ignored.
"""
If not inspect. isclass (CLS ):
Raise valueerror ('only classes may be registered .')
Elif not issubclass (CLS, self. _ registerable_class ):
Raise valueerror ('only % s classes or subclasses may be registered .'
% Self. _ registerable_class. _ name __)
If CLS not in self. _ registry:
Cls. _ registered_with = self
Self. _ registry [CLS] = Cls ()
Return self. _ registry [CLS]
Add the dashboard class à class instance ing to the _ registy ing of the Horizon object in horizon/base. py.
Registration Process of a panel
For example, instancs in Admin:
Openstack_dashboard/dashboards/admin/instances/panel. py
Import horizon
"Import the dashboard. py of the admin dashboard """
From openstack_dashboard.dashboards.admin import dashboard
Class aggregates (horizon. Panel ):
Name = _ ("host aggregates ")
Slug = 'aggregates'
Permissions = ('openstack. Services. compute ',)
"Register in dashboard as admin """
Dashboard. admin. Register (aggregates)
Horizon/base. py
Dashboard class:
@ Classmethod
Def register (CLS, panel ):
"Registers a: Class :'~ Horizon. Panel 'with this dashboard ."""
"Check whether CLs has been registered to the horizon object, and register the Panel in CLS """
Panel_class = horizon. register_panel (CLS, panel)
# Support template loading from panel template directories.
Panel_mod = import_module (panel. _ module __)
Panel_dir = OS. Path. dirname (panel_mod. _ file __)
Template_dir = OS. Path. Join (panel_dir, "templates ")
If OS. Path. exists (template_dir ):
Key = OS. Path. Join (CLS. slug, panel. slug)
Loaders. panel_template_dirs [Key] = template_dir
Return panel_class
Panel registration will first find the corresponding registered dashboard object from the horizon object, and then register the panel in the dashboard object. The registration process is similar to that of the dashboard.
Continue analysis...
Horizon/base. py
Site Class:
Site Class:
Def _ URLs (Self ):
"Actually calls horizoncomponent. _ get_default_urlpatterns to obtain urlpatterns in site_urls.py """
Urlpatterns = self. _ get_default_urlpatterns () [1]
"Actually called site. _ autodiscover: Import openstack_dashboard/settings. horizon_config in Py and dashboard in the installed_apps module. py and panel. PY, registration of the dashboard will be performed here "" [guess]
Self. _ autodiscover () [2]
"Find the Panel in each dashboard and import the Panel. py of each panel to register each panel """
For dash in self. _ registry. Values ():
Dash. _ autodiscover () [3]
...
# Compile the dynamic urlconf.
"Dash is a dashboard class """
For dash in self. _ registry. Values ():
Urlpatterns + = patterns ('',
URL (r '^ % S/' % dash. slug, include (Dash. _ decorated_urls )))
# Return the three arguments to Django. conf. URLs. Include
Return urlpatterns, self. namespace, self. Slug
Dashboard class:
@ Property
Def _ decorated_urls (Self ):
Urlpatterns = self. _ get_default_urlpatterns () [1]
Default_panel = none
# Add in each panel's views cannot for the default view.
"Panel is Panel Type """
For panel in self. _ registry. Values ():
If panel. slug = self. default_panel:
Default_panel = panel
Continue
Url_slug = panel. slug. Replace ('.','/')
Urlpatterns + = patterns ('',
URL (r '^ % S/' % url_slug, include (panel. _ decorated_urls )))
...
# Return the three arguments to Django. conf. URLs. Include
Return urlpatterns, self. slug, self. Slug
Panel class:
@ Property
Def _ decorated_urls (Self ):
": Find the Panel's URLs. py file """
Urlpatterns = self. _ get_default_urlpatterns () [1]
# Apply access controls to all views in the patterns
Permissions = getattr (self, 'permissions', [])
_ Decorate_urlconf (urlpatterns, require_perms, permissions)
_ Decorate_urlconf (urlpatterns, _ current_component, Panel = self)
# Return the three arguments to Django. conf. URLs. Include
Return urlpatterns, self. slug, self. Slug
4. Conclusion:
For requests:
Address:/dashboard/admin/instances/
Method: Post
Parameters:
Instances_filter_q:
Action: instances _ soft_reboot _ 89a8849b-a3cd-4ce0-9158-c3dd69e8508e
URL binding:
Openstack_dashboard/dashboards/admin/instances/URLs. py
5. API annotation in horizon/base. py
[1] horizoncomponent. _ get_default_urlpatterns
Obtain the urlpatterns In the URLs. py file specified by the object's URLs attribute or under the package of the object
[2] site. _ autodiscover
Def _ autodiscover (Self ):
"Discovers modules to register from ''settings. installed_apps ''.
This makes sure that the appropriate modules get imported to register
Themselves with horizon.
"""
If not getattr (self, '_ registerable_class', none ):
Raise improperlyconfigured ('you must set'
'"_ Registerable_class" Property'
'In order to use autodiscovery .')
# Discover both dashboards and panels, in that order
For mod_name in ('dashboard', 'panel '):
"Settings. installed_apps should be related to horizon_config and installed_apps in openstack_dashboard/settings. py """
For app in settings. installed_apps:
MoD = import_module (APP)
Try:
Before_import_registry = Copy. Copy (self. _ Registry)
Import_module ('% S. % s' % (app, mod_name ))
Failed t exception:
Self. _ registry = before_import_registry
If module_has_submodule (mod, mod_name ):
Raise
Import settings. dashboard in each module in installed_apps. PY or panel. PY, for example, the dashboard of each dashboard in openstack_dashboard/dashboard. PY, In the import dashboard. PY or panel. PY will execute the corresponding registration behavior
[3] dashboard. _ autodiscover
Import the Panel. py of each panel in the current dashboard.
Horizon source code analysis (1)