Merge branch 'master' into fix-gw-api-erros

This commit is contained in:
JianBo He 2022-10-28 10:18:21 +08:00 committed by GitHub
commit d995842f36
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
61 changed files with 1041 additions and 806 deletions

View File

@ -113,7 +113,7 @@ the check/consume will succeed, but it will be forced to wait for a short period
burst {
desc {
en: """The burst, This value is based on rate.</br>
en: """The burst, This value is based on rate.<br/>
This value + rate = the maximum limit that can be achieved when limiter burst."""
zh: """突发速率。
突发速率允许短时间内速率超过设置的速率值,突发速率 + 速率 = 当前桶能达到的最大速率值"""
@ -171,7 +171,7 @@ Once the limit is reached, the restricted client will be slow down even be hung
en: """The bytes_in limiter.
This is used to limit the inbound bytes rate for this EMQX node.
Once the limit is reached, the restricted client will be slow down even be hung for a while."""
zh: """流入字节率控制器.
zh: """流入字节率控制器
这个是用来控制当前节点上的数据流入的字节率,每条消息将会消耗和其二进制大小等量的令牌,当达到最大速率后,会话将会被限速甚至被强制挂起一小段时间"""
}
label: {

File diff suppressed because it is too large Load Diff

View File

@ -18,6 +18,7 @@
{emqx_license,2}.
{emqx_management,1}.
{emqx_management,2}.
{emqx_management,3}.
{emqx_mgmt_api_plugins,1}.
{emqx_mgmt_cluster,1}.
{emqx_mgmt_trace,1}.

View File

@ -124,7 +124,10 @@ filter_result(Delivery) ->
max_client_num() ->
emqx:get_config([rpc, tcp_client_num], ?DefaultClientNum).
-spec unwrap_erpc(emqx_rpc:erpc(A)) -> A | {error, _Err}.
-spec unwrap_erpc(emqx_rpc:erpc(A) | [emqx_rpc:erpc(A)]) -> A | {error, _Err} | list().
unwrap_erpc(Res) when is_list(Res) ->
[unwrap_erpc(R) || R <- Res];
unwrap_erpc({ok, A}) ->
A;
unwrap_erpc({throw, A}) ->

View File

@ -1698,7 +1698,7 @@ desc("stats") ->
desc("authorization") ->
"Settings for client authorization.";
desc("mqtt") ->
"Global MQTT configuration.</br>\n"
"Global MQTT configuration.<br/>"
"The configs here work as default values which can be overridden\n"
"in <code>zone</code> configs";
desc("cache") ->
@ -2115,11 +2115,11 @@ ref(Module, StructName) -> hoconsc:ref(Module, StructName).
mk_duration(Desc, OverrideMeta) ->
DefaultMeta = #{
desc => Desc ++
" Time interval is a string that contains a number followed by time unit:</br>\n"
" Time interval is a string that contains a number followed by time unit:<br/>"
"- `ms` for milliseconds,\n"
"- `s` for seconds,\n"
"- `m` for minutes,\n"
"- `h` for hours;\n</br>"
"- `h` for hours;\n<br/>"
"or combination of whereof: `1h5m0s`"
},
hoconsc:mk(typerefl:alias("string", duration()), maps:merge(DefaultMeta, OverrideMeta)).

View File

@ -57,7 +57,7 @@ emqx_authn_jwt {
endpoint {
desc {
en: """JWKS endpoint, it's a read-only endpoint that returns the server's public key set in the JWKS format."""
zh: """JWKS 端点, 它是一个以 JWKS 格式返回服务端的公钥集的只读端点。"""
zh: """JWKS 端点 它是一个以 JWKS 格式返回服务端的公钥集的只读端点。"""
}
label {
en: """JWKS Endpoint"""

View File

@ -2,7 +2,7 @@ emqx_authz_api_cache {
authorization_cache_delete {
desc {
en: """Clean all authorization cache in the cluster."""
zh: """清除集群中所有鉴权数据缓存"""
zh: """清除集群中所有授权数据缓存。"""
}
}
}

View File

@ -1,8 +1,8 @@
emqx_authz_api_schema {
enable {
desc {
en: """Set to <code>true</code> or <code>false</code> to disable this ACL provider"""
zh: """设为 <code>true</code> 或 <code>false</code> 以启用或禁用此访问控制数据源"""
en: """Set to <code>true</code> or <code>false</code> to disable this ACL provider."""
zh: """设为 <code>true</code> 或 <code>false</code> 以启用或禁用此访问控制数据源"""
}
label {
en: """enable"""
@ -13,7 +13,7 @@ emqx_authz_api_schema {
type {
desc {
en: """Backend type."""
zh: """数据后端类型"""
zh: """数据后端类型"""
}
label {
en: """type"""
@ -26,7 +26,7 @@ emqx_authz_api_schema {
rules {
desc {
en: """Authorization static file rules."""
zh: """静态鉴权文件规则"""
zh: """静态授权文件规则。"""
}
label {
en: """rules"""
@ -39,7 +39,7 @@ emqx_authz_api_schema {
method {
desc {
en: """HTTP method."""
zh: """HTTP 请求方法"""
zh: """HTTP 请求方法"""
}
label {
en: """method"""
@ -50,7 +50,7 @@ emqx_authz_api_schema {
url {
desc {
en: """URL of the auth server."""
zh: """认证服务器 URL"""
zh: """认证服务器 URL"""
}
label {
en: """url"""
@ -72,7 +72,7 @@ emqx_authz_api_schema {
headers_no_content_type {
desc {
en: """List of HTTP headers (without <code>content-type</code>)."""
zh: """HTTP Headers 列表(无 <code>content-type</code>"""
zh: """HTTP Headers 列表(无 <code>content-type</code>"""
}
label {
en: """headers_no_content_type"""
@ -83,7 +83,7 @@ emqx_authz_api_schema {
body {
desc {
en: """HTTP request body."""
zh: """HTTP 请求体"""
zh: """HTTP 请求体"""
}
label {
en: """body"""
@ -94,7 +94,7 @@ emqx_authz_api_schema {
request_timeout {
desc {
en: """Request timeout."""
zh: """请求超时时间"""
zh: """请求超时时间"""
}
label {
en: """request_timeout"""
@ -111,7 +111,7 @@ emqx_authz_api_schema {
collection {
desc {
en: """`MongoDB` collection containing the authorization data."""
zh: """`MongoDB` 鉴权数据集"""
zh: """`MongoDB` 授权数据集。"""
}
label {
en: """collection"""
@ -153,7 +153,7 @@ Filter supports the following placeholders:
cmd {
desc {
en: """Database query used to retrieve authorization data."""
zh: """访问控制数据查询命令"""
zh: """访问控制数据查询命令"""
}
label {
en: """cmd"""
@ -166,7 +166,7 @@ Filter supports the following placeholders:
query {
desc {
en: """Database query used to retrieve authorization data."""
zh: """访问控制数据查询语句"""
zh: """访问控制数据查询语句"""
}
label {
en: """query"""
@ -178,8 +178,8 @@ Filter supports the following placeholders:
position {
desc {
en: """Where to place the source"""
zh: """认证数据源位置"""
en: """Where to place the source."""
zh: """认证数据源位置"""
}
label {
en: """position"""

View File

@ -2,14 +2,14 @@ emqx_authz_api_settings {
authorization_settings_get {
desc {
en: """Get authorization settings"""
zh: """获取权配置"""
zh: """获取权配置"""
}
}
authorization_settings_put {
desc {
en: """Update authorization settings"""
zh: """更新权配置"""
zh: """更新权配置"""
}
}
}

View File

@ -2,56 +2,56 @@ emqx_authz_api_sources {
authorization_sources_get {
desc {
en: """List all authorization sources"""
zh: """列出所有权数据源"""
zh: """列出所有权数据源"""
}
}
authorization_sources_post {
desc {
en: """Add a new source"""
zh: """添加权数据源"""
zh: """添加权数据源"""
}
}
authorization_sources_type_get {
desc {
en: """Get a authorization source"""
zh: """获取指定类型的权数据源"""
zh: """获取指定类型的权数据源"""
}
}
authorization_sources_type_put {
desc {
en: """Update source"""
zh: """更新指定类型的权数据源"""
zh: """更新指定类型的权数据源"""
}
}
authorization_sources_type_delete {
desc {
en: """Delete source"""
zh: """删除指定类型的权数据源"""
zh: """删除指定类型的权数据源"""
}
}
authorization_sources_type_status_get {
desc {
en: """Get a authorization source"""
zh: """获取指定权数据源的状态"""
zh: """获取指定权数据源的状态"""
}
}
authorization_sources_type_move_post {
desc {
en: """Change the exection order of sources"""
zh: """更新权数据源的优先执行顺序"""
zh: """更新权数据源的优先执行顺序"""
}
}
sources {
desc {
en: """Authorization source"""
zh: """权数据源列表"""
zh: """权数据源列表"""
}
label {
en: """sources"""
@ -62,7 +62,7 @@ emqx_authz_api_sources {
sources {
desc {
en: """Authorization sources"""
zh: """权数据源列表"""
zh: """权数据源列表"""
}
label {
en: """sources"""
@ -84,7 +84,7 @@ emqx_authz_api_sources {
source {
desc {
en: """Authorization source"""
zh: """权数据源"""
zh: """权数据源"""
}
label {
en: """source"""

View File

@ -2,41 +2,41 @@ emqx_authz_schema {
sources {
desc {
en: """
Authorization data sources.</br>
Authorization data sources.<br/>
An array of authorization (ACL) data providers.
It is designed as an array, not a hash-map, so the sources can be
ordered to form a chain of access controls.</br>
ordered to form a chain of access controls.<br/>
When authorizing a 'publish' or 'subscribe' action, the configured
sources are checked in order. When checking an ACL source,
in case the client (identified by username or client ID) is not found,
it moves on to the next source. And it stops immediately
once an 'allow' or 'deny' decision is returned.</br>
once an 'allow' or 'deny' decision is returned.<br/>
If the client is not found in any of the sources,
the default action configured in 'authorization.no_match' is applied.</br>
the default action configured in 'authorization.no_match' is applied.<br/>
NOTE:
The source elements are identified by their 'type'.
It is NOT allowed to configure two or more sources of the same type.
"""
zh: """
鉴权数据源.</br>
鉴权(ACL)数据源的列表.
它被设计为一个数组,而不是一个散列映射,
所以可以作为链式访问控制.</br>
授权数据源。<br/>
授权ACL数据源的列表。
它被设计为一个数组,而不是一个散列映射,
所以可以作为链式访问控制。<br/>
当授权一个 'publish' 或 'subscribe' 行为时,
当授权一个 'publish' 或 'subscribe' 行为时
该配置列表中的所有数据源将按顺序进行检查。
如果在某个客户端未找到时(使用 ClientID 或 Username),
将会移动到下一个数据源. 直至得到 'allow' 或 'deny' 的结果.</br>
如果在某个客户端未找到时(使用 ClientID 或 Username)
将会移动到下一个数据源。直至得到 'allow' 或 'deny' 的结果。<br/>
如果在任何数据源中都未找到对应的客户端信息,
配置的默认行为 ('authorization.no_match') 将生效.</br>
如果在任何数据源中都未找到对应的客户端信息
配置的默认行为 ('authorization.no_match') 将生效。<br/>
注意:
数据源使用 'type' 进行标识.
使用同一类型的数据源多于一次不被允许.
注意
数据源使用 'type' 进行标识
使用同一类型的数据源多于一次不被允许
"""
}
label {
@ -83,7 +83,7 @@ It is NOT allowed to configure two or more sources of the same type.
file {
desc {
en: """Authorization using a static file."""
zh: """使用静态文件权"""
zh: """使用静态文件权"""
}
label {
en: """file"""
@ -109,7 +109,7 @@ and the old file will not be used anymore.
那么可以将该文件置于任何 EMQX 可以访问到的位置。
如果从 EMQX Dashboard 或 HTTP API 创建或修改了规则集,
那么EMQX将会生成一个新的文件并将它存放在 `data_dir` 下的 `authz` 子目录中,
那么EMQX将会生成一个新的文件并将它存放在 `data_dir` 下的 `authz` 子目录中
并从此弃用旧的文件。"""
}
label {
@ -123,7 +123,7 @@ and the old file will not be used anymore.
http_get {
desc {
en: """Authorization using an external HTTP server (via GET requests)."""
zh: """使用外部 HTTP 服务器权(GET 请求)。"""
zh: """使用外部 HTTP 服务器权(GET 请求)。"""
}
label {
en: """http_get"""
@ -134,7 +134,7 @@ and the old file will not be used anymore.
http_post {
desc {
en: """Authorization using an external HTTP server (via POST requests)."""
zh: """使用外部 HTTP 服务器权(POST 请求)。"""
zh: """使用外部 HTTP 服务器权(POST 请求)。"""
}
label {
en: """http_post"""
@ -156,7 +156,7 @@ and the old file will not be used anymore.
url {
desc {
en: """URL of the auth server."""
zh: """权 HTTP 服务器地址。"""
zh: """权 HTTP 服务器地址。"""
}
label {
en: """URL"""
@ -213,7 +213,7 @@ and the old file will not be used anymore.
mnesia {
desc {
en: """Authorization using a built-in database (mnesia)."""
zh: """使用内部数据库鉴权 (mnesia)."""
zh: """使用内部数据库授权mnesia"""
}
label {
en: """mnesia"""
@ -226,7 +226,7 @@ and the old file will not be used anymore.
mongo_single {
desc {
en: """Authorization using a single MongoDB instance."""
zh: """使用 MongoDB 鉴权(单实例)"""
zh: """使用 MongoDB 授权(单实例)。"""
}
label {
en: """mongo_single"""
@ -237,7 +237,7 @@ and the old file will not be used anymore.
mongo_rs {
desc {
en: """Authorization using a MongoDB replica set."""
zh: """使用 MongoDB 鉴权(副本集模式)"""
zh: """使用 MongoDB 授权(副本集模式)"""
}
label {
en: """mongo_rs"""
@ -248,7 +248,7 @@ and the old file will not be used anymore.
mongo_sharded {
desc {
en: """Authorization using a sharded MongoDB cluster."""
zh: """使用 MongoDB 鉴权(分片集群模式)"""
zh: """使用 MongoDB 授权(分片集群模式)。"""
}
label {
en: """mongo_sharded"""
@ -259,7 +259,7 @@ and the old file will not be used anymore.
collection {
desc {
en: """`MongoDB` collection containing the authorization data."""
zh: """`MongoDB` 鉴权数据集"""
zh: """`MongoDB` 授权数据集。"""
}
label {
en: """collection"""
@ -278,8 +278,8 @@ Filter supports the following placeholders:
zh: """
在查询中定义过滤条件的条件表达式。
过滤器支持如下占位符:
- <code>${username}</code>: 将在运行时被替换为客户端连接时使用的用户名
- <code>${clientid}</code>: 将在运行时被替换为客户端连接时使用的客户端标识符
- <code>${username}</code>将在运行时被替换为客户端连接时使用的用户名
- <code>${clientid}</code>将在运行时被替换为客户端连接时使用的客户端标识符
"""
}
label {
@ -293,7 +293,7 @@ Filter supports the following placeholders:
mysql {
desc {
en: """Authorization using a MySQL database."""
zh: """使用 MySOL 数据库权"""
zh: """使用 MySOL 数据库权"""
}
label {
en: """mysql"""
@ -306,7 +306,7 @@ Filter supports the following placeholders:
postgresql {
desc {
en: """Authorization using a PostgreSQL database."""
zh: """使用 PostgreSQL 数据库权"""
zh: """使用 PostgreSQL 数据库权"""
}
label {
en: """postgresql"""
@ -319,7 +319,7 @@ Filter supports the following placeholders:
redis_single {
desc {
en: """Authorization using a single Redis instance."""
zh: """使用 Redis 鉴权(单实例)"""
zh: """使用 Redis 授权(单实例)。"""
}
label {
en: """redis_single"""
@ -330,7 +330,7 @@ Filter supports the following placeholders:
redis_sentinel {
desc {
en: """Authorization using a Redis Sentinel."""
zh: """使用 Redis 鉴权(哨兵模式)"""
zh: """使用 Redis 授权(哨兵模式)。"""
}
label {
en: """redis_sentinel"""
@ -341,7 +341,7 @@ Filter supports the following placeholders:
redis_cluster {
desc {
en: """Authorization using a Redis cluster."""
zh: """使用 Redis 鉴权(集群模式)"""
zh: """使用 Redis 授权(集群模式)。"""
}
label {
en: """redis_cluster"""
@ -365,7 +365,7 @@ Filter supports the following placeholders:
query {
desc {
en: """Database query used to retrieve authorization data."""
zh: """访问控制数据查询语句/查询命令"""
zh: """访问控制数据查询语句/查询命令"""
}
label {
en: """query"""
@ -510,44 +510,44 @@ Filter supports the following placeholders:
metrics_total {
desc {
en: """The total number of times the authorization rule was triggered."""
zh: """权实例被触发的总次数。"""
zh: """权实例被触发的总次数。"""
}
label: {
en: """The Total Number of Times the Authorization Rule was Triggered"""
zh: """权实例被触发的总次数"""
zh: """权实例被触发的总次数"""
}
}
nomatch {
desc {
en: """The number of times that no authorization rules were matched."""
zh: """没有匹配到任何权规则的次数。"""
zh: """没有匹配到任何权规则的次数。"""
}
label: {
en: """The Number of Times that no Authorization Rules were Matched"""
zh: """没有匹配到任何权规则的次数"""
zh: """没有匹配到任何权规则的次数"""
}
}
allow {
desc {
en: """The number of times the authentication was successful."""
zh: """权成功的次数。"""
zh: """权成功的次数。"""
}
label: {
en: """The Number of Times the Authentication was Successful"""
zh: """权成功次数"""
zh: """权成功次数"""
}
}
deny {
desc {
en: """The number of authentication failures."""
zh: """权失败的次数。"""
zh: """权失败的次数。"""
}
label: {
en: """The Number of Authentication Failures"""
zh: """权失败次数"""
zh: """权失败次数"""
}
}
}

View File

@ -2,7 +2,7 @@ emqx_auto_subscribe_schema {
auto_subscribe {
desc {
en: """After the device logs in successfully, the subscription is automatically completed for the device through the pre-defined subscription representation. Supports the use of placeholders."""
zh: """设备登成功之后,通过预设的订阅表示符,为设备自动完成订阅。支持使用占位符。"""
zh: """设备登成功之后,通过预设的订阅表示符,为设备自动完成订阅。支持使用占位符。"""
}
lable {
en: """Auto Subscribe"""

View File

@ -15,13 +15,13 @@ emqx_bridge_schema {
desc {
en: """
The ID or the configs of the connector to be used for this bridge. Connector IDs must be of format:
<code>{type}:{name}</code>.</br>
<code>{type}:{name}</code>.<br/>
In config files, you can find the corresponding config entry for a connector by such path:
'connectors.{type}.{name}'.</br>
'connectors.{type}.{name}'.<br/>
"""
zh: """
Bridge 使用的 Connector 的 ID 或者配置。Connector ID 的格式必须为:<code>{type}:{name}</code>.</br>
在配置文件中,您可以通过以下路径找到 Connector 的相应配置条目:'connector.{type}.{name}'。</br>"""
Bridge 使用的 Connector 的 ID 或者配置。Connector ID 的格式必须为:<code>{type}:{name}</code>。<br/>
在配置文件中,您可以通过以下路径找到 Connector 的相应配置条目:'connector.{type}.{name}'。<br/>"""
}
label: {
en: "Connector ID"

View File

@ -25,16 +25,16 @@ emqx_bridge_webhook_schema {
config_url {
desc {
en: """
The URL of the HTTP Bridge.</br>
The URL of the HTTP Bridge.<br/>
Template with variables is allowed in the path, but variables cannot be used in the scheme, host,
or port part.</br>
or port part.<br/>
For example, <code> http://localhost:9901/${topic} </code> is allowed, but
<code> http://${host}:9901/message </code> or <code> http://localhost:${port}/message </code>
is not allowed.
"""
zh: """
HTTP Bridge 的 URL。</br>
路径中允许使用带变量的模板,但是 host port 不允许使用变量模板。</br>
HTTP Bridge 的 URL。<br/>
路径中允许使用带变量的模板,但是 host port 不允许使用变量模板。<br/>
例如,<code> http://localhost:9901/${topic} </code> 是允许的,
但是<code> http://${host}:9901/message </code>
或 <code> http://localhost:${port}/message </code>
@ -51,13 +51,13 @@ HTTP Bridge 的 URL。</br>
desc {
en: """
The MQTT topic filter to be forwarded to the HTTP server. All MQTT 'PUBLISH' messages with the topic
matching the local_topic will be forwarded.</br>
matching the local_topic will be forwarded.<br/>
NOTE: if this bridge is used as the action of a rule (EMQX rule engine), and also local_topic is
configured, then both the data got from the rule and the MQTT messages that match local_topic
will be forwarded.
"""
zh: """
发送到 'local_topic' 的消息都会转发到 HTTP 服务器。 </br>
发送到 'local_topic' 的消息都会转发到 HTTP 服务器。 <br/>
注意:如果这个 Bridge 被用作规则EMQX 规则引擎)的输出,同时也配置了 'local_topic' ,那么这两部分的消息都会被转发到 HTTP 服务器。
"""
}
@ -70,12 +70,12 @@ will be forwarded.
config_method {
desc {
en: """
The method of the HTTP request. All the available methods are: post, put, get, delete.</br>
Template with variables is allowed.</br>
The method of the HTTP request. All the available methods are: post, put, get, delete.<br/>
Template with variables is allowed.<br/>
"""
zh: """
HTTP 请求的方法。 所有可用的方法包括post、put、get、delete。</br>
允许使用带有变量的模板。</br>"""
HTTP 请求的方法。 所有可用的方法包括post、put、get、delete。<br/>
允许使用带有变量的模板。<br/>"""
}
label: {
en: "HTTP Method"
@ -86,11 +86,11 @@ HTTP 请求的方法。 所有可用的方法包括post、put、get、delete
config_headers {
desc {
en: """
The headers of the HTTP request.</br>
The headers of the HTTP request.<br/>
Template with variables is allowed.
"""
zh: """
HTTP 请求的标头。</br>
HTTP 请求的标头。<br/>
允许使用带有变量的模板。
"""
}
@ -103,11 +103,11 @@ HTTP 请求的标头。</br>
config_body {
desc {
en: """
The body of the HTTP request.</br>
The body of the HTTP request.<br/>
Template with variables is allowed.
"""
zh: """
HTTP 请求的正文。</br>
HTTP 请求的正文。<br/>
允许使用带有变量的模板。"""
}
label: {

View File

@ -1,7 +1,7 @@
%% -*- mode: erlang -*-
{application, emqx_bridge, [
{description, "An OTP application"},
{vsn, "0.1.3"},
{vsn, "0.1.4"},
{registered, []},
{mod, {emqx_bridge_app, []}},
{applications, [

View File

@ -94,7 +94,7 @@ direction_field(Dir, Desc) ->
#{
required => true,
default => egress,
desc => "The direction of the bridge. Can be one of 'ingress' or 'egress'.</br>" ++
desc => "The direction of the bridge. Can be one of 'ingress' or 'egress'.<br/>" ++
Desc
}
)}.

View File

@ -71,12 +71,12 @@ For more information, see: https://www.erlang.org/doc/man/erl.html
desc {
en: """Service discovery method for the cluster nodes."""
zh: """集群节点发现方式。可选值为:
- manual: 手动加入集群</br>
- static: 配置静态节点。配置几个固定的节点,新节点通过连接固定节点中的某一个来加入集群。</br>
- mcast: 使用 UDP 多播的方式发现节点。</br>
- dns: 使用 DNS A 记录的方式发现节点。</br>
- etcd: 使用 etcd 发现节点。</br>
- k8s: 使用 Kubernetes 发现节点。</br>
- manual: 手动加入集群<br/>
- static: 配置静态节点。配置几个固定的节点,新节点通过连接固定节点中的某一个来加入集群。<br/>
- mcast: 使用 UDP 多播的方式发现节点。<br/>
- dns: 使用 DNS A 记录的方式发现节点。<br/>
- etcd: 使用 etcd 发现节点。<br/>
- k8s: 使用 Kubernetes 发现节点。<br/>
"""
}
label {
@ -111,9 +111,9 @@ For more information, see: https://www.erlang.org/doc/man/erl.html
desc {
en: """The Erlang distribution protocol for the cluster."""
zh: """分布式 Erlang 集群协议类型。可选值为:
- inet_tcp: 使用 IPv4 </br>
- inet6_tcp 使用 IPv6 </br>
- inet_tls: 使用 TLS需要与 node.ssl_dist_optfile 配置一起使用。</br>
- inet_tcp: 使用 IPv4 <br/>
- inet6_tcp 使用 IPv6 <br/>
- inet_tls: 使用 TLS需要与 node.ssl_dist_optfile 配置一起使用。<br/>
"""
}
label {
@ -152,7 +152,7 @@ For more information, see: https://www.erlang.org/doc/man/erl.html
cluster_mcast_ports {
desc {
en: """List of UDP ports used for service discovery.</br>
en: """List of UDP ports used for service discovery.<br/>
Note: probe messages are broadcast to all the specified ports.
"""
zh: """指定多播端口。如有多个端口使用逗号 , 分隔。
@ -286,7 +286,7 @@ Applicable when <code>cluster.discovery_strategy = dns</code>
desc {
en: """Key prefix used for EMQX service discovery."""
zh: """指定 etcd 路径的前缀。每个节点在 etcd 中都会创建一个路径:
v2/keys/<prefix>/<cluster.name>/<node.name> </br>
v2/keys/<prefix>/<cluster.name>/<node.name> <br/>
当 cluster.discovery_strategy 为 etcd 时,此配置项才有效。
"""
}
@ -357,7 +357,7 @@ Setting <code>cluster.k8s.address_type</code> to <code>ip</code> will
make EMQX to discover IP addresses of peer nodes from Kubernetes API.
"""
zh: """当使用 k8s 方式集群时address_type 用来从 Kubernetes 接口的应答里获取什么形式的 Host 列表。
指定 <code>cluster.k8s.address_type</code. 为 <code>ip</code>,则将从 Kubernetes 接口中获取集群中其他节点
指定 <code>cluster.k8s.address_type</code> 为 <code>ip</code>,则将从 Kubernetes 接口中获取集群中其他节点
的IP地址。
"""
}
@ -382,7 +382,7 @@ make EMQX to discover IP addresses of peer nodes from Kubernetes API.
cluster_k8s_suffix {
desc {
en: """Node name suffix.</br>
en: """Node name suffix.<br/>
Note: this parameter is only relevant when <code>address_type</code> is <code>dns</code>
or <code>hostname</code>."""
zh: """当使用 k8s 方式并且 cluster.k8s.address_type 指定为 dns 类型时,可设置 emqx 节点名的后缀。
@ -426,26 +426,26 @@ belong to different clusters from accidentally connecting to each other."""
node_data_dir {
desc {
en: """
Path to the persistent data directory.</br>
Possible auto-created subdirectories are:</br>
- `mnesia/<node_name>`: EMQX's built-in database directory.</br>
For example, `mnesia/emqx@127.0.0.1`.</br>
There should be only one such subdirectory.</br>
Meaning, in case the node is to be renamed (to e.g. `emqx@10.0.1.1`),</br>
the old dir should be deleted first.</br>
- `configs`: Generated configs at boot time, and cluster/local override configs.</br>
- `patches`: Hot-patch beam files are to be placed here.</br>
- `trace`: Trace log files.</br>
Path to the persistent data directory.<br/>
Possible auto-created subdirectories are:<br/>
- `mnesia/<node_name>`: EMQX's built-in database directory.<br/>
For example, `mnesia/emqx@127.0.0.1`.<br/>
There should be only one such subdirectory.<br/>
Meaning, in case the node is to be renamed (to e.g. `emqx@10.0.1.1`),<br/>
the old dir should be deleted first.<br/>
- `configs`: Generated configs at boot time, and cluster/local override configs.<br/>
- `patches`: Hot-patch beam files are to be placed here.<br/>
- `trace`: Trace log files.<br/>
**NOTE**: One data dir cannot be shared by two or more EMQX nodes.
"""
zh: """
节点数据存放目录,可能会自动创建的子目录如下:</br>
- `mnesia/<node_name>`。EMQX的内置数据库目录。例如`mnesia/emqx@127.0.0.1`。</br>
如果节点要被重新命名(例如,`emqx@10.0.1.1`)。旧目录应该首先被删除。</br>
- `configs`。在启动时生成的配置,以及集群/本地覆盖的配置。</br>
- `patches`: 热补丁文件将被放在这里。</br>
- `trace`: 日志跟踪文件。</br>
节点数据存放目录,可能会自动创建的子目录如下:<br/>
- `mnesia/<node_name>`。EMQX的内置数据库目录。例如`mnesia/emqx@127.0.0.1`。<br/>
如果节点要被重新命名(例如,`emqx@10.0.1.1`)。旧目录应该首先被删除。<br/>
- `configs`。在启动时生成的配置,以及集群/本地覆盖的配置。<br/>
- `patches`: 热补丁文件将被放在这里。<br/>
- `trace`: 日志跟踪文件。<br/>
**注意**: 一个数据dir不能被两个或更多的EMQX节点同时使用。
"""
@ -566,9 +566,9 @@ significant: later configuration files override the previous ones.
db_backend {
desc {
en: """
Select the backend for the embedded database.</br>
Select the backend for the embedded database.<br/>
<code>rlog</code> is the default backend,
that is suitable for very large clusters.</br>
that is suitable for very large clusters.<br/>
<code>mnesia</code> is a backend that offers decent performance in small clusters.
"""
zh: """ rlog是默认的数据库他适用于大规模的集群。
@ -584,20 +584,20 @@ mnesia是备选数据库在小集群中提供了很好的性能。
db_role {
desc {
en: """
Select a node role.</br>
Select a node role.<br/>
<code>core</code> nodes provide durability of the data, and take care of writes.
It is recommended to place core nodes in different racks or different availability zones.</br>
It is recommended to place core nodes in different racks or different availability zones.<br/>
<code>replicant</code> nodes are ephemeral worker nodes. Removing them from the cluster
doesn't affect database redundancy</br>
It is recommended to have more replicant nodes than core nodes.</br>
doesn't affect database redundancy<br/>
It is recommended to have more replicant nodes than core nodes.<br/>
Note: this parameter only takes effect when the <code>backend</code> is set
to <code>rlog</code>.
"""
zh: """
选择节点的角色。</br>
<code>core</code> 节点提供数据的持久性,并负责写入。建议将核心节点放置在不同的机架或不同的可用区。</br>
<code>repliant</code> 节点是临时工作节点。 从集群中删除它们,不影响数据库冗余</br>
建议复制节点多于核心节点。</br>
选择节点的角色。<br/>
<code>core</code> 节点提供数据的持久性,并负责写入。建议将核心节点放置在不同的机架或不同的可用区。<br/>
<code>repliant</code> 节点是临时工作节点。 从集群中删除它们,不影响数据库冗余<br/>
建议复制节点多于核心节点。<br/>
注意:该参数仅在设置<code>backend</code>时生效到 <code>rlog</code>。
"""
}
@ -610,17 +610,17 @@ to <code>rlog</code>.
db_core_nodes {
desc {
en: """
List of core nodes that the replicant will connect to.</br>
List of core nodes that the replicant will connect to.<br/>
Note: this parameter only takes effect when the <code>backend</code> is set
to <code>rlog</code> and the <code>role</code> is set to <code>replicant</code>.</br>
This value needs to be defined for manual or static cluster discovery mechanisms.</br>
to <code>rlog</code> and the <code>role</code> is set to <code>replicant</code>.<br/>
This value needs to be defined for manual or static cluster discovery mechanisms.<br/>
If an automatic cluster discovery mechanism is being used (such as <code>etcd</code>),
there is no need to set this value.
"""
zh: """当前节点连接的核心节点列表。</br>
zh: """当前节点连接的核心节点列表。<br/>
注意:该参数仅在设置<code>backend</code>时生效到 <code>rlog</code>
并且设置<code>role</code>为<code>replicant</code>时生效。</br>
该值需要在手动或静态集群发现机制下设置。</br>
并且设置<code>role</code>为<code>replicant</code>时生效。<br/>
该值需要在手动或静态集群发现机制下设置。<br/>
如果使用了自动集群发现机制(如<code>etcd</code>),则不需要设置该值。
"""
}
@ -657,15 +657,15 @@ transaction log entry.
db_default_shard_transport {
desc {
en: """Defines the default transport for pushing transaction logs.</br>
en: """Defines the default transport for pushing transaction logs.<br/>
This may be overridden on a per-shard basis in <code>db.shard_transports</code>.
<code>gen_rpc</code> uses the <code>gen_rpc</code> library,
<code>distr</code> uses the Erlang distribution.</br>"""
<code>distr</code> uses the Erlang distribution.<br/>"""
zh: """
定义用于推送事务日志的默认传输。</br>
定义用于推送事务日志的默认传输。<br/>
这可以在 <code>db.shard_transports</code> 中基于每个分片被覆盖。
<code>gen_rpc</code> 使用 <code>gen_rpc</code> 库,
<code>distr</code> 使用 Erlang 发行版。</br>
<code>distr</code> 使用 Erlang 发行版。<br/>
"""
}
label {
@ -676,13 +676,13 @@ This may be overridden on a per-shard basis in <code>db.shard_transports</code>.
db_shard_transports {
desc {
en: """Allows to tune the transport method used for transaction log replication, on a per-shard basis.</br>
en: """Allows to tune the transport method used for transaction log replication, on a per-shard basis.<br/>
<code>gen_rpc</code> uses the <code>gen_rpc</code> library,
<code>distr</code> uses the Erlang distribution.</br>If not specified,
<code>distr</code> uses the Erlang distribution.<br/>If not specified,
the default is to use the value set in <code>db.default_shard_transport</code>."""
zh: """允许为每个 shard 下的事务日志复制操作的传输方法进行调优。</br>
zh: """允许为每个 shard 下的事务日志复制操作的传输方法进行调优。<br/>
<code>gen_rpc</code> 使用 <code>gen_rpc</code> 库,
<code>distr</code> 使用 Erlang 自带的 rpc 库。</br>如果未指定,
<code>distr</code> 使用 Erlang 自带的 rpc 库。<br/>如果未指定,
默认是使用 <code>db.default_shard_transport</code> 中设置的值。
"""
}
@ -763,12 +763,12 @@ Ensure that the number of completed transactions is less than the <code>max_hist
rpc_port_discovery {
desc {
en: """<code>manual</code>: discover ports by <code>tcp_server_port</code>.</br>
en: """<code>manual</code>: discover ports by <code>tcp_server_port</code>.<br/>
<code>stateless</code>: discover ports in a stateless manner, using the following algorithm.
If node name is <code>emqxN@127.0.0.1</code>, where the N is an integer,
then the listening port will be 5370 + N."""
zh: """<code>manual</code>: 通过 <code>tcp_server_port</code> 来发现端口。
</br><code>stateless</code>: 使用无状态的方式来发现端口,使用如下算法。如果节点名称是 <code>
<br/><code>stateless</code>: 使用无状态的方式来发现端口,使用如下算法。如果节点名称是 <code>
emqxN@127.0.0.1</code>, N 是一个数字,那么监听端口就是 5370 + N。
"""
}
@ -780,9 +780,9 @@ emqxN@127.0.0.1</code>, N 是一个数字,那么监听端口就是 5370 + N。
rpc_tcp_server_port {
desc {
en: """Listening port used by RPC local service.</br>
en: """Listening port used by RPC local service.<br/>
Note that this config only takes effect when rpc.port_discovery is set to manual."""
zh: """RPC 本地服务使用的 TCP 端口。</br>
zh: """RPC 本地服务使用的 TCP 端口。<br/>
只有当 rpc.port_discovery 设置为 manual 时,此配置才会生效。
"""
}
@ -794,10 +794,10 @@ Note that this config only takes effect when rpc.port_discovery is set to manual
rpc_ssl_server_port {
desc {
en: """Listening port used by RPC local service.</br>
en: """Listening port used by RPC local service.<br/>
Note that this config only takes effect when rpc.port_discovery is set to manual
and <code>driver</code> is set to <code>ssl</code>."""
zh: """RPC 本地服务使用的监听SSL端口。</br>
zh: """RPC 本地服务使用的监听SSL端口。<br/>
只有当 rpc.port_discovery 设置为 manual 且 <code> dirver </code> 设置为 <code>ssl</code>
此配置才会生效。
"""
@ -847,9 +847,9 @@ Note that this config only takes effect when <code>rpc.driver</code> is set to <
rpc_keyfile {
desc {
en: """Path to the private key file for the <code>rpc.certfile</code>.</br>
en: """Path to the private key file for the <code>rpc.certfile</code>.<br/>
Note: contents of this file are secret, so it's necessary to set permissions to 600."""
zh: """<code>rpc.certfile</code> 的私钥文件的路径。</br>
zh: """<code>rpc.certfile</code> 的私钥文件的路径。<br/>
注意:此文件内容是私钥,所以需要设置权限为 600。
"""
}
@ -861,9 +861,9 @@ Note: contents of this file are secret, so it's necessary to set permissions to
rpc_cacertfile {
desc {
en: """Path to certification authority TLS certificate file used to validate <code>rpc.certfile</code>.</br>
en: """Path to certification authority TLS certificate file used to validate <code>rpc.certfile</code>.<br/>
Note: certificates of all nodes in the cluster must be signed by the same CA."""
zh: """验证 <code>rpc.certfile</code> 的 CA 证书文件的路径。</br>
zh: """验证 <code>rpc.certfile</code> 的 CA 证书文件的路径。<br/>
注意:集群中所有节点的证书必须使用同一个 CA 签发。
"""
}
@ -1201,7 +1201,7 @@ Supervisor 报告的类型。默认为 error 类型。
desc {
en: """Enable log rotation feature."""
zh: """启用日志轮换功能。启动后生成日志文件后缀会加上对应的索引数字比如log/emqx.log.1。
系统会默认生成<code>*.siz/*.idx<code>用于记录日志位置,请不要手动修改这两个文件。
系统会默认生成<code>*.siz/*.idx</code>用于记录日志位置,请不要手动修改这两个文件。
"""
}
label {
@ -1301,17 +1301,17 @@ Supervisor 报告的类型。默认为 error 类型。
authorization {
desc {
en: """
Authorization a.k.a. ACL.</br>
In EMQX, MQTT client access control is extremely flexible.</br>
Authorization a.k.a. ACL.<br/>
In EMQX, MQTT client access control is extremely flexible.<br/>
An out-of-the-box set of authorization data sources are supported.
For example,</br>
'file' source is to support concise and yet generic ACL rules in a file;</br>
For example,<br/>
'file' source is to support concise and yet generic ACL rules in a file;<br/>
'built_in_database' source can be used to store per-client customizable rule sets,
natively in the EMQX node;</br>
'http' source to make EMQX call an external HTTP API to make the decision;</br>
'PostgreSQL' etc. to look up clients or rules from external databases;</br>
natively in the EMQX node;<br/>
'http' source to make EMQX call an external HTTP API to make the decision;<br/>
'PostgreSQL' etc. to look up clients or rules from external databases;<br/>
"""
zh: """ 授权ACL。EMQX 支持完整的客户端访问控制ACL。</br> """
zh: """ 授权ACL。EMQX 支持完整的客户端访问控制ACL。<br/> """
}
label {
en: "Authorization"
@ -1321,9 +1321,9 @@ natively in the EMQX node;</br>
desc_cluster {
desc {
en: """EMQX nodes can form a cluster to scale up the total capacity.</br>
en: """EMQX nodes can form a cluster to scale up the total capacity.<br/>
Here holds the configs to instruct how individual nodes can discover each other."""
zh: """EMQX 节点可以组成一个集群,以提高总容量。</br> 这里指定了节点之间如何连接。"""
zh: """EMQX 节点可以组成一个集群,以提高总容量。<br/> 这里指定了节点之间如何连接。"""
}
label {
en: "Cluster"
@ -1422,11 +1422,11 @@ The new node joins the cluster by connecting to one of the bootstrap nodes."""
desc_rpc {
desc {
en: """EMQX uses a library called <code>gen_rpc</code> for inter-broker communication.</br>
en: """EMQX uses a library called <code>gen_rpc</code> for inter-broker communication.<br/>
Most of the time the default config should work,
but in case you need to do performance fine-tuning or experiment a bit,
this is where to look."""
zh: """EMQX 使用 <code>gen_rpc</code> 库来实现跨节点通信。</br>
zh: """EMQX 使用 <code>gen_rpc</code> 库来实现跨节点通信。<br/>
大多数情况下,默认的配置应该可以工作,但如果你需要做一些性能优化或者实验,可以尝试调整这些参数。"""
}
label {
@ -1472,11 +1472,11 @@ Each sink is represented by a _log handler_, which can be configured independent
desc_log_rotation {
desc {
en: """
By default, the logs are stored in `./log` directory (for installation from zip file) or in `/var/log/emqx` (for binary installation).</br>
By default, the logs are stored in `./log` directory (for installation from zip file) or in `/var/log/emqx` (for binary installation).<br/>
This section of the configuration controls the number of files kept for each log handler.
"""
zh: """
默认情况下,日志存储在 `./log` 目录(用于从 zip 文件安装)或 `/var/log/emqx`(用于二进制安装)。</br>
默认情况下,日志存储在 `./log` 目录(用于从 zip 文件安装)或 `/var/log/emqx`(用于二进制安装)。<br/>
这部分配置,控制每个日志处理进程保留的文件数量。
"""
}
@ -1489,11 +1489,11 @@ This section of the configuration controls the number of files kept for each log
desc_log_overload_kill {
desc {
en: """
Log overload kill features an overload protection that activates when the log handlers use too much memory or have too many buffered log messages.</br>
Log overload kill features an overload protection that activates when the log handlers use too much memory or have too many buffered log messages.<br/>
When the overload is detected, the log handler is terminated and restarted after a cooldown period.
"""
zh: """
日志过载终止,具有过载保护功能。当日志处理进程使用过多内存,或者缓存的日志消息过多时该功能被激活。</br>
日志过载终止,具有过载保护功能。当日志处理进程使用过多内存,或者缓存的日志消息过多时该功能被激活。<br/>
检测到过载时,日志处理进程将终止,并在冷却期后重新启动。
"""
}

View File

@ -14,11 +14,11 @@ emqx_connector_api {
conn_test_post {
desc {
en: """
Test creating a new connector by given ID </br>
Test creating a new connector by given ID <br/>
The ID must be of format '{type}:{name}'
"""
zh: """
通过给定的 ID 测试创建一个新的连接器 </br>
通过给定的 ID 测试创建一个新的连接器 <br/>
ID 的格式必须为“{type}:{name}”
"""
}

View File

@ -2,14 +2,14 @@ emqx_connector_http {
base_url {
desc {
en: """
The base URL is the URL includes only the scheme, host and port.</br>
The base URL is the URL includes only the scheme, host and port.<br/>
When send an HTTP request, the real URL to be used is the concatenation of the base URL and the
path parameter (passed by the emqx_resource:query/2,3 or provided by the request parameter).</br>
path parameter (passed by the emqx_resource:query/2,3 or provided by the request parameter).<br/>
For example: `http://localhost:9901/`
"""
zh: """
base URL 只包含host和port。</br>
发送HTTP请求时真实的URL是由base URL 和 path parameter连接而成通过emqx_resource:query/2,3传递或者通过请求参数提供。</br>
base URL 只包含host和port。<br/>
发送HTTP请求时真实的URL是由base URL 和 path parameter连接而成通过emqx_resource:query/2,3传递或者通过请求参数提供。<br/>
示例:`http://localhost:9901/`
"""
}

View File

@ -47,13 +47,13 @@ emqx_connector_mongo {
server {
desc {
en: """
The IPv4 or IPv6 address or the hostname to connect to.</br>
A host entry has the following form: `Host[:Port]`.</br>
The IPv4 or IPv6 address or the hostname to connect to.<br/>
A host entry has the following form: `Host[:Port]`.<br/>
The MongoDB default port 27017 is used if `[:Port]` is not specified.
"""
zh: """
将要连接的 IPv4 或 IPv6 地址,或者主机名。</br>
主机名具有以下形式:`Host[:Port]`。</br>
将要连接的 IPv4 或 IPv6 地址,或者主机名。<br/>
主机名具有以下形式:`Host[:Port]`。<br/>
如果未指定 `[:Port]`,则使用 MongoDB 默认端口 27017。
"""
}

View File

@ -2,22 +2,22 @@ emqx_connector_mqtt_schema {
mode {
desc {
en: """
The mode of the MQTT Bridge.</br>
The mode of the MQTT Bridge.<br/>
- cluster_shareload: create an MQTT connection on each node in the emqx cluster.</br>
- cluster_shareload: create an MQTT connection on each node in the emqx cluster.<br/>
In 'cluster_shareload' mode, the incoming load from the remote broker is shared by
using shared subscription.</br>
using shared subscription.<br/>
Note that the 'clientid' is suffixed by the node name, this is to avoid
clientid conflicts between different nodes. And we can only use shared subscription
topic filters for 'remote_topic' of ingress connections.
topic filters for <code>remote_topic</code> of ingress connections.
"""
zh: """
MQTT 桥的模式。 </br>
MQTT 桥的模式。 <br/>
- cluster_shareload在 emqx 集群的每个节点上创建一个 MQTT 连接。</br>
在“cluster_shareload”模式下来自远程代理的传入负载通过共享订阅的方式接收。</br>
请注意,“clientid”以节点名称为后缀这是为了避免不同节点之间的clientid冲突。
而且对于入口连接的“remote_topic”,我们只能使用共享订阅主题过滤器。
- cluster_shareload在 emqx 集群的每个节点上创建一个 MQTT 连接。<br/>
在“cluster_shareload”模式下来自远程代理的传入负载通过共享订阅的方式接收。<br/>
请注意,<code>clientid</code> 以节点名称为后缀这是为了避免不同节点之间的clientid冲突。
而且对于入口连接的 <code>remote_topic</code>,我们只能使用共享订阅主题过滤器。
"""
}
label: {
@ -135,11 +135,11 @@ broker MUST support this feature.
ingress_local_topic {
desc {
en: """
Send messages to which topic of the local broker.</br>
Send messages to which topic of the local broker.<br/>
Template with variables is allowed.
"""
zh: """
向本地broker的哪个topic发送消息。</br>
向本地broker的哪个topic发送消息。<br/>
允许使用带有变量的模板。
"""
}
@ -152,11 +152,11 @@ Template with variables is allowed.
ingress_local_qos {
desc {
en: """
The QoS of the MQTT message to be sent.</br>
The QoS of the MQTT message to be sent.<br/>
Template with variables is allowed.
"""
zh: """
待发送 MQTT 消息的 QoS。</br>
待发送 MQTT 消息的 QoS。<br/>
允许使用带有变量的模板。
"""
}
@ -191,11 +191,11 @@ Template with variables is allowed.
egress_remote_topic {
desc {
en: """
Forward to which topic of the remote broker.</br>
Forward to which topic of the remote broker.<br/>
Template with variables is allowed.
"""
zh: """
转发到远程broker的哪个topic。</br>
转发到远程broker的哪个topic。<br/>
允许使用带有变量的模板。
"""
}
@ -208,11 +208,11 @@ Template with variables is allowed.
egress_remote_qos {
desc {
en: """
The QoS of the MQTT message to be sent.</br>
The QoS of the MQTT message to be sent.<br/>
Template with variables is allowed.
"""
zh: """
待发送 MQTT 消息的 QoS。</br>
待发送 MQTT 消息的 QoS。<br/>
允许使用带有变量的模板。
"""
}
@ -225,11 +225,11 @@ Template with variables is allowed.
dir {
desc {
en: """
The dir where the replayq file saved.</br>
The dir where the replayq file saved.<br/>
Set to 'false' disables the replayq feature.
"""
zh: """
replayq 文件保存的目录。</br>
replayq 文件保存的目录。<br/>
设置为 'false' 会禁用 replayq 功能。
"""
}
@ -242,12 +242,12 @@ replayq 文件保存的目录。</br>
seg_bytes {
desc {
en: """
The size in bytes of a single segment.</br>
The size in bytes of a single segment.<br/>
A segment is mapping to a file in the replayq dir. If the current segment is full, a new segment
(file) will be opened to write.
"""
zh: """
单个段的大小(以字节为单位)。</br>
单个段的大小(以字节为单位)。<br/>
一个段映射到 replayq 目录中的一个文件。 如果当前段已满,则新段(文件)将被打开写入。
"""
}
@ -260,12 +260,12 @@ A segment is mapping to a file in the replayq dir. If the current segment is ful
offload {
desc {
en: """
In offload mode, the disk queue is only used to offload queue tail segments.</br>
In offload mode, the disk queue is only used to offload queue tail segments.<br/>
The messages are cached in the memory first, then it writes to the replayq files after the size of
the memory cache reaches 'seg_bytes'.
"""
zh: """
在Offload模式下磁盘队列仅用于卸载队列尾段。</br>
在Offload模式下磁盘队列仅用于卸载队列尾段。<br/>
消息首先缓存在内存中然后写入replayq文件。内存缓大小为“seg_bytes” 指定的值。
"""
}
@ -278,11 +278,11 @@ the memory cache reaches 'seg_bytes'.
retain {
desc {
en: """
The 'retain' flag of the MQTT message to be sent.</br>
The 'retain' flag of the MQTT message to be sent.<br/>
Template with variables is allowed.
"""
zh: """
要发送的 MQTT 消息的“保留”标志。</br>
要发送的 MQTT 消息的“保留”标志。<br/>
允许使用带有变量的模板。
"""
}
@ -295,11 +295,11 @@ Template with variables is allowed.
payload {
desc {
en: """
The payload of the MQTT message to be sent.</br>
The payload of the MQTT message to be sent.<br/>
Template with variables is allowed.
"""
zh: """
要发送的 MQTT 消息的负载。</br>
要发送的 MQTT 消息的负载。<br/>
允许使用带有变量的模板。
"""
}
@ -323,13 +323,13 @@ Template with variables is allowed.
desc_ingress {
desc {
en: """
The ingress config defines how this bridge receive messages from the remote MQTT broker, and then send them to the local broker.</br>
Template with variables is allowed in 'local_topic', 'remote_qos', 'qos', 'retain', 'payload'.</br>
The ingress config defines how this bridge receive messages from the remote MQTT broker, and then send them to the local broker.<br/>
Template with variables is allowed in 'local_topic', 'remote_qos', 'qos', 'retain', 'payload'.<br/>
NOTE: if this bridge is used as the input of a rule (emqx rule engine), and also local_topic is configured, then messages got from the remote broker will be sent to both the 'local_topic' and the rule.
"""
zh: """
Ingress 模式定义了这个 bridge 如何从远程 MQTT broker 接收消息,然后将它们发送到本地 broker 。</br>
允许带有的模板变量: 'local_topic'、'remote_qos'、'qos'、'retain'、'payload' 。</br>
Ingress 模式定义了这个 bridge 如何从远程 MQTT broker 接收消息,然后将它们发送到本地 broker 。<br/>
允许带有的模板变量: 'local_topic'、'remote_qos'、'qos'、'retain'、'payload' 。<br/>
注意:如果这个 bridge 被用作规则的输入emqx 规则引擎),并且还配置了 local_topic那么从远程 broker 获取的消息将同时被发送到 'local_topic' 和规则引擎。
"""
}
@ -342,13 +342,13 @@ Ingress 模式定义了这个 bridge 如何从远程 MQTT broker 接收消息,
desc_egress {
desc {
en: """
The egress config defines how this bridge forwards messages from the local broker to the remote broker.</br>
Template with variables is allowed in 'remote_topic', 'qos', 'retain', 'payload'.</br>
The egress config defines how this bridge forwards messages from the local broker to the remote broker.<br/>
Template with variables is allowed in 'remote_topic', 'qos', 'retain', 'payload'.<br/>
NOTE: if this bridge is used as the action of a rule (emqx rule engine), and also local_topic is configured, then both the data got from the rule and the MQTT messages that matches local_topic will be forwarded.
"""
zh: """
Egress 模式定义了 bridge 如何将消息从本地 broker 转发到远程 broker。</br>
允许带有的模板变量: 'remote_topic'、'qos'、'retain'、'payload' 。</br>
Egress 模式定义了 bridge 如何将消息从本地 broker 转发到远程 broker。<br/>
允许带有的模板变量: 'remote_topic'、'qos'、'retain'、'payload' 。<br/>
注意:如果这个 bridge 作为规则emqx 规则引擎)的输出,并且还配置了 local_topic那么从规则引擎中获取的数据和匹配 local_topic 的 MQTT 消息都会被转发到远程 broker 。
"""
}

View File

@ -3,13 +3,13 @@ emqx_connector_mysql {
server {
desc {
en: """
The IPv4 or IPv6 address or the hostname to connect to.</br>
A host entry has the following form: `Host[:Port]`.</br>
The IPv4 or IPv6 address or the hostname to connect to.<br/>
A host entry has the following form: `Host[:Port]`.<br/>
The MySQL default port 3306 is used if `[:Port]` is not specified.
"""
zh: """
将要连接的 IPv4 或 IPv6 地址,或者主机名。</br>
主机名具有以下形式:`Host[:Port]`。</br>
将要连接的 IPv4 或 IPv6 地址,或者主机名。<br/>
主机名具有以下形式:`Host[:Port]`。<br/>
如果未指定 `[:Port]`,则使用 MySQL 默认端口 3306。
"""
}

View File

@ -3,13 +3,13 @@ emqx_connector_pgsql {
server {
desc {
en: """
The IPv4 or IPv6 address or the hostname to connect to.</br>
A host entry has the following form: `Host[:Port]`.</br>
The IPv4 or IPv6 address or the hostname to connect to.<br/>
A host entry has the following form: `Host[:Port]`.<br/>
The PostgreSQL default port 5432 is used if `[:Port]` is not specified.
"""
zh: """
将要连接的 IPv4 或 IPv6 地址,或者主机名。</br>
主机名具有以下形式:`Host[:Port]`。</br>
将要连接的 IPv4 或 IPv6 地址,或者主机名。<br/>
主机名具有以下形式:`Host[:Port]`。<br/>
如果未指定 `[:Port]`,则使用 PostgreSQL 默认端口 5432。
"""
}

View File

@ -47,13 +47,13 @@ emqx_connector_redis {
server {
desc {
en: """
The IPv4 or IPv6 address or the hostname to connect to.</br>
A host entry has the following form: `Host[:Port]`.</br>
The IPv4 or IPv6 address or the hostname to connect to.<br/>
A host entry has the following form: `Host[:Port]`.<br/>
The Redis default port 6379 is used if `[:Port]` is not specified.
"""
zh: """
将要连接的 IPv4 或 IPv6 地址,或者主机名。</br>
主机名具有以下形式:`Host[:Port]`。</br>
将要连接的 IPv4 或 IPv6 地址,或者主机名。<br/>
主机名具有以下形式:`Host[:Port]`。<br/>
如果未指定 `[:Port]`,则使用 MongoDB 默认端口 27017。
"""
}

View File

@ -14,11 +14,11 @@ emqx_connector_schema {
desc_connector {
desc {
en: """
Configuration for EMQX connectors.</br>
Configuration for EMQX connectors.<br/>
A connector maintains the data related to the external resources, such as MySQL database.
"""
zh: """
EMQX 连接器的配置。</br>
EMQX 连接器的配置。<br/>
连接器维护与外部资源相关的数据,比如 MySQL 数据库。
"""
}

View File

@ -25,14 +25,13 @@
-define(PGSQL_DEFAULT_PORT, 5432).
-define(SERVERS_DESC,
"A Node list for Cluster to connect to. The nodes should be separated with commas, such as: `Node[,Node].`\n"
"A Node list for Cluster to connect to. The nodes should be separated with commas, such as: `Node[,Node].`<br/>"
"For each Node should be: "
).
-define(SERVER_DESC(TYPE, DEFAULT_PORT),
"\n"
"The IPv4 or IPv6 address or the hostname to connect to.</br>\n"
"A host entry has the following form: `Host[:Port]`.</br>\n"
"The IPv4 or IPv6 address or the hostname to connect to.<br/>"
"A host entry has the following form: `Host[:Port]`.<br/>"
"The " ++ TYPE ++ " default port " ++ DEFAULT_PORT ++ " is used if `[:Port]` is not specified."
).

View File

@ -1,7 +1,7 @@
%% -*- mode: erlang -*-
{application, emqx_connector, [
{description, "An OTP application"},
{vsn, "0.1.6"},
{vsn, "0.1.7"},
{registered, []},
{mod, {emqx_connector_app, []}},
{applications, [

View File

@ -282,9 +282,9 @@ topic_mappings() ->
ingress_desc() ->
"\n"
"The ingress config defines how this bridge receive messages from the remote MQTT broker, and then\n"
"send them to the local broker.</br>\n"
"send them to the local broker.<br/>"
"Template with variables is allowed in 'local_topic', 'remote_qos', 'qos', 'retain',\n"
"'payload'.</br>\n"
"'payload'.<br/>"
"NOTE: if this bridge is used as the input of a rule (emqx rule engine), and also local_topic is\n"
"configured, then messages got from the remote broker will be sent to both the 'local_topic' and\n"
"the rule.\n".
@ -292,8 +292,8 @@ ingress_desc() ->
egress_desc() ->
"\n"
"The egress config defines how this bridge forwards messages from the local broker to the remote\n"
"broker.</br>\n"
"Template with variables is allowed in 'remote_topic', 'qos', 'retain', 'payload'.</br>\n"
"broker.<br/>"
"Template with variables is allowed in 'remote_topic', 'qos', 'retain', 'payload'.<br/>"
"NOTE: if this bridge is used as the action of a rule (emqx rule engine), and also local_topic\n"
"is configured, then both the data got from the rule and the MQTT messages that matches\n"
"local_topic will be forwarded.\n".

View File

@ -441,7 +441,7 @@ trans_description(Spec, Hocon) ->
undefined ->
Spec;
Desc ->
Desc1 = binary:replace(Desc, [<<"</br>\n">>, <<"\n">>], <<"</br>">>, [global]),
Desc1 = binary:replace(Desc, [<<"\n">>], <<"<br/>">>, [global]),
Spec#{description => Desc1}
end.

View File

@ -2,7 +2,7 @@ emqx_gateway_api_authn {
get_authn {
desc {
en: """Gets the configuration of the specified gateway authenticator.</br>
en: """Gets the configuration of the specified gateway authenticator.<br/>
Returns 404 when gateway or authentication is not enabled."""
zh: """获取指定网关认证器的配置
当网关或认证未启用时,返回 404。"""
@ -18,11 +18,11 @@ Returns 404 when gateway or authentication is not enabled."""
add_authn {
desc {
en: """Enables the authenticator for client authentication for the specified gateway. <\br>
When the authenticator is not configured or turned off, all client connections are assumed to be allowed. <\br>
en: """Enables the authenticator for client authentication for the specified gateway. <br/>
When the authenticator is not configured or turned off, all client connections are assumed to be allowed. <br/>
Note: Only one authenticator is allowed to be enabled at a time in the gateway, rather than allowing multiple authenticators to be configured to form an authentication chain as in MQTT."""
zh: """为指定网关开启认证器实现客户端认证的功能。<\br>
当未配置认证器或关闭认证器时,则认为允许所有客户端的连接。<\br>
zh: """为指定网关开启认证器实现客户端认证的功能。<br/>
当未配置认证器或关闭认证器时,则认为允许所有客户端的连接。<br/>
注:在网关中仅支持添加一个认证器,而不是像 MQTT 一样允许配置多个认证器构成认证链。"""
}
}

View File

@ -32,9 +32,9 @@ including current running status, number of connections, listener status, etc.""
update_gateway {
desc {
en: """Update the gateway basic configurations and running status.</br>
en: """Update the gateway basic configurations and running status.<br/>
Note: The Authentication and Listener configurations should be updated by other special APIs. """
zh: """更新指定网关的基础配置、和启用的状态。</br>
zh: """更新指定网关的基础配置、和启用的状态。<br/>
注:认证、和监听器的配置更新需参考对应的 API 接口。"""
}
}
@ -48,10 +48,10 @@ Note: The Authentication and Listener configurations should be updated by other
gateway_name_in_qs {
desc {
en: """Gateway Name.</br>
en: """Gateway Name.<br/>
It's enum with `stomp`, `mqttsn`, `coap`, `lwm2m`, `exproto`
"""
zh: """网关名称.</br>
zh: """网关名称.<br/>
可取值为 `stomp`、`mqttsn`、`coap`、`lwm2m`、`exproto`
"""
}
@ -66,9 +66,9 @@ It's enum with `stomp`, `mqttsn`, `coap`, `lwm2m`, `exproto`
gateway_status_in_qs {
desc {
en: """Filter gateways by status.</br>
en: """Filter gateways by status.<br/>
It is enum with `running`, `stopped`, `unloaded`"""
zh: """通过网关状态筛选</br>
zh: """通过网关状态筛选<br/>
可选值为 `running`、`stopped`、`unloaded`"""
}
}

View File

@ -9,9 +9,9 @@ emqx_gateway_api_listeners {
add_listener {
desc {
en: """Create the gateway listener.</br>
en: """Create the gateway listener.<br/>
Note: For listener types not supported by a gateway, this API returns `400: BAD_REQUEST`."""
zh: """为指定网关添加监听器。</br>
zh: """为指定网关添加监听器。<br/>
注:对于某网关不支持的监听器类型,该接口会返回 `400: BAD_REQUEST`。"""
}
}
@ -46,9 +46,9 @@ Note: For listener types not supported by a gateway, this API returns `400: BAD_
add_listener_authn {
desc {
en: """Enable authenticator for specified listener for client authentication.</br>
en: """Enable authenticator for specified listener for client authentication.<br/>
When authenticator is enabled for a listener, all clients connecting to that listener will use that authenticator for authentication."""
zh: """为指定监听器开启认证器以实现客户端认证的能力。</br>
zh: """为指定监听器开启认证器以实现客户端认证的能力。<br/>
当某一监听器开启认证后,所有连接到该监听器的客户端会使用该认证器进行认证。"""
}
}

View File

@ -146,7 +146,7 @@ This option specifies the QoS level for the CoAP Client when establishing a subs
"""
zh: """客户端订阅请求的默认 QoS 等级。
当 CoAP 客户端发起订阅请求时,如果未携带 `qos` 参数则会使用该默认值。默认值可设置为:
- qos0, qos1, qos2: 设置为固定的 QoS 等级
- qos0、 qos1、qos2: 设置为固定的 QoS 等级
- coap: 依据订阅操作的 CoAP 报文类型来动态决定
* 当订阅请求为 `non-confirmable` 类型时,取值为 qos0
* 当订阅请求为 `confirmable` 类型时,取值为 qos1
@ -165,7 +165,7 @@ This option specifies the QoS level for the CoAP Client when publishing a messag
zh: """客户端发布请求的默认 QoS 等级。
当 CoAP 客户端发起发布请求时,如果未携带 `qos` 参数则会使用该默认值。默认值可设置为:
- qos0, qos1, qos2: 设置为固定的 QoS 等级
- qos0、qos1、qos2: 设置为固定的 QoS 等级
- coap: 依据发布操作的 CoAP 报文类型来动态决定
* 当发布请求为 `non-confirmable` 类型时,取值为 qos0
* 当发布请求为 `confirmable` 类型时,取值为 qos1
@ -175,29 +175,29 @@ This option specifies the QoS level for the CoAP Client when publishing a messag
lwm2m {
desc {
en: """The LwM2M Gateway configuration. This gateway only supports the v1.0.1 protocol"""
zh: """LwM2M 网关配置。仅支持 v1.0.1 协议"""
en: """The LwM2M Gateway configuration. This gateway only supports the v1.0.1 protocol."""
zh: """LwM2M 网关配置。仅支持 v1.0.1 协议"""
}
}
lwm2m_xml_dir {
desc {
en: """The Directory for LwM2M Resource definition"""
zh: """LwM2M Resource 定义的 XML 文件目录路径"""
en: """The Directory for LwM2M Resource definition."""
zh: """LwM2M Resource 定义的 XML 文件目录路径"""
}
}
lwm2m_lifetime_min {
desc {
en: """Minimum value of lifetime allowed to be set by the LwM2M client"""
zh: """允许 LwM2M 客户端允许设置的心跳最小值"""
en: """Minimum value of lifetime allowed to be set by the LwM2M client."""
zh: """允许 LwM2M 客户端允许设置的心跳最小值"""
}
}
lwm2m_lifetime_max {
desc {
en: """Maximum value of lifetime allowed to be set by the LwM2M client"""
zh: """允许 LwM2M 客户端允许设置的心跳最大值"""
en: """Maximum value of lifetime allowed to be set by the LwM2M client."""
zh: """允许 LwM2M 客户端允许设置的心跳最大值"""
}
}
@ -207,14 +207,14 @@ This option specifies the QoS level for the CoAP Client when publishing a messag
For example, after receiving an update message from a client, any messages within this time window are sent directly to the LwM2M client, and all messages beyond this time window are temporarily stored in memory."""
zh: """在QMode模式下LwM2M网关认为网络链接有效的时间窗口的值。
例如在收到客户端的更新信息后在这个时间窗口内的任何信息都会直接发送到LwM2M客户端而超过这个时间窗口的所有信息都会暂时储存在内存中"""
例如在收到客户端的更新信息后在这个时间窗口内的任何信息都会直接发送到LwM2M客户端而超过这个时间窗口的所有信息都会暂时储存在内存中"""
}
}
lwm2m_auto_observe {
desc {
en: """Automatically observe the object list of REGISTER packet"""
zh: """自动 Observe REGISTER 数据包的 Object 列表"""
en: """Automatically observe the object list of REGISTER packet."""
zh: """自动 Observe REGISTER 数据包的 Object 列表"""
}
}
@ -226,15 +226,15 @@ For example, after receiving an update message from a client, any messages withi
"""
zh: """发布UPDATE事件消息的策略。
- always: 只要收到 UPDATE 请求,就发送更新事件。
- contains_object_list: 仅当 UPDATE 请求携带 Object 列表时才发送更新事件
- contains_object_list: 仅当 UPDATE 请求携带 Object 列表时才发送更新事件
"""
}
}
lwm2m_translators {
desc {
en: """Topic configuration for LwM2M's gateway publishing and subscription"""
zh: """LwM2M 网关订阅/发布消息的主题映射配置"""
en: """Topic configuration for LwM2M's gateway publishing and subscription."""
zh: """LwM2M 网关订阅/发布消息的主题映射配置"""
}
}
@ -244,14 +244,14 @@ For example, after receiving an update message from a client, any messages withi
For each new LwM2M client that succeeds in going online, the gateway creates a subscription relationship to receive downstream commands and send it to the LwM2M client"""
zh: """下行命令主题。
对于每个成功上线的新 LwM2M 客户端,网关会创建一个订阅关系来接收下行消息并将其发送给客户端"""
对于每个成功上线的新 LwM2M 客户端,网关会创建一个订阅关系来接收下行消息并将其发送给客户端"""
}
}
lwm2m_translators_response {
desc {
en: """The topic for gateway to publish the acknowledge events from LwM2M client"""
zh: """用于网关发布来自 LwM2M 客户端的确认事件的主题"""
zh: """用于网关发布来自 LwM2M 客户端的确认事件的主题"""
}
}
@ -261,28 +261,28 @@ For each new LwM2M client that succeeds in going online, the gateway creates a s
After succeed observe a resource of LwM2M client, Gateway will send the notify events via this topic, if the client reports any resource changes"""
zh: """用于发布来自 LwM2M 客户端的通知事件的主题。
在成功 Observe 到 LwM2M 客户端的资源后,如果客户端报告任何资源状态的变化,网关将通过该主题发送通知事件"""
在成功 Observe 到 LwM2M 客户端的资源后,如果客户端报告任何资源状态的变化,网关将通过该主题发送通知事件"""
}
}
lwm2m_translators_register {
desc {
en: """The topic for gateway to publish the register events from LwM2M client."""
zh: """用于发布来自 LwM2M 客户端的注册事件的主题"""
zh: """用于发布来自 LwM2M 客户端的注册事件的主题"""
}
}
lwm2m_translators_update {
desc {
en: """The topic for gateway to publish the update events from LwM2M client"""
zh: """用于发布来自LwM2M客户端的更新事件的主题"""
zh: """用于发布来自LwM2M客户端的更新事件的主题"""
}
}
translator {
desc {
en: """MQTT topic that corresponds to a particular type of event."""
zh: """配置某网关客户端对于发布消息或订阅的主题和 QoS 等级"""
zh: """配置某网关客户端对于发布消息或订阅的主题和 QoS 等级"""
}
}
@ -412,28 +412,28 @@ After succeed observe a resource of LwM2M client, Gateway will send the notify e
gateway_common_authentication {
desc {
en: """Default authentication configs for all the gateway listeners. For per-listener overrides see <code>authentication</code>\n in listener configs"""
zh: """网关的认证器配置,对该网关下所以的监听器生效。如果每个监听器需要配置不同的认证器,需要配置监听器下的 <code>authentication</code> 字段"""
zh: """网关的认证器配置,对该网关下所以的监听器生效。如果每个监听器需要配置不同的认证器,需要配置监听器下的 <code>authentication</code> 字段"""
}
}
tcp_udp_listeners {
desc {
en: """Settings for the listeners."""
zh: """监听器配置"""
zh: """监听器配置"""
}
}
tcp_listeners {
desc {
en: """Settings for the TCP listeners."""
zh: """配置 TCP 类型的监听器"""
zh: """配置 TCP 类型的监听器"""
}
}
udp_listeners {
desc {
en: """Settings for the UDP listeners."""
zh: """配置 UDP 类型的监听器"""
zh: """配置 UDP 类型的监听器"""
}
}
@ -454,7 +454,7 @@ After succeed observe a resource of LwM2M client, Gateway will send the notify e
tcp_listener_tcp_opts{
desc {
en: """Setting the TCP socket options."""
zh: """TCP Socket 配置"""
zh: """TCP Socket 配置"""
}
}
@ -484,7 +484,7 @@ EMQX will close the TCP connection if proxy protocol packet is not received with
ssl_listener_options {
desc {
en: """SSL Socket options."""
zh: """SSL Socket 配置"""
zh: """SSL Socket 配置"""
}
}
@ -498,7 +498,7 @@ EMQX will close the TCP connection if proxy protocol packet is not received with
udp_listener_udp_opts {
desc {
en: """Settings for the UDP sockets."""
zh: """UDP Socket 配置 """
zh: """UDP Socket 配置"""
}
}
@ -535,7 +535,7 @@ See: https://erlang.org/doc/man/inet.html#setopts-2"""
udp_listener_reuseaddr {
desc {
en: """Allow local reuse of port numbers."""
zh: """允许重用本地处于 TIME_WAIT 的端口号"""
zh: """允许重用本地处于 TIME_WAIT 的端口号"""
}
}

View File

@ -118,9 +118,11 @@ list_nodes() ->
Running = mria_mnesia:cluster_nodes(running),
Stopped = mria_mnesia:cluster_nodes(stopped),
DownNodes = lists:map(fun stopped_node_info/1, Stopped),
[{Node, node_info(Node)} || Node <- Running] ++ DownNodes.
[{Node, Info} || #{node := Node} = Info <- node_info(Running)] ++ DownNodes.
lookup_node(Node) -> node_info(Node).
lookup_node(Node) ->
[Info] = node_info([Node]),
Info.
node_info() ->
{UsedRatio, Total} = get_sys_memory(),
@ -152,8 +154,8 @@ get_sys_memory() ->
{0, 0}
end.
node_info(Node) ->
wrap_rpc(emqx_management_proto_v2:node_info(Node)).
node_info(Nodes) ->
emqx_rpc:unwrap_erpc(emqx_management_proto_v3:node_info(Nodes)).
stopped_node_info(Node) ->
#{name => Node, node_status => 'stopped'}.
@ -163,17 +165,19 @@ stopped_node_info(Node) ->
%%--------------------------------------------------------------------
list_brokers() ->
[{Node, broker_info(Node)} || Node <- mria_mnesia:running_nodes()].
Running = mria_mnesia:running_nodes(),
[{Node, Broker} || #{node := Node} = Broker <- broker_info(Running)].
lookup_broker(Node) ->
broker_info(Node).
[Broker] = broker_info([Node]),
Broker.
broker_info() ->
Info = maps:from_list([{K, iolist_to_binary(V)} || {K, V} <- emqx_sys:info()]),
Info#{node => node(), otp_release => otp_rel(), node_status => 'Running'}.
broker_info(Node) ->
wrap_rpc(emqx_management_proto_v2:broker_info(Node)).
broker_info(Nodes) ->
emqx_rpc:unwrap_erpc(emqx_management_proto_v3:broker_info(Nodes)).
%%--------------------------------------------------------------------
%% Metrics and Stats
@ -183,7 +187,7 @@ get_metrics() ->
nodes_info_count([get_metrics(Node) || Node <- mria_mnesia:running_nodes()]).
get_metrics(Node) ->
wrap_rpc(emqx_proto_v1:get_metrics(Node)).
unwrap_rpc(emqx_proto_v1:get_metrics(Node)).
get_stats() ->
GlobalStatsKeys =
@ -211,7 +215,7 @@ delete_keys(List, [Key | Keys]) ->
delete_keys(proplists:delete(Key, List), Keys).
get_stats(Node) ->
wrap_rpc(emqx_proto_v1:get_stats(Node)).
unwrap_rpc(emqx_proto_v1:get_stats(Node)).
nodes_info_count(PropList) ->
NodeCount =
@ -241,7 +245,7 @@ lookup_client({username, Username}, FormatFun) ->
]).
lookup_client(Node, Key, {M, F}) ->
case wrap_rpc(emqx_cm_proto_v1:lookup_client(Node, Key)) of
case unwrap_rpc(emqx_cm_proto_v1:lookup_client(Node, Key)) of
{error, Err} ->
{error, Err};
L ->
@ -264,7 +268,7 @@ kickout_client({ClientID, FormatFun}) ->
end.
kickout_client(Node, ClientId) ->
wrap_rpc(emqx_cm_proto_v1:kickout_client(Node, ClientId)).
unwrap_rpc(emqx_cm_proto_v1:kickout_client(Node, ClientId)).
list_authz_cache(ClientId) ->
call_client(ClientId, list_authz_cache).
@ -284,14 +288,14 @@ list_client_subscriptions(ClientId) ->
end.
client_subscriptions(Node, ClientId) ->
{Node, wrap_rpc(emqx_broker_proto_v1:list_client_subscriptions(Node, ClientId))}.
{Node, unwrap_rpc(emqx_broker_proto_v1:list_client_subscriptions(Node, ClientId))}.
clean_authz_cache(ClientId) ->
Results = [clean_authz_cache(Node, ClientId) || Node <- mria_mnesia:running_nodes()],
check_results(Results).
clean_authz_cache(Node, ClientId) ->
wrap_rpc(emqx_proto_v1:clean_authz_cache(Node, ClientId)).
unwrap_rpc(emqx_proto_v1:clean_authz_cache(Node, ClientId)).
clean_authz_cache_all() ->
Results = [{Node, clean_authz_cache_all(Node)} || Node <- mria_mnesia:running_nodes()],
@ -308,10 +312,10 @@ wrap_results(Results) ->
end.
clean_authz_cache_all(Node) ->
wrap_rpc(emqx_proto_v1:clean_authz_cache(Node)).
unwrap_rpc(emqx_proto_v1:clean_authz_cache(Node)).
clean_pem_cache_all(Node) ->
wrap_rpc(emqx_proto_v1:clean_pem_cache(Node)).
unwrap_rpc(emqx_proto_v1:clean_pem_cache(Node)).
set_ratelimit_policy(ClientId, Policy) ->
call_client(ClientId, {ratelimit, Policy}).
@ -357,7 +361,7 @@ do_call_client(ClientId, Req) ->
%% @private
call_client(Node, ClientId, Req) ->
wrap_rpc(emqx_management_proto_v2:call_client(Node, ClientId, Req)).
unwrap_rpc(emqx_management_proto_v3:call_client(Node, ClientId, Req)).
%%--------------------------------------------------------------------
%% Subscriptions
@ -376,7 +380,7 @@ do_list_subscriptions() ->
end.
list_subscriptions(Node) ->
wrap_rpc(emqx_management_proto_v2:list_subscriptions(Node)).
unwrap_rpc(emqx_management_proto_v3:list_subscriptions(Node)).
list_subscriptions_via_topic(Topic, FormatFun) ->
lists:append([
@ -385,7 +389,7 @@ list_subscriptions_via_topic(Topic, FormatFun) ->
]).
list_subscriptions_via_topic(Node, Topic, _FormatFun = {M, F}) ->
case wrap_rpc(emqx_broker_proto_v1:list_subscriptions_via_topic(Node, Topic)) of
case unwrap_rpc(emqx_broker_proto_v1:list_subscriptions_via_topic(Node, Topic)) of
{error, Reason} -> {error, Reason};
Result -> M:F(Result)
end.
@ -394,7 +398,7 @@ lookup_subscriptions(ClientId) ->
lists:append([lookup_subscriptions(Node, ClientId) || Node <- mria_mnesia:running_nodes()]).
lookup_subscriptions(Node, ClientId) ->
wrap_rpc(emqx_broker_proto_v1:list_client_subscriptions(Node, ClientId)).
unwrap_rpc(emqx_broker_proto_v1:list_client_subscriptions(Node, ClientId)).
%%--------------------------------------------------------------------
%% PubSub
@ -404,7 +408,7 @@ subscribe(ClientId, TopicTables) ->
subscribe(mria_mnesia:running_nodes(), ClientId, TopicTables).
subscribe([Node | Nodes], ClientId, TopicTables) ->
case wrap_rpc(emqx_management_proto_v2:subscribe(Node, ClientId, TopicTables)) of
case unwrap_rpc(emqx_management_proto_v3:subscribe(Node, ClientId, TopicTables)) of
{error, _} -> subscribe(Nodes, ClientId, TopicTables);
{subscribe, Res} -> {subscribe, Res, Node}
end;
@ -431,7 +435,7 @@ unsubscribe(ClientId, Topic) ->
-spec unsubscribe([node()], emqx_types:clientid(), emqx_types:topic()) ->
{unsubscribe, _} | {error, channel_not_found}.
unsubscribe([Node | Nodes], ClientId, Topic) ->
case wrap_rpc(emqx_management_proto_v2:unsubscribe(Node, ClientId, Topic)) of
case unwrap_rpc(emqx_management_proto_v3:unsubscribe(Node, ClientId, Topic)) of
{error, _} -> unsubscribe(Nodes, ClientId, Topic);
Re -> Re
end;
@ -454,7 +458,7 @@ unsubscribe_batch(ClientId, Topics) ->
-spec unsubscribe_batch([node()], emqx_types:clientid(), [emqx_types:topic()]) ->
{unsubscribe_batch, _} | {error, channel_not_found}.
unsubscribe_batch([Node | Nodes], ClientId, Topics) ->
case wrap_rpc(emqx_management_proto_v2:unsubscribe_batch(Node, ClientId, Topics)) of
case unwrap_rpc(emqx_management_proto_v3:unsubscribe_batch(Node, ClientId, Topics)) of
{error, _} -> unsubscribe_batch(Nodes, ClientId, Topics);
Re -> Re
end;
@ -477,16 +481,16 @@ get_alarms(Type) ->
[{Node, get_alarms(Node, Type)} || Node <- mria_mnesia:running_nodes()].
get_alarms(Node, Type) ->
add_duration_field(wrap_rpc(emqx_proto_v1:get_alarms(Node, Type))).
add_duration_field(unwrap_rpc(emqx_proto_v1:get_alarms(Node, Type))).
deactivate(Node, Name) ->
wrap_rpc(emqx_proto_v1:deactivate_alarm(Node, Name)).
unwrap_rpc(emqx_proto_v1:deactivate_alarm(Node, Name)).
delete_all_deactivated_alarms() ->
[delete_all_deactivated_alarms(Node) || Node <- mria_mnesia:running_nodes()].
delete_all_deactivated_alarms(Node) ->
wrap_rpc(emqx_proto_v1:delete_all_deactivated_alarms(Node)).
unwrap_rpc(emqx_proto_v1:delete_all_deactivated_alarms(Node)).
add_duration_field(Alarms) ->
Now = erlang:system_time(microsecond),
@ -523,10 +527,9 @@ delete_banned(Who) ->
%%--------------------------------------------------------------------
%% Internal Functions.
%%--------------------------------------------------------------------
wrap_rpc({badrpc, Reason}) ->
unwrap_rpc({badrpc, Reason}) ->
{error, Reason};
wrap_rpc(Res) ->
unwrap_rpc(Res) ->
Res.
otp_rel() ->
@ -546,7 +549,7 @@ check_row_limit([Tab | Tables], Limit) ->
check_results(Results) ->
case lists:any(fun(Item) -> Item =:= ok end, Results) of
true -> ok;
false -> wrap_rpc(lists:last(Results))
false -> unwrap_rpc(lists:last(Results))
end.
max_row_limit() ->

View File

@ -115,7 +115,7 @@ schema("/configs_reset/:rootname") ->
tags => ?TAGS,
description =>
<<
"Reset the config entry specified by the query string parameter `conf_path`.</br>\n"
"Reset the config entry specified by the query string parameter `conf_path`.<br/>"
"- For a config entry that has default value, this resets it to the default value;\n"
"- For a config entry that has no default value, an error 400 will be returned"
>>,

View File

@ -70,8 +70,8 @@ schema("/plugins") ->
'operationId' => list_plugins,
get => #{
description =>
"List all install plugins.</br>"
"Plugins are launched in top-down order.</br>"
"List all install plugins.<br/>"
"Plugins are launched in top-down order.<br/>"
"Using `POST /plugins/{name}/move` to change the boot order.",
tags => ?TAGS,
responses => #{
@ -136,9 +136,9 @@ schema("/plugins/:name/:action") ->
'operationId' => update_plugin,
put => #{
description =>
"start/stop a installed plugin.</br>"
"- **start**: start the plugin.</br>"
"- **stop**: stop the plugin.</br>",
"start/stop a installed plugin.<br/>"
"- **start**: start the plugin.<br/>"
"- **stop**: stop the plugin.<br/>",
tags => ?TAGS,
parameters => [
hoconsc:ref(name),
@ -272,9 +272,9 @@ fields(running_status) ->
{status,
hoconsc:mk(hoconsc:enum([running, stopped]), #{
desc =>
"Install plugin status at runtime</br>"
"1. running: plugin is running.</br>"
"2. stopped: plugin is stopped.</br>"
"Install plugin status at runtime<br/>"
"1. running: plugin is running.<br/>"
"2. stopped: plugin is stopped.<br/>"
})}
].

View File

@ -45,7 +45,16 @@ running_status() ->
BrokerStatus = broker_status(),
AppStatus = application_status(),
Body = io_lib:format("Node ~ts is ~ts~nemqx is ~ts", [node(), BrokerStatus, AppStatus]),
{200, #{<<"content-type">> => <<"text/plain">>}, list_to_binary(Body)};
StatusCode =
case AppStatus of
running -> 200;
not_running -> 503
end,
Headers = #{
<<"content-type">> => <<"text/plain">>,
<<"retry-after">> => <<"15">>
},
{StatusCode, Headers, list_to_binary(Body)};
false ->
{503, #{<<"retry-after">> => <<"15">>}, <<>>}
end.

View File

@ -0,0 +1,80 @@
%%--------------------------------------------------------------------
%% Copyright (c) 2022 EMQ Technologies Co., Ltd. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
%% You may obtain a copy of the License at
%%
%% http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing, software
%% distributed under the License is distributed on an "AS IS" BASIS,
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
%% See the License for the specific language governing permissions and
%% limitations under the License.
%%--------------------------------------------------------------------
-module(emqx_management_proto_v3).
-behaviour(emqx_bpapi).
-export([
introduced_in/0,
node_info/1,
broker_info/1,
list_subscriptions/1,
list_listeners/1,
subscribe/3,
unsubscribe/3,
unsubscribe_batch/3,
call_client/3,
get_full_config/1
]).
-include_lib("emqx/include/bpapi.hrl").
introduced_in() ->
"5.0.9".
-spec unsubscribe_batch(node(), emqx_types:clientid(), [emqx_types:topic()]) ->
{unsubscribe, _} | {error, _} | {badrpc, _}.
unsubscribe_batch(Node, ClientId, Topics) ->
rpc:call(Node, emqx_mgmt, do_unsubscribe_batch, [ClientId, Topics]).
-spec node_info([node()]) -> emqx_rpc:erpc_multicall(map()).
node_info(Nodes) ->
erpc:multicall(Nodes, emqx_mgmt, node_info, [], 30000).
-spec broker_info([node()]) -> emqx_rpc:erpc_multicall(map()).
broker_info(Nodes) ->
erpc:multicall(Nodes, emqx_mgmt, broker_info, [], 30000).
-spec list_subscriptions(node()) -> [map()] | {badrpc, _}.
list_subscriptions(Node) ->
rpc:call(Node, emqx_mgmt, do_list_subscriptions, []).
-spec list_listeners(node()) -> map() | {badrpc, _}.
list_listeners(Node) ->
rpc:call(Node, emqx_mgmt_api_listeners, do_list_listeners, []).
-spec subscribe(node(), emqx_types:clientid(), emqx_types:topic_filters()) ->
{subscribe, _} | {error, atom()} | {badrpc, _}.
subscribe(Node, ClientId, TopicTables) ->
rpc:call(Node, emqx_mgmt, do_subscribe, [ClientId, TopicTables]).
-spec unsubscribe(node(), emqx_types:clientid(), emqx_types:topic()) ->
{unsubscribe, _} | {error, _} | {badrpc, _}.
unsubscribe(Node, ClientId, Topic) ->
rpc:call(Node, emqx_mgmt, do_unsubscribe, [ClientId, Topic]).
-spec call_client(node(), emqx_types:clientid(), term()) -> term().
call_client(Node, ClientId, Req) ->
rpc:call(Node, emqx_mgmt, do_call_client, [ClientId, Req]).
-spec get_full_config(node()) -> map() | list() | {badrpc, _}.
get_full_config(Node) ->
rpc:call(Node, emqx_mgmt_api_configs, get_full_config, []).

View File

@ -113,3 +113,51 @@ t_node_metrics_api(_) ->
{error, {_, 400, _}},
emqx_mgmt_api_test_util:request_api(get, BadNodePath)
).
t_multiple_nodes_api(_) ->
net_kernel:start(['node_api@127.0.0.1', longnames]),
ct:timetrap({seconds, 120}),
snabbkaffe:fix_ct_logging(),
Seq1 = list_to_atom(atom_to_list(?MODULE) ++ "1"),
Seq2 = list_to_atom(atom_to_list(?MODULE) ++ "2"),
Cluster = [{Name, Opts}, {Name1, Opts1}] = cluster([{core, Seq1}, {core, Seq2}]),
ct:pal("Starting ~p", [Cluster]),
Node1 = emqx_common_test_helpers:start_slave(Name, Opts),
Node2 = emqx_common_test_helpers:start_slave(Name1, Opts1),
try
{200, NodesList} = rpc:call(Node1, emqx_mgmt_api_nodes, nodes, [get, #{}]),
All = [Node1, Node2],
lists:map(
fun(N) ->
N1 = maps:get(node, N),
?assertEqual(true, lists:member(N1, All))
end,
NodesList
),
?assertEqual(2, length(NodesList)),
{200, Node11} = rpc:call(Node1, emqx_mgmt_api_nodes, node, [
get, #{bindings => #{node => Node1}}
]),
?assertMatch(#{node := Node1}, Node11)
after
emqx_common_test_helpers:stop_slave(Node1),
emqx_common_test_helpers:stop_slave(Node2)
end,
ok.
cluster(Specs) ->
Env = [{emqx, boot_modules, []}],
emqx_common_test_helpers:emqx_cluster(Specs, [
{env, Env},
{apps, [emqx_conf]},
{load_schema, false},
{join_to, true},
{env_handler, fun
(emqx) ->
application:set_env(emqx, boot_modules, []),
ok;
(_) ->
ok
end}
]).

View File

@ -20,6 +20,12 @@
-include_lib("eunit/include/eunit.hrl").
-define(HOST, "http://127.0.0.1:18083/").
%%---------------------------------------------------------------------------------------
%% CT boilerplate
%%---------------------------------------------------------------------------------------
all() ->
emqx_common_test_helpers:all(?MODULE).
@ -30,8 +36,102 @@ init_per_suite(Config) ->
end_per_suite(_) ->
emqx_mgmt_api_test_util:end_suite().
t_status(_Config) ->
Path = emqx_mgmt_api_test_util:api_path_without_base_path(["/status"]),
Status = io_lib:format("Node ~ts is ~ts~nemqx is ~ts", [node(), started, running]),
{ok, Status} = emqx_mgmt_api_test_util:request_api(get, Path),
init_per_testcase(t_status_not_ok, Config) ->
ok = application:stop(emqx),
Config;
init_per_testcase(_TestCase, Config) ->
Config.
end_per_testcase(t_status_not_ok, _Config) ->
{ok, _} = application:ensure_all_started(emqx),
ok;
end_per_testcase(_TestCase, _Config) ->
ok.
%%---------------------------------------------------------------------------------------
%% Helper fns
%%---------------------------------------------------------------------------------------
do_request(Opts) ->
#{
path := Path0,
method := Method,
headers := Headers,
body := Body0
} = Opts,
URL = ?HOST ++ filename:join(Path0),
{ok, #{host := Host, port := Port, path := Path}} = emqx_http_lib:uri_parse(URL),
%% we must not use `httpc' here, because it keeps retrying when it
%% receives a 503 with `retry-after' header, and there's no option
%% to stop that behavior...
{ok, Gun} = gun:open(Host, Port, #{retry => 0}),
{ok, http} = gun:await_up(Gun),
Request =
fun() ->
case Body0 of
no_body -> gun:Method(Gun, Path, Headers);
{_Encoding, Body} -> gun:Method(Gun, Path, Headers, Body)
end
end,
Ref = Request(),
receive
{gun_response, Gun, Ref, nofin, StatusCode, Headers1} ->
Data = data_loop(Gun, Ref, _Acc = <<>>),
#{status_code => StatusCode, headers => maps:from_list(Headers1), body => Data}
after 5_000 ->
error({timeout, Opts, process_info(self(), messages)})
end.
data_loop(Gun, Ref, Acc) ->
receive
{gun_data, Gun, Ref, nofin, Data} ->
data_loop(Gun, Ref, <<Acc/binary, Data/binary>>);
{gun_data, Gun, Ref, fin, Data} ->
gun:shutdown(Gun),
<<Acc/binary, Data/binary>>
after 5000 ->
error(timeout)
end.
%%---------------------------------------------------------------------------------------
%% Test cases
%%---------------------------------------------------------------------------------------
t_status_ok(_Config) ->
#{
body := Resp,
status_code := StatusCode
} = do_request(#{
method => get,
path => ["status"],
headers => [],
body => no_body
}),
?assertEqual(200, StatusCode),
?assertMatch(
{match, _},
re:run(Resp, <<"emqx is running$">>)
),
ok.
t_status_not_ok(_Config) ->
#{
body := Resp,
headers := Headers,
status_code := StatusCode
} = do_request(#{
method => get,
path => ["status"],
headers => [],
body => no_body
}),
?assertEqual(503, StatusCode),
?assertMatch(
{match, _},
re:run(Resp, <<"emqx is not_running$">>)
),
?assertMatch(
#{<<"retry-after">> := <<"15">>},
Headers
),
ok.

View File

@ -2,14 +2,14 @@ emqx_plugins_schema {
plugins {
desc {
en: """
Manage EMQX plugins.</br>
Manage EMQX plugins.<br/>
Plugins can be pre-built as a part of EMQX package,
or installed as a standalone package in a location specified by
<code>install_dir</code> config key</br>
<code>install_dir</code> config key<br/>
The standalone-installed plugins are referred to as 'external' plugins.
"""
zh: """管理EMQX插件。</br>
插件可以是EMQX安装包中的一部分也可以是一个独立的安装包。</br>
zh: """管理EMQX插件。<br/>
插件可以是EMQX安装包中的一部分也可以是一个独立的安装包。<br/>
独立安装的插件称为“外部插件”。
"""
}
@ -30,11 +30,11 @@ The standalone-installed plugins are referred to as 'external' plugins.
}
name_vsn {
desc {
en: """The {name}-{version} of the plugin.</br>
It should match the plugin application name-version as the for the plugin release package name</br>
en: """The {name}-{version} of the plugin.<br/>
It should match the plugin application name-version as the for the plugin release package name<br/>
For example: my_plugin-0.1.0.
"""
zh: """插件的名称{name}-{version}。</br>
zh: """插件的名称{name}-{version}。<br/>
它应该与插件的发布包名称一致如my_plugin-0.1.0。"""
}
label {
@ -54,7 +54,7 @@ For example: my_plugin-0.1.0.
}
states {
desc {
en: """An array of plugins in the desired states.</br>
en: """An array of plugins in the desired states.<br/>
The plugins are started in the defined order"""
zh: """一组插件的状态。插件将按照定义的顺序启动"""
}
@ -69,11 +69,11 @@ The plugins are started in the defined order"""
The installation directory for the external plugins.
The plugin beam files and configuration files should reside in
the subdirectory named as <code>emqx_foo_bar-0.1.0</code>.
</br>
<br/>
NOTE: For security reasons, this directory should **NOT** be writable
by anyone except <code>emqx</code> (or any user which runs EMQX).
"""
zh: "插件安装包的目录, 不要自己创建, 只能由emqx用户创建与修改"
zh: "插件安装包的目录,出于安全考虑,该目录应该值允许 <code>emqx</code>,或用于运行 EMQX 服务的用户拥有写入权限。"
}
label {
en: "Install Directory"
@ -82,10 +82,10 @@ by anyone except <code>emqx</code> (or any user which runs EMQX).
}
check_interval {
desc {
en: """Check interval: check if the status of the plugins in the cluster is consistent, </br>
en: """Check interval: check if the status of the plugins in the cluster is consistent, <br/>
if the results of 3 consecutive checks are not consistent, then alarm.
"""
zh: """检查间隔:检查集群中插件的状态是否一致,</br>
zh: """检查间隔:检查集群中插件的状态是否一致,<br/>
如果连续3次检查结果不一致则报警。
"""
}

View File

@ -1 +1,2 @@
-define(APP, emqx_prometheus).
-define(PROMETHEUS, [prometheus]).

View File

@ -37,18 +37,8 @@
]
).
-export([
update/1,
start/0,
stop/0,
restart/0,
% for rpc
do_start/0,
do_stop/0
]).
%% APIs
-export([start_link/1]).
-export([start_link/1, info/0]).
%% gen_server callbacks
-export([
@ -69,88 +59,69 @@
-export([collect/1]).
-export([
%% For bpapi, deprecated_since 5.0.10, remove this when 5.1.x
do_start/0,
do_stop/0
]).
-define(C(K, L), proplists:get_value(K, L, 0)).
-define(TIMER_MSG, '#interval').
-record(state, {push_gateway, timer, interval}).
%%--------------------------------------------------------------------
%% update new config
update(Config) ->
case
emqx_conf:update(
[prometheus],
Config,
#{rawconf_with_defaults => true, override_to => cluster}
)
of
{ok, #{raw_config := NewConfigRows}} ->
case maps:get(<<"enable">>, Config, true) of
true ->
ok = restart();
false ->
ok = stop()
end,
{ok, NewConfigRows};
{error, Reason} ->
{error, Reason}
end.
start() ->
{_, []} = emqx_prometheus_proto_v1:start(mria_mnesia:running_nodes()),
ok.
stop() ->
{_, []} = emqx_prometheus_proto_v1:stop(mria_mnesia:running_nodes()),
ok.
restart() ->
ok = stop(),
ok = start().
do_start() ->
emqx_prometheus_sup:start_child(?APP, emqx_conf:get([prometheus])).
do_stop() ->
case emqx_prometheus_sup:stop_child(?APP) of
ok ->
ok;
{error, not_found} ->
ok
end.
-define(HTTP_OPTIONS, [{autoredirect, true}, {timeout, 60000}]).
%%--------------------------------------------------------------------
%% APIs
%%--------------------------------------------------------------------
start_link(Opts) ->
gen_server:start_link({local, ?MODULE}, ?MODULE, [Opts], []).
start_link([]) ->
gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
info() ->
gen_server:call(?MODULE, info).
%%--------------------------------------------------------------------
%% gen_server callbacks
%%--------------------------------------------------------------------
init([Opts]) ->
Interval = maps:get(interval, Opts),
PushGateway = maps:get(push_gateway_server, Opts),
{ok, ensure_timer(#state{push_gateway = PushGateway, interval = Interval})}.
init([]) ->
#{interval := Interval} = opts(),
{ok, #{timer => ensure_timer(Interval), ok => 0, failed => 0}}.
handle_call(info, _From, State = #{timer := Timer}) ->
{reply, State#{opts => opts(), next_push_ms => erlang:read_timer(Timer)}, State};
handle_call(_Msg, _From, State) ->
{noreply, State}.
{reply, ok, State}.
handle_cast(_Msg, State) ->
{noreply, State}.
handle_info({timeout, R, ?TIMER_MSG}, State = #state{timer = R, push_gateway = Uri}) ->
handle_info({timeout, Timer, ?TIMER_MSG}, State = #{timer := Timer}) ->
#{interval := Interval, push_gateway_server := Server} = opts(),
PushRes = push_to_push_gateway(Server),
NewTimer = ensure_timer(Interval),
NewState = maps:update_with(PushRes, fun(C) -> C + 1 end, 1, State#{timer => NewTimer}),
%% Data is too big, hibernate for saving memory and stop system monitor warning.
{noreply, NewState, hibernate};
handle_info(_Msg, State) ->
{noreply, State}.
push_to_push_gateway(Uri) ->
[Name, Ip] = string:tokens(atom_to_list(node()), "@"),
Url = lists:concat([Uri, "/metrics/job/", Name, "/instance/", Name, "~", Ip]),
Data = prometheus_text_format:format(),
httpc:request(post, {Url, [], "text/plain", Data}, [{autoredirect, true}], []),
%% Data is too big, hibernate for saving memory and stop system monitor warning.
{noreply, ensure_timer(State), hibernate};
handle_info(_Msg, State) ->
{noreply, State}.
case httpc:request(post, {Url, [], "text/plain", Data}, ?HTTP_OPTIONS, []) of
{ok, {{"HTTP/1.1", 200, "OK"}, _Headers, _Body}} ->
ok;
Error ->
?SLOG(error, #{
msg => "post_to_push_gateway_failed",
error => Error,
url => Url
}),
failed
end.
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
@ -158,11 +129,14 @@ code_change(_OldVsn, State, _Extra) ->
terminate(_Reason, _State) ->
ok.
ensure_timer(State = #state{interval = Interval}) ->
State#state{timer = emqx_misc:start_timer(Interval, ?TIMER_MSG)}.
ensure_timer(Interval) ->
emqx_misc:start_timer(Interval, ?TIMER_MSG).
%%--------------------------------------------------------------------
%% prometheus callbacks
%%--------------------------------------------------------------------
opts() ->
emqx_conf:get(?PROMETHEUS).
deregister_cleanup(_Registry) ->
ok.
@ -623,3 +597,11 @@ emqx_cluster_data() ->
{nodes_running, length(Running)},
{nodes_stopped, length(Stopped)}
].
%% deprecated_since 5.0.10, remove this when 5.1.x
do_start() ->
emqx_prometheus_sup:start_child(?APP).
%% deprecated_since 5.0.10, remove this when 5.1.x
do_stop() ->
emqx_prometheus_sup:stop_child(?APP).

View File

@ -84,7 +84,7 @@ schema("/prometheus/stats") ->
prometheus(get, _Params) ->
{200, emqx:get_raw_config([<<"prometheus">>], #{})};
prometheus(put, #{body := Body}) ->
case emqx_prometheus:update(Body) of
case emqx_prometheus_config:update(Body) of
{ok, NewConfig} ->
{200, NewConfig};
{error, Reason} ->
@ -120,7 +120,13 @@ prometheus_config_example() ->
#{
enable => true,
interval => "15s",
push_gateway_server => <<"http://127.0.0.1:9091">>
push_gateway_server => <<"http://127.0.0.1:9091">>,
vm_dist_collector => enabled,
mnesia_collector => enabled,
vm_statistics_collector => enabled,
vm_system_info_collector => enabled,
vm_memory_collector => enabled,
vm_msacc_collector => enabled
}.
prometheus_data_schema() ->

View File

@ -27,17 +27,10 @@
]).
start(_StartType, _StartArgs) ->
{ok, Sup} = emqx_prometheus_sup:start_link(),
maybe_enable_prometheus(),
{ok, Sup}.
Res = emqx_prometheus_sup:start_link(),
emqx_prometheus_config:add_handler(),
Res.
stop(_State) ->
emqx_prometheus_config:remove_handler(),
ok.
maybe_enable_prometheus() ->
case emqx_conf:get([prometheus, enable], false) of
true ->
emqx_prometheus_sup:start_child(?APP, emqx_conf:get([prometheus], #{}));
false ->
ok
end.

View File

@ -0,0 +1,57 @@
%%--------------------------------------------------------------------
%% Copyright (c) 2020-2022 EMQ Technologies Co., Ltd. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
%% You may obtain a copy of the License at
%%
%% http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing, software
%% distributed under the License is distributed on an "AS IS" BASIS,
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
%% See the License for the specific language governing permissions and
%% limitations under the License.
%%--------------------------------------------------------------------
-module(emqx_prometheus_config).
-behaviour(emqx_config_handler).
-include("emqx_prometheus.hrl").
-export([add_handler/0, remove_handler/0]).
-export([post_config_update/5]).
-export([update/1]).
update(Config) ->
case
emqx_conf:update(
[prometheus],
Config,
#{rawconf_with_defaults => true, override_to => cluster}
)
of
{ok, #{raw_config := NewConfigRows}} ->
{ok, NewConfigRows};
{error, Reason} ->
{error, Reason}
end.
add_handler() ->
ok = emqx_config_handler:add_handler(?PROMETHEUS, ?MODULE),
ok.
remove_handler() ->
ok = emqx_config_handler:remove_handler(?PROMETHEUS),
ok.
post_config_update(?PROMETHEUS, _Req, New, _Old, AppEnvs) ->
application:set_env(AppEnvs),
update_prometheus(New);
post_config_update(_ConfPath, _Req, _NewConf, _OldConf, _AppEnvs) ->
ok.
update_prometheus(#{enable := true}) ->
emqx_prometheus_sup:start_child(?APP);
update_prometheus(#{enable := false}) ->
emqx_prometheus_sup:stop_child(?APP).

View File

@ -24,12 +24,13 @@
namespace/0,
roots/0,
fields/1,
desc/1
desc/1,
translation/1
]).
namespace() -> "prometheus".
roots() -> ["prometheus"].
roots() -> [{"prometheus", ?HOCON(?R_REF("prometheus"), #{translate_to => ["prometheus"]})}].
fields("prometheus") ->
[
@ -124,3 +125,7 @@ fields("prometheus") ->
desc("prometheus") -> ?DESC(prometheus);
desc(_) -> undefined.
%% for CI test, CI don't load the whole emqx_conf_schema.
translation(Name) ->
emqx_conf_schema:translation(Name).

View File

@ -21,7 +21,6 @@
-export([
start_link/0,
start_child/1,
start_child/2,
stop_child/1
]).
@ -40,23 +39,27 @@
start_link() ->
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
-spec start_child(supervisor:child_spec()) -> ok.
-spec start_child(supervisor:child_spec() | atom()) -> ok.
start_child(ChildSpec) when is_map(ChildSpec) ->
assert_started(supervisor:start_child(?MODULE, ChildSpec)).
-spec start_child(atom(), map()) -> ok.
start_child(Mod, Opts) when is_atom(Mod) andalso is_map(Opts) ->
assert_started(supervisor:start_child(?MODULE, ?CHILD(Mod, Opts))).
assert_started(supervisor:start_child(?MODULE, ChildSpec));
start_child(Mod) when is_atom(Mod) ->
assert_started(supervisor:start_child(?MODULE, ?CHILD(Mod, []))).
-spec stop_child(any()) -> ok | {error, term()}.
stop_child(ChildId) ->
case supervisor:terminate_child(?MODULE, ChildId) of
ok -> supervisor:delete_child(?MODULE, ChildId);
{error, not_found} -> ok;
Error -> Error
end.
init([]) ->
{ok, {{one_for_one, 10, 3600}, []}}.
Children =
case emqx_conf:get([prometheus, enable], false) of
false -> [];
true -> [?CHILD(emqx_prometheus, [])]
end,
{ok, {{one_for_one, 10, 3600}, Children}}.
%%--------------------------------------------------------------------
%% Internal functions
@ -64,5 +67,5 @@ init([]) ->
assert_started({ok, _Pid}) -> ok;
assert_started({ok, _Pid, _Info}) -> ok;
assert_started({error, {already_tarted, _Pid}}) -> ok;
assert_started({error, Reason}) -> erlang:error(Reason).
assert_started({error, {already_started, _Pid}}) -> ok;
assert_started({error, Reason}) -> {error, Reason}.

View File

@ -20,13 +20,15 @@
-export([
introduced_in/0,
deprecated_since/0,
start/1,
stop/1
]).
-include_lib("emqx/include/bpapi.hrl").
deprecated_since() -> "5.0.10".
introduced_in() ->
"5.0.0".

View File

@ -71,10 +71,14 @@ load_config() ->
%%--------------------------------------------------------------------
t_start_stop(_) ->
?assertMatch(ok, emqx_prometheus:start()),
?assertMatch(ok, emqx_prometheus:stop()),
?assertMatch(ok, emqx_prometheus:restart()),
%% wait the interval timer tigger
App = emqx_prometheus,
?assertMatch(ok, emqx_prometheus_sup:start_child(App)),
%% start twice return ok.
?assertMatch(ok, emqx_prometheus_sup:start_child(App)),
?assertMatch(ok, emqx_prometheus_sup:stop_child(App)),
%% stop twice return ok.
?assertMatch(ok, emqx_prometheus_sup:stop_child(App)),
%% wait the interval timer trigger
timer:sleep(2000).
t_collector_no_crash_test(_) ->

View File

@ -71,16 +71,27 @@ t_prometheus_api(_) ->
#{
<<"push_gateway_server">> := _,
<<"interval">> := _,
<<"enable">> := _
<<"enable">> := _,
<<"vm_statistics_collector">> := _,
<<"vm_system_info_collector">> := _,
<<"vm_memory_collector">> := _,
<<"vm_msacc_collector">> := _
},
Conf
),
NewConf = Conf#{<<"interval">> := <<"2s">>},
#{<<"enable">> := Enable} = Conf,
?assertEqual(Enable, undefined =/= erlang:whereis(emqx_prometheus)),
NewConf = Conf#{<<"interval">> => <<"2s">>, <<"vm_statistics_collector">> => <<"disabled">>},
{ok, Response2} = emqx_mgmt_api_test_util:request_api(put, Path, "", Auth, NewConf),
Conf2 = emqx_json:decode(Response2, [return_maps]),
?assertMatch(NewConf, Conf2),
?assertEqual({ok, []}, application:get_env(prometheus, vm_statistics_collector_metrics)),
?assertEqual({ok, all}, application:get_env(prometheus, vm_memory_collector_metrics)),
NewConf1 = Conf#{<<"enable">> => (not Enable)},
{ok, _Response3} = emqx_mgmt_api_test_util:request_api(put, Path, "", Auth, NewConf1),
?assertEqual((not Enable), undefined =/= erlang:whereis(emqx_prometheus)),
ok.
t_stats_api(_) ->

View File

@ -16,7 +16,7 @@ The IDs and secrets can be provided from a file which is configurable by the <co
PSK 是 “Pre-Shared-Keys” 的缩写。
注意: 确保 SSL 监听器仅启用了 'tlsv1.2', 并且配置了PSK 密码套件,例如 'RSA-PSK-AES256-GCM-SHA384'。
注意: 确保 SSL 监听器仅启用了 'tlsv1.2'并且配置了PSK 密码套件,例如 'RSA-PSK-AES256-GCM-SHA384'。
可以通过查看监听器中的 SSL 选项,了解更多详细信息。

View File

@ -119,7 +119,7 @@ retainer_indices(type) ->
retainer_indices(desc) ->
"Retainer index specifications: list of arrays of positive ascending integers. "
"Each array specifies an index. Numbers in an index specification are 1-based "
"word positions in topics. Words from specified positions will be used for indexing.</br>"
"word positions in topics. Words from specified positions will be used for indexing.<br/>"
"For example, it is good to have <code>[2, 4]</code> index to optimize "
"<code>+/X/+/Y/...</code> topic wildcard subscriptions.";
retainer_indices(example) ->

View File

@ -2,7 +2,7 @@
{application, emqx_rule_engine, [
{description, "EMQX Rule Engine"},
% strict semver, bump manually!
{vsn, "5.0.2"},
{vsn, "5.0.3"},
{modules, []},
{registered, [emqx_rule_engine_sup, emqx_rule_engine]},
{applications, [kernel, stdlib, rulesql, getopt]},

View File

@ -671,8 +671,8 @@ event_info_client_connack() ->
event_info_client_check_authz_complete() ->
event_info_common(
'client.check_authz_complete',
{<<"client check authz complete">>, <<"权结果"/utf8>>},
{<<"client check authz complete">>, <<"权结果"/utf8>>},
{<<"client check authz complete">>, <<"权结果"/utf8>>},
{<<"client check authz complete">>, <<"权结果"/utf8>>},
<<"SELECT * FROM \"$events/client_check_authz_complete\"">>
).
event_info_session_subscribed() ->

View File

@ -2,14 +2,25 @@
## Enhancements
- Improve `/nodes` API responsiveness [#9221](https://github.com/emqx/emqx/pull/9221).
- Allow clear retained/delayed data when client is banned [#9139](https://github.com/emqx/emqx/pull/9139).
- Update `gen_rpc` library to version 3.0 [#9187](https://github.com/emqx/emqx/pull/9187).
- Improve memory usage on core nodes when bootstrapping a replicant [#9236](https://github.com/emqx/emqx/pull/9236).
- Improve stability of Prometheus Push Gateway and log errors when POST fails [#9235](http://github.com/emqx/emqx/pull/9235).
- Now it is possible to opt out VM internal metrics in prometheus stats [#9222](https://github.com/emqx/emqx/pull/9222).
When system load is high, reporting too much metrics data may cause the prometheus stats API timeout.
## Bug fixes
- Fix error log message when `mechanism` is missing in authentication config [#8924](https://github.com/emqx/emqx/pull/8924).
- Fix HTTP 500 issue when unknown `status` parameter is used in `/gateway` API call [#7794](https://github.com/emqx/emqx/pull/9225).
- Fix HTTP 500 issue when unknown `status` parameter is used in `/gateway` API call [#9225](https://github.com/emqx/emqx/pull/9225).
- Fixed the HTTP response status code for the `/status` endpoint [#9211](https://github.com/emqx/emqx/pull/9211).
Before the fix, it always returned `200` even if the EMQX application was not running. Now it returns `503` in that case.

View File

@ -2,14 +2,24 @@
## 增强
- 提升 `/nodes` API 响应速度 [#9221](https://github.com/emqx/emqx/pull/9221)。
- 支持拉黑客户端并从数据库中删除保留和延迟发布的消息 [#9139](https://github.com/emqx/emqx/pull/9139)。
- 升级 `gen_rpc` 库到 3.0 [#9187](https://github.com/emqx/emqx/pull/9187)。
- 在引导 `replicant` 节点时,改善 `core` 节点的内存使用量 [#9236](https://github.com/emqx/emqx/pull/9236)。
- 增加 Prometheus Push Gateway 的稳定性, 并在 POST 失败时打印错误日志 [#9235](http://github.com/emqx/emqx/pull/9235)。
- 可通过配置关闭 prometheus 中的部分内部指标,如果遇到机器负载过高 prometheus 接口返回超时可考虑关闭部分不关心指标,以提高响应速度 [#9222](https://github.com/emqx/emqx/pull/9222
## Bug fixes
- 优化认认证配置中 `mechanism` 字段缺失情况下的错误日志 [#8924](https://github.com/emqx/emqx/pull/8924)。
- 修复未知 `status` 参数导致 `/gateway` API 发生 HTTP 500 错误的问题 [#7794](https://github.com/emqx/emqx/pull/9225) [#7794](https://github.com/emqx/emqx/pull/9225).
- 修复未知 `status` 参数导致 `/gateway` API 发生 HTTP 500 错误的问题 [#9225](https://github.com/emqx/emqx/pull/9225)。
- 修正了 `/status` 端点的响应状态代码 [#9211](https://github.com/emqx/emqx/pull/9211)。
在此修复前,它总是返回 HTTP 状态码 `200`,即使 EMQX 没有完成启动或正在重启。 现在它在这些情况下会返回状态码 `503`

View File

@ -616,7 +616,7 @@ defmodule EMQXUmbrella.MixProject do
defp jq_dep() do
if enable_jq?(),
do: [{:jq, github: "emqx/jq", tag: "v0.3.6", override: true}],
do: [{:jq, github: "emqx/jq", tag: "v0.3.8", override: true}],
else: []
end

View File

@ -42,7 +42,7 @@ quicer() ->
{quicer, {git, "https://github.com/emqx/quic.git", {tag, "0.0.16"}}}.
jq() ->
{jq, {git, "https://github.com/emqx/jq", {tag, "v0.3.6"}}}.
{jq, {git, "https://github.com/emqx/jq", {tag, "v0.3.8"}}}.
deps(Config) ->
{deps, OldDeps} = lists:keyfind(deps, 1, Config),

View File

@ -1,4 +1,4 @@
EMQX configuration file is in [HOCON](https://github.com/emqx/hocon) format.
EMQX configuration files are in [HOCON](https://github.com/emqx/hocon) format.
HOCON, or Human-Optimized Config Object Notation is a format for human-readable data,
and a superset of JSON.
@ -7,7 +7,7 @@ and a superset of JSON.
EMQX configuration consists of 3 layers.
From bottom up:
1. Immutable base: `emqx.conf` + `EMQX_` prefixed environment variables.</br>
1. Immutable base: `emqx.conf` + `EMQX_` prefixed environment variables.<br/>
Changes in this layer require a full node restart to take effect.
1. Cluster overrides: `$EMQX_NODE__DATA_DIR/configs/cluster-override.conf`
1. Local node overrides: `$EMQX_NODE__DATA_DIR/configs/local-override.conf`
@ -94,14 +94,14 @@ Complex types define data 'boxes' which may contain other complex data
or primitive values.
There are quite some different primitive types, to name a few:
* `atom()`
* `boolean()`
* `string()`
* `integer()`
* `float()`
* `number()`
* `binary()` # another format of string()
* `emqx_schema:duration()` # time duration, another format of integer()
* `atom()`.
* `boolean()`.
* `string()`.
* `integer()`.
* `float()`.
* `number()`.
* `binary()`, another format of string().
* `emqx_schema:duration()`, time duration, another format of integer()
* ...
::: tip Tip
@ -146,7 +146,7 @@ For example, this environment variable sets an array value.
export EMQX_LISTENERS__SSL__L1__AUTHENTICATION__SSL__CIPHERS='["TLS_AES_256_GCM_SHA384"]'
```
However this also means a string value should be quoted if it happen to contain special
However this also means a string value should be quoted if it happens to contain special
characters such as `=` and `:`.
For example, a string value `"localhost:1883"` would be
@ -248,9 +248,9 @@ authentication=[{enable=true}]
#### TLS/SSL ciphers
Starting from v5.0.6, EMQX no longer pre-populate the ciphers list with a default
Starting from v5.0.6, EMQX no longer pre-populates the ciphers list with a default
set of cipher suite names.
Instead, the default ciphers are applyed at runtime when starting the listener
Instead, the default ciphers are applied at runtime when starting the listener
for servers, or when establishing a TLS connection as a client.
Below are the default ciphers selected by EMQX.

View File

@ -1,28 +1,28 @@
EMQX的配置文件格式是 [HOCON](https://github.com/emqx/hocon) .
EMQX的配置文件格式是 [HOCON](https://github.com/emqx/hocon)
HOCONHuman-Optimized Config Object Notation是一个JSON的超集非常适用于易于人类读写的配置数据存储。
## 分层结构
EMQX的配置文件可分为三层自底向上依次是
1. 不可变的基础层 `emqx.conf` 加上 `EMQX_` 前缀的环境变量.</br>
1. 不可变的基础层 `emqx.conf` 加上 `EMQX_` 前缀的环境变量<br/>
修改这一层的配置之后,需要重启节点来使之生效。
1. 集群范围重载层:`$EMQX_NODE__DATA_DIR/configs/cluster-override.conf`
1. 节点本地重载层:`$EMQX_NODE__DATA_DIR/configs/local-override.conf`
如果环境变量 `$EMQX_NODE__DATA_DIR` 没有设置,那么该目录会从 emqx.conf 的 `node.data_dir`配置中读取。
如果环境变量 `$EMQX_NODE__DATA_DIR` 没有设置,那么该目录会从 `emqx.conf``node.data_dir` 配置中读取。
配置文件 `cluster-override.conf` 的内容会在运行时被EMQX重写。
这些重写发生在 dashboard UI管理HTTP API或者CLI对集群配置进行修改时。
当EMQX运行在集群中时一个EMQX节点重启之后会从集群中其他节点复制该文件内容到本地。
:::tip Tip
有些配置项是不能被重载的(例如 `node.name`.
有些配置项是不能被重载的(例如 `node.name`
配置项如果有 `mapping: path.to.boot.config.key` 这个属性,
则不能被添加到重载文件 `*-override.conf` 中。
则不能被添加到重载文件 `*-override.conf` 中。
:::
更多的重载规则,请参考下文 [配置重载规则](#配置重载规则).
更多的重载规则,请参考下文 [配置重载规则](#配置重载规则)
## 配置文件语法
@ -70,7 +70,7 @@ EMQX的配置文件中有4中复杂数据结构类型它们分别是
1. Struct结构体都是有类型名称的结构体中可以有任意多个字段。
结构体和字段的名称由不带特殊字符的全小些字母组成,名称中可以带数字,但不得以数字开头,多个单词可用下划线分隔。
1. Map: Map与Struct结构体类似但是内部的字段不是预先定义好的.
1. Map: Map Struct结构体类似但是内部的字段不是预先定义好的
1. Union: 联合 `MemberType1 | MemberType2 | ...`,可以理解为:“不是这个,就是那个”
1. Array: 数组 `[ElementType]`
@ -89,19 +89,19 @@ myarray.2 = 75
复杂类型定义了数据 "盒子",其中可能包含其他复杂数据或原始值。
有很多不同的原始类型,仅举几个例子。
* 原子 `atom()`
* 布尔 `boolean()`.
* 字符串 `string()'
* 整形 `integer()'
* 浮点数 `float()'.
* 数值 `number()'
* 二进制编码的字符串 `binary()` # `string()` 的另一种格式
* 时间间隔 `emqx_schema:duration()` # 时间间隔,`integer()` 的另一种格式
* 原子 `atom()`
* 布尔 `boolean()`
* 字符串 `string()`
* 整形 `integer()`
* 浮点数 `float()`
* 数值 `number()`
* 二进制编码的字符串 `binary()``string()` 的另一种格式
* 时间间隔 `emqx_schema:duration()``integer()` 的另一种格式
* ...
::: tip Tip
原始类型的名称大多是自我描述的,所以不需要过多的注释。
但是有一些不是那么直观的数据类型,则需要配合字段的描述文档进行理解
但是有一些不是那么直观的数据类型,则需要配合字段的描述文档进行理解
:::
@ -110,7 +110,7 @@ myarray.2 = 75
如果我们把EMQX的配置值理解成一个类似目录树的结构那么类似于文件系统中使用斜杠或反斜杠进行层级分割
EMQX使用的配置路径的层级分割符是 `'.'`
`'.'`号分割的每一段则是Struct结构体的字段或Map的key.
`'.'` 号分割的每一段,则是 Struct结构体的字段或 Map 的 key。
下面有几个例子:
@ -122,7 +122,7 @@ authentication.1.enable = true
### 环境变量重载
因为`'.'` 分隔符不能使用于环境变量所以我们需要使用另一个分割符。EMQX选用的是双下划线`__`。
因为 `'.'` 分隔符不能使用于环境变量所以我们需要使用另一个分割符。EMQX选用的是双下划线 `__`
为了与其他的环境变量有所区分EMQX还增加了一个前缀 `EMQX_` 来用作环境变量命名空间。
例如 `node.name` 的重载变量名是 `EMQX_NODE__NAME`
@ -154,7 +154,7 @@ EMQX_BRIDGES__MQTT__MYBRIDGE__CONNECTOR_SERVER='"localhost:1883"'
[warning] unknown_env_vars: ["EMQX_AUTHENTICATION__ENABLED"]
```
这是因为正确的字段名称是 `enable`,而不是 `enabled`.
这是因为正确的字段名称是 `enable`,而不是 `enabled`
:::
### 配置重载规则
@ -168,8 +168,7 @@ HOCON的值是分层覆盖的普遍规则如下
#### 结构体
合并覆盖规则。在如下配置中,最后一行的 `debug` 值会覆盖覆盖原先`level`字段的 `error`
但是`enable` 字段保持不变。
合并覆盖规则。在如下配置中,最后一行的 `debug` 值会覆盖覆盖原先`level`字段的 `error` 值,但是 `enable` 字段保持不变。
```
log {
console_handler{
@ -178,7 +177,7 @@ log {
}
}
## 控制台日志打印先定义为`error`级,后被覆写成`debug`级
## 控制台日志打印先定义为 `error` 级,后被覆写成 `debug`
log.console_handler.level=debug
```
@ -186,7 +185,7 @@ log.console_handler.level=debug
#### Map
Map与结构体类似也是合并覆盖规则。
如下例子中,`zone1` 的 `max_packet_size` 可以在文件后面覆写.
如下例子中,`zone1` 的 `max_packet_size` 可以在文件后面覆写
```
zone {