novaclient的api调用流程与开发

http://blog.csdn.net/tpiperatgod/article/details/18375387?utm_source=tuicool

另一个地址:http://neuromancer.sinaapp.com/?p=64

从nova client的入口查看


cat /usr/bin/nova

[python]  view plain copy print ?
  1. cat /usr/bin/nova  
  2.   
  3. #!/usr/bin/python  
  4. # PBR Generated from 'console_scripts'  
  5.   
  6. import sys  
  7.   
  8. from novaclient.shell import main  
  9.   
  10. if __name__ == "__main__":  
  11.     sys.exit(main())  

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

[python]  view plain copy print ?
  1. def main():  
  2.     try:  
  3.         OpenStackComputeShell().main(map(strutils.safe_decode, sys.argv[1:]))  
  4.   
  5.     except Exception as e:  
  6.         logger.debug(e, exc_info=1)  
  7.         print("ERROR: %s" % strutils.safe_encode(six.text_type(e)),  
  8.               file=sys.stderr)  
  9.         sys.exit(1)  
  10.   
  11. OpenStackComputeShell.main()  
  12.         self.cs = client.Client(options.os_compute_api_version, os_username,  
  13.                 os_password, os_tenant_name, tenant_id=os_tenant_id,  
  14.                 auth_url=os_auth_url, insecure=insecure,  
  15.                 region_name=os_region_name, endpoint_type=endpoint_type,  
  16.                 extensions=self.extensions, service_type=service_type,  
  17.                 service_name=service_name, auth_system=os_auth_system,  
  18.                 auth_plugin=auth_plugin,  
  19.                 volume_service_name=volume_service_name,  
  20.                 timings=args.timings, bypass_url=bypass_url,  
  21.                 os_cache=os_cache, http_log_debug=options.debug,  
  22.                 cacert=cacert, timeout=timeout)  

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

[python]  view plain copy print ?
  1. def get_client_class(version):  
  2.     version_map = {  
  3.         '1.1''novaclient.v1_1.client.Client',  
  4.         '2''novaclient.v1_1.client.Client',  
  5.         '3''novaclient.v3.client.Client',  
  6.     }  
  7.     try:  
  8.         client_path = version_map[str(version)]  
  9.     except (KeyError, ValueError):  
  10.         msg = "Invalid client version '%s'. must be one of: %s" % (  
  11.               (version, ', '.join(version_map.keys())))  
  12.         raise exceptions.UnsupportedVersion(msg)  
  13.   
  14.     return utils.import_class(client_path)  
  15.   
  16. def Client(version, *args, **kwargs):  
  17.     client_class = get_client_class(version)  
  18.     return client_class(*args, **kwargs)  

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

[python]  view plain copy print ?
  1. class Client(object):  
  2.     """ 
  3.     Top-level object to access the OpenStack Compute API. 
  4.  
  5.     Create an instance with your creds:: 
  6.  
  7.         >>> client = Client(USERNAME, PASSWORD, PROJECT_ID, AUTH_URL) 
  8.  
  9.     Then call methods on its managers:: 
  10.  
  11.         >>> client.servers.list() 
  12.         ... 
  13.         >>> client.flavors.list() 
  14.         ... 
  15.  
  16.     """  

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

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

[python]  view plain copy print ?
  1. self.flavors = flavors.FlavorManager(self)  
  2.   
  3. flavors.list() 进入novaclient.v1_1.flavors.py  
  4.   
  5. class FlavorManager(base.ManagerWithFind):  
  6.     """ 
  7.     Manage :class:`Flavor` resources. 
  8.     """  
  9.     resource_class = Flavor  
  10.     is_alphanum_id_allowed = True  
  11.   
  12.     def list(self, detailed=True, is_public=True):  
  13.         """ 
  14.         Get a list of all flavors. 
  15.  
  16.         :rtype: list of :class:`Flavor`. 
  17.         """  
  18.         qparams = {}  
  19.         # is_public is ternary - None means give all flavors.  
  20.         # By default Nova assumes True and gives admins public flavors  
  21.         # and flavors from their own projects only.  
  22.         if not is_public:  
  23.             qparams['is_public'] = is_public  
  24.         query_string = "?%s" % urlutils.urlencode(qparams) if qparams else ""  
  25.   
  26.         detail = ""  
  27.         if detailed:  
  28.             detail = "/detail"  
  29.   
  30.         return self._list("/flavors%s%s" % (detail, query_string), "flavors")  

self._list进入novaclient.base.py

[python]  view plain copy print ?
  1. class Manager(utils.HookableMixin):  
  2.     """ 
  3.     Managers interact with a particular type of API (servers, flavors, images, 
  4.     etc.) and provide CRUD operations for them. 
  5.     """  
  6.     resource_class = None  
  7.   
  8.     def __init__(self, api):  
  9.         self.api = api  
  10.   
  11.     def _list(self, url, response_key, obj_class=None, body=None):  
  12.         if body:  
  13.             _resp, body = self.api.client.post(url, body=body)  
  14.         else:  
  15.             _resp, body = self.api.client.get(url)  
  16.   
  17.         if obj_class is None:  
  18.             obj_class = self.resource_class  
  19.   
  20.         data = body[response_key]  
  21.         # NOTE(ja): keystone returns values as list as {'values': [ ... ]}  
  22.         #           unlike other services which just return the list...  
  23.         if isinstance(data, dict):  
  24.             try:  
  25.                 data = data['values']  
  26.             except KeyError:  
  27.                 pass  
  28.   
  29.         with self.completion_cache('human_id', obj_class, mode="w"):  
  30.             with self.completion_cache('uuid', obj_class, mode="w"):  
  31.                 return [obj_class(self, res, loaded=True)  
  32.                         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 plain copy print ?
  1. if body:  
  2.     _resp, body = self.api.client.post(url, body=body)  
  3. else:  
  4.     _resp, body = self.api.client.get(url)  

[python]  view plain copy print ?
  1. 通过self.api到了nova的api里nova.api.openstack.compute.__init__.py  
  2.   
  3.         if init_only is None or 'flavors' in init_only:  
  4.             self.resources['flavors'] = flavors.create_resource()  
  5.             mapper.resource("flavor""flavors",  
  6.                             controller=self.resources['flavors'],  
  7.                             collection={'detail''GET'},  
  8.                             member={'action''POST'})  

找到nova.api.openstack.flavors.py
[python]  view plain copy print ?
  1. @wsgi.serializers(xml=MinimalFlavorsTemplate)  
  2. def index(self, req):  
  3.     """Return all flavors in brief."""  
  4.     limited_flavors = self._get_flavors(req)  
  5.     return self._view_builder.index(req, limited_flavors)  

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

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

[python]  view plain copy print ?
  1. def _list_view(self, func, request, flavors):  
  2.     """Provide a view for a list of flavors."""  
  3.     flavor_list = [func(request, flavor)["flavor"for flavor in flavors]  
  4.     flavors_links = self._get_collection_links(request,  
  5.             flavors,  
  6.             self._collection_name,  
  7.             "flavorid")  
  8.     flavors_dict = dict(flavors=flavor_list)  
  9.   
  10.     if flavors_links:  
  11.         flavors_dict["flavors_links"] = flavors_links  
  12.   
  13.     return flavors_dict  

添加一个新的client流程:

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

[plain]  view plain copy print ?
  1. curl -i http://:8774/v2//servers//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: " -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 plain copy print ?
  1. @utils.arg('server', metavar='', help='ID of server.')  
  2. @utils.arg('displayname',  
  3.             metavar='',  
  4.             help='Display name for backup.')  
  5. @utils.arg('description',  
  6.             default=None,  
  7.             metavar='',  
  8.             help='Description for backup.(Default None)')  
  9. def do_backup_instance(cs, args):  
  10.     """Make a quick backup for instance."""  
  11.     cs.servers.backup_instance(args.server,  
  12.                         args.displayname,  
  13.                         args.description)  

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

在ServerManager类里添加

[python]  view plain copy print ?
  1. def backup_instance(self, server, backup_name, backup_description):  
  2.     """ 
  3.     Backup a server instance quickly. 
  4.  
  5.     :param server: The :class:`Server` (or its ID) to share onto. 
  6.     :param backup_name: Name of the backup image 
  7.     :param backup_description: The backup description 
  8.     """  
  9.     body = {'name': backup_name,  
  10.             'description': backup_description}  
  11.     response_key = "id"  
  12.     return self._create("/servers/%s/backup_instance" % base.getid(server),  
  13.                     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

你可能感兴趣的:(openstack,nova)