Nova-api Source Analysis (app creation)

Source: Internet
Author: User

Second, the app loading process analysis in NOVA-API

The directory structure is as follows:

  

The above describes the Nova-api release of some Lib library, with the above basic knowledge, and then to analyze the NOVA-API release process, it is relatively easy. NOVA-API can provide a variety of API services: EC2, Osapi_compute, Osapi_volume, metadata. You can set which services to start by configuring the item Enabled_apis, by default, four services are started. From the executable script of NOVA-API, you can see that each NOVA-API service is managed by Nova.service.WSGIService:

 class  Wsgiservice (object):  def __init__ (self, name, loader=  None): self.name =  name SE Lf.manager =  Self._get_manager () Self.loader = loader or WSGI.     Loader () Self.app =  Self.loader.load_app (name) Self.host = GetAttr (FLAGS, '%s_listen '% name, "0.0.0.0" ) Self.port = GetAttr (Flags, '%s_listen_port '%  name, 0) self.workers = getattr (Flags, '%s_workers '%  nam E, None) Self.server = Wsgi. Server (name, #这里通过eventlet来启动服务 Self.app, Host=self.host, port=self. Port)  def  start (self): if  Self.manager:  self.manager.init_host ()  Self.server.start () ...               

From the above, Wsgiservice uses Self.app = Self.loader.load_app (name) to load Wsgi App,app when loading is complete, use Nova.wsgi.Server to publish the service. The server first instantiates a listening socket with the specified IP and port, and uses the Wsgi.server to publish the socket in a co-process manner, handing over the incoming HTTP request to the app. Here we mainly analyze how the Wsgi app that handles HTTP requests is built, and for each request, how it is distributed to specific specific functions based on the URL and request method.

1, Composite:osapi_compute

The loader in the last statement Self.loader.load_app (name) is an instance of Nova.wsgi.Loader. Loader.load_app (name) executes the following instruction, using deploy to load the Wsgi app:

Deploy.loadapp ("config:%s"% Self.config_path, Name=name)

Self.config_path is a Api-paste.ini file path, typically/etc/nova/api-paste.ini. Name is one of EC2, Osapi_compute, Osapi_volume, metadata, and loads a different Wsgi app depending on the name specified. The following is a detailed analysis of the Wsgi app that provides the OpenStack Compute API service when name= "Osapi_compute" is loaded. The Osapi_compute is configured as follows

  [Composite:osapi_compute] Use =  call:nova.api.openst                                               Ack.urlmap:urlmap_factory/: oscomputeversions /V2:OPENSTACK_COMPUTE_API_V2    

Osapi_compute is a nova.api.openstack.urlmap that is returned by calling the Urlmap_factory function. UrlMap instance, Nova.api.openstack.urlmap.URLMap inherits Paste.urlmap.URLMap, which provides a wsgi calling interface, so the instance is Wsgi app. But the function nova.api.openstack.urlmap.urlmap_factory is exactly the same as the paste.urlmap.urlmap_factory definition, but because they are in a different module, Make them use the urlmap that are in the same module as the UrlMap. The functionality of PASTE.URLMAP.URLMAP is simple: Map URLs to specific WSGI apps based on configuration and prioritize URLs based on their length, and URLs that are longer are preferred to match. So/v2 will match before/. UrlMap updates Script_name and path_info before invoking the lower-level WSGI app. Nova.api.openstack.urlmap.URLMap inherited the Paste.urlmap.URLMap, and wrote a bunch of code, in fact just to achieve the request type of judgment, and set environ[' Nova.best_content_ Type ']: If the suffix of the URL is json (such as/xxxx.json), then environ[' Nova.best_content_type ']= "Application/json". If the URL does not have a suffix, it will be judged by mimetype in the Content_Type field of the HTTP headers. Otherwise the default environ[' Nova.best_content_type ']= "Application/json".

2, COMPOSITE:OPENSTACK_COMPUTE_API_V2

The Osapi_compute loaded by the above configuration is a UrlMap instance, and the HTTP request that WSGI server accepts will be passed directly to the instance processing. It will submit a request for the URL '/v2 ' to the Openstack_compute_api_v2,url for the '/' request to oscomputerversions processing (it returns the system version number directly). Other URL requests, the NotFound is returned. The following continues the analysis of OPENSTACK_COMPUTE_API_V2, which is configured as follows:

[COMPOSITE:OPENSTACK_COMPUTE_API_V2]                                           Use = call:nova.api.auth:pipeline_factory                                      noauth = faultwrap sizelimit noauth ratelimit osapi_compute_app_ V2             keystone = faultwrap sizelimit authtoken keystonecontext ratelimit osapi_compute_app_v2keystone_nolimit = Faultwrap sizelimit authtoken keystonecontext osapi_compute_app_v2  

OPENSTACK_COMPUTE_API_V2 is the Wsgi app that calls Nova.api.auth.pipeline_factory () to return. Pipeline_factory () loads different filter and final OSAPI_COMPUTE_APP_V2 according to the configuration item auth_strategy. The approximate configuration of the filter is as follows:

[Filter:faultwrap]                                                             Paste.filter_factory = Nova.api.openstack:FaultWrapper.factory

The filter in Nova corresponds to Nova.wsgi.Middleware, which is defined as follows:

ClassMiddleware (application):    @classmethod def factory (CLS, Global_config, * * local_config): def  _factory (APP):     Return CLS (APP, * *  local_config) return  _factory  def __init__  (self, application): Self.application =  application  def  process_request (SE    LF, req): Return  None  def  process_response (self, Response): Return  response  @webob. Dec.wsgify (requestclass=  Request) def __call__  (self, req): Response =  Self.process_request (r eq) If  response:return  response response =  Req.get_response (self.application) return Self.process_response (response)            

Middleware Initialize receives a WSGI app, performs process_request () pre-processing the request before invoking the Wsgi app, determines whether the request is handed to the incoming WSGI app, returns directly, or modifies req to the incoming WSGI App processing. The response returned by the Wsgi app is handed over to Process_response () processing. For example, for the logic of validation, it can be placed in the process_request, if the validation pass will continue to the app processing, otherwise return "authentication required". But looking at all of the Nova Mddlerware's writing doesn't seem to use this well-defined structure, but instead puts the processing logic into the __call__, which leads to __call__ becoming complicated and the code less tidy. ,openstack_compute_api_v2=faultwrapper-> requestbodysizelimiter-> auth_token-when auth_strategy= "Keystone" > novakeystonecontext-> ratelimitingmiddleware-> osapi_compute_app_v2. So HTTP requests need to be processed by five middleware to reach Osapi_compute_app_v2. These five middleware are completed separately:

1) exception capture, prevent the service internal processing exception causes WSGI server to hang off;

2) Limit HTTP request body size, for too large body, will return directly to Badrequest;

3) Verify the token ID of the header in the request Keystone;

4) Initialize a Nova.context.RequestContext instance with headers and assign to req.environ[' Nova.context '];

5) Limit the user's access speed.

Note that the filter above is a positive sequence call and returns in reverse order. That is, positive order Processing request, reverse processing results!

3, APP:OSAPI_COMPUTE_APP_V2

When the HTTP request is processed by the above five middlerware, it is finally handed to osapi_compute_app_v2, how does it continue to process it? It is configured as follows:

[APP:OSAPI_COMPUTE_APP_V2]                                                     Paste.app_factory = Nova.api.openstack.compute:APIRouter.factory

OSAPI_COMPUTE_APP_V2 is a Apirouter instance that is returned by calling Nova.api.openstack.compute.APIRouter.factory (). The specific request invokes Apirouter's __call__ function. Basically, the app load is mainly constructs the apirouter, calls the __init__ function, then diffuses to construct the other resource (or controller), walks this one clue, but the request processing mainly is invokes Apirouter's __call__ function, Then match to the appropriate controller, call the controller's function, walk this clue. can refer to:

Http://www.choudan.net/2013/07/30/OpenStack-API%E5%88%86%E6%9E%90 (%e4%b8%80). html

First look at this part of the class relationship, as shown in:

3.1 First analysis of the structure of Apirouter

nova/api/openstack/__init__.py

Apirouter class: Def __init__ (self, ext_mgr=none, init_only=None):    if Ext_mgr was none:        if self . Extensionmanager:            ext_mgr = self. Extensionmanager ()        else:            Raise Exception (_ ("must specify an Extensionmanager class"))    mapper = projectmapper () self.resources = {} self._setup_routes (Mapper, Ext_mgr, init_only) self._setup_ext_routes ( Mapper, Ext_mgr, init_only) self._setup_extensions (ext_mgr) Super (Apirouter, self). __init__ (mapper)  

nova/wsgi.py

Router class: Def __init__(self, mapper):    self.map = Mapper    self._router = Routes.middleware.RoutesMiddleware (Self._dispatch,                                                      self.map) 

Apirouter establishes and maintains a mapping between a URL and a controller through its member variable Self.map (mapper). The mapper is an instance of Nova.api.openstack.ProjectMapper, which inherits Nova.api.openstack.APIMapper (routes. Mapper). Apimapper restricts the format of each URL to JSON or XML, and the URL for the other extension returns NotFound. Projectmapper adds a project_id to each request URL so that each requested URL needs to take the project ID that the user belongs to, so the URL for the general request is/v2/project_id/resources.

Apirouter the mapper is set by self._setup_routes,self._setup_ext_routes,self._setup_extensions three functions, detailed analysis is performed below. The Extensionmanager instance in which the instance is constructed can be found in the following: Http://www.cnblogs.com/littlebugfish/p/4049853.html, which is no longer detailed here, An instance of the extension class in the extension module will be indexed in the Extensionmanager property. Finally call the __init__ function of the parent class router, where Self._router is an instance of Routes.middleware.RoutesMiddleware, initialized with Self._dispatch and Self.map.

3.1.1 _setup_routes Analysis (core Resource)

 class  Apirouter (Nova.api.openstack.APIRouter): Extensionmanager =  extensions. Extensionmanager  def  _setup_routes (self, Mapper, ext_mgr): self.resources[' Servers '] =  servers.create_resource (ext_mgr) mapper.resource ("Server", "Servers" , C ontroller=self.resources[' servers ' ])  self.resources[' ips '] =  ips.create_resource () mapper.res                      Ource ("IP", "IPs", controller=self.resources[' IPs ' ], parent_resource=dict (member_name= ' Server ' , Collection_name= ' servers ' ) ...         

Apirouter establishes a restful API by calling the Routes.Mapper.resource () function, or it can be routes. Mapper.connect () to establish a mapping of the URL to the controller. As shown above, the controller for the servers related request is set to Servers.create_resource (Ext_mgr), The function returns a Nova.api.openstack.compute.servers.Controller () As an Nova.api.openstack.wsgi.Resource instance of the initialization parameter, the Controller for the IPS-related request is set to Nova.api.openstack.ips.Controller () Initializes an Nova.api.openstack.wsgi.Resource instance. Because the call to Mapper.resource establishes the IPs URL map, a parent_resource parameter is added, which makes the URL of the request IPS-related API form/v2/project_id/servers/server_id/ips. Similar to requests for limits, flavors, metadata, and so on.

3.1.2 _setup_ext_routes Analysis (extended Resource)

Def_setup_ext_routes (self, mapper, Ext_mgr, init_only): for resource inExt_mgr.get_resources (): Log.debug (_ (' Extended resource:%s ')), resource.collection) if init_only is not None and resource.collection not in  init_o Nly:continue  Inherits =  None if  resource.inherits:inherits =  self.resources.ge T (resource.inherits) if not  Resource.controller:resource.controller =  Inherits.controller Wsgi_resource =  Wsgi. Resource (Resource.controller, inherits=  inherits) self.resources[resource.collection] =  Wsgi_resource Kargs =  dict (controller=  wsgi_resource, collection=  resource.collection_actions, member=  resource.member_actions) If  resource.parent:kargs[' parent_resource '] =  resource.parent Mapper.resource ( Resource.collection, Resource.collection, **kargs) if  resource.custom_routes_fn:resource.custom_routes_fn ( Mapper, Wsgi_resource)             

The Extensionmanager get_resources function is called first, which iterates through the Get_resources function that invokes the instance of the extended class registered in Extensionmanager (that is, nova/api/openstack/ The Get_resources function of the class that corresponds to the filename within each file in the Compute/contrib to get a list of Nova.api.openstack.ResourceExtension objects. The controllers of these Resourceextension objects are then encapsulated into Nova.api.openstack.wsgi.Resource objects, and the Mapper.resource function is used to construct the URLs to these resource mappings.

3.1.3 _setup_extensions Analysis (Extended controller)

 def  _setup_extensions (self, ext_mgr): For extension in  ext_mgr.get_controller_extensions (): col lection =  extension.collection controller =  Extension.controller msg_format_dict = {' Collection ' : Collection, ' Ext_name ' : extension.extension.name} If collection not in  self. Resources:LOG.warning (_ (' Extension% (ext_name) s:cannot extend ' Resource% (collection) S:no such resource ' ), MSG _FORMAT_DICT) Continue  Log.debug (_ (' Extension% (ext_name) s extending resource: '% (collection) s ' ), Msg_ format_dict) resource = Self.resources[collection] Resource.register_actions (Controller) Resource.register_ Extensions (Controller)           

The Get_controller_extensions function of Extensionmanager is called first, and the function iterates through the invocation of an instance of an extension class registered in Extensionmanager Get_controller_ The extensions function (that is, the get_controller_extensions function of the class that corresponds to the filename in each file in Nova/api/openstack/compute/contrib), Thus obtaining a list of Nova.api.openstack. Controllerextension objects. The Nova.api.openstack.wsgi.Resource resource corresponding to collection in each controllerextension is then registered to each function of the controller in Controllerextension.

Nova-api Source Analysis (app creation)

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.