分享

怎样写 OpenStack Neutron 的 Extension (一)

坎蒂丝_Swan 发表于 2014-12-7 18:06:50 [显示全部楼层] 回帖奖励 阅读模式 关闭右栏 2 15812
本帖最后由 坎蒂丝_Swan 于 2014-12-7 18:06 编辑


问题导读


问题1:定义新类的时候需要注意哪些事项?
问题2:如何配置 /etc/neutron/neutron.conf 文件?







Neutron 已经预定义了很多扩展,可以参看 neutron/extensions 下面的文件,我在这里就不一一列举了。如果正好有一种是你需要的,那直接拿过来用就好了。如果需要自己从头搭起的话,可以现在 自己的 plugin 文件夹下面创建一个 extensions 文件夹,然后在这个文件夹下面创建两个文件: __init__.py 和 myextension.py:
- neutron/
  - plugins/
    - myplugin/
      - __init__.py
      - plugin.py
      - extensions/
        - __init__.py
        - myextension.py

__init__.py 是空的就行了。在 myextension.py 中需要定义两个东西:一个叫RESOURCE_ATTRIBUTE_MAP 的词典和一个叫 Myextension 的类。RESOURCE_ATTRIBUTE_MAP里面放的就是你的这个新扩展的属性,例如:

  1. RESOURCE_ATTRIBUTE_MAP = {
  2.     'myextensions': {
  3.         'id': {'allow_post': False, 'allow_put': False,
  4.                'is_visible': True},
  5.         'name': {'allow_post': True, 'allow_put': True,
  6.                           'is_visible': True},
  7.         'tenant_id': {'allow_post': True, 'allow_put': False,
  8.                       'validate': {'type:string': None},
  9.                       'required_by_policy': True,
  10.                       'is_visible': True}
  11.         }
  12.     }
复制代码

需要注意的是在词典中,第一层的 key ‘myextensions’ 就是文件名 ’myextension‘ 加上一个 ‘s'。第二层的 keys ’id‘, ’name‘, ’tenant_id‘ 就是这个扩展的三个属性。第三层的 keys 在 neutron/api/v2/attributes.py 中有比较详细的解释,我把它搬到这里来了:
  1. # The following is a short reference for understanding attribute info:
  2. # default: default value of the attribute (if missing, the attribute
  3. # becomes mandatory.
  4. # allow_post: the attribute can be used on POST requests.
  5. # allow_put: the attribute can be used on PUT requests.
  6. # validate: specifies rules for validating data in the attribute.
  7. # convert_to: transformation to apply to the value before it is returned
  8. # is_visible: the attribute is returned in GET responses.
  9. # required_by_policy: the attribute is required by the policy engine and
  10. # should therefore be filled by the API layer even if not present in
  11. # request body.
  12. # enforce_policy: the attribute is actively part of the policy enforcing
  13. # mechanism, ie: there might be rules which refer to this attribute.
复制代码

定义新类的时候需要注意一点,这个类的名字与包含这个类的文件名的唯一区别必须是一个首字母大写,另一个首字母小写。也就是说把MyExtension当做类的名字可能就会导致出错。具体原因可以参考 neutron/api/extensions.py 中 ExtensionManager 的_load_all_extensions_from_path 方法的实现。Myextension 这个类可以继承 neutron/api/extensions.py 这个文件中的一个类:ExtensionDescriptor,也可以自己定义。下面给出一个继承了该类的定义:
  1. from neutron.api import extensions
  2. from neutron import manager
  3. from neutron.api.v2 import base
  4. class Myextension(extensions.ExtensionDescriptor):
  5.     # The name of this class should be the same as the file name
  6.     # The first letter must be changed from lower case to upper case
  7.     # There are a couple of methods and their properties defined in the
  8.     # parent class of this class, ExtensionDescriptor you can check them
  9.     @classmethod
  10.     def get_name(cls):
  11.         # You can coin a name for this extension
  12.         return "My Extension"
  13.    
  14.     @classmethod
  15.     def get_alias(cls):
  16.         # This alias will be used by your core_plugin class to load
  17.         # the extension
  18.         return "my-extensions"
  19.     @classmethod
  20.     def get_description(cls):
  21.         # A small description about this extension
  22.         return "An extension defined by myself. Haha!"
  23.     @classmethod
  24.     def get_namespace(cls):
  25.         # The XML namespace for this extension
  26.         return "http://docs.openstack.org/ext/myextension/api/v1.0"
  27.     @classmethod
  28.     def get_updated(cls):
  29.         # Specify when was this extension last updated,
  30.         # good for management when there are changes in the design
  31.         return "2014-08-07T00:00:00-00:00"
  32.     @classmethod
  33.     def get_resources(cls):
  34.         # This method registers the URL and the dictionary  of
  35.         # attributes on the neutron-server.
  36.         exts = []
  37.         plugin = manager.NeutronManager.get_plugin()
  38.         resource_name = 'myextension'
  39.         collection_name = '%ss' % resource_name
  40.         params = RESOURCE_ATTRIBUTE_MAP.get(collection_name, dict())
  41.         controller = base.create_resource(collection_name, resource_name,
  42.                                           plugin, params, allow_bulk=False)
  43.         ex = extensions.ResourceExtension(collection_name, controller)
  44.         exts.append(ex)
  45.         return exts
复制代码

到这一步为止,这个 myextension.py 文件基本就算是大功告成了,接下来需要去配置 /etc/neutron/neutron.conf 文件,告诉 Neutron 去哪里找到这个扩展。那么在该文件的[DEFAULT]下面,我们可以找到一个选项叫做api_extensions_path,并且把刚刚创建的 extensions 文件夹的位置赋给它,例如:
api_extensions_path = /usr/lib/python2.7/dist-packages/neutron/plugins/myplugin/extensions

然后在自己的 MyPlugin 类的定义中还要加一句话,告诉 Neutron 我的插件支持这个扩展。需要注意的是这里的方括号中的名字应该与上面 get_alias() 方法获得的名字一致。

  1. class MyPlugin(db_base_plugin_v2.NeutronDbPluginV2):
  2.   ...
  3.   supported_extension_aliases = ['my-extensions']
  4.   
  5.   def __init__(self):
  6.     ...
  7.   ...
复制代码

最后重启一下 neutron server, “service neutron-server restart”, 如果看到 /var/log/neutron/server.log 里面有 Loaded extension: my-extensions 的字样就说明成功了。
在接下来的一些文章中,我会继续讨论一下如何实现一个扩展的不同操作,如何在 CLI 中加入对自定义扩展的命令支持等内容。





欢迎加入about云群90371779322273151432264021 ,云计算爱好者群,亦可关注about云腾讯认证空间||关注本站微信

已有(2)人评论

跳转到指定楼层
dulei 发表于 2014-12-8 08:52:07
回复

使用道具 举报

kevin4th 发表于 2016-9-9 16:39:17
提示ExtensionsNotFound: Extensions not found: ['my-extensions']
neutron.plugins.constants.EXT_TO_SERVICE_MAPPING 中是否需要增加my-extensions 类型,
回复

使用道具 举报

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

本版积分规则

关闭

推荐上一条 /2 下一条