OpenStack Cinder服务启动过程中的资源加载和扩展源码解析之三
问题导读1、如何实现新的Restful资源功能又对已有的Restful资源功能实现扩展?
2、语句controller_exts.extend(get_ext_method())的实现过程是什么?
http://www.aboutyun.com/static/image/hrline/4.gif
(4)self._setup_extensions(ext_mgr)
在前面的博客中,我们说过在/cinder/api/contrib/目录下的文件都是用来实现功能扩展的,这里主要分为两部分:1.在一个控制器中单纯地实现新的Restful资源功能;2.即可实现新的Restful资源功能又可对已有的Restful资源功能实现扩展。(这里总觉得有点理解的不正确,后续会修正或者改正这部分的内容。)
在这里我们将主要分析/cinder/api/contrib/目录下如何即实现新的Restful资源功能又对已有的Restful资源功能实现扩展。
现在我们回到类/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_extensions(ext_mgr),具体来看方法_setup_extensions的源码实现:
def _setup_extensions(self, ext_mgr):
for extension in ext_mgr.get_controller_extensions():
collection = extension.collection
controller = extension.controller
if collection not in self.resources:
LOG.warning(_('Extension %(ext_name)s: Cannot extend '
'resource %(collection)s: No such resource'),
{'ext_name': extension.extension.name,
'collection': collection})
continue
LOG.debug(_('Extension %(ext_name)s extending resource: '
'%(collection)s'),
{'ext_name': extension.extension.name,
'collection': collection})
resource = self.resources
resource.register_actions(controller)
resource.register_extensions(controller)
来看方法中的语句:for extension in ext_mgr.get_controller_extensions(),进一步来看方法get_controller_extensions的源码实现:
def get_controller_extensions(self):
"""
Returns a list of ControllerExtension objects.
获取ControllerExtension对象的列表;
"""
controller_exts = []
for ext in self.extensions.values():
try:
get_ext_method = ext.get_controller_extensions
except AttributeError:
continue
controller_exts.extend(get_ext_method())
return controller_exts
来看语句:
for ext in self.extensions.values():
get_ext_method = ext.get_controller_extensions
示例输出:
self.extensions = {
'OS-SCH-HNT': ,
'os-hosts': ,
'os-vol-tenant-attr': ,
'os-quota-sets': ,
'os-types-manage': ,
'os-volume-encryption-metadata': ,
'os-snapshot-actions': ,
'backups': ,
'os-volume-actions': ,
'os-vol-host-attr': ,
'encryption': ,
'os-availability-zone': ,
'os-types-extra-specs': ,
'os-vol-mig-status-attr': ,
'os-image-create': ,
'os-extended-snapshot-attributes': ,
'qos-specs': ,
'os-quota-class-sets': ,
'os-volume-transfer': ,
'os-vol-image-meta': ,
'os-admin-actions': ,
'os-services': }
根据上一篇博客中的相关内容,我们可以验证,这里分为两部分:
第一部分的类中直接实现了方法get_controller_extensions:
ext = <cinder.api.contrib.scheduler_hints.Scheduler_hints object at 0x1f39a50>
ext = <cinder.api.contrib.volume_tenant_attribute.Volume_tenant_attribute object at 0x2906ad0>
ext = <cinder.api.contrib.types_manage.Types_manage object at 0x2816c50>
ext = <cinder.api.contrib.snapshot_actions.Snapshot_actions object at 0x1e04550>
ext = <cinder.api.contrib.volume_actions.Volume_actions object at 0x280d950>
ext = <cinder.api.contrib.volume_host_attribute.Volume_host_attribute object at 0x1f28090>
ext = <cinder.api.contrib.volume_type_encryption.Volume_type_encryption object at 0x1e04210>
ext = <cinder.api.contrib.volume_mig_status_attribute.Volume_mig_status_attribute object at 0x1f39750>
ext = <cinder.api.contrib.extended_snapshot_attributes.Extended_snapshot_attributes object at 0x28210d0>
ext = <cinder.api.contrib.volume_image_metadata.Volume_image_metadata object at 0x2906ed0>
ext = <cinder.api.contrib.admin_actions.Admin_actions object at 0x2821950>
第二部分的类中没有继承父类的get_controller_extensions方法,这里调用的是其父类中的get_controller_extensions方法:
ext = <cinder.api.contrib.hosts.Hosts object at 0x1e04b90>
ext = <cinder.api.contrib.quotas.Quotas object at 0x1f28290>
ext = <cinder.api.contrib.volume_encryption_metadata.Volume_encryption_metadata object at 0x1e04790>
ext = <cinder.api.contrib.backups.Backups object at 0x280d850>
ext = <cinder.api.contrib.availability_zones.Availability_zones object at 0x280d2d0>
ext = <cinder.api.contrib.types_extra_specs.Types_extra_specs object at 0x1f39210>
ext = <cinder.api.contrib.image_create.Image_create object at 0x1e04610>
ext = <cinder.api.contrib.qos_specs_manage.Qos_specs_manage object at 0x29064d0>
ext = <cinder.api.contrib.quota_classes.Quota_classes object at 0x1e04a90>
ext = <cinder.api.contrib.volume_transfer.Volume_transfer object at 0x2821d10>
ext = <cinder.api.contrib.services.Services object at 0x1f39cd0>
来看语句controller_exts.extend(get_ext_method())的实现(看几个例子,看一下实现过程);
第一部分的类中直接实现了方法get_controller_extensions:
=============================================================
ext = <cinder.api.contrib.scheduler_hints.Scheduler_hints object at 0x1f39a50>
class Scheduler_hints(extensions.ExtensionDescriptor):
"""Pass arbitrary key/value pairs to the scheduler."""
name = "SchedulerHints"
alias = "OS-SCH-HNT"
namespace = volumes.SCHEDULER_HINTS_NAMESPACE
updated = "2013-04-18T00:00:00+00:00"
def get_controller_extensions(self):
controller = SchedulerHintsController()
ext = extensions.ControllerExtension(self, 'volumes', controller)
return
class SchedulerHintsController(wsgi.Controller):
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.volume_tenant_attribute.Volume_tenant_attribute object at 0x2906ad0>
class Volume_tenant_attribute(extensions.ExtensionDescriptor):
"""Expose the internal project_id as an attribute of a volume."""
name = "VolumeTenantAttribute"
alias = "os-vol-tenant-attr"
namespace = ("http://docs.openstack.org/volume/ext/"
"volume_tenant_attribute/api/v1")
updated = "2011-11-03T00:00:00+00:00"
def get_controller_extensions(self):
controller = VolumeTenantAttributeController()
extension = extensions.ControllerExtension(self, 'volumes', controller)
return
class VolumeTenantAttributeController(wsgi.Controller):
def __init__(self, *args, **kwargs):
super(VolumeTenantAttributeController, self).__init__(*args, **kwargs)
self.volume_api = volume.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
=============================================================
ext = <cinder.api.contrib.types_manage.Types_manage object at 0x2816c50>
class Types_manage(extensions.ExtensionDescriptor):
"""Types manage support."""
name = "TypesManage"
alias = "os-types-manage"
namespace = "http://docs.openstack.org/volume/ext/types-manage/api/v1"
updated = "2011-08-24T00:00:00+00:00"
def get_controller_extensions(self):
controller = VolumeTypesManageController()
extension = extensions.ControllerExtension(self, 'types', controller)
return
class VolumeTypesManageController(wsgi.Controller):
"""
The volume types API controller for the OpenStack API.
"""
_view_builder_class = views_types.ViewBuilder
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.snapshot_actions.Snapshot_actions object at 0x1e04550>
class Snapshot_actions(extensions.ExtensionDescriptor):
"""Enable snapshot manager actions."""
name = "SnapshotActions"
alias = "os-snapshot-actions"
namespace = \
"http://docs.openstack.org/volume/ext/snapshot-actions/api/v1.1"
updated = "2013-07-16T00:00:00+00:00"
def get_controller_extensions(self):
controller = SnapshotActionsController()
extension = extensions.ControllerExtension(self,
'snapshots',
controller)
return
class SnapshotActionsController(wsgi.Controller):
def __init__(self, *args, **kwargs):
super(SnapshotActionsController, self).__init__(*args, **kwargs)
LOG.debug("SnapshotActionsController initialized")
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_controller_extensions方法,这里调用的是其父类中的get_controller_extensions方法:
class ExtensionDescriptor(object):
def get_controller_extensions(self):
"""
List of extensions.ControllerExtension extension objects.
Controller extensions are used to extend existing controllers.
"""
controller_exts = []
return controller_exts
可见没有做什么具体的工作;
我们再来看看在上述第一部分的类所对应的控制器类中,是如何实现即定义新的Restful资源功能又对已有的Restful资源功能实现扩展的。
我们可以看到在这些控制器类中的方法中,有两类装饰器,即@action和@extension,其中定义新的Restful资源功能就是应用装饰器@action实现的,而扩展已有的Restful资源功能就是应用装饰器@extension实现的。我们来看它们是如何实现的。首先来看这两个装饰器:
def action(name):
"""
Mark a function as an action.
The given name will be taken as the action key in the body.
This is also overloaded to allow extensions to provide
non-extending definitions of create and delete operations.
"""
def decorator(func):
func.wsgi_action = name
return func
return decoratordef extends(*args, **kwargs):
"""
Indicate a function extends an operation.
Can be used as either::
@extends
def index(...):
pass
or as::
@extends(action='resize')
def _action_resize(...):
pass
"""
def decorator(func):
# Store enough information to find what we're extending
func.wsgi_extends = (func.__name__, kwargs.get('action'))
return func
# If we have positional arguments, call the decorator
if args:
return decorator(*args)
# OK, return the decorator instead
return decorator
我们关注这里两条语句,即:
func.wsgi_action = name
func.wsgi_extends = (func.__name__, kwargs.get('action'))
我们再回来看上面的输出示例,如:
=============================================================
ext = <cinder.api.contrib.types_manage.Types_manage object at 0x2816c50>
class Types_manage(extensions.ExtensionDescriptor):
"""Types manage support."""
name = "TypesManage"
alias = "os-types-manage"
namespace = "http://docs.openstack.org/volume/ext/types-manage/api/v1"
updated = "2011-08-24T00:00:00+00:00"
def get_controller_extensions(self):
controller = VolumeTypesManageController()
extension = extensions.ControllerExtension(self, 'types', controller)
return
class VolumeTypesManageController(wsgi.Controller):
"""
The volume types API controller for the OpenStack API.
"""
_view_builder_class = views_types.ViewBuilder
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
=============================================================
我们可以看到这些控制器类的父类class Controller(object)中,都会获取类ControllerMetaclass的实例化对象,我们进一步来看看方法class
ControllerMetaclass(type)----def __new__的源码实现(对于__init__和__new__方法的区别,可以查询相关资料):
class ControllerMetaclass(type):
"""
Controller metaclass.
This metaclass automates the task of assembling a dictionary
mapping action keys to method names.
"""
def __new__(self, mcs, name, bases, cls_dict):
"""Adds the wsgi_actions dictionary to the class."""
# Find all actions
actions = {}
extensions = []
# start with wsgi actions from base classes
for base in bases:
actions.update(getattr(base, 'wsgi_actions', {}))
for key, value in cls_dict.items():
if not callable(value):
continue
if getattr(value, 'wsgi_action', None):
actions = key
elif getattr(value, 'wsgi_extends', None):
extensions.append(value.wsgi_extends)
# Add the actions and extensions to the class dict
cls_dict['wsgi_actions'] = actions
cls_dict['wsgi_extensions'] = extensions
return super(ControllerMetaclass, mcs).__new__(mcs, name, bases, cls_dict)
在这个方法中,将wsgi_action和wsgi_extends收集起来,保存在相应的字典中,来看输出示例:
cls_dict = {'__module__': 'cinder.api.contrib.admin_actions', '_update': <function _update at 0x35ea5f0>, '_delete': <function _delete at 0x35ea848>, 'wsgi_actions': {'os-reset_status': '_reset_status', 'os-force_delete': '_force_delete'}, 'collection': 'snapshots', '_get': <function _get at 0x35ea7d0>, 'wsgi_extensions': [], '__doc__': 'AdminController for Snapshots.'}cls_dict = {'__module__': 'cinder.api.contrib.admin_actions', '_update': <function _update at 0x35ea320>, 'validate_update': <function validate_update at 0x35ea578>, '_delete': <function _delete at 0x35ea500>, '_migrate_volume': <function _migrate_volume at 0x35ea6e0>, '_force_detach': <function _force_detach at 0x35ea668>, 'wsgi_actions': {'os-migrate_volume_completion': '_migrate_volume_completion', 'os-reset_status': '_reset_status', 'os-force_delete': '_force_delete', 'os-migrate_volume': '_migrate_volume', 'os-force_detach': '_force_detach'}, 'collection': 'volumes', '_get': <function _get at 0x35ea488>, 'valid_status': set(['available', 'creating', 'in-use', 'error_deleting', 'attaching','detaching','error','deleting']), 'wsgi_extensions': [], '__doc__': 'AdminController for Volumes.', '_migrate_volume_completion': <function _migrate_volume_completion at 0x35ea758>}cls_dict = {'__module__': 'cinder.api.contrib.extended_snapshot_attributes', 'show': <function show at 0x3526320>, '_get_snapshots': <function _get_snapshots at 0x3526230>, 'detail': <function detail at 0x3526398>, '_extend_snapshot': <function _extend_snapshot at 0x35262a8>, 'wsgi_extensions': [('show', None), ('detail', None)], '__init__': <function __init__ at 0x35261b8>, 'wsgi_actions': {}}我们关注其中的wsgi_actions和wsgi_extensions,在后续应用中应该会对其进行解析,这样http请求就可以把名称和具体实现方法一一对应起来。
(5)super(APIRouter, self).__init__(mapper)
class Router(object):
"""WSGI middleware that maps incoming requests to WSGI apps."""
def __init__(self, mapper):
self.map = mapper
self._router = routes.middleware.RoutesMiddleware(self._dispatch, self.map)
至此,OpenStack Cinder服务启动过程中的资源加载和扩展的源码简单解析完成了。
相关文章
OpenStack Cinder服务启动过程中的资源加载和扩展源码解析之一
http://www.aboutyun.com/thread-10222-1-1.html
OpenStack Cinder服务启动过程中的资源加载和扩展源码解析之二
http://www.aboutyun.com/thread-10223-1-1.html
原文链接:http://blog.csdn.net/gaoxingnengjisuan/article/details/21829361
{:soso_e181:}
页:
[1]