您的位置:首页 > 其它

novaclient的api调用流程与开发

2015-05-21 19:54 417 查看
从nova client的入口查看

cat /usr/bin/nova

[python] view
plaincopyprint?





cat /usr/bin/nova

#!/usr/bin/python

# PBR Generated from 'console_scripts'

import sys

from novaclient.shell import main

if __name__ == "__main__":

sys.exit(main())

其中导入了novaclient.shell这个文件中导入了main方法,进入novaclient.shell.py查看

[python] view
plaincopyprint?





def main():

try:

OpenStackComputeShell().main(map(strutils.safe_decode, sys.argv[1:]))

except Exception as e:

logger.debug(e, exc_info=1)

print("ERROR: %s" % strutils.safe_encode(six.text_type(e)),

file=sys.stderr)

sys.exit(1)

OpenStackComputeShell.main()

self.cs = client.Client(options.os_compute_api_version, os_username,

os_password, os_tenant_name, tenant_id=os_tenant_id,

auth_url=os_auth_url, insecure=insecure,

region_name=os_region_name, endpoint_type=endpoint_type,

extensions=self.extensions, service_type=service_type,

service_name=service_name, auth_system=os_auth_system,

auth_plugin=auth_plugin,

volume_service_name=volume_service_name,

timings=args.timings, bypass_url=bypass_url,

os_cache=os_cache, http_log_debug=options.debug,

cacert=cacert, timeout=timeout)

self.cs是从client中创建出的一个Client实例,进入novaclient.client.py查看这个实例的具体方法

[python] view
plaincopyprint?





def get_client_class(version):

version_map = {

'1.1': 'novaclient.v1_1.client.Client',

'2': 'novaclient.v1_1.client.Client',

'3': 'novaclient.v3.client.Client',

}

try:

client_path = version_map[str(version)]

except (KeyError, ValueError):

msg = "Invalid client version '%s'. must be one of: %s" % (

(version, ', '.join(version_map.keys())))

raise exceptions.UnsupportedVersion(msg)

return utils.import_class(client_path)

def Client(version, *args, **kwargs):

client_class = get_client_class(version)

return client_class(*args, **kwargs)

用的是v1_1这个版本的api,对应的是novaclient.v1_1.client.py里的Client类

[python] view
plaincopyprint?





class Client(object):

"""

Top-level object to access the OpenStack Compute API.

Create an instance with your creds::

>>> client = Client(USERNAME, PASSWORD, PROJECT_ID, AUTH_URL)

Then call methods on its managers::

>>> client.servers.list()

...

>>> client.flavors.list()

...

"""

注释里讲了怎么使用python命令行调用nova的client

client里给流入的指令分了很多类,以flavors为例,看nova flavor-list这个命令的流程

[python] view
plaincopyprint?





self.flavors = flavors.FlavorManager(self)

flavors.list() 进入novaclient.v1_1.flavors.py

class FlavorManager(base.ManagerWithFind):

"""

Manage :class:`Flavor` resources.

"""

resource_class = Flavor

is_alphanum_id_allowed = True

def list(self, detailed=True, is_public=True):

"""

Get a list of all flavors.

:rtype: list of :class:`Flavor`.

"""

qparams = {}

# is_public is ternary - None means give all flavors.

# By default Nova assumes True and gives admins public flavors

# and flavors from their own projects only.

if not is_public:

qparams['is_public'] = is_public

query_string = "?%s" % urlutils.urlencode(qparams) if qparams else ""

detail = ""

if detailed:

detail = "/detail"

return self._list("/flavors%s%s" % (detail, query_string), "flavors")

self._list进入novaclient.base.py

[python] view
plaincopyprint?





class Manager(utils.HookableMixin):

"""

Managers interact with a particular type of API (servers, flavors, images,

etc.) and provide CRUD operations for them.

"""

resource_class = None

def __init__(self, api):

self.api = api

def _list(self, url, response_key, obj_class=None, body=None):

if body:

_resp, body = self.api.client.post(url, body=body)

else:

_resp, body = self.api.client.get(url)

if obj_class is None:

obj_class = self.resource_class

data = body[response_key]

# NOTE(ja): keystone returns values as list as {'values': [ ... ]}

# unlike other services which just return the list...

if isinstance(data, dict):

try:

data = data['values']

except KeyError:

pass

with self.completion_cache('human_id', obj_class, mode="w"):

with self.completion_cache('uuid', obj_class, mode="w"):

return [obj_class(self, res, loaded=True)

for res in data if res]

novaclient.v1_1.flavors.py里FlavorManager的resource_class = Flavor即class Flavor(base.Resource)

所以最后obj_class为Flavor

调用api的过程:

[python] view
plaincopyprint?





if body:

_resp, body = self.api.client.post(url, body=body)

else:

_resp, body = self.api.client.get(url)

[python] view
plaincopyprint?





通过self.api到了nova的api里nova.api.openstack.compute.__init__.py

if init_only is None or 'flavors' in init_only:

self.resources['flavors'] = flavors.create_resource()

mapper.resource("flavor", "flavors",

controller=self.resources['flavors'],

collection={'detail': 'GET'},

member={'action': 'POST'})

找到nova.api.openstack.flavors.py

[python] view
plaincopyprint?





@wsgi.serializers(xml=MinimalFlavorsTemplate)

def index(self, req):

"""Return all flavors in brief."""

limited_flavors = self._get_flavors(req)

return self._view_builder.index(req, limited_flavors)

它最后会返回一个存放flavors信息的字典,这些原始数据经过提取和加工,最后在终端被打印出来

nova.api.openstack.compute.views.flavors.py

[python] view
plaincopyprint?





def _list_view(self, func, request, flavors):

"""Provide a view for a list of flavors."""

flavor_list = [func(request, flavor)["flavor"] for flavor in flavors]

flavors_links = self._get_collection_links(request,

flavors,

self._collection_name,

"flavorid")

flavors_dict = dict(flavors=flavor_list)

if flavors_links:

flavors_dict["flavors_links"] = flavors_links

return flavors_dict

添加一个新的client流程:

功能:快速备份虚拟机,三个参数,虚拟机uuid、备份的名字、备份的描述,调用地方和方法如下:

[plain] view
plaincopyprint?





curl -i http://<nova_ip>:8774/v2/<tenant_id>/servers/<user_id>/backup_instance -X POST -H "X-Auth-Project-Id: admin" -H "Content-Type: application/json" -H "User-Agent: python-novaclient" -H "Accept: application/json" -H "X-Auth-Token: <token>" -d '{"name" : "backup", "description" : "backup's description"}'

novaclient.shell.py

class OpenStackComputeShell(object) 的get_subcommand_parser 方法里指定了actions_module

转到novaclient.v1_1.shell.py

增加一个新的方法,装饰器里是需要的参数,有顺序,和执行时的参数顺序一致

[python] view
plaincopyprint?





@utils.arg('server', metavar='<server>', help='ID of server.')

@utils.arg('displayname',

metavar='<name>',

help='Display name for backup.')

@utils.arg('description',

default=None,

metavar='<description>',

help='Description for backup.(Default None)')

def do_backup_instance(cs, args):

"""Make a quick backup for instance."""

cs.servers.backup_instance(args.server,

args.displayname,

args.description)

这个功能是加在servers部分里的,转到novaclient.v1_1.servers.py

在ServerManager类里添加

[python] view
plaincopyprint?





def backup_instance(self, server, backup_name, backup_description):

"""

Backup a server instance quickly.

:param server: The :class:`Server` (or its ID) to share onto.

:param backup_name: Name of the backup image

:param backup_description: The backup description

"""

body = {'name': backup_name,

'description': backup_description}

response_key = "id"

return self._create("/servers/%s/backup_instance" % base.getid(server),

body, response_key, return_raw=True)

response_key是指返回数据里的key,这里返回的数据是{'id': "*****"},所以response_key = "id"

因为这个api返回的是一个json字符串,不能通过novaclient.base.py里Manager类里的方法把数据提取出来(它需要字典),于是把return_raw这个参数设置为True

然后就可以在nova的命令行里看到这个新的功能了:nova backup-instance;使用方法:nova backup-instance <server_id> <bak_name> <bak_description>

转载自:http://blog.csdn.net/tpiperatgod/article/details/18375387?utm_source=tuicool
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: