shihailong123 发表于 2014-11-22 15:18:39

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





wubaozhou 发表于 2014-12-28 17:25:47

{:soso_e181:}
页: [1]
查看完整版本: OpenStack Cinder服务启动过程中的资源加载和扩展源码解析之三