OpenStack Cinder服务启动过程中的资源加载和扩展源码解析之二

感谢朋友支持本博客,欢迎共同探讨交流,由于能力和时间有限,错误之处在所难免,欢迎指正!
如果转载,请保留作者信息。
博客地址:http://blog.csdn.net/gaoxingnengjisuan
邮箱地址:[email protected]


(2) self._setup_routes(mapper, ext_mgr)

现在我们回到类/cinder/api/openstack/__init__.py----class APIRouter中的初始化方法:

class APIRouter(base_wsgi.Router):
    def __init__(self, ext_mgr=None):
        if ext_mgr is None:
            if self.ExtensionManager:
                ext_mgr = self.ExtensionManager() (1)
            else:
                raise Exception(_("Must specify an ExtensionManager class"))
        
        mapper = ProjectMapper()        
        self.resources = {}
        self._setup_routes(mapper, ext_mgr) (2)
        self._setup_ext_routes(mapper, ext_mgr) (3)
        self._setup_extensions(ext_mgr) (4)
        super(APIRouter, self).__init__(mapper) (5)

来看第二条比较重要的语句:self._setup_routes(mapper, ext_mgr),具体来看方法_setup_routes的实现:

def _setup_routes(self, mapper, ext_mgr):
        """
        mapper = Route name Methods Path
        mapper.connect = <bound method ProjectMapper.connect of <cinder.api.openstack.ProjectMapper object at 0x2e5bc10>>
        
        # 示例:
        # map.resource("message", "messages", collection={"rss": "GET"})
        # "GET /message/rss"  =>  ``Messages.rss()``.
        # map.resource('message', 'messages', member={'mark':'POST'})
        # "POST /message/1/mark"  =>  ``Messages.mark(1)``
        """
        self.resources['versions'] = versions.create_resource()
        mapper.connect("versions", "/",
                       controller=self.resources['versions'],
                       action='show')
        """
        mapper = 
        Route name         Methods Path
        versions           /
        """
                
        mapper.redirect("", "/")

        self.resources['volumes'] = volumes.create_resource(ext_mgr)
        mapper.resource("volume", "volumes",
                        controller=self.resources['volumes'],
                        collection={'detail': 'GET'},
                        member={'action': 'POST'})
        """
        mapper = 
        Route name               Methods Path                                        
        ......                   ......
                                 POST    /{project_id}/volumes.:(format)             
                                 POST    /{project_id}/volumes                       
        formatted_detail_volumes GET     /{project_id}/volumes/detail.:(format)      
        detail_volumes           GET     /{project_id}/volumes/detail                
        formatted_volumes        GET     /{project_id}/volumes.:(format)             
        volumes                  GET     /{project_id}/volumes                       
        formatted_new_volume     GET     /{project_id}/volumes/new.:(format)         
        new_volume               GET     /{project_id}/volumes/new                   
                                 PUT     /{project_id}/volumes/:(id).:(format)       
                                 PUT     /{project_id}/volumes/:(id)                 
        formatted_action_volume  POST    /{project_id}/volumes/:(id)/action.:(format)
        action_volume            POST    /{project_id}/volumes/:(id)/action          
                                 DELETE  /{project_id}/volumes/:(id).:(format)       
                                 DELETE  /{project_id}/volumes/:(id)                 
        formatted_edit_volume    GET     /{project_id}/volumes/:(id)/edit.:(format)  
        edit_volume              GET     /{project_id}/volumes/:(id)/edit            
        formatted_volume         GET     /{project_id}/volumes/:(id).:(format)       
        volume                   GET     /{project_id}/volumes/:(id)                 
        """
                
        self.resources['types'] = types.create_resource()
        mapper.resource("type", "types",
                        controller=self.resources['types'])
        """
        mapper = 
        Route name               Methods Path                                        
        ......                   ......
                                 POST    /{project_id}/types.:(format)               
                                 POST    /{project_id}/types                         
        formatted_types          GET     /{project_id}/types.:(format)               
        types                    GET     /{project_id}/types                         
        formatted_new_type       GET     /{project_id}/types/new.:(format)           
        new_type                 GET     /{project_id}/types/new                     
                                 PUT     /{project_id}/types/:(id).:(format)         
                                 PUT     /{project_id}/types/:(id)                   
                                 DELETE  /{project_id}/types/:(id).:(format)         
                                 DELETE  /{project_id}/types/:(id)                   
        formatted_edit_type      GET     /{project_id}/types/:(id)/edit.:(format)    
        edit_type                GET     /{project_id}/types/:(id)/edit              
        formatted_type           GET     /{project_id}/types/:(id).:(format)         
        type                     GET     /{project_id}/types/:(id)                   
        """
              
        self.resources['snapshots'] = snapshots.create_resource(ext_mgr)
        mapper.resource("snapshot", "snapshots",
                        controller=self.resources['snapshots'],
                        collection={'detail': 'GET'},
                        member={'action': 'POST'})
        """
        mapper = 
        Route name                 Methods Path                                          
        ......                     ......                 
                                   POST    /{project_id}/snapshots.:(format)             
                                   POST    /{project_id}/snapshots                       
        formatted_detail_snapshots GET     /{project_id}/snapshots/detail.:(format)      
        detail_snapshots           GET     /{project_id}/snapshots/detail                
        formatted_snapshots        GET     /{project_id}/snapshots.:(format)             
        snapshots                  GET     /{project_id}/snapshots                       
        formatted_new_snapshot     GET     /{project_id}/snapshots/new.:(format)         
        new_snapshot               GET     /{project_id}/snapshots/new                   
                                   PUT     /{project_id}/snapshots/:(id).:(format)       
                                   PUT     /{project_id}/snapshots/:(id)                 
        formatted_action_snapshot  POST    /{project_id}/snapshots/:(id)/action.:(format)
        action_snapshot            POST    /{project_id}/snapshots/:(id)/action          
                                   DELETE  /{project_id}/snapshots/:(id).:(format)       
                                   DELETE  /{project_id}/snapshots/:(id)                 
        formatted_edit_snapshot    GET     /{project_id}/snapshots/:(id)/edit.:(format)  
        edit_snapshot              GET     /{project_id}/snapshots/:(id)/edit            
        formatted_snapshot         GET     /{project_id}/snapshots/:(id).:(format)       
        snapshot                   GET     /{project_id}/snapshots/:(id)                 
        """
                
        self.resources['snapshot_metadata'] = snapshot_metadata.create_resource()
        snapshot_metadata_controller = self.resources['snapshot_metadata']
        mapper.resource("snapshot_metadata", "metadata",
                        controller=snapshot_metadata_controller,
                        parent_resource=dict(member_name='snapshot',
                                             collection_name='snapshots'))
        """
        mapper = 
        Route name                                Methods Path                                                              
        ......                                    ......                                                 
                                                  POST    /{project_id}/snapshots/:snapshot_id/metadata.:(format)           
                                                  POST    /{project_id}/snapshots/:snapshot_id/metadata                     
        formatted_snapshot_metadata               GET     /{project_id}/snapshots/:snapshot_id/metadata.:(format)           
        snapshot_metadata                         GET     /{project_id}/snapshots/:snapshot_id/metadata                     
        formatted_snapshot_new_snapshot_metadata  GET     /{project_id}/snapshots/:snapshot_id/metadata/new.:(format)       
        snapshot_new_snapshot_metadata            GET     /{project_id}/snapshots/:snapshot_id/metadata/new                 
                                                  PUT     /{project_id}/snapshots/:snapshot_id/metadata/:(id).:(format)     
                                                  PUT     /{project_id}/snapshots/:snapshot_id/metadata/:(id)               
                                                  DELETE  /{project_id}/snapshots/:snapshot_id/metadata/:(id).:(format)     
                                                  DELETE  /{project_id}/snapshots/:snapshot_id/metadata/:(id)               
        formatted_snapshot_edit_snapshot_metadata GET     /{project_id}/snapshots/:snapshot_id/metadata/:(id)/edit.:(format)
        snapshot_edit_snapshot_metadata           GET     /{project_id}/snapshots/:snapshot_id/metadata/:(id)/edit          
        formatted_snapshot_snapshot_metadata      GET     /{project_id}/snapshots/:snapshot_id/metadata/:(id).:(format)     
        snapshot_snapshot_metadata                GET     /{project_id}/snapshots/:snapshot_id/metadata/:(id)               
        """
                
        mapper.connect("metadata",
                       "/{project_id}/snapshots/{snapshot_id}/metadata",
                       controller=snapshot_metadata_controller,
                       action='update_all',
                       conditions={"method": ['PUT']})
        """
        mapper = 
        Route name                                Methods Path
        ......                                    ......                                                 
        metadata                                  PUT     /{project_id}/snapshots/{snapshot_id}/metadata                
        """
                
        self.resources['limits'] = limits.create_resource()
        mapper.resource("limit", "limits",controller=self.resources['limits'])
        """
        mapper = 
        Route name                                Methods Path
        ......                                    ......                                                         
                                                  POST    /{project_id}/limits.:(format)                                    
                                                  POST    /{project_id}/limits                                              
        formatted_limits                          GET     /{project_id}/limits.:(format)                                    
        limits                                    GET     /{project_id}/limits                                              
        formatted_new_limit                       GET     /{project_id}/limits/new.:(format)                                
        new_limit                                 GET     /{project_id}/limits/new                                          
                                                  PUT     /{project_id}/limits/:(id).:(format)                              
                                                  PUT     /{project_id}/limits/:(id)                                        
                                                  DELETE  /{project_id}/limits/:(id).:(format)                              
                                                  DELETE  /{project_id}/limits/:(id)                                        
        formatted_edit_limit                      GET     /{project_id}/limits/:(id)/edit.:(format)                         
        edit_limit                                GET     /{project_id}/limits/:(id)/edit                                   
        formatted_limit                           GET     /{project_id}/limits/:(id).:(format)                              
        limit                                     GET     /{project_id}/limits/:(id)                
        """
                
        self.resources['volume_metadata'] = volume_metadata.create_resource()
        volume_metadata_controller = self.resources['volume_metadata']
        mapper.resource("volume_metadata", "metadata",
                        controller=volume_metadata_controller,
                        parent_resource=dict(member_name='volume',
                                             collection_name='volumes'))
        """
        mapper = 
        Route name                                Methods Path
        ......                                    ......                                                         
                                                  POST    /{project_id}/volumes/:volume_id/metadata.:(format)               
                                                  POST    /{project_id}/volumes/:volume_id/metadata                         
        formatted_volume_metadata                 GET     /{project_id}/volumes/:volume_id/metadata.:(format)               
        volume_metadata                           GET     /{project_id}/volumes/:volume_id/metadata                         
        formatted_volume_new_volume_metadata      GET     /{project_id}/volumes/:volume_id/metadata/new.:(format)           
        volume_new_volume_metadata                GET     /{project_id}/volumes/:volume_id/metadata/new                     
                                                  PUT     /{project_id}/volumes/:volume_id/metadata/:(id).:(format)         
                                                  PUT     /{project_id}/volumes/:volume_id/metadata/:(id)                   
                                                  DELETE  /{project_id}/volumes/:volume_id/metadata/:(id).:(format)         
                                                  DELETE  /{project_id}/volumes/:volume_id/metadata/:(id)                   
        formatted_volume_edit_volume_metadata     GET     /{project_id}/volumes/:volume_id/metadata/:(id)/edit.:(format)    
        volume_edit_volume_metadata               GET     /{project_id}/volumes/:volume_id/metadata/:(id)/edit              
        formatted_volume_volume_metadata          GET     /{project_id}/volumes/:volume_id/metadata/:(id).:(format)         
        volume_volume_metadata                    GET     /{project_id}/volumes/:volume_id/metadata/:(id)                   
        """
                
        mapper.connect("metadata",
                       "/{project_id}/volumes/{volume_id}/metadata",
                       controller=volume_metadata_controller,
                       action='update_all',
                       conditions={"method": ['PUT']})
        """
        mapper = 
        Route name                                Methods Path                                                              
        ......                                    ......                                                         
        metadata                                  PUT     /{project_id}/volumes/{volume_id}/metadata                        
        """
这里调用了方法mapper.connect和mapper.resource,实现进而调用python库routes,来实现从url提取相应的参数,如controller,action或者其它用户自己定义的变量,从而实现URL和相应action的映射。具体实现没有进行解析。也就是可以简单的理解为,通过得到的URL,通过这里实现的映射关系,进行格式匹配,具体定位到所要调用的方法上。具体的输出示例,如上述源码中已经给出,可以作为参考。

需要注意的是,这里实现的是模块中正规的功能的URL和具体方法的映射关系,也就是/cinder/api/v1/或者是/cinder/api/v2/包下的各个py文件中控制类下的功能方法。对于扩展功能方法的URL映射关系,在后面的语句中进行了实现。

(3)self._setup_ext_routes(mapper, ext_mgr)
来看方法/cinder/api/openstack/__init__.py----class APIRouter----def __init__中第三条比较重要的语句:
self._setup_ext_routes(mapper, ext_mgr)
具体来看方法_setup_ext_routes的源码实现:

def _setup_ext_routes(self, mapper, ext_mgr):
        """
        mapper = 
        Route name                                Methods Path                                                              
        versions                                          /                                                                 
        ......                                    ......  ......                  
        formatted_volume_edit_volume_metadata     GET     /{project_id}/volumes/:volume_id/metadata/:(id)/edit.:(format)    
        volume_edit_volume_metadata               GET     /{project_id}/volumes/:volume_id/metadata/:(id)/edit              
        formatted_volume_volume_metadata          GET     /{project_id}/volumes/:volume_id/metadata/:(id).:(format)         
        volume_volume_metadata                    GET     /{project_id}/volumes/:volume_id/metadata/:(id)                   
        metadata                                  PUT     /{project_id}/volumes/{volume_id}/metadata  
        """

        # ext_mgr.get_resources():获取ResourceExtension对象列表;
        for resource in ext_mgr.get_resources():
            LOG.debug(_('Extended resource: %s'), resource.collection)

            wsgi_resource = wsgi.Resource(resource.controller)
            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)

注:需要说明的是在/cinder/api/contrib/目录下的文件都是用来实现功能扩展的,这里主要分为两部分:1.在一个控制器中单纯地实现新的Restful资源功能;2.在一个控制器中即可实现新的Restful资源功能又可对已有的Restful资源功能实现扩展。

方法_setup_ext_routes中针对的是上述第一类,也就是在一个控制器中单纯地实现新的Restful资源功能这个方法主要实现了两部分的功能,即得到alias和self.extensions[alias]一一对应的关系,以及获取新定义Restful资源功能的URL和具体功能方法的映射关系。

首先来看方法中的语句:

for resource in ext_mgr.get_resources()

    wsgi_resource = wsgi.Resource(resource.controller)

来看输出示例:

resource.controller = <cinder.api.extensions.ExtensionsResource object at 0x3579bd0>
resource.controller = <cinder.api.contrib.hosts.HostController object at 0x3579cd0>
resource.controller = <cinder.api.contrib.quotas.QuotaSetsController object at 0x3579d90>
resource.controller = <cinder.api.contrib.volume_encryption_metadata.VolumeEncryptionMetadataController object at 0x3579e10>
resource.controller = <cinder.api.contrib.backups.BackupsController object at 0x3579ed0>
resource.controller = <cinder.api.contrib.volume_type_encryption.VolumeTypeEncryptionController object at 0x35cf050>
resource.controller = <cinder.api.contrib.availability_zones.Controller object at 0x35cf450>
resource.controller = <cinder.api.contrib.types_extra_specs.VolumeTypeExtraSpecsController object at 0x35cf490>
resource.controller = <cinder.api.contrib.qos_specs_manage.QoSSpecsController object at 0x35cf550>
resource.controller = <cinder.api.contrib.quota_classes.QuotaClassSetsController object at 0x35cf5d0>
resource.controller = <cinder.api.contrib.volume_transfer.VolumeTransferController object at 0x35cf890>
resource.controller = <cinder.api.contrib.services.ServiceController object at 0x35cf710>

我们看到这里除了cinder.api.extensions.ExtensionsResource,一共实现了11个扩展类的变量controller的值,应该是在这22个扩展功能的实现类中,其中的11个中实现了方法get_resources。我们继续来看方法get_resources的具体实现:

def get_resources(self):
        """
        Returns a list of ResourceExtension objects.
        获取ResourceExtension对象列表;
        """
        resources = []
        resources.append(ResourceExtension('extensions',ExtensionsResource(self)))
        for ext in self.extensions.values():
            try:
                resources.extend(ext.get_resources())
                
            except AttributeError:
                pass

        return resources
我们首先来看输出示例:
self.extensions = {
        'OS-SCH-HNT': <cinder.api.contrib.scheduler_hints.Scheduler_hints object at 0x18f9a10>,
        'os-hosts': <cinder.api.contrib.hosts.Hosts object at 0x18b0b50>,
        'os-vol-tenant-attr': <cinder.api.contrib.volume_tenant_attribute.Volume_tenant_attribute object at 0x236aa90>,
        'os-quota-sets': <cinder.api.contrib.quotas.Quotas object at 0x1908250>,
        'os-types-manage': <cinder.api.contrib.types_manage.Types_manage object at 0x2277c10>,
        'os-volume-encryption-metadata': <cinder.api.contrib.volume_encryption_metadata.Volume_encryption_metadata object at 0x18b0750>,
        'os-snapshot-actions': <cinder.api.contrib.snapshot_actions.Snapshot_actions object at 0x18b0510>,
        'backups': <cinder.api.contrib.backups.Backups object at 0x226f810>,
        'os-volume-actions': <cinder.api.contrib.volume_actions.Volume_actions object at 0x226f910>,
        'os-vol-host-attr': <cinder.api.contrib.volume_host_attribute.Volume_host_attribute object at 0x1908050>,
        'encryption': <cinder.api.contrib.volume_type_encryption.Volume_type_encryption object at 0x18b01d0>,
        'os-availability-zone': <cinder.api.contrib.availability_zones.Availability_zones object at 0x226f290>,
        'os-types-extra-specs': <cinder.api.contrib.types_extra_specs.Types_extra_specs object at 0x18f91d0>,
        'os-vol-mig-status-attr': <cinder.api.contrib.volume_mig_status_attribute.Volume_mig_status_attribute object at 0x18f9710>,
        'os-image-create': <cinder.api.contrib.image_create.Image_create object at 0x18b05d0>,
        'os-extended-snapshot-attributes': <cinder.api.contrib.extended_snapshot_attributes.Extended_snapshot_attributes object at 0x2282090>,
        'qos-specs': <cinder.api.contrib.qos_specs_manage.Qos_specs_manage object at 0x236a490>,
        'os-quota-class-sets': <cinder.api.contrib.quota_classes.Quota_classes object at 0x18b0a50>,
        'os-volume-transfer': <cinder.api.contrib.volume_transfer.Volume_transfer object at 0x2282cd0>,
        'os-vol-image-meta': <cinder.api.contrib.volume_image_metadata.Volume_image_metadata object at 0x236ae90>,
        'os-admin-actions': <cinder.api.contrib.admin_actions.Admin_actions object at 0x2282910>,
        'os-services': <cinder.api.contrib.services.Services object at 0x18f9c90>}

我们可以看到,这里实现了22个alias和具体实现类的对应字典,即是上篇博客中分析的语句ext_mgr = self.ExtensionManager()所实现的扩展功能目录下所有功能alias和具体实现类的对应。
通过一一到具体类中的验证,我们可以发现其中10个类只实现了方法get_resources,10个类只实现了方法get_controller_extensions,而1个类中即实现了方法get_resources也实现了方法get_controller_extensions。还有一个类中两个方法都没由直接实现;

输出示例(分类):
只实现了方法get_resources:
ext = <cinder.api.contrib.hosts.Hosts object at 0x18b0b50>                
ext = <cinder.api.contrib.quotas.Quotas object at 0x1908250>                
ext = <cinder.api.contrib.volume_encryption_metadata.Volume_encryption_metadata object at 0x18b0750>               
ext = <cinder.api.contrib.backups.Backups object at 0x226f810>              
ext = <cinder.api.contrib.availability_zones.Availability_zones object at 0x226f290>
ext = <cinder.api.contrib.types_extra_specs.Types_extra_specs object at 0x18f91d0>               
ext = <cinder.api.contrib.qos_specs_manage.Qos_specs_manage object at 0x236a490>
ext = <cinder.api.contrib.quota_classes.Quota_classes object at 0x18b0a50>
ext = <cinder.api.contrib.volume_transfer.Volume_transfer object at 0x2282cd0>              
ext = <cinder.api.contrib.services.Services object at 0x18f9c90>

只实现了方法get_controller_extensions:
ext = <cinder.api.contrib.volume_image_metadata.Volume_image_metadata object at 0x236ae90>
ext = <cinder.api.contrib.admin_actions.Admin_actions object at 0x2282910>
ext = <cinder.api.contrib.volume_mig_status_attribute.Volume_mig_status_attribute object at 0x18f9710>
ext = <cinder.api.contrib.volume_actions.Volume_actions object at 0x226f910>
ext = <cinder.api.contrib.snapshot_actions.Snapshot_actions object at 0x18b0510>
ext = <cinder.api.contrib.types_manage.Types_manage object at 0x2277c10>
ext = <cinder.api.contrib.volume_tenant_attribute.Volume_tenant_attribute object at 0x236aa90>
ext = <cinder.api.contrib.scheduler_hints.Scheduler_hints object at 0x18f9a10>
ext = <cinder.api.contrib.volume_host_attribute.Volume_host_attribute object at 0x1908050>
ext = <cinder.api.contrib.extended_snapshot_attributes.Extended_snapshot_attributes object at 0x2282090>

即实现了方法get_resources也实现了方法get_controller_extensions:
ext = <cinder.api.contrib.volume_type_encryption.Volume_type_encryption object at 0x18b01d0>
两个方法都没由直接实现:
ext = <cinder.api.contrib.image_create.Image_create object at 0x18b05d0>
经上分析,返回了11个类ResourceExtension的初始化对象;

来看方法get_resources中的语句:resources.extend(ext.get_resources()),这里的方法get_resources()调用了具体类中的get_resources()方法,而类中没有实现get_resources()方法的,在其父类class ExtensionDescriptor(object)中有实现,我们来看具体的类中get_resources的实现,我简单进行了一个归纳:

直接实现了方法get_resources的类(看几个例子,看一下实现过程):
==========================================================
ext = <cinder.api.contrib.backups.Backups object at 0x226f810>:
class Backups(extensions.ExtensionDescriptor):
    """Backups support."""

    name = 'Backups'
    alias = 'backups'
    namespace = 'http://docs.openstack.org/volume/ext/backups/api/v1'
    updated = '2012-12-12T00:00:00+00:00'

    def get_resources(self):
        resources = []
        res = extensions.ResourceExtension(
            Backups.alias,
            BackupsController(),
            collection_actions={'detail': 'GET'},
            member_actions={'restore': 'POST'})
        resources.append(res)
        return resources

class BackupsController(wsgi.Controller):
    """
    The Backups API controller for the OpenStack API.
    OpenStack的备份操作API控制器;
    """

    _view_builder_class = backup_views.ViewBuilder

    def __init__(self):
        self.backup_api = backupAPI.API()
        super(BackupsController, self).__init__()

class Controller(object):
    """Default controller."""

    __metaclass__ = ControllerMetaclass

    _view_builder_class = None

    def __init__(self, view_builder=None):
        """Initialize controller with a view builder instance."""
        if view_builder:
            self._view_builder = view_builder
        elif self._view_builder_class:
            self._view_builder = self._view_builder_class()
        else:
            self._view_builder = None
==========================================================
ext = <cinder.api.contrib.hosts.Hosts object at 0x18b0b50>:
class Hosts(extensions.ExtensionDescriptor):
    """Admin-only host administration"""

    name = "Hosts"
    alias = "os-hosts"
    namespace = "http://docs.openstack.org/volume/ext/hosts/api/v1.1"
    updated = "2011-06-29T00:00:00+00:00"

    def get_resources(self):
        resources = [extensions.ResourceExtension('os-hosts',
                                                  HostController(),
                                                  collection_actions={'update': 'PUT'},
                                                  member_actions={
                                                      'startup': 'GET',
                                                      'shutdown': 'GET',
                                                      'reboot': 'GET'})]
        return resources

class HostController(object):
    """
    The Hosts API controller for the OpenStack API.
    主机控制API;
    """
    def __init__(self):
        self.api = volume_api.HostAPI()
        super(HostController, self).__init__()
==========================================================
ext = <cinder.api.contrib.quotas.Quotas object at 0x1908250>:
class Quotas(extensions.ExtensionDescriptor):
    """Quotas management support"""

    name = "Quotas"
    alias = "os-quota-sets"
    namespace = "http://docs.openstack.org/volume/ext/quotas-sets/api/v1.1"
    updated = "2011-08-08T00:00:00+00:00"

    def get_resources(self):
        resources = []

        res = extensions.ResourceExtension('os-quota-sets',
                                           QuotaSetsController(),
                                           member_actions={'defaults': 'GET'})
        resources.append(res)

        return resources

class QuotaSetsController(object)
==========================================================
ext = <cinder.api.contrib.volume_encryption_metadata.Volume_encryption_metadata object at 0x18b0750>:
class Volume_encryption_metadata(extensions.ExtensionDescriptor):
    """Volume encryption metadata retrieval support."""

    name = "VolumeEncryptionMetadata"
    alias = "os-volume-encryption-metadata"
    namespace = ("http://docs.openstack.org/volume/ext/"
                 "os-volume-encryption-metadata/api/v1")
    updated = "2013-07-10T00:00:00+00:00"

    def get_resources(self):
        resources = []
        res = extensions.ResourceExtension('encryption',
                                           VolumeEncryptionMetadataController(),
                                           parent=dict(member_name='volume', collection_name='volumes'))
        resources.append(res)
        return resources

class VolumeEncryptionMetadataController(wsgi.Controller):
    """
    The volume encryption metadata API extension
    卷加密元数据控制API类;
    """

class Controller(object):
    """Default controller."""

    __metaclass__ = ControllerMetaclass

    _view_builder_class = None

    def __init__(self, view_builder=None):
        """Initialize controller with a view builder instance."""
        if view_builder:
            self._view_builder = view_builder
        elif self._view_builder_class:
            self._view_builder = self._view_builder_class()
        else:
            self._view_builder = None
==========================================================

没有实现get_resources()方法的类,在其父类class ExtensionDescriptor(object)中有实现:

def get_resources(self):
        """
        List of extensions.ResourceExtension extension objects.
        Resources define new nouns, and are accessible through URLs.
        """
        resources = []
        return resources

可见没有做什么具体的工作;
从分析中可以看到,类中直接实现了get_resources()的部分,都进行了类class Resource(wsgi.Application)的初始化工作,简单来看类class Resource(wsgi.Application)的初始化方法:

class Resource(wsgi.Application):
    def __init__(self, controller, action_peek=None, **deserializers):
        """
        :param controller: object that implement methods created by routes lib
        :param action_peek: dictionary of routines for peeking into an action request body to determine the desired action
        """

        self.controller = controller

        # 获取和更新默认的反序列化方法;
        default_deserializers = dict(xml=XMLDeserializer, json=JSONDeserializer)
        default_deserializers.update(deserializers)
        self.default_deserializers = default_deserializers
        # 获取默认的序列化方法;
        self.default_serializers = dict(xml=XMLDictSerializer, json=JSONDictSerializer)

        # 获取和确认所要引用的动作;
        # action_peek_xml:通过解析xml字符串,实现确定所要引用的动作;
        # action_peek_json:通过反序列化操作,实现确定所要引用的动作;
        self.action_peek = dict(xml=action_peek_xml, json=action_peek_json)
        self.action_peek.update(action_peek or {})

        # Copy over the actions dictionary
        self.wsgi_actions = {}
        if controller:
            self.register_actions(controller)

        # Save a mapping of extensions
        self.wsgi_extensions = {}
        self.wsgi_action_extensions = {}

其中的语句:self.register_actions(controller)实现的功能就是把self.resources和wsgi_resource一一对应起来。
方法get_resources(self)先分析到这里,我们回到方法_setup_ext_routes:

def _setup_ext_routes(self, mapper, ext_mgr):
        """
        mapper = 
        Route name                                Methods Path                                                              
        versions                                          /                                                                 
        ......                                    ......  ......                  
        formatted_volume_edit_volume_metadata     GET     /{project_id}/volumes/:volume_id/metadata/:(id)/edit.:(format)    
        volume_edit_volume_metadata               GET     /{project_id}/volumes/:volume_id/metadata/:(id)/edit              
        formatted_volume_volume_metadata          GET     /{project_id}/volumes/:volume_id/metadata/:(id).:(format)         
        volume_volume_metadata                    GET     /{project_id}/volumes/:volume_id/metadata/:(id)                   
        metadata                                  PUT     /{project_id}/volumes/{volume_id}/metadata  
        """

        # ext_mgr.get_resources():获取ResourceExtension对象列表;
        for resource in ext_mgr.get_resources():
            LOG.debug(_('Extended resource: %s'), resource.collection)

            wsgi_resource = wsgi.Resource(resource.controller)
            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)
再来看语句:
kargs = dict(controller=wsgi_resource,
        collection=resource.collection_actions,
        member=resource.member_actions)
if resource.parent:
        kargs['parent_resource'] = resource.parent
这里实现的功能就是获取各个类中的collection_actions和member_actions,分别赋值给collection和member,实现格式的统一,为后续的调用做准备;

再来看语句:
mapper.resource(resource.collection, resource.collection, **kargs)
实现的功能就是获取新定义Restful资源功能的URL和具体功能方法的映射关系
输出示例:


            ==================================================================================
            mapper =
            Route name                                Methods Path
            ......                                                  ......     ......
                                                      POST    /{project_id}/extensions.:(format)                                
                                                      POST    /{project_id}/extensions                                          
            formatted_extensions                      GET     /{project_id}/extensions.:(format)                                
            extensions                                GET     /{project_id}/extensions                                          
            formatted_new_extensions                  GET     /{project_id}/extensions/new.:(format)                            
            new_extensions                            GET     /{project_id}/extensions/new                                      
                                                      PUT     /{project_id}/extensions/:(id).:(format)                          
                                                      PUT     /{project_id}/extensions/:(id)                                    
                                                      DELETE  /{project_id}/extensions/:(id).:(format)                          
                                                      DELETE  /{project_id}/extensions/:(id)                                    
            formatted_edit_extensions                 GET     /{project_id}/extensions/:(id)/edit.:(format)                     
            edit_extensions                           GET     /{project_id}/extensions/:(id)/edit                               
            formatted_extensions                      GET     /{project_id}/extensions/:(id).:(format)                          
            extensions                                GET     /{project_id}/extensions/:(id)                                    
            ==================================================================================
            mapper =
            Route name                                Methods Path
            ......                                                  ......     ......
                                                      PUT     /{project_id}/os-hosts.:(format)                                  
                                                      PUT     /{project_id}/os-hosts                                            
                                                      POST    /{project_id}/os-hosts.:(format)                                  
                                                      POST    /{project_id}/os-hosts                                            
            formatted_os-hosts                        GET     /{project_id}/os-hosts.:(format)                                  
            os-hosts                                  GET     /{project_id}/os-hosts                                            
            formatted_new_os-hosts                    GET     /{project_id}/os-hosts/new.:(format)                              
            new_os-hosts                              GET     /{project_id}/os-hosts/new                                        
                                                      PUT     /{project_id}/os-hosts/:(id).:(format)                            
                                                      PUT     /{project_id}/os-hosts/:(id)                                      
                                                      DELETE  /{project_id}/os-hosts/:(id).:(format)                            
                                                      DELETE  /{project_id}/os-hosts/:(id)                                      
            formatted_edit_os-hosts                   GET     /{project_id}/os-hosts/:(id)/edit.:(format)                       
            edit_os-hosts                             GET     /{project_id}/os-hosts/:(id)/edit                                 
            formatted_startup_os-hosts                GET     /{project_id}/os-hosts/:(id)/startup.:(format)                    
            startup_os-hosts                          GET     /{project_id}/os-hosts/:(id)/startup                              
            formatted_reboot_os-hosts                 GET     /{project_id}/os-hosts/:(id)/reboot.:(format)                     
            reboot_os-hosts                           GET     /{project_id}/os-hosts/:(id)/reboot                               
            formatted_shutdown_os-hosts               GET     /{project_id}/os-hosts/:(id)/shutdown.:(format)                   
            shutdown_os-hosts                         GET     /{project_id}/os-hosts/:(id)/shutdown                             
            formatted_os-hosts                        GET     /{project_id}/os-hosts/:(id).:(format)                            
            os-hosts                                  GET     /{project_id}/os-hosts/:(id)                                      
            ==================================================================================
            mapper =
            Route name                                Methods Path
            ......                                                  ......     ......
                                                      POST    /{project_id}/os-quota-sets.:(format)                             
                                                      POST    /{project_id}/os-quota-sets                                       
            formatted_os-quota-sets                   GET     /{project_id}/os-quota-sets.:(format)                             
            os-quota-sets                             GET     /{project_id}/os-quota-sets                                       
            formatted_new_os-quota-sets               GET     /{project_id}/os-quota-sets/new.:(format)                         
            new_os-quota-sets                         GET     /{project_id}/os-quota-sets/new                                   
                                                      PUT     /{project_id}/os-quota-sets/:(id).:(format)                       
                                                      PUT     /{project_id}/os-quota-sets/:(id)                                 
                                                      DELETE  /{project_id}/os-quota-sets/:(id).:(format)                       
                                                      DELETE  /{project_id}/os-quota-sets/:(id)                                 
            formatted_edit_os-quota-sets              GET     /{project_id}/os-quota-sets/:(id)/edit.:(format)                  
            edit_os-quota-sets                        GET     /{project_id}/os-quota-sets/:(id)/edit                            
            formatted_defaults_os-quota-sets          GET     /{project_id}/os-quota-sets/:(id)/defaults.:(format)              
            defaults_os-quota-sets                    GET     /{project_id}/os-quota-sets/:(id)/defaults                        
            formatted_os-quota-sets                   GET     /{project_id}/os-quota-sets/:(id).:(format)                       
            os-quota-sets                             GET     /{project_id}/os-quota-sets/:(id)                                 
            ==================================================================================
            mapper =
            Route name                                Methods Path
            ......                                                  ......     ......
                                                      POST    /{project_id}/volumes/:volume_id/encryption.:(format)             
                                                      POST    /{project_id}/volumes/:volume_id/encryption                       
            formatted_volume_encryption               GET     /{project_id}/volumes/:volume_id/encryption.:(format)             
            volume_encryption                         GET     /{project_id}/volumes/:volume_id/encryption                       
            formatted_volume_new_encryption           GET     /{project_id}/volumes/:volume_id/encryption/new.:(format)         
            volume_new_encryption                     GET     /{project_id}/volumes/:volume_id/encryption/new                   
                                                      PUT     /{project_id}/volumes/:volume_id/encryption/:(id).:(format)       
                                                      PUT     /{project_id}/volumes/:volume_id/encryption/:(id)                 
                                                      DELETE  /{project_id}/volumes/:volume_id/encryption/:(id).:(format)       
                                                      DELETE  /{project_id}/volumes/:volume_id/encryption/:(id)                 
            formatted_volume_edit_encryption          GET     /{project_id}/volumes/:volume_id/encryption/:(id)/edit.:(format)  
            volume_edit_encryption                    GET     /{project_id}/volumes/:volume_id/encryption/:(id)/edit            
            formatted_volume_encryption               GET     /{project_id}/volumes/:volume_id/encryption/:(id).:(format)       
            volume_encryption                         GET     /{project_id}/volumes/:volume_id/encryption/:(id)                 
            ==================================================================================
            mapper =
            Route name                                Methods Path
            ......                                                  ......     ......
                                                      POST    /{project_id}/backups.:(format)                                   
                                                      POST    /{project_id}/backups                                             
            formatted_detail_backups                  GET     /{project_id}/backups/detail.:(format)                            
            detail_backups                            GET     /{project_id}/backups/detail                                      
            formatted_backups                         GET     /{project_id}/backups.:(format)                                   
            backups                                   GET     /{project_id}/backups                                             
            formatted_new_backups                     GET     /{project_id}/backups/new.:(format)                               
            new_backups                               GET     /{project_id}/backups/new                                         
                                                      PUT     /{project_id}/backups/:(id).:(format)                             
                                                      PUT     /{project_id}/backups/:(id)                                       
            formatted_restore_backups                 POST    /{project_id}/backups/:(id)/restore.:(format)                     
            restore_backups                           POST    /{project_id}/backups/:(id)/restore                               
                                                      DELETE  /{project_id}/backups/:(id).:(format)                             
                                                      DELETE  /{project_id}/backups/:(id)                                       
            formatted_edit_backups                    GET     /{project_id}/backups/:(id)/edit.:(format)                        
            edit_backups                              GET     /{project_id}/backups/:(id)/edit                                  
            formatted_backups                         GET     /{project_id}/backups/:(id).:(format)                             
            backups                                   GET     /{project_id}/backups/:(id)                                       
            ==================================================================================
            mapper =
            Route name                                Methods Path
            ......                                                  ......     ......
                                                      POST    /{project_id}/types/:type_id/encryption.:(format)                 
                                                      POST    /{project_id}/types/:type_id/encryption                           
            formatted_type_encryption                 GET     /{project_id}/types/:type_id/encryption.:(format)                 
            type_encryption                           GET     /{project_id}/types/:type_id/encryption                           
            formatted_type_new_encryption             GET     /{project_id}/types/:type_id/encryption/new.:(format)             
            type_new_encryption                       GET     /{project_id}/types/:type_id/encryption/new                       
                                                      PUT     /{project_id}/types/:type_id/encryption/:(id).:(format)           
                                                      PUT     /{project_id}/types/:type_id/encryption/:(id)                     
                                                      DELETE  /{project_id}/types/:type_id/encryption/:(id).:(format)           
                                                      DELETE  /{project_id}/types/:type_id/encryption/:(id)                     
            formatted_type_edit_encryption            GET     /{project_id}/types/:type_id/encryption/:(id)/edit.:(format)      
            type_edit_encryption                      GET     /{project_id}/types/:type_id/encryption/:(id)/edit                
            formatted_type_encryption                 GET     /{project_id}/types/:type_id/encryption/:(id).:(format)           
            type_encryption                           GET     /{project_id}/types/:type_id/encryption/:(id)                     
            ==================================================================================
            mapper =
            Route name                                Methods Path
            ......                                                  ......     ......
                                                      POST    /{project_id}/os-availability-zone.:(format)                      
                                                      POST    /{project_id}/os-availability-zone                                
            formatted_os-availability-zone            GET     /{project_id}/os-availability-zone.:(format)                      
            os-availability-zone                      GET     /{project_id}/os-availability-zone                                
            formatted_new_os-availability-zone        GET     /{project_id}/os-availability-zone/new.:(format)                  
            new_os-availability-zone                  GET     /{project_id}/os-availability-zone/new                            
                                                      PUT     /{project_id}/os-availability-zone/:(id).:(format)                
                                                      PUT     /{project_id}/os-availability-zone/:(id)                          
                                                      DELETE  /{project_id}/os-availability-zone/:(id).:(format)                
                                                      DELETE  /{project_id}/os-availability-zone/:(id)                          
            formatted_edit_os-availability-zone       GET     /{project_id}/os-availability-zone/:(id)/edit.:(format)           
            edit_os-availability-zone                 GET     /{project_id}/os-availability-zone/:(id)/edit                     
            formatted_os-availability-zone            GET     /{project_id}/os-availability-zone/:(id).:(format)                
            os-availability-zone                      GET     /{project_id}/os-availability-zone/:(id)                          
            ==================================================================================
            mapper =
            Route name                                Methods Path
            ......                                                  ......     ......
                                                      POST    /{project_id}/types/:type_id/extra_specs.:(format)                
                                                      POST    /{project_id}/types/:type_id/extra_specs                          
            formatted_type_extra_specs                GET     /{project_id}/types/:type_id/extra_specs.:(format)                
            type_extra_specs                          GET     /{project_id}/types/:type_id/extra_specs                          
            formatted_type_new_extra_specs            GET     /{project_id}/types/:type_id/extra_specs/new.:(format)            
            type_new_extra_specs                      GET     /{project_id}/types/:type_id/extra_specs/new                      
                                                      PUT     /{project_id}/types/:type_id/extra_specs/:(id).:(format)          
                                                      PUT     /{project_id}/types/:type_id/extra_specs/:(id)                    
                                                      DELETE  /{project_id}/types/:type_id/extra_specs/:(id).:(format)          
                                                      DELETE  /{project_id}/types/:type_id/extra_specs/:(id)                    
            formatted_type_edit_extra_specs           GET     /{project_id}/types/:type_id/extra_specs/:(id)/edit.:(format)     
            type_edit_extra_specs                     GET     /{project_id}/types/:type_id/extra_specs/:(id)/edit               
            formatted_type_extra_specs                GET     /{project_id}/types/:type_id/extra_specs/:(id).:(format)          
            type_extra_specs                          GET     /{project_id}/types/:type_id/extra_specs/:(id)                    
            ==================================================================================
            mapper =
            Route name                                Methods Path
            ......                                                  ......     ......
                                                      POST    /{project_id}/qos-specs.:(format)                                 
                                                      POST    /{project_id}/qos-specs                                           
            formatted_qos-specs                       GET     /{project_id}/qos-specs.:(format)                                 
            qos-specs                                 GET     /{project_id}/qos-specs                                           
            formatted_new_qos-specs                   GET     /{project_id}/qos-specs/new.:(format)                             
            new_qos-specs                             GET     /{project_id}/qos-specs/new                                       
            formatted_delete_keys_qos-specs           PUT     /{project_id}/qos-specs/:(id)/delete_keys.:(format)               
            delete_keys_qos-specs                     PUT     /{project_id}/qos-specs/:(id)/delete_keys                         
                                                      PUT     /{project_id}/qos-specs/:(id).:(format)                           
                                                      PUT     /{project_id}/qos-specs/:(id)                                     
                                                      DELETE  /{project_id}/qos-specs/:(id).:(format)                           
                                                      DELETE  /{project_id}/qos-specs/:(id)                                     
            formatted_associations_qos-specs          GET     /{project_id}/qos-specs/:(id)/associations.:(format)              
            associations_qos-specs                    GET     /{project_id}/qos-specs/:(id)/associations                        
            formatted_disassociate_all_qos-specs      GET     /{project_id}/qos-specs/:(id)/disassociate_all.:(format)          
            disassociate_all_qos-specs                GET     /{project_id}/qos-specs/:(id)/disassociate_all                    
            formatted_disassociate_qos-specs          GET     /{project_id}/qos-specs/:(id)/disassociate.:(format)              
            disassociate_qos-specs                    GET     /{project_id}/qos-specs/:(id)/disassociate                        
            formatted_associate_qos-specs             GET     /{project_id}/qos-specs/:(id)/associate.:(format)                 
            associate_qos-specs                       GET     /{project_id}/qos-specs/:(id)/associate                           
            formatted_edit_qos-specs                  GET     /{project_id}/qos-specs/:(id)/edit.:(format)                      
            edit_qos-specs                            GET     /{project_id}/qos-specs/:(id)/edit                                
            formatted_qos-specs                       GET     /{project_id}/qos-specs/:(id).:(format)                           
            qos-specs                                 GET     /{project_id}/qos-specs/:(id)                                     
            ==================================================================================
            mapper =
            Route name                                Methods Path
            ......                                                  ......     ......
                                                      POST    /{project_id}/os-quota-class-sets.:(format)                       
                                                      POST    /{project_id}/os-quota-class-sets                                 
            formatted_os-quota-class-sets             GET     /{project_id}/os-quota-class-sets.:(format)                       
            os-quota-class-sets                       GET     /{project_id}/os-quota-class-sets                                 
            formatted_new_os-quota-class-sets         GET     /{project_id}/os-quota-class-sets/new.:(format)                   
            new_os-quota-class-sets                   GET     /{project_id}/os-quota-class-sets/new                             
                                                      PUT     /{project_id}/os-quota-class-sets/:(id).:(format)                 
                                                      PUT     /{project_id}/os-quota-class-sets/:(id)                           
                                                      DELETE  /{project_id}/os-quota-class-sets/:(id).:(format)                 
                                                      DELETE  /{project_id}/os-quota-class-sets/:(id)                           
            formatted_edit_os-quota-class-sets        GET     /{project_id}/os-quota-class-sets/:(id)/edit.:(format)            
            edit_os-quota-class-sets                  GET     /{project_id}/os-quota-class-sets/:(id)/edit                      
            formatted_os-quota-class-sets             GET     /{project_id}/os-quota-class-sets/:(id).:(format)                 
            os-quota-class-sets                       GET     /{project_id}/os-quota-class-sets/:(id)
            ==================================================================================
            mapper =
            Route name                                Methods Path
            ......                                                  ......     ......
                                                      POST    /{project_id}/os-volume-transfer.:(format)                        
                                                      POST    /{project_id}/os-volume-transfer                                  
            formatted_detail_os-volume-transfer       GET     /{project_id}/os-volume-transfer/detail.:(format)                 
            detail_os-volume-transfer                 GET     /{project_id}/os-volume-transfer/detail                           
            formatted_os-volume-transfer              GET     /{project_id}/os-volume-transfer.:(format)                        
            os-volume-transfer                        GET     /{project_id}/os-volume-transfer                                  
            formatted_new_os-volume-transfer          GET     /{project_id}/os-volume-transfer/new.:(format)                    
            new_os-volume-transfer                    GET     /{project_id}/os-volume-transfer/new                              
                                                      PUT     /{project_id}/os-volume-transfer/:(id).:(format)                  
                                                      PUT     /{project_id}/os-volume-transfer/:(id)                            
            formatted_accept_os-volume-transfer       POST    /{project_id}/os-volume-transfer/:(id)/accept.:(format)           
            accept_os-volume-transfer                 POST    /{project_id}/os-volume-transfer/:(id)/accept                     
                                                      DELETE  /{project_id}/os-volume-transfer/:(id).:(format)                  
                                                      DELETE  /{project_id}/os-volume-transfer/:(id)                            
            formatted_edit_os-volume-transfer         GET     /{project_id}/os-volume-transfer/:(id)/edit.:(format)             
            edit_os-volume-transfer                   GET     /{project_id}/os-volume-transfer/:(id)/edit                       
            formatted_os-volume-transfer              GET     /{project_id}/os-volume-transfer/:(id).:(format)                  
            os-volume-transfer                        GET     /{project_id}/os-volume-transfer/:(id)                            
            =================================================================================         
            mapper =
            Route name                                Methods Path
            ......                                                  ......     ......
                                                      POST    /{project_id}/os-services.:(format)                               
                                                      POST    /{project_id}/os-services                                         
            formatted_os-services                     GET     /{project_id}/os-services.:(format)                               
            os-services                               GET     /{project_id}/os-services                                         
            formatted_new_os-services                 GET     /{project_id}/os-services/new.:(format)                           
            new_os-services                           GET     /{project_id}/os-services/new                                     
                                                      PUT     /{project_id}/os-services/:(id).:(format)                         
                                                      PUT     /{project_id}/os-services/:(id)                                   
                                                      DELETE  /{project_id}/os-services/:(id).:(format)                         
                                                      DELETE  /{project_id}/os-services/:(id)                                   
            formatted_edit_os-services                GET     /{project_id}/os-services/:(id)/edit.:(format)                    
            edit_os-services                          GET     /{project_id}/os-services/:(id)/edit                              
            formatted_os-services                     GET     /{project_id}/os-services/:(id).:(format)                         
            os-services                               GET     /{project_id}/os-services/:(id)                                   
            =================================================================================

至此方法def _setup_ext_routes(self, mapper, ext_mgr)的实现分析完成。

你可能感兴趣的:(源代码,openstack,cinder)