设为首页 收藏本站
查看: 808|回复: 0

[经验分享] OpenStack Cinder服务启动过程中的资源加载和扩展源码解析之三

[复制链接]

尚未签到

发表于 2015-10-11 07:41:26 | 显示全部楼层 |阅读模式
  感谢朋友支持本博客,欢迎共同探讨交流,由于能力和时间有限,错误之处在所难免,欢迎指正!

如果转载,请保留作者信息。

博客地址:http://blog.iyunv.com/gaoxingnengjisuan

邮箱地址:dong.liu@siat.ac.cn

  
  (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[collection]
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': <cinder.api.contrib.scheduler_hints.Scheduler_hints object at 0x1f39a50>,

        'os-hosts': <cinder.api.contrib.hosts.Hosts object at 0x1e04b90>,

        'os-vol-tenant-attr': <cinder.api.contrib.volume_tenant_attribute.Volume_tenant_attribute object at 0x2906ad0>,

        'os-quota-sets': <cinder.api.contrib.quotas.Quotas object at 0x1f28290>,

        'os-types-manage': <cinder.api.contrib.types_manage.Types_manage object at 0x2816c50>,

        'os-volume-encryption-metadata': <cinder.api.contrib.volume_encryption_metadata.Volume_encryption_metadata object at 0x1e04790>,

        'os-snapshot-actions': <cinder.api.contrib.snapshot_actions.Snapshot_actions object at 0x1e04550>,

        'backups': <cinder.api.contrib.backups.Backups object at 0x280d850>,

        'os-volume-actions': <cinder.api.contrib.volume_actions.Volume_actions object at 0x280d950>,

        'os-vol-host-attr': <cinder.api.contrib.volume_host_attribute.Volume_host_attribute object at 0x1f28090>,

        'encryption': <cinder.api.contrib.volume_type_encryption.Volume_type_encryption object at 0x1e04210>,

        'os-availability-zone': <cinder.api.contrib.availability_zones.Availability_zones object at 0x280d2d0>,

        'os-types-extra-specs': <cinder.api.contrib.types_extra_specs.Types_extra_specs object at 0x1f39210>,

        'os-vol-mig-status-attr': <cinder.api.contrib.volume_mig_status_attribute.Volume_mig_status_attribute object at 0x1f39750>,

        'os-image-create': <cinder.api.contrib.image_create.Image_create object at 0x1e04610>,

        'os-extended-snapshot-attributes': <cinder.api.contrib.extended_snapshot_attributes.Extended_snapshot_attributes object at 0x28210d0>,

        'qos-specs': <cinder.api.contrib.qos_specs_manage.Qos_specs_manage object at 0x29064d0>,

        'os-quota-class-sets': <cinder.api.contrib.quota_classes.Quota_classes object at 0x1e04a90>,

        'os-volume-transfer': <cinder.api.contrib.volume_transfer.Volume_transfer object at 0x2821d10>,

        'os-vol-image-meta': <cinder.api.contrib.volume_image_metadata.Volume_image_metadata object at 0x2906ed0>,

        'os-admin-actions': <cinder.api.contrib.admin_actions.Admin_actions object at 0x2821950>,

        'os-services': <cinder.api.contrib.services.Services object at 0x1f39cd0>}

  根据上一篇博客中的相关内容,我们可以验证,这里分为两部分:
  第一部分的类中直接实现了方法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):

    &quot;&quot;&quot;Pass arbitrary key/value pairs to the scheduler.&quot;&quot;&quot;



    name = &quot;SchedulerHints&quot;

    alias = &quot;OS-SCH-HNT&quot;

    namespace = volumes.SCHEDULER_HINTS_NAMESPACE

    updated = &quot;2013-04-18T00:00:00&#43;00:00&quot;



    def get_controller_extensions(self):

        controller = SchedulerHintsController()

        ext = extensions.ControllerExtension(self, 'volumes', controller)

        return [ext]



class SchedulerHintsController(wsgi.Controller):



class Controller(object):

    &quot;&quot;&quot;Default controller.&quot;&quot;&quot;



    __metaclass__ = ControllerMetaclass



    _view_builder_class = None



    def __init__(self, view_builder=None):

        &quot;&quot;&quot;Initialize controller with a view builder instance.&quot;&quot;&quot;

        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):

    &quot;&quot;&quot;Expose the internal project_id as an attribute of a volume.&quot;&quot;&quot;



    name = &quot;VolumeTenantAttribute&quot;

    alias = &quot;os-vol-tenant-attr&quot;

    namespace = (&quot;http://docs.openstack.org/volume/ext/&quot;

                 &quot;volume_tenant_attribute/api/v1&quot;)

    updated = &quot;2011-11-03T00:00:00&#43;00:00&quot;



    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):

    &quot;&quot;&quot;Default controller.&quot;&quot;&quot;



    __metaclass__ = ControllerMetaclass



    _view_builder_class = None



    def __init__(self, view_builder=None):

        &quot;&quot;&quot;Initialize controller with a view builder instance.&quot;&quot;&quot;

        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):

    &quot;&quot;&quot;Types manage support.&quot;&quot;&quot;



    name = &quot;TypesManage&quot;

    alias = &quot;os-types-manage&quot;

    namespace = &quot;http://docs.openstack.org/volume/ext/types-manage/api/v1&quot;

    updated = &quot;2011-08-24T00:00:00&#43;00:00&quot;



    def get_controller_extensions(self):

        controller = VolumeTypesManageController()

        extension = extensions.ControllerExtension(self, 'types', controller)

        return [extension]



class VolumeTypesManageController(wsgi.Controller):

    &quot;&quot;&quot;

    The volume types API controller for the OpenStack API.

    &quot;&quot;&quot;

    _view_builder_class = views_types.ViewBuilder



class Controller(object):

    &quot;&quot;&quot;Default controller.&quot;&quot;&quot;



    __metaclass__ = ControllerMetaclass



    _view_builder_class = None



    def __init__(self, view_builder=None):

        &quot;&quot;&quot;Initialize controller with a view builder instance.&quot;&quot;&quot;

        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):

    &quot;&quot;&quot;Enable snapshot manager actions.&quot;&quot;&quot;



    name = &quot;SnapshotActions&quot;

    alias = &quot;os-snapshot-actions&quot;

    namespace = \

        &quot;http://docs.openstack.org/volume/ext/snapshot-actions/api/v1.1&quot;

    updated = &quot;2013-07-16T00:00:00&#43;00:00&quot;



    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(&quot;SnapshotActionsController initialized&quot;)



class Controller(object):

    &quot;&quot;&quot;Default controller.&quot;&quot;&quot;



    __metaclass__ = ControllerMetaclass



    _view_builder_class = None



    def __init__(self, view_builder=None):

        &quot;&quot;&quot;Initialize controller with a view builder instance.&quot;&quot;&quot;

        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):

        &quot;&quot;&quot;

        List of extensions.ControllerExtension extension objects.

        Controller extensions are used to extend existing controllers.

        &quot;&quot;&quot;

        controller_exts = []

        return controller_exts

  可见没有做什么具体的工作;

我们再来看看在上述第一部分的类所对应的控制器类中,是如何实现即定义新的Restful资源功能又对已有的Restful资源功能实现扩展的。

我们可以看到在这些控制器类中的方法中,有两类装饰器,即@action和@extension,其中定义新的Restful资源功能就是应用装饰器@action实现的,而扩展已有的Restful资源功能就是应用装饰器@extension实现的。我们来看它们是如何实现的。首先来看这两个装饰器:

  

def action(name):
&quot;&quot;&quot;
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.
&quot;&quot;&quot;
def decorator(func):
func.wsgi_action = name
return func
return decoratordef extends(*args, **kwargs):
&quot;&quot;&quot;
    Indicate a function extends an operation.
Can be used as either::
@extends
def index(...):
pass
or as::
@extends(action='resize')
def _action_resize(...):
pass
&quot;&quot;&quot;
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):

    &quot;&quot;&quot;Types manage support.&quot;&quot;&quot;



    name = &quot;TypesManage&quot;

    alias = &quot;os-types-manage&quot;

    namespace = &quot;http://docs.openstack.org/volume/ext/types-manage/api/v1&quot;

    updated = &quot;2011-08-24T00:00:00&#43;00:00&quot;



    def get_controller_extensions(self):

        controller = VolumeTypesManageController()

        extension = extensions.ControllerExtension(self, 'types', controller)

        return [extension]



class VolumeTypesManageController(wsgi.Controller):

    &quot;&quot;&quot;

    The volume types API controller for the OpenStack API.

    &quot;&quot;&quot;

    _view_builder_class = views_types.ViewBuilder



class Controller(object):

    &quot;&quot;&quot;Default controller.&quot;&quot;&quot;



    __metaclass__ = ControllerMetaclass



    _view_builder_class = None



    def __init__(self, view_builder=None):

        &quot;&quot;&quot;Initialize controller with a view builder instance.&quot;&quot;&quot;

        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):
&quot;&quot;&quot;
    Controller metaclass.
This metaclass automates the task of assembling a dictionary
mapping action keys to method names.
&quot;&quot;&quot;
def __new__(self, mcs, name, bases, cls_dict):
&quot;&quot;&quot;Adds the wsgi_actions dictionary to the class.&quot;&quot;&quot;
# 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[value.wsgi_action] = 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_actionwsgi_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)


  

class Router(object):
&quot;&quot;&quot;WSGI middleware that maps incoming requests to WSGI apps.&quot;&quot;&quot;
def __init__(self, mapper):
self.map = mapper
self._router = routes.middleware.RoutesMiddleware(self._dispatch, self.map)至此,OpenStack Cinder服务启动过程中的资源加载和扩展的源码简单解析完成了。  这几篇博客是我边看源码边写的,肯定会有不严谨和理解偏差的地方,欢迎大家批评指正。



版权声明:本文为博主原创文章,未经博主允许不得转载。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-125235-1-1.html 上篇帖子: openstack创建instance的流程 下篇帖子: openstack juno 完全按照官方文档安装
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表