openstack如何扩展API之一:新添加API

时间:2022-05-07
本文章向大家介绍openstack如何扩展API之一:新添加API,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

(本文以nova-api为例子,完整的描述了如何添加一个新的nova-api过程,并写一个测试程序进行测试)

一。创建API资源模块

为新的Restful资源写一个controller实现标准操作(如index、create、delete…),并且可以根据需要定制其他的动作。定义extensions.V21APIExtensionBase 的一个子类,此子类实现get_resources和get_controller_extensions方法,建立一个新的资源或控制器扩展。添加一个文件:

nova/api/openstack/compute/extended_comcat api/openstack/compute/extended_common.py

"""The instance interface extension."""

import webob

from webob import exc

from nova.api.openstack import common

from nova.api.openstack.compute.schemas import extended_common

from nova.api.openstack import extensions

from nova.api.openstack import wsgi

from nova.api import validation

from nova import compute

from nova import exception

from nova import db

from nova.i18n import _

from nova.policies import extended_common as extended_common_policies

from oslo_log import log as logging

LOG = logging.getLogger(__name__)

ALIAS = 'os-extended-common'

class ExtendedCommonController(wsgi.Controller):

    def __init__(self):

        self.compute_api = compute.API()

        super(ExtendedCommonController, self).__init__()

    @extensions.expected_errors(404)

    @validation.schema(extended_common.create)

    def create(self, req, body):

        context = req.environ['nova.context']

        context.can(extended_common_policies.BASE_POLICY_NAME)

        context.can(extended_common_policies.POLICY_ROOT % 'create')

        opt = None

        if body and body.has_key('MyTest'):

            opt = 'MyTest'

        else:

            msg = _("Must input method or unsupported method")

            raise exc.HTTPBadRequest(explanation=msg)

        if opt == 'MyTest':

            LOG.info(body['MyTest'])

        else:

            pass

    @extensions.expected_errors(())

    def gettest(self, req):

        context = req.environ['nova.context']

        return dict(controller={'myhost': 'compute1'} )

class ExtendedCommon(extensions.V21APIExtensionBase):

    """extended common support."""

    name = "ExtendedCommon"

    alias = ALIAS

    version = 1

    def get_resources(self):

        member_actions = {'action': 'POST'}

        collection_actions = {'gettest': 'GET'}

        resources = [

            extensions.ResourceExtension(

                ALIAS,

                ExtendedCommonController(),

                collection_actions=collection_actions,

                member_actions=member_actions)]

        return resources

    def get_controller_extensions(self):

        """It's an abstract function V21APIExtensionBase and the extension

        will not be loaded without it.

        """

        return []

这里我们建立了一个新的文件:extended_common.py;在里面建立了类ExtendedCommon。其ALIAS='os-extended-common'。这些后面会使用到。

二。规定API调用到的数据结构

nova/api/openstack/compute/schemas/extended_common.py

from nova.api.validation import parameter_types

create = {

    'type': 'object',

    'properties': {

        'MyTest': {

            'type': 'object',

            'properties': {

                'myhost': parameter_types.hostname,

            },

            'additionalProperties': False,

        },

    },

    'additionalProperties': False,

}

三。注册API

nova/policies/__init__.py

from nova.policies import extended_common

......

def list_rules():

    return itertools.chain(

        ......

        extended_common.list_rules(),

        ......

nova/policies/extended_common.py

from oslo_policy import policy

from nova.policies import base

BASE_POLICY_NAME = 'os_compute_api:os-extended-common'

POLICY_ROOT = 'os_compute_api:os-extended-common:%s'

extended_common_policies = [

    policy.RuleDefault(

        name=BASE_POLICY_NAME,

        check_str=base.RULE_ADMIN_API),

    policy.RuleDefault(

        name=POLICY_ROOT % 'create',

        check_str=base.RULE_ANY),

    policy.RuleDefault(

        name=POLICY_ROOT % 'discoverable',

        check_str=base.RULE_ANY),

    policy.RuleDefault(

        name=POLICY_ROOT % 'show',

        check_str=base.RULE_ANY),

]

def list_rules():

    return extended_common_policies

四。添加entry_points

nova.egg-info/entry_points.txt

extended_common = nova.api.openstack.compute.extended_common:ExtendedCommon

五。查看API是否被导出

# systemctl restart nova-api

# nova list-extensions

应该能看到os-extended-common。

六。测试

测试程序

import json

import urllib2

CONTROLLER_HOSTNAME='controller'

class Opthttp(object):

    def __init__(self, passwd):

        self.token = None

        self.tenant = None

        self.token, self.tenant = self.__get_token(passwd)

    def __get_token(self, passwd):

        url = 'http://%s:5000/v2.0/tokens' % CONTROLLER_HOSTNAME

        values = {"auth": {"tenantName": "admin", "passwordCredentials": {"username": "admin", "password": passwd}}}

        data = self.http_post(url, values)

        token = data['access']['token']['id']

        tenant = data['access']['token']['tenant']['id']

        return token, tenant

    def http_get(self, url):

        req = urllib2.Request(url)

        req.add_header('X-Auth-Token', self.token)

        response = urllib2.urlopen(req)

        data = response.read()

        data = json.loads(data)

        return data

    def _do_http_post(self, method, url, body):

        if body:

            jdata = json.dumps(body)

            req = urllib2.Request(url, jdata)

        else:

            req = urllib2.Request(url, None)

        req.add_header('Content-Type', 'application/json')

        req.add_header('Accept', 'application/json')

        if self.token:

            req.add_header('X-Auth-Token', self.token)

        req.get_method = lambda: method

        response = urllib2.urlopen(req)

        data = response.read()

        if data != '':

            data = json.loads(data)

        return data

    def http_post(self, url, body):

        return self._do_http_post('POST', url, body)

    def http_put(self, url, body):

        return self._do_http_post('PUT', url, body)

    def http_delete(self, url, body):

        return self._do_http_post('DELETE', url, body)

url = '%s/5ad08373b2814d16833959228c714329/os-extended-common' %('http://127.0.0.1:8774/v2.1')

body = {"MyTest": {'myhost': 'compute2'}}

ret = Opthttp('cloud').http_post(url, body)

url = '%s/5ad08373b2814d16833959228c714329/os-extended-common/gettest' %('http://127.0.0.1:8774/v2.1')

controller = Opthttp('cloud').http_get(url)

print controller

关注本公众号,了解更多关于云计算虚拟化的知识。