Skip to main content
# python-cliclient
A python CLI client example using python-openstackclient plugin mechanism.

## 还是需要 python-openstackclient

首先,openstack client是用[cliff](http://docs.openstack.org/developer/cliff/)实现,所以建议先熟读cliff的官方文档,知道cliff的实现机制,这样才能对openstack client的机制有了解,这是熟悉openstack client的基础。如果你不是为了实现 openstack 命令,可以跳过此文直接参考 cliff 给出的一个[示例](https://docs.openstack.org/cliff/latest/user/demoapp.html)照猫画虎即可。

cliff 中 App 初始化时,初始化参数 `command_manager=CommandManager('cliff.demo')` 告诉你,命令都在 setup.cfg 中的 `cliff.demo` 命名空间中定义。

从OSC 2.4.0版本以后,从openstack client又提取出一个叫osc-lib的可重用的库,新的plugin可以继承这个osc-lib来集成openstack命令,但是plugin的加载还是由openstack client来完成。从设计层次上讲,osc-lib继承自cliff,而openstack client和其他的extension其实是平级结构,都继承自osc-lib,只是由openstack client入口而已。

> 所以,你自己的 CLI 命令要生效,还需要依赖 python-openstackclient,因为 CLI 中的 openstack 命令是安装完 python-openstackclient 后才有。

## python-openstackclient 都做了什么

入口在 `openstackclient.shell:main`

OpenStackShell 类最终继承自 cliff 中的 App。python-openstackclient 的实现之所以复杂,是因为它除了扮演 CLI 总入口的责任外,还需要为其他 plugin 提供支持,承担一些公共事务(比如 keystone 鉴权),让 plugin 只需要关注自己的业务实现。

所以,当你在 CLI 下每次执行 openstack 命令时,python-openstackclient 都会动态的[加载](https://github.com/openstack/python-openstackclient/blob/cc47c075a067e3f4f3bb80dd933cdd4d483b8105/openstackclient/common/clientmanager.py#L131)系统中所有已注册的 plugin,根据约定好的规则,获取它们的名字,版本,命令行参数等,并把这些 plugin module 注册到 osc-lib 的 clientmanager.ClientManager 类中,属性名由 `API_NAME` 定义,属性的值是一个[描述符对象](https://lingxiankong.github.io/2014-03-28-python-descriptor.html),被访问时会获取函数 `def make_client(instance)` 的返回值,其中的 instance 就是一个 clientmanager.ClientManager 实例。

在 `initialize_app` 函数执行时,命令行参数已经经过解析。此时,除了 OpenStackShell 初始化时 command_manager 参数指定的命名空间,在这里还有机会再注册其他命令。各个 openstack plugin 命令就是在此时注册。

在 `prepare_to_run_command` 函数中主要是实例化 clientmanager.ClientManager,如果 `command.auth_required = True` 则进行鉴权操作,因为大家在使用命令行时,同样的两个命令,传递的鉴权信息会不一样,因此必须在每个命令执行前进行鉴权。所以 ClientManager 对象保存了鉴权信息。

通过openstack client工程的setup.cfg可以看出,openstack client默认集成了Nova, Keystone, Glance, Neutron, Swift, Cinder这6个项目(在openstack.cli.base命名空间中),同时,从setup.cfg中也可以看到,openstack client有两个全局的命令,分别是openstack command list和openstack module list(在openstack.cli命名空间中),用以查询加载的模块和支持的命令列表。

最终,在command处理时,比如命令行:openstack compute agent list,会调用`self.app.client_manager.compute.agents.list`处理。还记得那个ClientManager类变量么?compute就是类变量之一,当访问clientmanager.compute时,就会调用openstackclient.compute.client提供的`make_client`方法,传入clientmanager对象。

## 你的 client 需要做什么

根据上述的过程,python-openstackclient 把该做的都做了,你只需要按照约定填空即可。

1. setup.cfg
你需要定义:

```python
openstack.cli.extension =
runit = mycli.osc.plugin
openstack.runit.v1 =
runit_echo = mycli.echo:Echo
```

让 python-openstackclient 找到你的 plugin 定义。

2. 在 `mycli/osc/plugin.py` 文件中,按照[这里](https://github.com/openstack/python-openstackclient/blob/cc47c075a067e3f4f3bb80dd933cdd4d483b8105/openstackclient/shell.py#L68)的代码流程定义一些变量。比如:

- `API_NAME`,你的 plugin 名字,比如 runit
- `API_VERSION_OPTION`,比如 `os_runit_version`
- `DEFAULT_API_VERSION`,比如 1,这个变量最好定义,否则你的 command 不会生效。最终,根据字符串拼接会注册命名空间 `openstack.runit.v1` 下的 commands

3. 如果 runit 这个程序不是一个 openstack service client,就没有必要实现 `make_client` 方法。

4. 在 `mycli/echo.py` 文件中:

```python
from osc_lib.command import command


class Echo(command.Command):
auth_required = False

def get_parser(self, prog_name):
parser = super(Echo, self).get_parser(prog_name)
parser.add_argument(
'-m', '--message', default='Hello, World!', help='Echo message.'
)
return parser

def take_action(self, parsed_args):
print(parsed_args.message)
```

5. 安装和试用。

```shell
$ mkvirtualenv openstack
$ cd ~/code/python-cliclient
$ pip install -e .
$ openstack runit echo
Hello, World!
```



Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

python-cliclient-1.0.0.tar.gz (9.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

python_cliclient-1.0.0-py2-none-any.whl (10.5 kB view details)

Uploaded Python 2

File details

Details for the file python-cliclient-1.0.0.tar.gz.

File metadata

File hashes

Hashes for python-cliclient-1.0.0.tar.gz
Algorithm Hash digest
SHA256 18ccb106e9630a54c434333b8812cc3b2a4d58992379b22cd4d86573dc3d9b1c
MD5 4683cec8b0ee44f31581669e57fa39a0
BLAKE2b-256 122bbbbc6c372876c2317b97111ec2c50a248220b7c68b85efb9239809f7b33a

See more details on using hashes here.

File details

Details for the file python_cliclient-1.0.0-py2-none-any.whl.

File metadata

File hashes

Hashes for python_cliclient-1.0.0-py2-none-any.whl
Algorithm Hash digest
SHA256 b96ac70a672d23affce04da86f0fa097650bef0abef2146966bc8e036db52383
MD5 36b4cc5fd1c33cce7ed5d64a74f14fd2
BLAKE2b-256 1d42a1fbadd401a2e1f154e41eb6ebdd3bf0c0807ac62803ad2934da209d0557

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

1.0.0 This release

2 files

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page