共计 8365 个字符,预计需要花费 21 分钟才能阅读完成。
这篇文章主要介绍 ceph-deploy 中源码结构与 cli 是怎么样的,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!
ceph-deploy 源码分析(一)——源码结构与 cli
ceph-deploy 是部署 Ceph 集群的工具,可以通过 SSH 方式往远程主机上安装 Ceph 软件包、创建集群、增加监视器、收集(或销毁)密钥、增加 OSD 和元数据服务器、配置管理主机,甚至拆除集群。
ceph-deploy 使用 Python 开发,GitHub 为 https://github.com/ceph/ceph-deploy。本次源码分析的 ceph-deploy 版本为 1.5.37。
源码结构
ceph-deploy-1.5.37 源码目录
├── ceph_deploy # ceph-deploy 源码目录
├── ceph_deploy.egg-info # egg-info 目录
├── CONTRIBUTING.rst # 贡献指南
├── LICENSE # MIT LICENSE
├── MANIFEST.in # 打包规则
├── PKG-INFO # PKG-INFO 文件
├── README.rst # ceph-deploy 介绍
├── scripts # 启动脚本目录
├── setup.cfg # setup.py 配置
├── setup.py # ceph-deploy 安装脚本
├── tox.ini # 标准化测试
└── vendor.py
ceph_deploy 源码目录文件
├── admin.py # 子命令 admin 模块,将 ceph.conf 和 client.admin key push 到远程主机
├── calamari.py # 子命令 calamari 模块,连接 calamari master
├── cli.py # CLI 入口
├── cliutil.py # 为装饰器函数增加 priority
├── conf # ceph.conf 与 cephdeploy.conf 读取与写入相关操作目录
├── config.py # 子命令 config 模块,push ceph.conf 文件到远程主机;从远程主机 pull ceph.conf 文件
├── connection.py # 连接本地主机、远程主机
├── exc.py # 异常处理 Error
├── forgetkeys.py # 子命令 forgetkeys 模块,本地移除 authentication keys
├── gatherkeys.py # 子命令 gatherkeys 模块,从 mon 主机上拉取 authentication keys
├── hosts # ceph-deploy 在不同操作系统(centos、debian、fedora、rhel、suse)的操作
├── __init__.py # 初始化版本号信息,当前版本 1.5.37
├── install.py # 子命令 install 模块,安装、卸载 ceph 包,清除数据
├── lib # vendor 类库
├── mds.py # 子命令 mds 模块,mds 管理
├── misc.py # 其他工具类,比如:mon host 组装 tuples
├── mon.py # 子命令 mon 模块,mon 管理
├── new.py # 子命令 new 模块,部署集群
├── osd.py # 子命令 osd 模块,osd 管理
├── pkg.py # 子命令 pkg 模块,逗号分隔的包安装、卸载
├── repo.py # 子命令 repo 模块,添加 yum repo
├── rgw.py # 子命令 rgw 模块,rgw 管理
├── tests # 测试文件目录
├── util # util 目录
└── validate.py # 参数校验函数
源码入口
script 目录下的 ceph-deploy 文件是 ceph-deploy 的入口,安装之后是 /usr/bin/ceph-deploy。
ceph-deploy 的__main__函数调用 ceph_deploy.cli 的 main 函数
...
from ceph_deploy.cli import main
if __name__ == __main__ :
sys.exit(main())
cli 模块
cli.py 是命令行操作模块。
main 函数调用_main 函数
def main(args=None, namespace=None):
try:
_main(args=args, namespace=namespace)
finally:
# This block is crucial to avoid having issues with
# Python spitting non-sense thread exceptions. We have already
# handled what we could, so close stderr and stdout.
if not os.environ.get(CEPH_DEPLOY_TEST):
try:
sys.stdout.close()
except:
pass
try:
sys.stderr.close()
except:
pass
_main 函数
设置日志:Console Logger 与 File Logger 添加到 root_logger
调用 argparse 模块,解析 cli 参数
调用 conf 目录下的 ceph-deploy 模块 set_overrides 函数,从当前目录的 cephdeploy.conf 或~/.cephdeploy.conf 文件获取 ceph-deploy-global、ceph-deploy-[subcmd]配置项写入 args
调用执行 subcmd 相应的模块
@catches((KeyboardInterrupt, RuntimeError, exc.DeployError,), handle_all=True)
def _main(args=None, namespace=None):
# Set console logging first with some defaults, to prevent having exceptions
# before hitting logging configuration. The defaults can/will get overridden
# later.
# Console Logger
# 命令行控制台日志
sh = logging.StreamHandler()
# 不同级别的日志,使用不同的颜色区别:DEBUG 蓝色;WARNIN 黄色;ERROR 红色;INFO 白色
sh.setFormatter(log.color_format())
# 设置日志级别为 WARNING
sh.setLevel(logging.WARNING)
# because we re in a module already, __name__ is not the ancestor of
# the rest of the package; use the root as the logger for everyone
# root_logger 日志
root_logger = logging.getLogger()
# allow all levels at root_logger, handlers control individual levels
# 设置 root_logger 日志级别为 DEBUG
root_logger.setLevel(logging.DEBUG)
# 将 sh 添加到 root_logger
root_logger.addHandler(sh)
# 获取解析 cli 的 argparse,调用 argparse 模块
parser = get_parser()
if len(sys.argv) 2:
parser.print_help()
sys.exit()
else:
# 解析获取 sys.argv 中的 ceph-deploy 子命令和参数
args = parser.parse_args(args=args, namespace=namespace)
# 设置日志级别
console_loglevel = logging.DEBUG # start at DEBUG for now
if args.quiet:
console_loglevel = logging.WARNING
if args.verbose:
console_loglevel = logging.DEBUG
# Console Logger
sh.setLevel(console_loglevel)
# File Logger
# 文件日志
fh = logging.FileHandler(ceph-deploy-{cluster}.log .format(cluster=args.cluster))
fh.setLevel(logging.DEBUG)
fh.setFormatter(logging.Formatter(log.FILE_FORMAT))
# 将 fh 添加到 root_logger
root_logger.addHandler(fh)
# Reads from the config file and sets values for the global
# flags and the given sub-command
# the one flag that will never work regardless of the config settings is
# logging because we cannot set it before hand since the logging config is
# not ready yet. This is the earliest we can do.
# 从当前目录的 cephdeploy.conf 或~/.cephdeploy.conf 文件获取 ceph-deploy 配置覆盖命令行参数
args = ceph_deploy.conf.cephdeploy.set_overrides(args)
LOG.info(Invoked (%s): %s % (
ceph_deploy.__version__,
.join(sys.argv))
)
log_flags(args)
# args.func 为 cli 中的 subcmd 子命令,调用相应的模块
return args.func(args)
get_parser 函数 [ceph_deploy.cli] 以以下方式配置:
模块名 = 模块包名: 执行函数
比如:new = ceph_deploy.new:make
new 作为 ceph-deploy 的子命令,执行 ceph-deploy new 命令时,执行 make 函数
其他的模块也类似:
mon = ceph_deploy.mon:make
osd = ceph_deploy.osd:make
rgw = ceph_deploy.rgw:make
mds = ceph_deploy.mds:make
config = ceph_deploy.config:make
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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
def get_parser():
# 调用 argparse 模块
parser = argparse.ArgumentParser(
prog= ceph-deploy ,
formatter_ >
description= Easy Ceph deployment\n\n%s % __header__,
)
verbosity = parser.add_mutually_exclusive_group(required=False)
verbosity.add_argument(
-v , –verbose ,
action= store_true , dest= verbose , default=False,
help= be more verbose ,
)
verbosity.add_argument(
-q , –quiet ,
action= store_true , dest= quiet ,
help= be less verbose ,
)
parser.add_argument(
–version ,
action= version ,
version= %s % ceph_deploy.__version__,
help= the current installed version of ceph-deploy ,
)
parser.add_argument(
–username ,
help= the username to connect to the remote host ,
)
parser.add_argument(
–overwrite-conf ,
action= store_true ,
help= overwrite an existing conf file on remote host (if present) ,
)
parser.add_argument(
–cluster ,
metavar= NAME ,
help= name of the cluster ,
type=validate.alphanumeric,
)
parser.add_argument(
–ceph-conf ,
dest= ceph_conf ,
help= use (or reuse) a given ceph.conf file ,
)
sub = parser.add_subparsers(
title= commands ,
metavar= COMMAND ,
help= description ,
)
sub.required = True
# 获取 ceph_deploy.cli 下的 entry_points
entry_points = [
(ep.name, ep.load())
for ep in pkg_resources.iter_entry_points(ceph_deploy.cli)
]
# 根据 priority 排序
entry_points.sort(
key=lambda name_fn: getattr(name_fn[1], priority , 100),
)
# 将模块加入到子命令
for (name, fn) in entry_points:
p = sub.add_parser(
name,
description=fn.__doc__,
help=fn.__doc__,
)
if not os.environ.get(CEPH_DEPLOY_TEST):
p.set_defaults(cd_conf=ceph_deploy.conf.cephdeploy.load())
# flag if the default release is being used
p.set_defaults(default_release=False)
fn(p)
p.required = True
parser.set_defaults(
cluster= ceph ,
)
return parser
argparse 模块
cli 命令的解析使用了 argparse.py 模块。argparse 是 Python 标准库中命令行选项、参数和子命令的解析器,其是为替代已经过时的 optparse 模块,argparse 在 Python2.7 中被引入。
argparse 模块请参考
https://docs.python.org/2.7/library/argparse.html
http://python.usyiyi.cn/translate/python_278/library/argparse.html
set_overrides 函数
conf 目录下的 ceph-deploy 模块 set_overrides 函数
调用 load()函数
判断 ceph-deploy 配置文件 ceph-deploy-global、ceph-deploy-[subcommand]配置项,调用 override_subcommand()函数写入 args。
def set_overrides(args, _conf=None):
Read the configuration file and look for ceph-deploy sections
to set flags/defaults from the values found. This will alter the
“args“ object that is created by argparse.
# Get the subcommand name to avoid overwritting values from other
# subcommands that are not going to be used
subcommand = args.func.__name__
command_section = ceph-deploy-%s % subcommand
# 加载 ceph-deploy 配置
conf = _conf or load()
for section_name in conf.sections():
if section_name in [ceph-deploy-global , command_section]:
# ceph-deploy-global、ceph-deploy-[subcommand]配置项写入 args
override_subcommand(
section_name,
conf.items(section_name),
args
)
return args
load 函数,调用 location()函数
1
2
3
4
5
def load():
parser = Conf()
# 读取解析 ceph-deploy 配置文件
parser.read(location())
return parser
location 函数,调用_locate_or_create()函数
1
2
3
4
5
6
def location():
Find and return the location of the ceph-deploy configuration file. If this
file does not exist, create one in a default location.
return _locate_or_create()
_locate_or_create 函数,判断当前目录的 cephdeploy.conf 或~/.cephdeploy.conf 文件是否存在。
如果都不存在则调用 create_stub 函数创建一个~/.cephdeploy.conf 文件。这个文件是根据模板创建的,内容为空。
如果存在(提前创建)cephdeploy.conf 或~/.cephdeploy.conf 文件,可以在文件中配置 public_network、cluster_network、overwrite-conf 等。
def _locate_or_create():
home_config = path.expanduser(~/.cephdeploy.conf)
# With order of importance
locations = [
path.join(os.getcwd(), cephdeploy.conf ),
home_config,
]
for location in locations:
if path.exists(location):
logger.debug(found configuration file at: %s % location)
return location
logger.info(could not find configuration file, will create one in $HOME)
create_stub(home_config)
return home_config
以上是“ceph-deploy 中源码结构与 cli 是怎么样的”这篇文章的所有内容,感谢各位的阅读!希望分享的内容对大家有帮助,更多相关知识,欢迎关注丸趣 TV 行业资讯频道!