Cliff(CommandLine Interface Formulation Framework),即命令行接口制定框架。可定义多级命令、输出格式以及其他一些扩展来创建命令行相关项目。Cliff框架中定义的主程序处理参数解析,并调用子命令来完成工作。
Cliff借助Python的优势能够动态的装载代码,允许主程序中用到的子命令分布式的实现,并向用户提供统一的命令行界面,方便开发者组织源码。Neutron提供了命令行模式、交互式模式,正是基于cliff架构实现的。
1 theapplication
Cliff.app.App是cliff框架的主程序,负责参数解析、配置logging、设置I/O流等。
2 theCommandManager
cliff.commandmanager.CommandManager 用于加载子命令,默认是通过setuptools entry points机制实现。
3 theCommand
cliff.command.Command 可通过继承该类实现相应的子命令供主程序调用。
4 theInteractive Application
主程序调用cliff.interactive.InteractiveApp实例向用户提供command-shell模式,用户可输入多个命令。
Cliff.app.App类中,初始化函数包括定义self.commandmanager,它是cliff.commandmanager.CommandManager的实例,self.interactive-app-factory,它是cliff.interactive.InteractiveApp的实例。run()函数是主程序入口函数。
List命令提供的输出格式:csv, table, value, yaml, json, HTML,使用方法是在命令后面输入:-f 输出格式;Show命令提供的输出格式:table,shell, value, yaml, json, HTML,下面举例介绍各种格式的特点,HTML格式需要安装cliff-tablib,这里不做演示。
Csv格式:
(.venv)$ cliffdemo files -f csv "Name","Size" "build",136 "cliffdemo.log",2690 "Makefile",5569 "source",408 |
Table格式:
(.venv)$ cliffdemo files +---------------+------+ | Name | Size | +---------------+------+ | build | 136 | | cliffdemo.log | 2546 | | Makefile | 5569 | | source | 408 | +---------------+------+ |
Value格式
(.venv)$ cliffdemo files -f value build 136 cliffdemo.log 2690 Makefile 5569 source 408 |
Yaml格式:
(.venv)$ cliffdemo files -f yaml - Name: dist Size: 4096 - Name: cliffdemo.egg-info Size: 4096 - Name: README.rst Size: 960 - Name: setup.py Size: 1807 |
Json 格式:
(.venv)$ cliffdemo files -f json [ { "Name": "source", "Size": 4096 }, { "Name": "Makefile", "Size": 5569 }, ] |
Shell格式:
(.venv)$ cliffdemo file -f shell setup.py name="setup.py" size="5916" uid="527" gid="501" modified_time="1335655655.0" |
Openstack提供的命令行程序正是基于cliff框架编写。Neutron-client实现了用于调用Neutron APIs 命令行接口。Neutronclient的主程序NeutronShell类继承cliff.app.App类,初始化函数中定义了command-manager,interactive-app。对终端输入的neutron命令进行参数解析、配置logging并调用相关子命令来完成neutron命令操作。输入的命令是由sys.argv[1:]获取。
Neutronclient目录结构:
neutronclient ---common ---neutron --v2_0 --client.py ---tests ---v2_0 ---client.py ---i18n.py ---shell.py ---version.py |
通过添加neutronservice-create命令来介绍,当终端输入service-create命令时,要求输出service-create命令所有的参数,且参数可用。
1、注册新的CLI命令
Neutron提供的命令行接口是定义在python-neutronclient/neutronclient/shell.py文件,以字典形式注册在COMMAND_V2中,因此需要在COMMAND_V2中注册新的命令:
COMMAND_V2 = { 'net-list': network.ListNetwork, … 'service-create': network.CreateService, } |
Service-create具体实现是在network.py文件提供的CreateService类中实现。
2、设置service-create命令提供的参数
这部分设置是在类CreateService中实现。
import argparse # 调用argparse模块用于参数解析,参数添加,参数行为设置等
from neutronclient.common import exceptions from neutronclient.i18n import _ from neutronclient.neutron import v2_0 as neutronV20 # 该类提供了CreateCommand类
class CreateService(neutronV20.CreateCommand): """Create a service."""
resource = 'service' # neutron client向OpenStack API端对service资源进行操作
def add_known_arguments(self, parser): # 对service-create命令添加参数,并设置参数的行为 parser.add_argument( '--admin-state-down', dest='admin_state', action='store_false', help=_('Set admin state up to false.')) parser.add_argument( '--admin_state_down', dest='admin_state', action='store_false', help=argparse.SUPPRESS) parser.add_argument( 'name', metavar='NAME', help=_('Name of service to create.')) parser.add_argument( '--description', dest='description', help=_('Description of the service')) parser.add_argument( '--shared', dest='share', choices=['True', 'False'], default=argparse.SUPPRESS, help=_('Shared or not')) parser.add_argument( '--test', dest='test', action='store_const', const='value-to-const', help=_('Test for const value')) parser.add_argument( '--ips', dest='ips', nargs=2, default='a', help=_('Add multible arguments')) parser.add_argument( '-r', '--retries', metavar="NUM", dest='r', type=int, default=0, help=_("How many times the request to the Neutron server should " "be retried if it fails."))
def args2body(self, parsed_args): body = {'service': { 'name': parsed_args.name, 'admin_state_up': parsed_args.admin_state, 'ips': parsed_args.ips, 'description':parsed_args.description, 'test': parsed_args.test, 'shared': parsed_args.share, 'r': parsed_args.r}, } neutronV20.update_dict(parsed_args, body['service'], ['shared', 'tenant_id']) return body |
代码中向service-create命令添加了如下参数:
1 --admin-state-down/--admin_state_down,其action:store-false,表示其默认值为false,输入为true。
2 name,前面没有添加‘—’表示为必选参数,输入service-create命令时必须输入name。
3 --description,没有添加action,但默认action是type=str,表示该值是字符串形式。
4 --shared,带有choice选项,表示该值只可是choice中的一个值。
5 --test,action值为‘store-const’,表示test值在const中指定。
6 --ips,action值为‘nargs=2’,表示ips可选参数后面需加两个值。
7 -r,参数--retries,是-r参数的别名,区别是前面的短横线个数不同。其中type=int,表示其输入值是整形数值。
3、显示新添加的命令其参数值
根据neutron-client中代码执行走向,在CreateService类的父类CreateCommand中定义的get-data()函数中输出命令的返回结果。
class CreateCommand(NeutronCommand, show.ShowOne): """Create a resource for a given tenant."" def get_parser(self, prog_name): … … def get_data(self, parsed_args): self.log.debug('get_data(%s)' % parsed_args) _extra_values = parse_args_to_dict(self.values_specs) _merge_args(self, parsed_args, _extra_values, self.values_specs) body = self.args2body(parsed_args) # body中返回所创建的service下所有的参数及对应的值 print("_extra_values") print(_extra_values) print("body:") print(body) return neutron_client = self.get_client() # 设置neutron-client,调用OpenStack APIs neutron_client.format = parsed_args.request_format … … |
执行service-createabc --retries 2 - -shared True ,或者执行service-create abc -r 2 - -shared True,返回结果相同。
service-create abc --retries 2 --shared True _extra_values {} body: {'service': {'description': None, 'admin_state_up': True, 'ips': 'a, b', 'r': 2, 'test': None, 'shared': 'True', 'name': 'abc'}} |
Cliff文档:http://docs.openstack.org/developer/cliff/
Cliff源码:https://github.com/dreamhost/cliff
Argparse模块:http://www.2cto.com/kf/201208/149418.html
http://blog.itpub.net/26250550/viewspace-1281968/
http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=21633169&id=4387657