分享

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

shihailong123 发表于 2014-11-22 15:18:39 [显示全部楼层] 回帖奖励 阅读模式 关闭右栏 1 12437
问题导读

1、如何实现新的Restful资源功能又对已有的Restful资源功能实现扩展?
2、语句controller_exts.extend(get_ext_method())的实现过程是什么?



(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中的初始化方法:
  
  1. class APIRouter(base_wsgi.Router):  
  2.         def __init__(self, ext_mgr=None):  
  3.             if ext_mgr is None:  
  4.                 if self.ExtensionManager:  
  5.                     ext_mgr = self.ExtensionManager() (1)  
  6.                 else:  
  7.                     raise Exception(_("Must specify an ExtensionManager class"))  
  8.               
  9.             mapper = ProjectMapper()         
  10.             self.resources = {}  
  11.             self._setup_routes(mapper, ext_mgr) (2)  
  12.             self._setup_ext_routes(mapper, ext_mgr) (3)  
  13.             self._setup_extensions(ext_mgr) (4)  
  14.             super(APIRouter, self).__init__(mapper) (5)
复制代码

来看第四条比较重要的语句self._setup_extensions(ext_mgr),具体来看方法_setup_extensions的源码实现:

  1. def _setup_extensions(self, ext_mgr):           
  2.         for extension in ext_mgr.get_controller_extensions():  
  3.             collection = extension.collection
  4.             controller = extension.controller
  5.             if collection not in self.resources:
  6.                 LOG.warning(_('Extension %(ext_name)s: Cannot extend '
  7.                               'resource %(collection)s: No such resource'),
  8.                             {'ext_name': extension.extension.name,
  9.                              'collection': collection})
  10.                 continue
  11.             LOG.debug(_('Extension %(ext_name)s extending resource: '
  12.                         '%(collection)s'),
  13.                       {'ext_name': extension.extension.name,
  14.                        'collection': collection})
  15.             resource = self.resources[collection]
  16.             resource.register_actions(controller)
  17.             resource.register_extensions(controller)
复制代码

来看方法中的语句:for extension in ext_mgr.get_controller_extensions(),进一步来看方法get_controller_extensions的源码实现:

  1. def get_controller_extensions(self):
  2.         """
  3.         Returns a list of ControllerExtension objects.
  4.         获取ControllerExtension对象的列表;
  5.         """
  6.         controller_exts = []
  7.         for ext in self.extensions.values():
  8.             
  9.             try:
  10.                 get_ext_method = ext.get_controller_extensions
  11.             except AttributeError:
  12.                 continue
  13.             controller_exts.extend(get_ext_method())
  14.             
  15.         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 [ext]
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 [extension]
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 [extension]
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 [extension]
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实现的。我们来看它们是如何实现的。首先来看这两个装饰器:

  1. def action(name):
  2.     """
  3.     Mark a function as an action.
  4.     The given name will be taken as the action key in the body.
  5.     This is also overloaded to allow extensions to provide
  6.     non-extending definitions of create and delete operations.
  7.     """
  8.     def decorator(func):
  9.         func.wsgi_action = name
  10.         return func
  11.     return decorator
复制代码
  1. def extends(*args, **kwargs):
  2.     """
  3.     Indicate a function extends an operation.
  4.     Can be used as either::
  5.         @extends
  6.         def index(...):
  7.             pass
  8.     or as::
  9.         @extends(action='resize')
  10.         def _action_resize(...):
  11.             pass
  12.     """
  13.     def decorator(func):
  14.         # Store enough information to find what we're extending
  15.         func.wsgi_extends = (func.__name__, kwargs.get('action'))
  16.         return func
  17.     # If we have positional arguments, call the decorator
  18.     if args:
  19.         return decorator(*args)
  20.     # OK, return the decorator instead
  21.     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 [extension]
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__方法的区别,可以查询相关资料):

  1. class ControllerMetaclass(type):
  2.     """
  3.     Controller metaclass.
  4.     This metaclass automates the task of assembling a dictionary
  5.     mapping action keys to method names.
  6.     """
  7.     def __new__(self, mcs, name, bases, cls_dict):
  8.         """Adds the wsgi_actions dictionary to the class."""
  9.         # Find all actions
  10.         actions = {}
  11.         extensions = []
  12.         # start with wsgi actions from base classes
  13.         for base in bases:
  14.             actions.update(getattr(base, 'wsgi_actions', {}))
  15.             
  16.         for key, value in cls_dict.items():
  17.             if not callable(value):
  18.                 continue
  19.             
  20.             if getattr(value, 'wsgi_action', None):
  21.                 actions[value.wsgi_action] = key
  22.             
  23.             elif getattr(value, 'wsgi_extends', None):
  24.                 extensions.append(value.wsgi_extends)
  25.         # Add the actions and extensions to the class dict
  26.         cls_dict['wsgi_actions'] = actions
  27.         cls_dict['wsgi_extensions'] = extensions
  28.         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_actionswsgi_extensions,在后续应用中应该会对其进行解析,这样http请求就可以把名称和具体实现方法一一对应起来。
(5)super(APIRouter, self).__init__(mapper)
  1. class Router(object):
  2.     """WSGI middleware that maps incoming requests to WSGI apps."""
  3.     def __init__(self, mapper):
  4.         self.map = mapper
  5.         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





已有(1)人评论

跳转到指定楼层
wubaozhou 发表于 2014-12-28 17:25:47
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关闭

推荐上一条 /2 下一条