欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Nova API的实现——V2 API上添加新资源

程序员文章站 2022-05-11 17:25:35
...
为Nova添加新的API,或者对现有API进行扩展是件相对容易的事情,我们并不需要去过多关注一个HTTP请求是如何路由到新增的资源及其操作上,需要做的仅仅是遵循一些固定的规则与步骤。
首先看如何在v2 API中添加新的资源。
一 添加新资源与对应的Controller
对核心资源,需要在nova/api/openstack/compute目录下添加新文件,对于扩展资源则是nova/api/openstack/compute/contrib目录。
通常我们遇到的情况也仅仅是新增一个扩展资源,所以这里以现有的扩展资源keypairs为例进行说明。nova/api/openstack/compute/contrib/keypairs.py
定义该扩展资源对应的Controller,继承于所扩展核心资源的Controller,这里的keypairs是对核心资源的扩展
class Controller(servers.Controller):
                .......
     #Controller中的action,需要添加@wsgi.extends修饰
    @wsgi.extends
    def show(self, req, resp_obj, id):
        context = req.environ['nova.context']
        if soft_authorize(context):
            self._show(req, resp_obj)
    @wsgi.extends
    def detail(self, req, resp_obj):
        context = req.environ['nova.context']
        if 'servers' in resp_obj.obj and soft_authorize(context):
            resp_obj.attach(xml=ServersKeyNameTemplate())
            servers = resp_obj.obj['servers']
            self._add_key_name(req, servers)
#定义扩展资源对应的类,继承于ExtensionDescriptor,类名与文件名相同,只是首字母需大写
class Keypairs(extensions.ExtensionDescriptor):
    """Keypair Support."""
    #实现v2 API扩展资源必须定义4个变量name、alias、namespace、updated
    #alias必须保证唯一
    name = "Keypairs"
    alias = "os-keypairs"
    namespace = "http://docs.openstack.org/compute/ext/keypairs/api/v1.1";
    updated = "2011-08-08T00:00:00Z"
    #重载get_resources()创建新资源
    def get_resources(self):
        resources = []
        res = extensions.ResourceExtension(
                'os-keypairs',
                KeypairController())
        resources.append(res)
        return resources
     #对于扩展资源,需要重载get_controller_extensions(),并需要一个新的Controller,且该Controller继承于所扩展的核心资源的Controller
    def get_controller_extensions(self):
        controller = Controller(self.ext_mgr)
        extension = extensions.ControllerExtension(self, 'servers', controller)
        return [extension]
如果新的扩展资源除了扩展核心资源之外,还定义了新的独立资源,则需要定义自己专属的Controller,比如KeypairController,并实现一些基本的CRUD操作,比如index、show、create、delete等。

二 修改核心资源的代码
新增一个扩展资源后,通常需要修改核心资源的实现去处理扩展资源引入的参数。比如新增扩展资源keypairs之后,核心资源servers的create操作需要添加如下处理:
    # optional openstack extensions:
    key_name = None
    if self.ext_mgr.is_loaded('os-keypairs'):
        key_name = server_dict.get('key_name')
往往需要修改核心资源代码扩展资源才能够工作,这也是v2 API框架缺点之一。

三 当前V2 API存在的问题如下:
The development of the Nova v3 API will give us the opportunity to rework the extension framework. The current framework suffers from:
1 extension specific code required to exist in core code for specific extensions to work
eg nova/api/openstack/compute/servers.py:Controller:create where there are hard coded references to parameters specific to extensions to pass kwargs to the server create call
2 issues around efficiency with extensions each doing their own db lookup loops
3 Can’t have CamelCase class names for extension classes due to extension loading mechanism
第一个问题主要指当前的extension机制中,增加一个contrib后,往往需要在所谓的“core code”中添加必要的参数处理来将extension中引入的参数传入到内部的API中。需要注意的是这里的core code指的是nova.api.openstack.compute.*,即仅仅指的是API层次中核心资源相关的API Handlers,并非指的是各个Module内部的API/RPCAPI->Manager->Driver的代码层次结构中的代码。
第二个问题,在上文的bugs链接中已经描述的比较清楚,以servers为例,问题主要是指在GET等方法中,各个extension的处理逻辑中往往需要往返回的server信息中追加extension相关的信息,如disk_config扩展需要追加存储在DB中的disk config相关的信息等,故在各个extension中均会分别进行数据库查询操作,从而导致性能问题。
不过从目前HAVANA的代码来看,此问题已经通过一种方法缓解了,但从commit来看,和V3 API并不属于同一系列的提交。以servers为例,此问题现在的解决办法是,在core API处理时,就将可能需要从db中读取出来的servers相关的信息全部一次性读取出来并放入Cache中的Instance对象,在各个extension处理时只需要从Cache中取出所需的属性即可。在core API中一次性读出的信息除了instances表中一些extension添加的字段外,还会读出关联的instance_metadata、instance_system_metadata等多个表的信息。具体可参考nova.db.sqlalchemy.api:instance_get等相关的方法实现。
第三个问题是关于扩展资源的命名,v2 API中不能使用骆驼命名法,比如对于扩展资源Server Group,v2中命名为
Class Server_groups(extensions.ExtensionsDescriptor):
而v3中为
Class ServerGroups(extensions.V3APIExtensionBase):
相关标签: Nova