注意
本文档适用于 Ceph 开发版本。
ceph-mgr module developer’s guide
警告
这是开发者文档,描述了 Ceph 内部结构,这些结构仅与编写 ceph-mgr 模块的的人员相关。
创建一个模块
在 pybind/mgr/ 中创建一个 Python 模块。在您的模块中,创建一个从MgrModule
继承的类。为了使 ceph-mgr 能够检测到您的模块,您的目录必须包含一个名为module.py.
最重要需要重写的方法是:
a
serve
服务器类型模块的成员函数。此函数应永久阻塞。a
notify
如果您的模块需要在新的集群数据可用时采取行动的成员函数。a
handle_command
如果您的模块暴露了 CLI 命令的成员函数。但是,这种暴露命令的方法已弃用。有关更多详细信息,请参阅暴露命令.
一些模块与外部编排器接口以部署 Ceph 服务。这些模块也继承自Orchestrator
,它为基本类添加了其他方法。有关创建这些模块的更多信息,请参阅MgrModule
class. See
编排器模块。
安装一个模块
一旦您的模块位于配置设置指定的位置,您就可以通过mgr module path
configuration setting, you can enable it
via the ceph mgr module enable
command:
ceph mgr module enable mymodule
启用它。注意,MgrModule 接口不稳定,因此任何在 Ceph 树外维护的模块在运行任何较新或较旧的 Ceph 版本时都可能会中断。
日志记录功能来调试 ceph-mgr 模块。但是,有些人可能会想念
Ceph 管理器模块中的日志记录与其他任何 Python 程序一样进行。只需导入logging
包并使用logging.getLogger
function.
获取日志记录器实例。log_level
选项,该选项指定了模块当前的 Python 日志记录级别。
ceph config get mgr mgr/<module_name>/log_level
ceph config set mgr mgr/<module_name>/log_level <info|debug|critical|error|warning|>
模块启动时使用的日志记录级别由 mgr 守护进程当前的日志记录级别决定,除非之前使用log_level
命令使用config set ...
命令设置了
<= 0 是 CRITICAL
<= 1 是 WARNING
<= 4 是 INFO
<= +inf 是 DEBUG
我们可以通过运行以下命令来取消设置模块日志级别并回退到 mgr 守护进程的日志记录级别:
ceph config set mgr mgr/<module_name>/log_level ''
默认情况下,模块的日志消息由 Ceph 日志记录层处理,它们将被记录在 mgr 守护进程的日志文件中。
模块的日志文件将位于 mgr 守护进程的日志文件所在的同一目录,并具有以下名称模式:
<mgr_daemon_log_file_name>.<module_name>.log
要启用模块上的文件日志记录,请使用以下命令:
ceph config set mgr mgr/<module_name>/log_to_file true
当模块的文件日志记录启用时,模块的日志消息将停止写入 mgr 守护进程的日志文件,并且只写入模块的日志文件。
还可以检查状态并禁用文件日志记录,使用以下命令:
ceph config get mgr mgr/<module_name>/log_to_file
ceph config set mgr mgr/<module_name>/log_to_file false
暴露命令
有两种方法可以暴露命令。第一种方法涉及使用@CLICommand
装饰器来装饰处理命令所需的方法。第二种方法使用模块类中定义的COMMANDS
属性。
CLICommand 方法
@CLICommand('antigravity send to blackhole',
perm='rw')
def send_to_blackhole(self, oid: str, blackhole: Optional[str] = None, inbuf: Optional[str] = None):
'''
Send the specified object to black hole
'''
obj = self.find_object(oid)
if obj is None:
return HandleCommandResult(-errno.ENOENT, stderr=f"object '{oid}' not found")
if blackhole is not None and inbuf is not None:
try:
location = self.decrypt(blackhole, passphrase=inbuf)
except ValueError:
return HandleCommandResult(-errno.EINVAL, stderr='unable to decrypt location')
else:
location = blackhole
self.send_object_to(obj, location)
return HandleCommandResult(stdout=f"the black hole swallowed '{oid}'")
传递给CLICommand
的第一个参数是命令的“名称”。由于 Ceph 中有很多命令,我们倾向于使用公共前缀来分组相关的命令。在这种情况下,“antigravity”用于此目的。
The 类型注解对于ceph
CLI 报告命令的使用情况,并且管理器守护进程可以在将序列化的命令参数发送给处理方法之前将其转换为预期类型。使用正确实现的类型,还可以对参数执行一些基本的检查!
参数的名称是命令接口的一部分,因此更改它们时请考虑向后兼容性。但是,您不能更改inbuf
参数的名称,它用于传递由ceph --in-file
option.
指定的文件的内容。
管理器守护进程根据这些成分制作命令的使用情况,例如:
antigravity send to blackhole <oid> [<blackhole>] Send the specified object to black hole
作为ceph --help
.
输出的一部分@CLICommand
,如果您的命令只需要读取权限或写入权限,您也可以使用@CLIReadCommand
或@CLIWriteCommand
。
COMMANDS 方法
此方法使用模块的COMMANDS
类属性来定义一个像这样列表示例:
COMMANDS = [
{
"cmd": "foobar name=myarg,type=CephString",
"desc": "Do something awesome",
"perm": "rw",
# optional:
"poll": "true"
}
]
The cmd
每个条目的部分都像内部 Ceph mon 和 admin 套接字命令一样进行解析(有关示例,请参阅 Ceph 源代码中的 mon/MonCommands.h)。注意,“poll”字段是可选的,默认设置为 False;这表示向ceph
CLIceph -h
和其--period
选项)。
每个命令都期望返回一个元组(retval, stdout, stderr)
.
retval
是一个表示 libc 错误代码的整数(例如 EINVAL、EPERM,或 0 表示无错误),stdout
是包含任何非错误输出的字符串,stderr
是包含任何进度或错误说明输出的字符串。这两个字符串中的一个或两个可能为空。
实现handle_command
函数以响应发送的命令:
- MgrModule.handle_command(inbuf, cmd)
由 ceph-mgr 调用,请求插件处理它声明在 self.COMMANDS
返回状态代码、输出缓冲区和输出字符串。输出缓冲区用于数据结果,输出字符串用于信息性文本。
- 参数:
inbuf (字符串) -- 任何“-i <file>”提供给 ceph cli 的内容
cmd (字典) -- 来自 Ceph 的 cmdmap_t
- 返回类型:
Union
[HandleCommandResult
,Tuple
[int
,str
,str
]]- 返回:
HandleCommandResult 或一个包含三个元素的元组 (int, str, str)
响应和格式化
处理管理器命令的函数期望返回一个包含三个元素的元组,类型签名Tuple[int, str, str]
。第一个元素是返回值/错误代码,其中零表示无错误,负数errno通常用于错误情况。第二个元素对应于命令的“输出”。第三个元素对应于命令的“错误输出”(类似于 stderr)并且经常用于在返回代码非零时报告文本错误详细信息。类型mgr_module.HandleCommandResult
type
can also be used in lieu of a response tuple.
当命令的实现引发异常时,存在两种处理异常的方法。首先,命令函数可以不做任何事,让异常冒泡到管理器。当这种情况发生时,管理器将自动设置返回代码为 -EINVAL 并在错误输出中记录跟踪记录。这种跟踪记录在某些情况下可能非常长。第二种方法是使用 try-except 块在内部处理异常,并将异常转换为更适合异常的错误代码(例如,将 KeyError 转换为 -ENOENT)。在这种情况下,错误输出也可以由调用命令的人设置为更具体和可操作的值。
在许多情况下,尤其是在 Ceph 的较新版本中,管理器命令设计为向调用者返回结构化输出。结构化输出包括机器可解析的数据,例如 JSON、YAML、XML 等。JSON 是管理器命令返回的最常见的结构化输出格式。从 Ceph Reef 开始,有多个新的装饰器可以从object_format
模块中提供,帮助管理输出格式和自动处理异常。目的是大多数管理器命令的实现可以以习惯的方式(即“Pythonic”)编写,而装饰器将处理格式化输出和返回管理器响应元组所需的大部分工作。
在大多数情况下,新代码应使用Responder
装饰器。示例:
@CLICommand('antigravity list wormholes', perm='r')
@Responder()
def list_wormholes(self, oid: str, details: bool = False) -> List[Dict[str, Any]]:
'''List wormholes associated with the supplied oid.
'''
with self.open_wormhole_db() as db:
wormholes = db.query(oid=oid)
if not details:
return [{'name': wh.name} for wh in wormholes]
return [{'name': wh.name, 'age': wh.get_age(), 'destination': wh.dest}
for wh in wormholes]
格式化
The Responder
装饰器自动将 Python 对象转换为具有格式化输出的响应元组。默认情况下,此装饰器可以自动返回 JSON 和 YAML。在从命令行调用时,可以使用--format
标志来选择响应格式。如果未指定,将返回 JSON。自动格式化可以应用于任何基本 Python 类型:列表、字典、str、int 等。其他对象如果满足SimpleDataProvider
协议 - 它们提供to_simplified
方法,则可以自动格式化。函数to_simplified
function must return
a simplified representation of the object made out of basic types.
class MyCleverObject:
def to_simplified(self) -> Dict[str, int]:
# returns a python object(s) made up from basic types
return {"gravitons": 999, "tachyons": 404}
@CLICommand('antigravity list wormholes', perm='r')
@Responder()
def list_wormholes(self, oid: str, details: bool = False) -> MyCleverObject:
'''List wormholes associated with the supplied oid.
'''
...
自动输出格式化的行为可以自定义并扩展到其他类型的格式(XML、纯文本等)。由于这是一个复杂的话题,请参阅模块文档中的object_format
模块。
错误处理
Additionally, theResponder
装饰器可以自动处理将某些异常转换为响应元组。任何从ErrorResponseBase
继承的异常都将被自动转换为响应元组。ErrorResponse
, an exception type that
can be used directly and has arguments for the error output and return value or
it can be constructed from an existing exception using the wrap
类方法从现有异常构建的参数。wrap 类方法将自动使用异常文本,如果可用,则使用其他异常的errno
属性。
将我们的先前示例转换为使用此异常处理方法:
@CLICommand('antigravity list wormholes', perm='r')
@Responder()
def list_wormholes(self, oid: str, details: bool = False) -> List[Dict[str, Any]]:
'''List wormholes associated with the supplied oid.
'''
try:
with self.open_wormhole_db() as db:
wormholes = db.query(oid=oid)
except UnknownOIDError:
raise ErrorResponse(f"Unknown oid: {oid}", return_value=-errno.ENOENT)
except WormholeDBError as err:
raise ErrorResponse.wrap(err)
if not details:
return [{'name': wh.name} for wh in wormholes]
return [{'name': wh.name, 'age': wh.get_age(), 'destination': wh.dest}
for wh in wormholes]
Note
由于装饰器无法区分编程错误和预期错误条件,因此它不会尝试捕获所有异常。
Additional Decorators
The object_format
模块提供了额外的装饰器来补充Responder
but for cases where Responder
is insufficient or too “heavy
weight”.
The ErrorResponseHandler
装饰器存在于您仍然返回管理器响应元组但希望将错误作为异常处理(如典型 Python 代码)的情况。简而言之,它就像must still
return a manager response tuple but want to handle errors as exceptions (as in
typical Python code). In short, it works like Responder
but only with
regards to exceptions. Just like Responder
it handles exceptions that
inherit from ErrorResponseBase
. This can be useful in cases where you need
to return raw data in the output. Example:
@CLICommand('antigravity dump config', perm='r')
@ErrorResponseHandler()
def dump_config(self, oid: str) -> Tuple[int, str, str]:
'''Dump configuration
'''
# we have no control over what data is inside the blob!
try:
blob = self.fetch_raw_config_blob(oid)
return 0, blob, ''
except KeyError:
raise ErrorResponse("Blob does not exist", return_value=-errno.ENOENT)
The EmptyResponder
装饰器存在于在成功情况下不应生成任何输出的情况下。如果您使用Responder
and
default JSON formatting you may always see outputs like {}
或[]
if the
command completes without error. Instead, EmptyResponder
helps you create
manager commands that obey the Rule of Silence when the command has no
interesting output to emit on success. The functions that EmptyResponder
decorate should always return None
. Like both Responder
和ErrorResponseHandler
exceptions that inhert from ErrorResponseBase
will
be automatically processed. Example:
@CLICommand('antigravity create wormhole', perm='rw')
@EmptyResponder()
def create_wormhole(self, oid: str, name: str) -> None:
'''Create a new wormhole.
'''
try:
with self.open_wormhole_db() as db:
wh = Wormhole(name)
db.insert(oid=oid, wormhole=wh)
except UnknownOIDError:
raise ErrorResponse(f"Unknown oid: {oid}", return_value=-errno.ENOENT)
except InvalidWormholeError as err:
raise ErrorResponse.wrap(err)
except WormholeDBError as err:
raise ErrorResponse.wrap(err)
配置选项
模块可以使用set_module_option
和get_module_option
methods.
Note
使用set_module_option
和get_module_option
加载和存储配置选项,以管理用户可见的配置选项,这些选项不是 blob(例如证书)。如果您想持久化模块内部数据或二进制配置数据,请考虑使用KV 存储.
您必须在MODULE_OPTIONS
类属性中声明您的可用配置选项,如下所示:
MODULE_OPTIONS = [
Option(name="my_option")
]
如果您尝试在MODULE_OPTIONS
中未声明的选项上使用 set_module_option 或 get_module_option,将引发异常。
您可以选择在模块中提供设置命令来执行高级验证。用户也可以使用正常的ceph config set命令来修改配置,其中管理器模块的配置选项的名称类似于mgr/<module name>/<option>.
如果配置选项根据 mgr 运行的节点而不同,则使用本地化 configuration (
get_localized_module_option
, set_localized_module_option
)。ceph config set
外部设置,其中键名类似于mgr/<module name>/<mgr id>/<option>
如果您需要加载和存储数据(例如,一些较大的、二进制的或多行数据),请使用 KV 存储,而不是配置选项(下一节将介绍)。
使用配置选项的提示:
读取速度快:ceph-mgr 保持一个本地内存副本,因此在这种情况下,您只需在每次使用选项时执行一次 get_module_option,而不是将其复制到变量中。
写操作会阻塞,直到值被持久化(即到监控器的往返),但另一个线程从另一个线程读取时会立即看到新值。
如果用户从命令行使用config set,则新值将立即对get_module_option可见,尽管 mon->mgr 更新是异步的,所以config set将在新的值在 mgr 上可见之前返回一小部分时间。
要删除配置值(即恢复默认值),只需将
None
传递给 set_module_option。
- MgrModule.get_module_option(key, default=无)
检索持久配置设置的值
- 返回类型:
Union
[bool
,int
,float
,str
,None
]
- MgrModule.set_module_option(key, val)
设置持久配置设置的值
- 参数:
key (字符串) --
- Raises:
ValueError-- 如果val无法解析或它超出指定的范围
- 返回类型:
None
- MgrModule.get_localized_module_option(key, default=无)
检索此 ceph-mgr 实例的本地化配置
- 返回类型:
Union
[bool
,int
,float
,str
,None
]
- MgrModule.set_localized_module_option(key, val)
设置此 ceph-mgr 实例的本地化配置
None
:return: str
KV 存储
模块可以访问一个私有的(每个模块一个)键值存储,它使用监控器的“config-key”命令实现。使用set_store
和get_store
方法从您的模块访问 KV 存储。
KV 存储命令的工作方式与配置命令类似。读取速度快,操作从本地缓存。写入操作会阻塞以进行持久化,并执行到监控器的往返。
此数据可以从 ceph-mgr 外部使用ceph config-key [get|set]
命令访问。键名遵循与配置选项相同的约定。请注意,从 ceph-mgr 外部更新的任何值都不会在运行中的模块中可见,直到下次重新启动。应鼓励用户不要从外部访问模块 KV 数据——如果用户需要填充数据,模块应提供特殊命令通过模块设置数据。
使用get_store_prefix
函数用于枚举特定前缀(即所有以特定子字符串开头的键)中的键。
- MgrModule.get_store(key, default=无)
从此模块的持久键值存储中获取值
- 返回类型:
Optional
[str
]
- MgrModule.set_store(key, val)
在此模块的持久键值存储中设置值。如果 val 是 None,则从存储中删除键
- 返回类型:
None
- MgrModule.get_localized_store(key, default=无)
- 返回类型:
Optional
[str
]
- MgrModule.set_localized_store(key, val)
- 返回类型:
None
- MgrModule.get_store_prefix(key_prefix)
获取键前缀为给定前缀的 KV 存储键值对字典
- 参数:
key_prefix (字符串) --
- 返回类型:
Dict
[str
,str
]- 返回:
字符串
访问集群数据
模块可以访问由 mgr 维护的 Ceph 集群状态的内存副本。访问器函数作为 MgrModule 的成员公开。
访问集群或守护进程状态的调用通常是从 Python 进入原生 C++ 例程。这样做有一些开销,但远小于调用 REST API 或调用 SQL 数据库。
对集群结构或守护进程元数据的访问没有一致性规则。例如,一个 OSD 可能存在于 OSDMap 中但没有元数据,或者反之亦然。在一个健康的集群上,这些将是非常罕见的瞬时状态,但模块应编写以应对这种可能性。
注意,这些访问器不能在模块__init__
函数中调用。这将导致循环锁定异常。
- MgrModule.get(data_name)
由插件调用以从 ceph-mgr 获取命名的集群对象。
- 参数:
data_name (字符串) -- 可以获取的有效事物是 osdmap_crush_map_text、osd_map、osd_map_tree、osd_map_crush、config、mon_map、fs_map、osd_metadata、pg_summary、io_rate、pg_dump、df、osd_stats、health、mon_status、devices、device <devid>、pg_stats、pool_stats、pg_ready、osd_ping_times、mgr_map、mgr_ips、modified_config_options、service_map、mds_metadata,
- 注意:
所有这些结构都有自己的 JSON 表示形式:实验或查看 C++
dump()
方法以了解它们。
- 返回类型:
Any
- MgrModule.get_server(hostname)
由插件调用以获取特定主机名的元数据 ceph-mgr。
这是由 ceph-mgr 从在特定服务器上运行的守护进程报告的守护进程元数据。
- 参数:
hostname (
str
) -- 一个主机名- 返回类型:
Dict
[str
,Union
[str
,List
[Dict
[str
,str
]]]]
- MgrModule.list_servers()
像
get_server
,但提供有关所有服务器的信息(即所有唯一主机名,这些主机名已在守护进程元数据中提到)- 返回:
所有服务器的信息列表
- 返回类型:
列表
- MgrModule.get_metadata(svc_type, svc_id, default=无)
获取特定服务的守护进程元数据。
ceph-mgr 异步获取元数据,因此在服务添加/删除的窗口时间内,元数据对模块不可用。
None
如果没有元数据可用,则返回- 参数:
svc_type (字符串) -- 服务类型(例如,‘mds’,‘osd’,‘mon’)
svc_id (字符串) -- 服务 ID。调用此
- 返回类型:
字典,或 None 如果没有找到元数据
- MgrModule.get_daemon_status(svc_type, svc_id)
获取特定服务守护进程的最新状态。
This method may return
None
如果没有状态信息可用,例如因为守护进程尚未完全启动。- 参数:
svc_type (
str
) -- 字符串(例如,‘rgw’)svc_id (
str
) -- 字符串
- 返回类型:
Dict
[str
,str
]- 返回:
字典,或 None 如果找不到服务
- MgrModule.get_unlabeled_perf_schema(svc_type, svc_name)
由插件调用以获取未标记的性能计数器模式信息。
- 参数:
svc_type (字符串) --
svc_name (字符串) --
- 返回类型:
Dict
[str
,Dict
[str
,Dict
[str
,Union
[str
,int
]]]]- 返回:
描述请求计数器的列表的字典
- MgrModule.get_unlabeled_counter(svc_type, svc_name, path)
由插件调用以获取特定服务上特定计数器的最新性能计数器数据。
- 参数:
svc_type (字符串) --
svc_name (字符串) --
path (字符串) -- 一个由子系统和计数器名称组成的周期性连接字符串,例如 “mds.inodes”。
- 返回类型:
Dict
[str
,List
[Tuple
[float
,int
]]]- 返回:
一个包含计数器名称及其值的字典。每个值是一个包含两个元组的列表 (timestamp, value)。如果没有数据可用,则此列表可能为空。
- MgrModule.get_latest_unlabeled_counter(svc_type, svc_name, path)
由插件调用以获取特定服务上特定计数器的最新性能未标记计数器数据点。
- 参数:
svc_type (字符串) --
svc_name (字符串) --
path (字符串) -- 一个由子系统和计数器名称组成的周期性连接字符串,例如 “mds.inodes”。
- 返回类型:
Dict
[str
,Union
[Tuple
[float
,int
],Tuple
[float
,int
,int
]]]- 返回:
返回一个包含两个元组 (timestamp, value) 或三个元组 (timestamp, value, count) 的列表。如果没有数据可用,则此列表可能为空。
- MgrModule.get_perf_schema(svc_type, svc_name)
由插件调用以获取性能计数器模式信息。
- 参数:
svc_type (字符串) --
svc_name (字符串) --
- 返回类型:
Dict
[str
,Dict
[str
,Dict
[str
,Union
[str
,int
]]]]- 返回:
描述请求计数器的列表的字典
- MgrModule.get_latest_counter(svc_type, svc_name, counter_name, sub_counter_name, labels)
由插件调用以获取特定服务上特定计数器的最新性能计数器数据点。
- 参数:
svc_type (字符串) --
svc_name (字符串) --
counter_name (字符串) -- 计数器的 key_name,例如 “osd_scrub_sh_repl”
sub_counter_name (字符串) -- key_name 下存在的计数器,例如 “successful_scrubs_elapsed”
labels (列表[(字符串, 字符串)]) -- 与计数器关联的标签,例如 [("level", "deep"), ("pooltype", "ec")]
- 返回类型:
Dict
[str
,Union
[Tuple
[float
,int
],Tuple
[float
,int
,int
]]]- 返回:
返回一个包含两个元组 (timestamp, value) 或三个元组 (timestamp, value, count) 的列表。如果没有数据可用,则此列表可能为空。
- MgrModule.get_mgr_id()
检索管理器守护进程的名称,其中当前正在执行插件(即活动管理器)。
- 返回类型:
str
- 返回:
字符串
- MgrModule.get_daemon_health_metrics()
获取每个守护进程的健康指标列表。这包括 MON 和 OSD 守护进程中的 SLOW_OPS 健康指标以及 OSD 的 PENDING_CREATING_PGS 健康指标。
- 返回类型:
Dict
[str
,List
[Dict
[str
,Any
]]]
暴露健康检查
模块可以引发第一类的 Ceph 健康检查,这些健康检查将报告在ceph status
输出中以及其他报告集群健康的地方。
如果您使用set_health_checks
报告问题,请确保在问题消失时再次调用它以清除您的健康检查。
- MgrModule.set_health_checks(checks)
设置模块的当前健康检查映射。参数是一个键名到信息的字典,形式如下:
{ 'CHECK_FOO': { 'severity': 'warning', # or 'error' 'summary': 'summary string', 'count': 4, # quantify badness 'detail': [ 'list', 'of', 'detail', 'strings' ], }, 'CHECK_BAR': { 'severity': 'error', 'summary': 'bars are bad', 'detail': [ 'too hard' ], }, }
- 参数:
列表-- 健康检查字典
- 返回类型:
None
如果 mons 停机怎么办?
管理器守护进程的大部分状态(例如集群地图)都从监控器获取。如果监控器集群不可访问,则任何活动管理器将继续运行,其最新的状态仍然保存在内存中。
但是,如果您正在创建一个向用户显示集群状态的模块,则您可能不希望通过显示过时的状态来误导他们。
要检查管理器守护进程当前是否具有到监控器集群的连接,请使用此函数:
- MgrModule.have_mon_connection()
检查此 ceph-mgr 守护进程是否具有到监控器的打开连接。如果没有,那么我们关于集群的信息可能已过时,并且/或者监控器集群已停机。
- 返回类型:
bool
如果您的模块无法运行,请报告
如果由于任何原因(例如缺少依赖项),您的模块无法运行,则您可以通过实现can_run
function.
- 静态 MgrModule.can_run()
实现此函数以报告模块的依赖项是否满足。例如,如果模块需要导入特定依赖项才能工作,请在文件作用域周围使用 try/except 块进行导入,然后在上述函数中报告导入失败。
这将在 C++ 代码中阻塞地调用,因此在此函数中不要执行任何可能阻塞的 I/O。
:返回一个包含布尔值和解释性字符串的 2 元组
- 返回类型:
Tuple
[bool
,str
]
注意,如果您的模块始终可以被导入,则此函数才能正常工作:如果您正在导入可能缺失的依赖项,则请在 try/except 块中进行导入,以便您的模块可以加载到足以使用can_run
即使依赖项缺失。
发送命令
提供了一个非阻塞设施来向集群发送监控器命令。
- MgrModule.send_command(result, svc_type, svc_id, command, tag, inbuf=无, *, one_shot=False)
由插件调用以向 mon 集群发送命令。
- 参数:
result (CommandResult) -- MgrModule 相同模块中的
CommandResult
类的实例,定义在 MgrModule 的同一模块中。它充当完成并存储命令的输出。如果您想阻塞等待完成,请使用CommandResult.wait()
inbufsvc_type (字符串) --
svc_id (字符串) --
command (字符串) -- a JSON-serialized command. This uses the same format as the ceph command line, which is a dictionary of command arguments, with the extra
prefix
key containing the command name itself. Consult MonCommands.h for available commands and their expected arguments.tag (字符串) -- used for nonblocking operation: when a command completes, the
notify()
callback on the MgrModule instance is triggered, with notify_type set to “command”, and notify_id set to the tag of the command.inbuf (字符串) -- input buffer for sending additional data.
one_shot (bool) -- a keyword-only param to make the command abort with EPIPE when the target resets or refuses to reconnect
- 返回类型:
None
接收通知
The manager daemon calls the notify
function on all active modules
when certain important pieces of cluster state are updated, such as the
cluster maps.
The actual data is not passed into this function, rather it is a cue for the module to go and read the relevant structure if it is interested. Most modules ignore most types of notification: to ignore a notification simply return from this function without doing anything.
- MgrModule.notify(notify_type, notify_id)
Called by the ceph-mgr service to notify the Python plugin that new state is available. This method is only called for notify_types that are listed in the NOTIFY_TYPES string list member of the module class.
- 参数:
notify_type (
NotifyType
) -- string indicating what kind of notification, such as osd_map, mon_map, fs_map, mon_status, health, pg_summary, command, service_mapnotify_id (
str
) -- string (may be empty) that optionally specifies which entity is being notified about. With “command” notifications this is set to the tagfrom send_command
.
- 返回类型:
None
访问 RADOS 或 CephFS
如果您想使用 librados python API 访问存储在 Ceph 集群中的数据,您可以访问您的rados
属性。这是一个MgrModule
实例的rados.Rados
实例,它使用 mgr 守护进程现有的 Ceph 上下文(C++ Ceph 代码的内部细节)构建的。
始终使用此专门构建的 librados 实例,而不是手动构建一个。
类似地,如果您正在使用 libcephfs 访问文件系统,则使用 libcephfscreate_with_rados
从 librados 实例构建它,从而继承正确的上下文。MgrModule.rados
librados instance, and thereby inherit the correct context.
请记住,您的模块可能在集群的其他部分停机时运行:不要假设 librados 或 libcephfs 调用将立即返回——请考虑是否要使用超时或如果集群其他部分未完全可用,则阻塞。
实现备用模式
对于某些模块,在备用管理器守护进程以及活动守护进程上运行也很有用。例如,一个 HTTP 服务器可以有效地从备用管理器提供 HTTP 重定向响应,以便用户可以将其浏览器指向任何管理器守护进程,而无需担心哪个是活动的。
备用管理器守护进程会查找每个模块中的StandbyModule
的子类。如果找不到该类,则模块在备用守护进程上不会被使用。如果找到了该类,则调用其serve
方法。备用模式的实现必须从StandbyModule
must inherit from mgr_module.MgrStandbyModule
.
继承。The interface ofMgrStandbyModule
与MgrModule
相比,限制得多——没有 Ceph 集群状态可用于模块。serve
和shutdown
方法与正常模块类中的方法一样使用。Theget_active_uri
方法使备用模块能够发现其活动对端的地址,以便进行重定向。请参阅 Ceph 源代码中的MgrStandbyModule
定义以获取完整的方法列表。
要了解如何使用此接口的示例,请查看dashboard
模块。
模块之间通信
模块可以调用其他模块的成员函数。
- MgrModule.remote(module_name, method_name, *args, **kwargs)
调用另一个模块上的方法。所有参数和来自其他模块的返回值都必须是可序列化的。
限制:不要在调用方法时导入任何模块。否则,您将在 Python 2 中获得错误:
RuntimeError('cannot unmarshal code objects in restricted execution mode',)
- 参数:
module_name (
str
) -- 其他模块的名称。如果模块未加载,将引发 ImportError 异常。method_name (
str
) -- 方法名称。如果不存在,将引发 NameError 异常。args (
Any
) -- 参数元组kwargs (
Any
) -- 关键字参数字典
- Raises:
RuntimeError--在方法中引发的任何错误都将转换为 RuntimeError
ImportError-- 没有此模块
- 返回类型:
Any
请确保处理ImportError
以处理模块未启用的情况。
如果远程方法引发 Python 异常,这将转换为调用方的 RuntimeError,其中消息字符串描述了最初抛出的异常。如果您希望干净地处理某些错误,最好修改远程方法以返回错误值而不是引发异常。
写入时,模块之间的调用没有副本或序列化,因此当您返回 Python 对象时,您正在返回对调用模块的引用。建议依赖此引用传递,因为未来的实现可能会更改以序列化参数和返回值。firefly 发布。Firefly 将延迟至少另一个冲刺,以便我们可以对新代码进行一些操作经验,并进行一些额外的测试,然后再承诺长期支持。 to rely on this reference passing, as in future the implementation may change to serialize arguments and return values.
清洁关闭
如果模块实现了serve()
方法,则它还应该实现shutdown()
方法以干净地关闭:行为不良的模块可能会阻止 ceph-mgr 的干净关闭。
限制
不可能在模块的__init__()
方法中回调 C++ 代码。例如,调用self.get_module_option()
在此点将导致 ceph-mgr 中的断言失败。对于实现serve()
方法中进行大多数初始化。
调试
显然,我们可以始终使用日志记录功能来调试 ceph-mgr 模块。但是,有些人可能会想念 facility
for debugging a ceph-mgr module. But some of us might miss PDB和交互式 Python 解释器。是的,我们也可以在开发 ceph-mgr 模块时使用它们!ceph_mgr_repl.py
可以将您放入一个与selftest
模块对话的交互式 shell 中。使用此工具,您可以查看和操作 ceph-mgr 模块,并使用与我们在 Python 命令行解释器中使用的相同方式使用所有公开的设施。要使用ceph_mgr_repl.py
,我们需要
准备一个 Ceph 集群
启用
selftest
模块设置必要的环境变量
启动该工具
以下是一个示例会话,其中通过在提示符处输入print(mgr.version)
来查询 Ceph 版本。稍后timeit
模块被导入以测量mgr.get_mgr_id().
$ cd build
$ MDS=0 MGR=1 OSD=3 MON=1 ../src/vstart.sh -n -x
$ bin/ceph mgr module enable selftest
$ ../src/pybind/ceph_mgr_repl.py --show-env
$ export PYTHONPATH=/home/me/ceph/src/pybind:/home/me/ceph/build/lib/cython_modules/lib.3:/home/me/ceph/src/python-common:$PYTHONPATH
$ export LD_LIBRARY_PATH=/home/me/ceph/build/lib:$LD_LIBRARY_PATH
$ export PYTHONPATH=/home/me/ceph/src/pybind:/home/me/ceph/build/lib/cython_modules/lib.3:/home/me/ceph/src/python-common:$PYTHONPATH
$ export LD_LIBRARY_PATH=/home/me/ceph/build/lib:$LD_LIBRARY_PATH
$ ../src/pybind/ceph_mgr_repl.py
$ ../src/pybind/ceph_mgr_repl.py
Python 3.9.2 (default, Feb 28 2021, 17:03:44)
[GCC 10.2.1 20210110] on linux
Type "help", "copyright", "credits" or "license" for more information.
(MgrModuleInteractiveConsole)
[mgr self-test eval] >>> print(mgr.version)
ceph version Development (no_version) quincy (dev)
[mgr self-test eval] >>> from timeit import timeit
[mgr self-test eval] >>> timeit(mgr.get_mgr_id)
0.16303414600042743
[mgr self-test eval] >>>
如果您想与selftest
使用此工具“谈话”其他 ceph-mgr 模块,您可以像添加到mgr self-test eval
命令一样向要调试的模块添加一个命令。或者,我们可以通过将selftest
中eval()
方法提升为专门的混合类并从它继承您的 class and inherit your MgrModule
子类,使其更简单。假设命令的前缀是mgr my-module eval
,
one can just put
../src/pybind/ceph_mgr_repl.py --prefix "mgr my-module eval"
放在要调试的模块中即可。
ceph-mgr python 接口尚未确定。如果您有未满足当前接口的需求,请在 ceph-devel 邮件列表上提出。虽然希望避免接口膨胀,但如果有一个很好的理由,当有理由时,通常很容易将现有数据暴露给 Python 代码。
由 Ceph 基金会带给您
Ceph 文档是一个社区资源,由非盈利的 Ceph 基金会资助和托管Ceph Foundation. 如果您想支持这一点和我们的其他工作,请考虑加入现在加入.