前段时间开始认真看了一下Ryu的源码,发现oslo是一个非常方便的命令行解析库,可以用于CLI和CONF的解析。oslo是 OpenStack发起的项目,全称为OpenStack Common Libraries,是OpenStack Projects共享的基础库。
在RYU的目录下可以找到cfg.py文件,这个文件中import了oslo的相关模块,以便调用时减少引用数目。从文件中可以发现 oslo.config.cfg文件是关键文件,其在系统中的文件位置在:/usr/local/lib/python2.7/dist- packages/oslo/config/cfg.py。想查看源码的读者可以自行查看。在该cfg.py文件中 定义了ConfigOpts类,包含了_opts, _groups等成员变量。该类完成了命令行和配置参数的解析。
如果要快速学习某一个知识,最好的办法就是把它用起来。所以首先我会介绍一个入门的教程。如果你没有看懂,可以去看原始的教程。
首先安装python-virtualenv,此python库可以用于创建一个虚拟的,与外界隔离的运行环境,听起来和docker好像有点像。
1
2
3
4
5
6
7
|
sudo
apt
-
get
install
python
-
virtualenv
virtualenv
example
-
app
cd
example
-
app
source
bin
/
activate
pip
install
oslo
.config
touch
app
.py
touch
app
.conf
|
然后修改app.conf。添加了两个group:simple和morestuff。simple组中有一个BoolOpt:enable。morestuff组有StrOpt, ListOpt, DictOpt, IntOpt,和FloatOpt。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
[
simple
]
enable
=
True
[
morestuff
]
# StrOpt
message
=
Hello
World
# ListOpt
usernames
=
[
'Licheng'
,
'Muzixing'
,
'Distance'
]
# DictOpt
jobtitles
=
{
'Licheng'
:
'Manager'
,
'Muzixing'
:
'CEO'
,
'Distance'
:
'Security Guard'
}
# IntOpt
payday
=
20
# FloatOpt
pi
=
3.14
|
修改app.py文件。首先定义两个group,再对两个group的option进行定义。最后使用registergroup和registeropts函数来完成group和option的注册。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
from
__future__
import
print_function
from
oslo
.
config
import
cfg
opt_simple_group
=
cfg
.
OptGroup
(
name
=
'simple'
,
title
=
'A Simple Example'
)
opt_morestuff_group
=
cfg
.
OptGroup
(
name
=
'morestuff'
,
title
=
'A More Complex Example'
)
simple_opts
=
[
cfg
.
BoolOpt
(
'enable'
,
default
=
False
,
help
=
(
'True enables, False disables'
)
)
]
morestuff_opts
=
[
cfg
.
StrOpt
(
'message'
,
default
=
'No data'
,
help
=
(
'A message'
)
)
,
cfg
.
ListOpt
(
'usernames'
,
default
=
None
,
help
=
(
'A list of usernames'
)
)
,
cfg
.
DictOpt
(
'jobtitles'
,
default
=
None
,
help
=
(
'A dictionary of usernames and job titles'
)
)
,
cfg
.
IntOpt
(
'payday'
,
default
=
30
,
help
=
(
'Default payday monthly date'
)
)
,
cfg
.
FloatOpt
(
'pi'
,
default
=
0.0
,
help
=
(
'The value of Pi'
)
)
]
CONF
=
cfg
.
CONF
CONF
.
register_group
(
opt_simple_group
)
CONF
.
register_opts
(
simple_opts
,
opt_simple_group
)
CONF
.
register_group
(
opt_morestuff_group
)
CONF
.
register_opts
(
morestuff_opts
,
opt_morestuff_group
)
if
__name__
==
"__main__"
:
CONF
(
default_config_files
=
[
'app.conf'
]
)
print
(
'(simple) enable: {}'
.
format
(
CONF
.
simple
.
enable
)
)
print
(
'(morestuff) message :{}'
.
format
(
CONF
.
morestuff
.
message
)
)
print
(
'(morestuff) usernames: {}'
.
format
(
CONF
.
morestuff
.
usernames
)
)
print
(
'(morestuff) jobtitles: {}'
.
format
(
CONF
.
morestuff
.
jobtitles
)
)
print
(
'(morestuff) payday: {}'
.
format
(
CONF
.
morestuff
.
payday
)
)
print
(
'(morestuff) pi: {}'
.
format
(
CONF
.
morestuff
.
pi
)
)
|
完成之后,运行app.py文件。可以查看到相关输出。
回到RYU中,之前一篇博客介绍了Ryu的main函数。在ryu/ryu/cmd/manager.py文件中我们可以看到如下的代码:
1
2
3
4
5
6
7
|
CONF
.
register_cli_opts
(
[
cfg
.
ListOpt
(
'app-lists'
,
default
=
[
]
,
help
=
'application module name to run'
)
,
cfg
.
MultiStrOpt
(
'app'
,
positional
=
True
,
default
=
[
]
,
help
=
'application module name to run'
)
,
cfg
.
StrOpt
(
'pid-file'
,
default
=
None
,
help
=
'pid file name'
)
,
]
)
|
以上的注册了三个Option,其中的app-lists和app参数是运行ryu-manager时的参数,即APP的名称。在以下的main函数中,我们可以看到首先获取了输入的参数,若参数为空,则默认开启ofp_handler应用。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
def
main
(
args
=
None
,
prog
=
None
)
:
try
:
CONF
(
args
=
args
,
prog
=
prog
,
project
=
'ryu'
,
version
=
'ryu-manager %s'
%
version
,
default_config_files
=
[
'/usr/local/etc/ryu/ryu.conf'
]
)
except
cfg
.
ConfigFilesNotFoundError
:
CONF
(
args
=
args
,
prog
=
prog
,
project
=
'ryu'
,
version
=
'ryu-manager %s'
%
version
)
log
.
init_log
(
)
if
CONF
.
pid_file
:
import
os
with
open
(
CONF
.
pid_file
,
'w'
)
as
pid_file
:
pid_file
.
write
(
str
(
os
.
getpid
(
)
)
)
app_lists
=
CONF
.
app_lists
+
CONF
.
app
# keep old behaivor, run ofp if no application is specified.
if
not
app_lists
:
app_lists
=
[
'ryu.controller.ofp_handler'
]
|
oslo模块使用能够使得整个工程的不同模块可以使用同一个配置文件,从而减少了命令冲突的可能,此外,oslo提供的模板,可以让命令解析更方便。oslo模块以此优势被广泛应用与大型项目中,如openstack。
oslo模块中使用了argparse。argparse是python标准库中的模块。以下以一个简单例子介绍此模块,更详细的中文教程,可以查看《Python中的命令行解析工具介绍》。
在argparse模块中定义了ArgumentParser类。我们可以调用该类的add_argument函数添加参数。其函数说明如下:
1
|
ArgumentParser
.
add_argument
(
name
or
flags
.
.
.
[
,
action
]
[
,
nargs
]
[
,
const
]
[
,
default
]
[
,
type
]
[
,
choices
]
[
,
required
]
[
,
help
]
[
,
metavar
]
[
,
dest
]
)
|
从以上说明可以看出,add_argument函数可以添加action, type, choices,help等重要的属性。具体参数解释,引用自《Python中的命令行解析工具介绍》如下:
使用案例举例如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
#filename:prog.py
import
argparse
parser
=
argparse
.
ArgumentParser
(
)
# parser.add_argument("echo", help="Print the arguments.")
parser
.
add_argument
(
"-v"
,
"--verbosity"
,
default
=
0
,
action
=
"count"
,
help
=
"increase output verbosity."
)
parser
.
add_argument
(
"x"
,
type
=
int
,
help
=
"the base"
)
parser
.
add_argument
(
"y"
,
type
=
int
,
help
=
"the exponent"
)
#parser.add_argument("square", help="Return square of given number.", type=int)
args
=
parser
.
parse_args
(
)
answer
=
args
.
x
*
*
args
.
y
if
args
.
verbosity
>=
2
:
print
"{} to the power {} equals {}"
.
format
(
args
.
x
,
args
.
y
,
answer
)
elif
args
.
verbosity
>=
1
:
print
"{}^{} =={}"
.
format
(
args
.
x
,
args
.
y
,
answer
)
else
:
print
answer
|
可以通过一下命令运行prog.py去查看到相关信息:
1
2
3
4
|
python
prog
.py
-
h
python
prog
.py
python
prog
.py
2
5
-
v
python
prog
.py
2
5
-
vv
|
查看原文:http://www.zoues.com/index.php/2015/08/25/oslo-config/