好贷网好贷款

Python-ceilometerclient 代码分析

发布时间:2016-12-4 3:49:34 编辑:www.fx114.net 分享查询网我要评论
本篇文章主要介绍了"Python-ceilometerclient 代码分析",主要涉及到Python-ceilometerclient 代码分析方面的内容,对于Python-ceilometerclient 代码分析感兴趣的同学可以参考一下。

整体结构 从目录层次上来看,代码结构如下 --ceilometerclient --common/ --openstack/ --tests/ --v1/ --v2/ --client.py --shell.py --exc.py 其中commonopenstack提供utils帮助类,tests是测试用例目录,v1v2分别对应ceilometer的v1和v2版本。client.py提供获取client的方法,包括keystone的client,提供获取endpoint和token的方法;还包括获取ceilometer的client的函数。shell.py是模块的入口,提供对命令行的解析和命令的调用。exc.py提供用到的异常类。 在每个版本目录下,代码的组织如下(v2为例): --v2 --client.py --shell.py --alarms.py --event_types.py --events.py --meters.py -- … … 每个版本目录下也有一个client.py和一个shell.py,这里的shell.py里面提供了do_**的函数完成从上层shell.py传进来的命令并返回结果。其它的py文件按照名称以Manager类的形式分别对应ceilometer各个资源的操作实现。client.py引用所有的Manager,这样shell.py只需要依赖client一个就可以完成对各个资源的操作。所以从控制的角度分析,代码的依赖关系大致是: shell.py ------> client.py ---->alarms/events/meters/samples.py … ^ ^ |(v1/v2) | (v1/v2) | | shell.py ------> client.py (根目录) 关键代码分析 1.程序入口 def main(self, argv): parsed = self.parse_args(argv) if parsed == 0: return 0 api_version, args = parsed # Short-circuit and deal with help command right away. if args.func == self.do_help: self.do_help(args) return 0 elif args.func == self.do_bash_completion: self.do_bash_completion(args) return 0 if not (args.os_auth_token and args.ceilometer_url): if not args.os_username: raise exc.CommandError("You must provide a username via " "either --os-username or via " "env[OS_USERNAME]") if not args.os_password: raise exc.CommandError("You must provide a password via " "either --os-password or via " "env[OS_PASSWORD]") if not (args.os_tenant_id or args.os_tenant_name): raise exc.CommandError("You must provide a tenant_id via " "either --os-tenant-id or via " "env[OS_TENANT_ID]") if not args.os_auth_url: raise exc.CommandError("You must provide an auth url via " "either --os-auth-url or via " "env[OS_AUTH_URL]") client = ceiloclient.get_client(api_version, **(args.__dict__)) # call whatever callback was selected try: args.func(client, args) except exc.Unauthorized: raise exc.CommandError("Invalid OpenStack Identity credentials.") 说明: 当用户输入ceilometerXXX-***后,程序通过main函数启动。首先是解析输入的命令参数。具体实现语句self.parse_args(argv)后面会详细介绍,这里实际也对输入的合法性做了验证,如果输入关键字不对或者格式不符合,会有相应的错误信息提示并退出。如果只输入ceilometer,则会直接调用do_help函数,效果等效于输入ceilometerhelp.如果解析正常,则parse_args返回版本信息api_version和解析结果args. 如果用户输入的是ceilometerhelp/bash_completion,则解析后的args中的func属性就对应为do_help/do_bash_completion函数(原理后面会解释)。 如果输入的是实际的操作命令(比如ceilometermeter-list),则先会做keystone鉴权认证,故执行命令前要设置好环境变量或者在命令中加上鉴权的参数;然后再根据版本号得到ceilometer的client,最后执行args.func(client,args)完成对应命令的实现(这里会调用do_meter_list函数)。 2. 子命令解析 parse_args函数解析命令行参数之前,会先获取由argparse提供的解析器parser,这里有两类parser并分主次。主parser提供了通用的可选命令行选项,比如-h/-v/--os-username等,而subparser提供了具体的命令和选项,具体实现在get_subcommand_parser函数中。 def get_subcommand_parser(self, version): parser = self.get_base_parser() self.subcommands = {} subparsers = parser.add_subparsers(metavar='<subcommand>') submodule = utils.import_versioned_module(version, 'shell') self._find_actions(subparsers, submodule) self._find_actions(subparsers, self) self._add_bash_completion_subparser(subparsers) return parser 说明:子解析器有多个(每个子命令对应一个),要获取每个子命令的解析器,首先根据版本号去版本目录下面获取shell模块,比如ceilometerclient.v2.shell,然后在通过_find_actions函数来创建子命令解析器。 def _find_actions(self, subparsers, actions_module): for attr in (a for a in dir(actions_module) if a.startswith('do_')): # I prefer to be hypen-separated instead of underscores. command = attr[3:].replace('_', '-') callback = getattr(actions_module, attr) desc = callback.__doc__ or '' help = desc.strip().split('\n')[0] arguments = getattr(callback, 'arguments', []) subparser = subparsers.add_parser(command, help=help, description=desc, add_help=False, formatter_class=HelpFormatter) subparser.add_argument('-h', '--help', action='help', help=argparse.SUPPRESS) self.subcommands[command] = subparser for (args, kwargs) in arguments: subparser.add_argument(*args, **kwargs) subparser.set_defaults(func=callback) 说明: _find_actions在相应的(shell)模块中查找满足条件的函数,这里是以do_开头作为过滤条件。然后将函数名转换成具体的子命令command(比如do_meter_list转换成meter-list),函数本身作为执行该命令的callback。然后根据command创建子命令解析器subparser。这里还要获取函数的arguments属性,作为子命令的选项,[email protected](详见ceilometerclient.common.utils)。arguments中的数据最终添加到子命令解析器中去,最后将callback函数作为func也加进去从而完成子命令解析器的创建和配置。 3. 子命令实现(meter-list为例) 当执行ceilometermeter-list -q xxx的时候,根据上面的分析,首先会创建好command为meter-list的subparser用来解析命令行,通过匹配最终将命令行字串解析成python对象,(比如meter-list解析成do_meter_list函数,-qxxx 解析为args.query).最终通过args.func(client,args)语句来执行do_meter_list。 @utils.arg('-q', '--query', metavar='<QUERY>', help='key[op]data_type::value; list. data_type is optional, ' 'but if supplied must be string, integer, float, or boolean') def do_meter_list(cc, args={}): '''List the user's meters.''' meters = cc.meters.list(q=options.cli_to_array(args.query)) field_labels = ['Name', 'Type', 'Unit', 'Resource ID', 'User ID', 'Project ID'] fields = ['name', 'type', 'unit', 'resource_id', 'user_id', 'project_id'] utils.print_list(meters, fields, field_labels, sortby=0) 说明:cc即ceilometerclient.通过cc.meters.list列出满足args.query的meters值,最后通过utils.print_list打印出相应的字段。 小结 不仅是python-ceilomerclient,python-***client的代码都是类似的代码结构和处理流程,因此掌握好一个模块的,再分析其他模块的或者做二次开发就会比较得心应手。

上一篇:万年历
下一篇:DataGridView单元格只输入小数或整数

相关文章

相关评论