感谢朋友支持本博客,欢迎共同探讨交流,由于能力和时间有限,错误之处在所难免,欢迎指正!
如果转载,请保留作者信息。
博客地址:http://blog.csdn.net/gaoxingnengjisuan
邮箱地址:dong.liu@siat.ac.cn
(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)的实现分析完成。