Merge branch 'master' into fix-gw-api-erros
This commit is contained in:
commit
d995842f36
|
@ -113,7 +113,7 @@ the check/consume will succeed, but it will be forced to wait for a short period
|
||||||
|
|
||||||
burst {
|
burst {
|
||||||
desc {
|
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."""
|
This value + rate = the maximum limit that can be achieved when limiter burst."""
|
||||||
zh: """突发速率。
|
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.
|
en: """The bytes_in limiter.
|
||||||
This is used to limit the inbound bytes rate for this EMQX node.
|
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."""
|
Once the limit is reached, the restricted client will be slow down even be hung for a while."""
|
||||||
zh: """流入字节率控制器.
|
zh: """流入字节率控制器。
|
||||||
这个是用来控制当前节点上的数据流入的字节率,每条消息将会消耗和其二进制大小等量的令牌,当达到最大速率后,会话将会被限速甚至被强制挂起一小段时间"""
|
这个是用来控制当前节点上的数据流入的字节率,每条消息将会消耗和其二进制大小等量的令牌,当达到最大速率后,会话将会被限速甚至被强制挂起一小段时间"""
|
||||||
}
|
}
|
||||||
label: {
|
label: {
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -18,6 +18,7 @@
|
||||||
{emqx_license,2}.
|
{emqx_license,2}.
|
||||||
{emqx_management,1}.
|
{emqx_management,1}.
|
||||||
{emqx_management,2}.
|
{emqx_management,2}.
|
||||||
|
{emqx_management,3}.
|
||||||
{emqx_mgmt_api_plugins,1}.
|
{emqx_mgmt_api_plugins,1}.
|
||||||
{emqx_mgmt_cluster,1}.
|
{emqx_mgmt_cluster,1}.
|
||||||
{emqx_mgmt_trace,1}.
|
{emqx_mgmt_trace,1}.
|
||||||
|
|
|
@ -124,7 +124,10 @@ filter_result(Delivery) ->
|
||||||
max_client_num() ->
|
max_client_num() ->
|
||||||
emqx:get_config([rpc, tcp_client_num], ?DefaultClientNum).
|
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}) ->
|
unwrap_erpc({ok, A}) ->
|
||||||
A;
|
A;
|
||||||
unwrap_erpc({throw, A}) ->
|
unwrap_erpc({throw, A}) ->
|
||||||
|
|
|
@ -1698,7 +1698,7 @@ desc("stats") ->
|
||||||
desc("authorization") ->
|
desc("authorization") ->
|
||||||
"Settings for client authorization.";
|
"Settings for client authorization.";
|
||||||
desc("mqtt") ->
|
desc("mqtt") ->
|
||||||
"Global MQTT configuration.</br>\n"
|
"Global MQTT configuration.<br/>"
|
||||||
"The configs here work as default values which can be overridden\n"
|
"The configs here work as default values which can be overridden\n"
|
||||||
"in <code>zone</code> configs";
|
"in <code>zone</code> configs";
|
||||||
desc("cache") ->
|
desc("cache") ->
|
||||||
|
@ -2115,11 +2115,11 @@ ref(Module, StructName) -> hoconsc:ref(Module, StructName).
|
||||||
mk_duration(Desc, OverrideMeta) ->
|
mk_duration(Desc, OverrideMeta) ->
|
||||||
DefaultMeta = #{
|
DefaultMeta = #{
|
||||||
desc => Desc ++
|
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"
|
"- `ms` for milliseconds,\n"
|
||||||
"- `s` for seconds,\n"
|
"- `s` for seconds,\n"
|
||||||
"- `m` for minutes,\n"
|
"- `m` for minutes,\n"
|
||||||
"- `h` for hours;\n</br>"
|
"- `h` for hours;\n<br/>"
|
||||||
"or combination of whereof: `1h5m0s`"
|
"or combination of whereof: `1h5m0s`"
|
||||||
},
|
},
|
||||||
hoconsc:mk(typerefl:alias("string", duration()), maps:merge(DefaultMeta, OverrideMeta)).
|
hoconsc:mk(typerefl:alias("string", duration()), maps:merge(DefaultMeta, OverrideMeta)).
|
||||||
|
|
|
@ -57,7 +57,7 @@ emqx_authn_jwt {
|
||||||
endpoint {
|
endpoint {
|
||||||
desc {
|
desc {
|
||||||
en: """JWKS endpoint, it's a read-only endpoint that returns the server's public key set in the JWKS format."""
|
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 {
|
label {
|
||||||
en: """JWKS Endpoint"""
|
en: """JWKS Endpoint"""
|
||||||
|
|
|
@ -2,7 +2,7 @@ emqx_authz_api_cache {
|
||||||
authorization_cache_delete {
|
authorization_cache_delete {
|
||||||
desc {
|
desc {
|
||||||
en: """Clean all authorization cache in the cluster."""
|
en: """Clean all authorization cache in the cluster."""
|
||||||
zh: """清除集群中所有鉴权数据缓存"""
|
zh: """清除集群中所有授权数据缓存。"""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
emqx_authz_api_schema {
|
emqx_authz_api_schema {
|
||||||
enable {
|
enable {
|
||||||
desc {
|
desc {
|
||||||
en: """Set to <code>true</code> or <code>false</code> to disable this ACL provider"""
|
en: """Set to <code>true</code> or <code>false</code> to disable this ACL provider."""
|
||||||
zh: """设为 <code>true</code> 或 <code>false</code> 以启用或禁用此访问控制数据源"""
|
zh: """设为 <code>true</code> 或 <code>false</code> 以启用或禁用此访问控制数据源。"""
|
||||||
}
|
}
|
||||||
label {
|
label {
|
||||||
en: """enable"""
|
en: """enable"""
|
||||||
|
@ -13,7 +13,7 @@ emqx_authz_api_schema {
|
||||||
type {
|
type {
|
||||||
desc {
|
desc {
|
||||||
en: """Backend type."""
|
en: """Backend type."""
|
||||||
zh: """数据后端类型"""
|
zh: """数据后端类型。"""
|
||||||
}
|
}
|
||||||
label {
|
label {
|
||||||
en: """type"""
|
en: """type"""
|
||||||
|
@ -26,7 +26,7 @@ emqx_authz_api_schema {
|
||||||
rules {
|
rules {
|
||||||
desc {
|
desc {
|
||||||
en: """Authorization static file rules."""
|
en: """Authorization static file rules."""
|
||||||
zh: """静态鉴权文件规则"""
|
zh: """静态授权文件规则。"""
|
||||||
}
|
}
|
||||||
label {
|
label {
|
||||||
en: """rules"""
|
en: """rules"""
|
||||||
|
@ -39,7 +39,7 @@ emqx_authz_api_schema {
|
||||||
method {
|
method {
|
||||||
desc {
|
desc {
|
||||||
en: """HTTP method."""
|
en: """HTTP method."""
|
||||||
zh: """HTTP 请求方法"""
|
zh: """HTTP 请求方法。"""
|
||||||
}
|
}
|
||||||
label {
|
label {
|
||||||
en: """method"""
|
en: """method"""
|
||||||
|
@ -50,7 +50,7 @@ emqx_authz_api_schema {
|
||||||
url {
|
url {
|
||||||
desc {
|
desc {
|
||||||
en: """URL of the auth server."""
|
en: """URL of the auth server."""
|
||||||
zh: """认证服务器 URL"""
|
zh: """认证服务器 URL。"""
|
||||||
}
|
}
|
||||||
label {
|
label {
|
||||||
en: """url"""
|
en: """url"""
|
||||||
|
@ -72,7 +72,7 @@ emqx_authz_api_schema {
|
||||||
headers_no_content_type {
|
headers_no_content_type {
|
||||||
desc {
|
desc {
|
||||||
en: """List of HTTP headers (without <code>content-type</code>)."""
|
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 {
|
label {
|
||||||
en: """headers_no_content_type"""
|
en: """headers_no_content_type"""
|
||||||
|
@ -83,7 +83,7 @@ emqx_authz_api_schema {
|
||||||
body {
|
body {
|
||||||
desc {
|
desc {
|
||||||
en: """HTTP request body."""
|
en: """HTTP request body."""
|
||||||
zh: """HTTP 请求体"""
|
zh: """HTTP 请求体。"""
|
||||||
}
|
}
|
||||||
label {
|
label {
|
||||||
en: """body"""
|
en: """body"""
|
||||||
|
@ -94,7 +94,7 @@ emqx_authz_api_schema {
|
||||||
request_timeout {
|
request_timeout {
|
||||||
desc {
|
desc {
|
||||||
en: """Request timeout."""
|
en: """Request timeout."""
|
||||||
zh: """请求超时时间"""
|
zh: """请求超时时间。"""
|
||||||
}
|
}
|
||||||
label {
|
label {
|
||||||
en: """request_timeout"""
|
en: """request_timeout"""
|
||||||
|
@ -111,7 +111,7 @@ emqx_authz_api_schema {
|
||||||
collection {
|
collection {
|
||||||
desc {
|
desc {
|
||||||
en: """`MongoDB` collection containing the authorization data."""
|
en: """`MongoDB` collection containing the authorization data."""
|
||||||
zh: """`MongoDB` 鉴权数据集"""
|
zh: """`MongoDB` 授权数据集。"""
|
||||||
}
|
}
|
||||||
label {
|
label {
|
||||||
en: """collection"""
|
en: """collection"""
|
||||||
|
@ -153,7 +153,7 @@ Filter supports the following placeholders:
|
||||||
cmd {
|
cmd {
|
||||||
desc {
|
desc {
|
||||||
en: """Database query used to retrieve authorization data."""
|
en: """Database query used to retrieve authorization data."""
|
||||||
zh: """访问控制数据查询命令"""
|
zh: """访问控制数据查询命令。"""
|
||||||
}
|
}
|
||||||
label {
|
label {
|
||||||
en: """cmd"""
|
en: """cmd"""
|
||||||
|
@ -166,7 +166,7 @@ Filter supports the following placeholders:
|
||||||
query {
|
query {
|
||||||
desc {
|
desc {
|
||||||
en: """Database query used to retrieve authorization data."""
|
en: """Database query used to retrieve authorization data."""
|
||||||
zh: """访问控制数据查询语句"""
|
zh: """访问控制数据查询语句。"""
|
||||||
}
|
}
|
||||||
label {
|
label {
|
||||||
en: """query"""
|
en: """query"""
|
||||||
|
@ -178,8 +178,8 @@ Filter supports the following placeholders:
|
||||||
|
|
||||||
position {
|
position {
|
||||||
desc {
|
desc {
|
||||||
en: """Where to place the source"""
|
en: """Where to place the source."""
|
||||||
zh: """认证数据源位置"""
|
zh: """认证数据源位置。"""
|
||||||
}
|
}
|
||||||
label {
|
label {
|
||||||
en: """position"""
|
en: """position"""
|
||||||
|
|
|
@ -2,14 +2,14 @@ emqx_authz_api_settings {
|
||||||
authorization_settings_get {
|
authorization_settings_get {
|
||||||
desc {
|
desc {
|
||||||
en: """Get authorization settings"""
|
en: """Get authorization settings"""
|
||||||
zh: """获取鉴权配置"""
|
zh: """获取授权配置"""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
authorization_settings_put {
|
authorization_settings_put {
|
||||||
desc {
|
desc {
|
||||||
en: """Update authorization settings"""
|
en: """Update authorization settings"""
|
||||||
zh: """更新鉴权配置"""
|
zh: """更新授权配置"""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,56 +2,56 @@ emqx_authz_api_sources {
|
||||||
authorization_sources_get {
|
authorization_sources_get {
|
||||||
desc {
|
desc {
|
||||||
en: """List all authorization sources"""
|
en: """List all authorization sources"""
|
||||||
zh: """列出所有鉴权数据源"""
|
zh: """列出所有授权数据源"""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
authorization_sources_post {
|
authorization_sources_post {
|
||||||
desc {
|
desc {
|
||||||
en: """Add a new source"""
|
en: """Add a new source"""
|
||||||
zh: """添加鉴权数据源"""
|
zh: """添加授权数据源"""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
authorization_sources_type_get {
|
authorization_sources_type_get {
|
||||||
desc {
|
desc {
|
||||||
en: """Get a authorization source"""
|
en: """Get a authorization source"""
|
||||||
zh: """获取指定类型的鉴权数据源"""
|
zh: """获取指定类型的授权数据源"""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
authorization_sources_type_put {
|
authorization_sources_type_put {
|
||||||
desc {
|
desc {
|
||||||
en: """Update source"""
|
en: """Update source"""
|
||||||
zh: """更新指定类型的鉴权数据源"""
|
zh: """更新指定类型的授权数据源"""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
authorization_sources_type_delete {
|
authorization_sources_type_delete {
|
||||||
desc {
|
desc {
|
||||||
en: """Delete source"""
|
en: """Delete source"""
|
||||||
zh: """删除指定类型的鉴权数据源"""
|
zh: """删除指定类型的授权数据源"""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
authorization_sources_type_status_get {
|
authorization_sources_type_status_get {
|
||||||
desc {
|
desc {
|
||||||
en: """Get a authorization source"""
|
en: """Get a authorization source"""
|
||||||
zh: """获取指定鉴权数据源的状态"""
|
zh: """获取指定授权数据源的状态"""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
authorization_sources_type_move_post {
|
authorization_sources_type_move_post {
|
||||||
desc {
|
desc {
|
||||||
en: """Change the exection order of sources"""
|
en: """Change the exection order of sources"""
|
||||||
zh: """更新鉴权数据源的优先执行顺序"""
|
zh: """更新授权数据源的优先执行顺序"""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sources {
|
sources {
|
||||||
desc {
|
desc {
|
||||||
en: """Authorization source"""
|
en: """Authorization source"""
|
||||||
zh: """鉴权数据源列表"""
|
zh: """授权数据源列表"""
|
||||||
}
|
}
|
||||||
label {
|
label {
|
||||||
en: """sources"""
|
en: """sources"""
|
||||||
|
@ -62,7 +62,7 @@ emqx_authz_api_sources {
|
||||||
sources {
|
sources {
|
||||||
desc {
|
desc {
|
||||||
en: """Authorization sources"""
|
en: """Authorization sources"""
|
||||||
zh: """鉴权数据源列表"""
|
zh: """授权数据源列表"""
|
||||||
}
|
}
|
||||||
label {
|
label {
|
||||||
en: """sources"""
|
en: """sources"""
|
||||||
|
@ -84,7 +84,7 @@ emqx_authz_api_sources {
|
||||||
source {
|
source {
|
||||||
desc {
|
desc {
|
||||||
en: """Authorization source"""
|
en: """Authorization source"""
|
||||||
zh: """鉴权数据源"""
|
zh: """授权数据源"""
|
||||||
}
|
}
|
||||||
label {
|
label {
|
||||||
en: """source"""
|
en: """source"""
|
||||||
|
|
|
@ -2,41 +2,41 @@ emqx_authz_schema {
|
||||||
sources {
|
sources {
|
||||||
desc {
|
desc {
|
||||||
en: """
|
en: """
|
||||||
Authorization data sources.</br>
|
Authorization data sources.<br/>
|
||||||
An array of authorization (ACL) data providers.
|
An array of authorization (ACL) data providers.
|
||||||
It is designed as an array, not a hash-map, so the sources can be
|
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
|
When authorizing a 'publish' or 'subscribe' action, the configured
|
||||||
sources are checked in order. When checking an ACL source,
|
sources are checked in order. When checking an ACL source,
|
||||||
in case the client (identified by username or client ID) is not found,
|
in case the client (identified by username or client ID) is not found,
|
||||||
it moves on to the next source. And it stops immediately
|
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,
|
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:
|
NOTE:
|
||||||
The source elements are identified by their 'type'.
|
The source elements are identified by their 'type'.
|
||||||
It is NOT allowed to configure two or more sources of the same type.
|
It is NOT allowed to configure two or more sources of the same type.
|
||||||
"""
|
"""
|
||||||
zh: """
|
zh: """
|
||||||
鉴权数据源.</br>
|
授权数据源。<br/>
|
||||||
鉴权(ACL)数据源的列表.
|
授权(ACL)数据源的列表。
|
||||||
它被设计为一个数组,而不是一个散列映射,
|
它被设计为一个数组,而不是一个散列映射,
|
||||||
所以可以作为链式访问控制.</br>
|
所以可以作为链式访问控制。<br/>
|
||||||
|
|
||||||
当授权一个 'publish' 或 'subscribe' 行为时,
|
当授权一个 'publish' 或 'subscribe' 行为时,
|
||||||
该配置列表中的所有数据源将按顺序进行检查。
|
该配置列表中的所有数据源将按顺序进行检查。
|
||||||
如果在某个客户端未找到时(使用 ClientID 或 Username),
|
如果在某个客户端未找到时(使用 ClientID 或 Username)。
|
||||||
将会移动到下一个数据源. 直至得到 'allow' 或 'deny' 的结果.</br>
|
将会移动到下一个数据源。直至得到 'allow' 或 'deny' 的结果。<br/>
|
||||||
|
|
||||||
如果在任何数据源中都未找到对应的客户端信息,
|
如果在任何数据源中都未找到对应的客户端信息。
|
||||||
配置的默认行为 ('authorization.no_match') 将生效.</br>
|
配置的默认行为 ('authorization.no_match') 将生效。<br/>
|
||||||
|
|
||||||
注意:
|
注意:
|
||||||
数据源使用 'type' 进行标识.
|
数据源使用 'type' 进行标识。
|
||||||
使用同一类型的数据源多于一次不被允许.
|
使用同一类型的数据源多于一次不被允许。
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
label {
|
label {
|
||||||
|
@ -83,7 +83,7 @@ It is NOT allowed to configure two or more sources of the same type.
|
||||||
file {
|
file {
|
||||||
desc {
|
desc {
|
||||||
en: """Authorization using a static file."""
|
en: """Authorization using a static file."""
|
||||||
zh: """使用静态文件鉴权"""
|
zh: """使用静态文件授权"""
|
||||||
}
|
}
|
||||||
label {
|
label {
|
||||||
en: """file"""
|
en: """file"""
|
||||||
|
@ -109,7 +109,7 @@ and the old file will not be used anymore.
|
||||||
那么可以将该文件置于任何 EMQX 可以访问到的位置。
|
那么可以将该文件置于任何 EMQX 可以访问到的位置。
|
||||||
|
|
||||||
如果从 EMQX Dashboard 或 HTTP API 创建或修改了规则集,
|
如果从 EMQX Dashboard 或 HTTP API 创建或修改了规则集,
|
||||||
那么EMQX将会生成一个新的文件并将它存放在 `data_dir` 下的 `authz` 子目录中,
|
那么EMQX将会生成一个新的文件并将它存放在 `data_dir` 下的 `authz` 子目录中,
|
||||||
并从此弃用旧的文件。"""
|
并从此弃用旧的文件。"""
|
||||||
}
|
}
|
||||||
label {
|
label {
|
||||||
|
@ -123,7 +123,7 @@ and the old file will not be used anymore.
|
||||||
http_get {
|
http_get {
|
||||||
desc {
|
desc {
|
||||||
en: """Authorization using an external HTTP server (via GET requests)."""
|
en: """Authorization using an external HTTP server (via GET requests)."""
|
||||||
zh: """使用外部 HTTP 服务器鉴权(GET 请求)。"""
|
zh: """使用外部 HTTP 服务器授权(GET 请求)。"""
|
||||||
}
|
}
|
||||||
label {
|
label {
|
||||||
en: """http_get"""
|
en: """http_get"""
|
||||||
|
@ -134,7 +134,7 @@ and the old file will not be used anymore.
|
||||||
http_post {
|
http_post {
|
||||||
desc {
|
desc {
|
||||||
en: """Authorization using an external HTTP server (via POST requests)."""
|
en: """Authorization using an external HTTP server (via POST requests)."""
|
||||||
zh: """使用外部 HTTP 服务器鉴权(POST 请求)。"""
|
zh: """使用外部 HTTP 服务器授权(POST 请求)。"""
|
||||||
}
|
}
|
||||||
label {
|
label {
|
||||||
en: """http_post"""
|
en: """http_post"""
|
||||||
|
@ -156,7 +156,7 @@ and the old file will not be used anymore.
|
||||||
url {
|
url {
|
||||||
desc {
|
desc {
|
||||||
en: """URL of the auth server."""
|
en: """URL of the auth server."""
|
||||||
zh: """鉴权 HTTP 服务器地址。"""
|
zh: """授权 HTTP 服务器地址。"""
|
||||||
}
|
}
|
||||||
label {
|
label {
|
||||||
en: """URL"""
|
en: """URL"""
|
||||||
|
@ -213,7 +213,7 @@ and the old file will not be used anymore.
|
||||||
mnesia {
|
mnesia {
|
||||||
desc {
|
desc {
|
||||||
en: """Authorization using a built-in database (mnesia)."""
|
en: """Authorization using a built-in database (mnesia)."""
|
||||||
zh: """使用内部数据库鉴权 (mnesia)."""
|
zh: """使用内部数据库授权(mnesia)。"""
|
||||||
}
|
}
|
||||||
label {
|
label {
|
||||||
en: """mnesia"""
|
en: """mnesia"""
|
||||||
|
@ -226,7 +226,7 @@ and the old file will not be used anymore.
|
||||||
mongo_single {
|
mongo_single {
|
||||||
desc {
|
desc {
|
||||||
en: """Authorization using a single MongoDB instance."""
|
en: """Authorization using a single MongoDB instance."""
|
||||||
zh: """使用 MongoDB 鉴权(单实例)"""
|
zh: """使用 MongoDB 授权(单实例)。"""
|
||||||
}
|
}
|
||||||
label {
|
label {
|
||||||
en: """mongo_single"""
|
en: """mongo_single"""
|
||||||
|
@ -237,7 +237,7 @@ and the old file will not be used anymore.
|
||||||
mongo_rs {
|
mongo_rs {
|
||||||
desc {
|
desc {
|
||||||
en: """Authorization using a MongoDB replica set."""
|
en: """Authorization using a MongoDB replica set."""
|
||||||
zh: """使用 MongoDB 鉴权(副本集模式)"""
|
zh: """使用 MongoDB 授权(副本集模式)"""
|
||||||
}
|
}
|
||||||
label {
|
label {
|
||||||
en: """mongo_rs"""
|
en: """mongo_rs"""
|
||||||
|
@ -248,7 +248,7 @@ and the old file will not be used anymore.
|
||||||
mongo_sharded {
|
mongo_sharded {
|
||||||
desc {
|
desc {
|
||||||
en: """Authorization using a sharded MongoDB cluster."""
|
en: """Authorization using a sharded MongoDB cluster."""
|
||||||
zh: """使用 MongoDB 鉴权(分片集群模式)"""
|
zh: """使用 MongoDB 授权(分片集群模式)。"""
|
||||||
}
|
}
|
||||||
label {
|
label {
|
||||||
en: """mongo_sharded"""
|
en: """mongo_sharded"""
|
||||||
|
@ -259,7 +259,7 @@ and the old file will not be used anymore.
|
||||||
collection {
|
collection {
|
||||||
desc {
|
desc {
|
||||||
en: """`MongoDB` collection containing the authorization data."""
|
en: """`MongoDB` collection containing the authorization data."""
|
||||||
zh: """`MongoDB` 鉴权数据集"""
|
zh: """`MongoDB` 授权数据集。"""
|
||||||
}
|
}
|
||||||
label {
|
label {
|
||||||
en: """collection"""
|
en: """collection"""
|
||||||
|
@ -278,8 +278,8 @@ Filter supports the following placeholders:
|
||||||
zh: """
|
zh: """
|
||||||
在查询中定义过滤条件的条件表达式。
|
在查询中定义过滤条件的条件表达式。
|
||||||
过滤器支持如下占位符:
|
过滤器支持如下占位符:
|
||||||
- <code>${username}</code>: 将在运行时被替换为客户端连接时使用的用户名
|
- <code>${username}</code>:将在运行时被替换为客户端连接时使用的用户名
|
||||||
- <code>${clientid}</code>: 将在运行时被替换为客户端连接时使用的客户端标识符
|
- <code>${clientid}</code>:将在运行时被替换为客户端连接时使用的客户端标识符
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
label {
|
label {
|
||||||
|
@ -293,7 +293,7 @@ Filter supports the following placeholders:
|
||||||
mysql {
|
mysql {
|
||||||
desc {
|
desc {
|
||||||
en: """Authorization using a MySQL database."""
|
en: """Authorization using a MySQL database."""
|
||||||
zh: """使用 MySOL 数据库鉴权"""
|
zh: """使用 MySOL 数据库授权"""
|
||||||
}
|
}
|
||||||
label {
|
label {
|
||||||
en: """mysql"""
|
en: """mysql"""
|
||||||
|
@ -306,7 +306,7 @@ Filter supports the following placeholders:
|
||||||
postgresql {
|
postgresql {
|
||||||
desc {
|
desc {
|
||||||
en: """Authorization using a PostgreSQL database."""
|
en: """Authorization using a PostgreSQL database."""
|
||||||
zh: """使用 PostgreSQL 数据库鉴权"""
|
zh: """使用 PostgreSQL 数据库授权"""
|
||||||
}
|
}
|
||||||
label {
|
label {
|
||||||
en: """postgresql"""
|
en: """postgresql"""
|
||||||
|
@ -319,7 +319,7 @@ Filter supports the following placeholders:
|
||||||
redis_single {
|
redis_single {
|
||||||
desc {
|
desc {
|
||||||
en: """Authorization using a single Redis instance."""
|
en: """Authorization using a single Redis instance."""
|
||||||
zh: """使用 Redis 鉴权(单实例)"""
|
zh: """使用 Redis 授权(单实例)。"""
|
||||||
}
|
}
|
||||||
label {
|
label {
|
||||||
en: """redis_single"""
|
en: """redis_single"""
|
||||||
|
@ -330,7 +330,7 @@ Filter supports the following placeholders:
|
||||||
redis_sentinel {
|
redis_sentinel {
|
||||||
desc {
|
desc {
|
||||||
en: """Authorization using a Redis Sentinel."""
|
en: """Authorization using a Redis Sentinel."""
|
||||||
zh: """使用 Redis 鉴权(哨兵模式)"""
|
zh: """使用 Redis 授权(哨兵模式)。"""
|
||||||
}
|
}
|
||||||
label {
|
label {
|
||||||
en: """redis_sentinel"""
|
en: """redis_sentinel"""
|
||||||
|
@ -341,7 +341,7 @@ Filter supports the following placeholders:
|
||||||
redis_cluster {
|
redis_cluster {
|
||||||
desc {
|
desc {
|
||||||
en: """Authorization using a Redis cluster."""
|
en: """Authorization using a Redis cluster."""
|
||||||
zh: """使用 Redis 鉴权(集群模式)"""
|
zh: """使用 Redis 授权(集群模式)。"""
|
||||||
}
|
}
|
||||||
label {
|
label {
|
||||||
en: """redis_cluster"""
|
en: """redis_cluster"""
|
||||||
|
@ -365,7 +365,7 @@ Filter supports the following placeholders:
|
||||||
query {
|
query {
|
||||||
desc {
|
desc {
|
||||||
en: """Database query used to retrieve authorization data."""
|
en: """Database query used to retrieve authorization data."""
|
||||||
zh: """访问控制数据查询语句/查询命令"""
|
zh: """访问控制数据查询语句/查询命令。"""
|
||||||
}
|
}
|
||||||
label {
|
label {
|
||||||
en: """query"""
|
en: """query"""
|
||||||
|
@ -510,44 +510,44 @@ Filter supports the following placeholders:
|
||||||
metrics_total {
|
metrics_total {
|
||||||
desc {
|
desc {
|
||||||
en: """The total number of times the authorization rule was triggered."""
|
en: """The total number of times the authorization rule was triggered."""
|
||||||
zh: """鉴权实例被触发的总次数。"""
|
zh: """授权实例被触发的总次数。"""
|
||||||
}
|
}
|
||||||
label: {
|
label: {
|
||||||
en: """The Total Number of Times the Authorization Rule was Triggered"""
|
en: """The Total Number of Times the Authorization Rule was Triggered"""
|
||||||
zh: """鉴权实例被触发的总次数"""
|
zh: """授权实例被触发的总次数"""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nomatch {
|
nomatch {
|
||||||
desc {
|
desc {
|
||||||
en: """The number of times that no authorization rules were matched."""
|
en: """The number of times that no authorization rules were matched."""
|
||||||
zh: """没有匹配到任何鉴权规则的次数。"""
|
zh: """没有匹配到任何授权规则的次数。"""
|
||||||
}
|
}
|
||||||
label: {
|
label: {
|
||||||
en: """The Number of Times that no Authorization Rules were Matched"""
|
en: """The Number of Times that no Authorization Rules were Matched"""
|
||||||
zh: """没有匹配到任何鉴权规则的次数"""
|
zh: """没有匹配到任何授权规则的次数"""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
allow {
|
allow {
|
||||||
desc {
|
desc {
|
||||||
en: """The number of times the authentication was successful."""
|
en: """The number of times the authentication was successful."""
|
||||||
zh: """鉴权成功的次数。"""
|
zh: """授权成功的次数。"""
|
||||||
}
|
}
|
||||||
label: {
|
label: {
|
||||||
en: """The Number of Times the Authentication was Successful"""
|
en: """The Number of Times the Authentication was Successful"""
|
||||||
zh: """鉴权成功次数"""
|
zh: """授权成功次数"""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
deny {
|
deny {
|
||||||
desc {
|
desc {
|
||||||
en: """The number of authentication failures."""
|
en: """The number of authentication failures."""
|
||||||
zh: """鉴权失败的次数。"""
|
zh: """授权失败的次数。"""
|
||||||
}
|
}
|
||||||
label: {
|
label: {
|
||||||
en: """The Number of Authentication Failures"""
|
en: """The Number of Authentication Failures"""
|
||||||
zh: """鉴权失败次数"""
|
zh: """授权失败次数"""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ emqx_auto_subscribe_schema {
|
||||||
auto_subscribe {
|
auto_subscribe {
|
||||||
desc {
|
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."""
|
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 {
|
lable {
|
||||||
en: """Auto Subscribe"""
|
en: """Auto Subscribe"""
|
||||||
|
|
|
@ -15,13 +15,13 @@ emqx_bridge_schema {
|
||||||
desc {
|
desc {
|
||||||
en: """
|
en: """
|
||||||
The ID or the configs of the connector to be used for this bridge. Connector IDs must be of format:
|
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:
|
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: """
|
zh: """
|
||||||
Bridge 使用的 Connector 的 ID 或者配置。Connector ID 的格式必须为:<code>{type}:{name}</code>.</br>
|
Bridge 使用的 Connector 的 ID 或者配置。Connector ID 的格式必须为:<code>{type}:{name}</code>。<br/>
|
||||||
在配置文件中,您可以通过以下路径找到 Connector 的相应配置条目:'connector.{type}.{name}'。</br>"""
|
在配置文件中,您可以通过以下路径找到 Connector 的相应配置条目:'connector.{type}.{name}'。<br/>"""
|
||||||
}
|
}
|
||||||
label: {
|
label: {
|
||||||
en: "Connector ID"
|
en: "Connector ID"
|
||||||
|
|
|
@ -25,16 +25,16 @@ emqx_bridge_webhook_schema {
|
||||||
config_url {
|
config_url {
|
||||||
desc {
|
desc {
|
||||||
en: """
|
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,
|
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
|
For example, <code> http://localhost:9901/${topic} </code> is allowed, but
|
||||||
<code> http://${host}:9901/message </code> or <code> http://localhost:${port}/message </code>
|
<code> http://${host}:9901/message </code> or <code> http://localhost:${port}/message </code>
|
||||||
is not allowed.
|
is not allowed.
|
||||||
"""
|
"""
|
||||||
zh: """
|
zh: """
|
||||||
HTTP Bridge 的 URL。</br>
|
HTTP Bridge 的 URL。<br/>
|
||||||
路径中允许使用带变量的模板,但是 host, port 不允许使用变量模板。</br>
|
路径中允许使用带变量的模板,但是 host, port 不允许使用变量模板。<br/>
|
||||||
例如,<code> http://localhost:9901/${topic} </code> 是允许的,
|
例如,<code> http://localhost:9901/${topic} </code> 是允许的,
|
||||||
但是<code> http://${host}:9901/message </code>
|
但是<code> http://${host}:9901/message </code>
|
||||||
或 <code> http://localhost:${port}/message </code>
|
或 <code> http://localhost:${port}/message </code>
|
||||||
|
@ -51,13 +51,13 @@ HTTP Bridge 的 URL。</br>
|
||||||
desc {
|
desc {
|
||||||
en: """
|
en: """
|
||||||
The MQTT topic filter to be forwarded to the HTTP server. All MQTT 'PUBLISH' messages with the topic
|
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
|
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
|
configured, then both the data got from the rule and the MQTT messages that match local_topic
|
||||||
will be forwarded.
|
will be forwarded.
|
||||||
"""
|
"""
|
||||||
zh: """
|
zh: """
|
||||||
发送到 'local_topic' 的消息都会转发到 HTTP 服务器。 </br>
|
发送到 'local_topic' 的消息都会转发到 HTTP 服务器。 <br/>
|
||||||
注意:如果这个 Bridge 被用作规则(EMQX 规则引擎)的输出,同时也配置了 'local_topic' ,那么这两部分的消息都会被转发到 HTTP 服务器。
|
注意:如果这个 Bridge 被用作规则(EMQX 规则引擎)的输出,同时也配置了 'local_topic' ,那么这两部分的消息都会被转发到 HTTP 服务器。
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
|
@ -70,12 +70,12 @@ will be forwarded.
|
||||||
config_method {
|
config_method {
|
||||||
desc {
|
desc {
|
||||||
en: """
|
en: """
|
||||||
The method of the HTTP request. All the available methods are: post, put, get, delete.</br>
|
The method of the HTTP request. All the available methods are: post, put, get, delete.<br/>
|
||||||
Template with variables is allowed.</br>
|
Template with variables is allowed.<br/>
|
||||||
"""
|
"""
|
||||||
zh: """
|
zh: """
|
||||||
HTTP 请求的方法。 所有可用的方法包括:post、put、get、delete。</br>
|
HTTP 请求的方法。 所有可用的方法包括:post、put、get、delete。<br/>
|
||||||
允许使用带有变量的模板。</br>"""
|
允许使用带有变量的模板。<br/>"""
|
||||||
}
|
}
|
||||||
label: {
|
label: {
|
||||||
en: "HTTP Method"
|
en: "HTTP Method"
|
||||||
|
@ -86,11 +86,11 @@ HTTP 请求的方法。 所有可用的方法包括:post、put、get、delete
|
||||||
config_headers {
|
config_headers {
|
||||||
desc {
|
desc {
|
||||||
en: """
|
en: """
|
||||||
The headers of the HTTP request.</br>
|
The headers of the HTTP request.<br/>
|
||||||
Template with variables is allowed.
|
Template with variables is allowed.
|
||||||
"""
|
"""
|
||||||
zh: """
|
zh: """
|
||||||
HTTP 请求的标头。</br>
|
HTTP 请求的标头。<br/>
|
||||||
允许使用带有变量的模板。
|
允许使用带有变量的模板。
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
|
@ -103,11 +103,11 @@ HTTP 请求的标头。</br>
|
||||||
config_body {
|
config_body {
|
||||||
desc {
|
desc {
|
||||||
en: """
|
en: """
|
||||||
The body of the HTTP request.</br>
|
The body of the HTTP request.<br/>
|
||||||
Template with variables is allowed.
|
Template with variables is allowed.
|
||||||
"""
|
"""
|
||||||
zh: """
|
zh: """
|
||||||
HTTP 请求的正文。</br>
|
HTTP 请求的正文。<br/>
|
||||||
允许使用带有变量的模板。"""
|
允许使用带有变量的模板。"""
|
||||||
}
|
}
|
||||||
label: {
|
label: {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
%% -*- mode: erlang -*-
|
%% -*- mode: erlang -*-
|
||||||
{application, emqx_bridge, [
|
{application, emqx_bridge, [
|
||||||
{description, "An OTP application"},
|
{description, "An OTP application"},
|
||||||
{vsn, "0.1.3"},
|
{vsn, "0.1.4"},
|
||||||
{registered, []},
|
{registered, []},
|
||||||
{mod, {emqx_bridge_app, []}},
|
{mod, {emqx_bridge_app, []}},
|
||||||
{applications, [
|
{applications, [
|
||||||
|
|
|
@ -94,7 +94,7 @@ direction_field(Dir, Desc) ->
|
||||||
#{
|
#{
|
||||||
required => true,
|
required => true,
|
||||||
default => egress,
|
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
|
Desc
|
||||||
}
|
}
|
||||||
)}.
|
)}.
|
||||||
|
|
|
@ -71,12 +71,12 @@ For more information, see: https://www.erlang.org/doc/man/erl.html
|
||||||
desc {
|
desc {
|
||||||
en: """Service discovery method for the cluster nodes."""
|
en: """Service discovery method for the cluster nodes."""
|
||||||
zh: """集群节点发现方式。可选值为:
|
zh: """集群节点发现方式。可选值为:
|
||||||
- manual: 手动加入集群</br>
|
- manual: 手动加入集群<br/>
|
||||||
- static: 配置静态节点。配置几个固定的节点,新节点通过连接固定节点中的某一个来加入集群。</br>
|
- static: 配置静态节点。配置几个固定的节点,新节点通过连接固定节点中的某一个来加入集群。<br/>
|
||||||
- mcast: 使用 UDP 多播的方式发现节点。</br>
|
- mcast: 使用 UDP 多播的方式发现节点。<br/>
|
||||||
- dns: 使用 DNS A 记录的方式发现节点。</br>
|
- dns: 使用 DNS A 记录的方式发现节点。<br/>
|
||||||
- etcd: 使用 etcd 发现节点。</br>
|
- etcd: 使用 etcd 发现节点。<br/>
|
||||||
- k8s: 使用 Kubernetes 发现节点。</br>
|
- k8s: 使用 Kubernetes 发现节点。<br/>
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
label {
|
label {
|
||||||
|
@ -111,9 +111,9 @@ For more information, see: https://www.erlang.org/doc/man/erl.html
|
||||||
desc {
|
desc {
|
||||||
en: """The Erlang distribution protocol for the cluster."""
|
en: """The Erlang distribution protocol for the cluster."""
|
||||||
zh: """分布式 Erlang 集群协议类型。可选值为:
|
zh: """分布式 Erlang 集群协议类型。可选值为:
|
||||||
- inet_tcp: 使用 IPv4 </br>
|
- inet_tcp: 使用 IPv4 <br/>
|
||||||
- inet6_tcp 使用 IPv6 </br>
|
- inet6_tcp 使用 IPv6 <br/>
|
||||||
- inet_tls: 使用 TLS,需要与 node.ssl_dist_optfile 配置一起使用。</br>
|
- inet_tls: 使用 TLS,需要与 node.ssl_dist_optfile 配置一起使用。<br/>
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
label {
|
label {
|
||||||
|
@ -152,7 +152,7 @@ For more information, see: https://www.erlang.org/doc/man/erl.html
|
||||||
|
|
||||||
cluster_mcast_ports {
|
cluster_mcast_ports {
|
||||||
desc {
|
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.
|
Note: probe messages are broadcast to all the specified ports.
|
||||||
"""
|
"""
|
||||||
zh: """指定多播端口。如有多个端口使用逗号 , 分隔。
|
zh: """指定多播端口。如有多个端口使用逗号 , 分隔。
|
||||||
|
@ -286,7 +286,7 @@ Applicable when <code>cluster.discovery_strategy = dns</code>
|
||||||
desc {
|
desc {
|
||||||
en: """Key prefix used for EMQX service discovery."""
|
en: """Key prefix used for EMQX service discovery."""
|
||||||
zh: """指定 etcd 路径的前缀。每个节点在 etcd 中都会创建一个路径:
|
zh: """指定 etcd 路径的前缀。每个节点在 etcd 中都会创建一个路径:
|
||||||
v2/keys/<prefix>/<cluster.name>/<node.name> </br>
|
v2/keys/<prefix>/<cluster.name>/<node.name> <br/>
|
||||||
当 cluster.discovery_strategy 为 etcd 时,此配置项才有效。
|
当 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.
|
make EMQX to discover IP addresses of peer nodes from Kubernetes API.
|
||||||
"""
|
"""
|
||||||
zh: """当使用 k8s 方式集群时,address_type 用来从 Kubernetes 接口的应答里获取什么形式的 Host 列表。
|
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地址。
|
的IP地址。
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
|
@ -382,7 +382,7 @@ make EMQX to discover IP addresses of peer nodes from Kubernetes API.
|
||||||
|
|
||||||
cluster_k8s_suffix {
|
cluster_k8s_suffix {
|
||||||
desc {
|
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>
|
Note: this parameter is only relevant when <code>address_type</code> is <code>dns</code>
|
||||||
or <code>hostname</code>."""
|
or <code>hostname</code>."""
|
||||||
zh: """当使用 k8s 方式并且 cluster.k8s.address_type 指定为 dns 类型时,可设置 emqx 节点名的后缀。
|
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 {
|
node_data_dir {
|
||||||
desc {
|
desc {
|
||||||
en: """
|
en: """
|
||||||
Path to the persistent data directory.</br>
|
Path to the persistent data directory.<br/>
|
||||||
Possible auto-created subdirectories are:</br>
|
Possible auto-created subdirectories are:<br/>
|
||||||
- `mnesia/<node_name>`: EMQX's built-in database directory.</br>
|
- `mnesia/<node_name>`: EMQX's built-in database directory.<br/>
|
||||||
For example, `mnesia/emqx@127.0.0.1`.</br>
|
For example, `mnesia/emqx@127.0.0.1`.<br/>
|
||||||
There should be only one such subdirectory.</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>
|
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>
|
the old dir should be deleted first.<br/>
|
||||||
- `configs`: Generated configs at boot time, and cluster/local override configs.</br>
|
- `configs`: Generated configs at boot time, and cluster/local override configs.<br/>
|
||||||
- `patches`: Hot-patch beam files are to be placed here.</br>
|
- `patches`: Hot-patch beam files are to be placed here.<br/>
|
||||||
- `trace`: Trace log files.</br>
|
- `trace`: Trace log files.<br/>
|
||||||
|
|
||||||
**NOTE**: One data dir cannot be shared by two or more EMQX nodes.
|
**NOTE**: One data dir cannot be shared by two or more EMQX nodes.
|
||||||
"""
|
"""
|
||||||
zh: """
|
zh: """
|
||||||
节点数据存放目录,可能会自动创建的子目录如下:</br>
|
节点数据存放目录,可能会自动创建的子目录如下:<br/>
|
||||||
- `mnesia/<node_name>`。EMQX的内置数据库目录。例如,`mnesia/emqx@127.0.0.1`。</br>
|
- `mnesia/<node_name>`。EMQX的内置数据库目录。例如,`mnesia/emqx@127.0.0.1`。<br/>
|
||||||
如果节点要被重新命名(例如,`emqx@10.0.1.1`)。旧目录应该首先被删除。</br>
|
如果节点要被重新命名(例如,`emqx@10.0.1.1`)。旧目录应该首先被删除。<br/>
|
||||||
- `configs`。在启动时生成的配置,以及集群/本地覆盖的配置。</br>
|
- `configs`。在启动时生成的配置,以及集群/本地覆盖的配置。<br/>
|
||||||
- `patches`: 热补丁文件将被放在这里。</br>
|
- `patches`: 热补丁文件将被放在这里。<br/>
|
||||||
- `trace`: 日志跟踪文件。</br>
|
- `trace`: 日志跟踪文件。<br/>
|
||||||
|
|
||||||
**注意**: 一个数据dir不能被两个或更多的EMQX节点同时使用。
|
**注意**: 一个数据dir不能被两个或更多的EMQX节点同时使用。
|
||||||
"""
|
"""
|
||||||
|
@ -566,9 +566,9 @@ significant: later configuration files override the previous ones.
|
||||||
db_backend {
|
db_backend {
|
||||||
desc {
|
desc {
|
||||||
en: """
|
en: """
|
||||||
Select the backend for the embedded database.</br>
|
Select the backend for the embedded database.<br/>
|
||||||
<code>rlog</code> is the default backend,
|
<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.
|
<code>mnesia</code> is a backend that offers decent performance in small clusters.
|
||||||
"""
|
"""
|
||||||
zh: """ rlog是默认的数据库,他适用于大规模的集群。
|
zh: """ rlog是默认的数据库,他适用于大规模的集群。
|
||||||
|
@ -584,20 +584,20 @@ mnesia是备选数据库,在小集群中提供了很好的性能。
|
||||||
db_role {
|
db_role {
|
||||||
desc {
|
desc {
|
||||||
en: """
|
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.
|
<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
|
<code>replicant</code> nodes are ephemeral worker nodes. Removing them from the cluster
|
||||||
doesn't affect database redundancy</br>
|
doesn't affect database redundancy<br/>
|
||||||
It is recommended to have more replicant nodes than core nodes.</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
|
Note: this parameter only takes effect when the <code>backend</code> is set
|
||||||
to <code>rlog</code>.
|
to <code>rlog</code>.
|
||||||
"""
|
"""
|
||||||
zh: """
|
zh: """
|
||||||
选择节点的角色。</br>
|
选择节点的角色。<br/>
|
||||||
<code>core</code> 节点提供数据的持久性,并负责写入。建议将核心节点放置在不同的机架或不同的可用区。</br>
|
<code>core</code> 节点提供数据的持久性,并负责写入。建议将核心节点放置在不同的机架或不同的可用区。<br/>
|
||||||
<code>repliant</code> 节点是临时工作节点。 从集群中删除它们,不影响数据库冗余</br>
|
<code>repliant</code> 节点是临时工作节点。 从集群中删除它们,不影响数据库冗余<br/>
|
||||||
建议复制节点多于核心节点。</br>
|
建议复制节点多于核心节点。<br/>
|
||||||
注意:该参数仅在设置<code>backend</code>时生效到 <code>rlog</code>。
|
注意:该参数仅在设置<code>backend</code>时生效到 <code>rlog</code>。
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
|
@ -610,17 +610,17 @@ to <code>rlog</code>.
|
||||||
db_core_nodes {
|
db_core_nodes {
|
||||||
desc {
|
desc {
|
||||||
en: """
|
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
|
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>
|
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>
|
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>),
|
If an automatic cluster discovery mechanism is being used (such as <code>etcd</code>),
|
||||||
there is no need to set this value.
|
there is no need to set this value.
|
||||||
"""
|
"""
|
||||||
zh: """当前节点连接的核心节点列表。</br>
|
zh: """当前节点连接的核心节点列表。<br/>
|
||||||
注意:该参数仅在设置<code>backend</code>时生效到 <code>rlog</code>
|
注意:该参数仅在设置<code>backend</code>时生效到 <code>rlog</code>
|
||||||
并且设置<code>role</code>为<code>replicant</code>时生效。</br>
|
并且设置<code>role</code>为<code>replicant</code>时生效。<br/>
|
||||||
该值需要在手动或静态集群发现机制下设置。</br>
|
该值需要在手动或静态集群发现机制下设置。<br/>
|
||||||
如果使用了自动集群发现机制(如<code>etcd</code>),则不需要设置该值。
|
如果使用了自动集群发现机制(如<code>etcd</code>),则不需要设置该值。
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
|
@ -657,15 +657,15 @@ transaction log entry.
|
||||||
|
|
||||||
db_default_shard_transport {
|
db_default_shard_transport {
|
||||||
desc {
|
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>.
|
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>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: """
|
zh: """
|
||||||
定义用于推送事务日志的默认传输。</br>
|
定义用于推送事务日志的默认传输。<br/>
|
||||||
这可以在 <code>db.shard_transports</code> 中基于每个分片被覆盖。
|
这可以在 <code>db.shard_transports</code> 中基于每个分片被覆盖。
|
||||||
<code>gen_rpc</code> 使用 <code>gen_rpc</code> 库,
|
<code>gen_rpc</code> 使用 <code>gen_rpc</code> 库,
|
||||||
<code>distr</code> 使用 Erlang 发行版。</br>
|
<code>distr</code> 使用 Erlang 发行版。<br/>
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
label {
|
label {
|
||||||
|
@ -676,13 +676,13 @@ This may be overridden on a per-shard basis in <code>db.shard_transports</code>.
|
||||||
|
|
||||||
db_shard_transports {
|
db_shard_transports {
|
||||||
desc {
|
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>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>."""
|
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>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> 中设置的值。
|
默认是使用 <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 {
|
rpc_port_discovery {
|
||||||
desc {
|
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.
|
<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,
|
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."""
|
then the listening port will be 5370 + N."""
|
||||||
zh: """<code>manual</code>: 通过 <code>tcp_server_port</code> 来发现端口。
|
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。
|
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 {
|
rpc_tcp_server_port {
|
||||||
desc {
|
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."""
|
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 时,此配置才会生效。
|
只有当 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 {
|
rpc_ssl_server_port {
|
||||||
desc {
|
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
|
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>."""
|
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>,
|
只有当 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 {
|
rpc_keyfile {
|
||||||
desc {
|
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."""
|
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。
|
注意:此文件内容是私钥,所以需要设置权限为 600。
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
|
@ -861,9 +861,9 @@ Note: contents of this file are secret, so it's necessary to set permissions to
|
||||||
|
|
||||||
rpc_cacertfile {
|
rpc_cacertfile {
|
||||||
desc {
|
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."""
|
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 签发。
|
注意:集群中所有节点的证书必须使用同一个 CA 签发。
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
|
@ -1201,7 +1201,7 @@ Supervisor 报告的类型。默认为 error 类型。
|
||||||
desc {
|
desc {
|
||||||
en: """Enable log rotation feature."""
|
en: """Enable log rotation feature."""
|
||||||
zh: """启用日志轮换功能。启动后生成日志文件后缀会加上对应的索引数字,比如:log/emqx.log.1。
|
zh: """启用日志轮换功能。启动后生成日志文件后缀会加上对应的索引数字,比如:log/emqx.log.1。
|
||||||
系统会默认生成<code>*.siz/*.idx<code>用于记录日志位置,请不要手动修改这两个文件。
|
系统会默认生成<code>*.siz/*.idx</code>用于记录日志位置,请不要手动修改这两个文件。
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
label {
|
label {
|
||||||
|
@ -1301,17 +1301,17 @@ Supervisor 报告的类型。默认为 error 类型。
|
||||||
authorization {
|
authorization {
|
||||||
desc {
|
desc {
|
||||||
en: """
|
en: """
|
||||||
Authorization a.k.a. ACL.</br>
|
Authorization a.k.a. ACL.<br/>
|
||||||
In EMQX, MQTT client access control is extremely flexible.</br>
|
In EMQX, MQTT client access control is extremely flexible.<br/>
|
||||||
An out-of-the-box set of authorization data sources are supported.
|
An out-of-the-box set of authorization data sources are supported.
|
||||||
For example,</br>
|
For example,<br/>
|
||||||
'file' source is to support concise and yet generic ACL rules in a file;</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,
|
'built_in_database' source can be used to store per-client customizable rule sets,
|
||||||
natively in the EMQX node;</br>
|
natively in the EMQX node;<br/>
|
||||||
'http' source to make EMQX call an external HTTP API to make the decision;</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>
|
'PostgreSQL' etc. to look up clients or rules from external databases;<br/>
|
||||||
"""
|
"""
|
||||||
zh: """ 授权(ACL)。EMQX 支持完整的客户端访问控制(ACL)。</br> """
|
zh: """ 授权(ACL)。EMQX 支持完整的客户端访问控制(ACL)。<br/> """
|
||||||
}
|
}
|
||||||
label {
|
label {
|
||||||
en: "Authorization"
|
en: "Authorization"
|
||||||
|
@ -1321,9 +1321,9 @@ natively in the EMQX node;</br>
|
||||||
|
|
||||||
desc_cluster {
|
desc_cluster {
|
||||||
desc {
|
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."""
|
Here holds the configs to instruct how individual nodes can discover each other."""
|
||||||
zh: """EMQX 节点可以组成一个集群,以提高总容量。</br> 这里指定了节点之间如何连接。"""
|
zh: """EMQX 节点可以组成一个集群,以提高总容量。<br/> 这里指定了节点之间如何连接。"""
|
||||||
}
|
}
|
||||||
label {
|
label {
|
||||||
en: "Cluster"
|
en: "Cluster"
|
||||||
|
@ -1422,11 +1422,11 @@ The new node joins the cluster by connecting to one of the bootstrap nodes."""
|
||||||
|
|
||||||
desc_rpc {
|
desc_rpc {
|
||||||
desc {
|
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,
|
Most of the time the default config should work,
|
||||||
but in case you need to do performance fine-tuning or experiment a bit,
|
but in case you need to do performance fine-tuning or experiment a bit,
|
||||||
this is where to look."""
|
this is where to look."""
|
||||||
zh: """EMQX 使用 <code>gen_rpc</code> 库来实现跨节点通信。</br>
|
zh: """EMQX 使用 <code>gen_rpc</code> 库来实现跨节点通信。<br/>
|
||||||
大多数情况下,默认的配置应该可以工作,但如果你需要做一些性能优化或者实验,可以尝试调整这些参数。"""
|
大多数情况下,默认的配置应该可以工作,但如果你需要做一些性能优化或者实验,可以尝试调整这些参数。"""
|
||||||
}
|
}
|
||||||
label {
|
label {
|
||||||
|
@ -1472,11 +1472,11 @@ Each sink is represented by a _log handler_, which can be configured independent
|
||||||
desc_log_rotation {
|
desc_log_rotation {
|
||||||
desc {
|
desc {
|
||||||
en: """
|
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.
|
This section of the configuration controls the number of files kept for each log handler.
|
||||||
"""
|
"""
|
||||||
zh: """
|
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_log_overload_kill {
|
||||||
desc {
|
desc {
|
||||||
en: """
|
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.
|
When the overload is detected, the log handler is terminated and restarted after a cooldown period.
|
||||||
"""
|
"""
|
||||||
zh: """
|
zh: """
|
||||||
日志过载终止,具有过载保护功能。当日志处理进程使用过多内存,或者缓存的日志消息过多时该功能被激活。</br>
|
日志过载终止,具有过载保护功能。当日志处理进程使用过多内存,或者缓存的日志消息过多时该功能被激活。<br/>
|
||||||
检测到过载时,日志处理进程将终止,并在冷却期后重新启动。
|
检测到过载时,日志处理进程将终止,并在冷却期后重新启动。
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,11 +14,11 @@ emqx_connector_api {
|
||||||
conn_test_post {
|
conn_test_post {
|
||||||
desc {
|
desc {
|
||||||
en: """
|
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}'
|
The ID must be of format '{type}:{name}'
|
||||||
"""
|
"""
|
||||||
zh: """
|
zh: """
|
||||||
通过给定的 ID 测试创建一个新的连接器 </br>
|
通过给定的 ID 测试创建一个新的连接器 <br/>
|
||||||
ID 的格式必须为“{type}:{name}”
|
ID 的格式必须为“{type}:{name}”
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,14 +2,14 @@ emqx_connector_http {
|
||||||
base_url {
|
base_url {
|
||||||
desc {
|
desc {
|
||||||
en: """
|
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
|
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/`
|
For example: `http://localhost:9901/`
|
||||||
"""
|
"""
|
||||||
zh: """
|
zh: """
|
||||||
base URL 只包含host和port。</br>
|
base URL 只包含host和port。<br/>
|
||||||
发送HTTP请求时,真实的URL是由base URL 和 path parameter连接而成(通过emqx_resource:query/2,3传递,或者通过请求参数提供)。</br>
|
发送HTTP请求时,真实的URL是由base URL 和 path parameter连接而成(通过emqx_resource:query/2,3传递,或者通过请求参数提供)。<br/>
|
||||||
示例:`http://localhost:9901/`
|
示例:`http://localhost:9901/`
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,13 +47,13 @@ emqx_connector_mongo {
|
||||||
server {
|
server {
|
||||||
desc {
|
desc {
|
||||||
en: """
|
en: """
|
||||||
The IPv4 or IPv6 address or the hostname to connect to.</br>
|
The IPv4 or IPv6 address or the hostname to connect to.<br/>
|
||||||
A host entry has the following form: `Host[:Port]`.</br>
|
A host entry has the following form: `Host[:Port]`.<br/>
|
||||||
The MongoDB default port 27017 is used if `[:Port]` is not specified.
|
The MongoDB default port 27017 is used if `[:Port]` is not specified.
|
||||||
"""
|
"""
|
||||||
zh: """
|
zh: """
|
||||||
将要连接的 IPv4 或 IPv6 地址,或者主机名。</br>
|
将要连接的 IPv4 或 IPv6 地址,或者主机名。<br/>
|
||||||
主机名具有以下形式:`Host[:Port]`。</br>
|
主机名具有以下形式:`Host[:Port]`。<br/>
|
||||||
如果未指定 `[:Port]`,则使用 MongoDB 默认端口 27017。
|
如果未指定 `[:Port]`,则使用 MongoDB 默认端口 27017。
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,22 +2,22 @@ emqx_connector_mqtt_schema {
|
||||||
mode {
|
mode {
|
||||||
desc {
|
desc {
|
||||||
en: """
|
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
|
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
|
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
|
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: """
|
zh: """
|
||||||
MQTT 桥的模式。 </br>
|
MQTT 桥的模式。 <br/>
|
||||||
|
|
||||||
- cluster_shareload:在 emqx 集群的每个节点上创建一个 MQTT 连接。</br>
|
- cluster_shareload:在 emqx 集群的每个节点上创建一个 MQTT 连接。<br/>
|
||||||
在“cluster_shareload”模式下,来自远程代理的传入负载通过共享订阅的方式接收。</br>
|
在“cluster_shareload”模式下,来自远程代理的传入负载通过共享订阅的方式接收。<br/>
|
||||||
请注意,“clientid”以节点名称为后缀,这是为了避免不同节点之间的clientid冲突。
|
请注意,<code>clientid</code> 以节点名称为后缀,这是为了避免不同节点之间的clientid冲突。
|
||||||
而且对于入口连接的“remote_topic”,我们只能使用共享订阅主题过滤器。
|
而且对于入口连接的 <code>remote_topic</code>,我们只能使用共享订阅主题过滤器。
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
label: {
|
label: {
|
||||||
|
@ -135,11 +135,11 @@ broker MUST support this feature.
|
||||||
ingress_local_topic {
|
ingress_local_topic {
|
||||||
desc {
|
desc {
|
||||||
en: """
|
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.
|
Template with variables is allowed.
|
||||||
"""
|
"""
|
||||||
zh: """
|
zh: """
|
||||||
向本地broker的哪个topic发送消息。</br>
|
向本地broker的哪个topic发送消息。<br/>
|
||||||
允许使用带有变量的模板。
|
允许使用带有变量的模板。
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
|
@ -152,11 +152,11 @@ Template with variables is allowed.
|
||||||
ingress_local_qos {
|
ingress_local_qos {
|
||||||
desc {
|
desc {
|
||||||
en: """
|
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.
|
Template with variables is allowed.
|
||||||
"""
|
"""
|
||||||
zh: """
|
zh: """
|
||||||
待发送 MQTT 消息的 QoS。</br>
|
待发送 MQTT 消息的 QoS。<br/>
|
||||||
允许使用带有变量的模板。
|
允许使用带有变量的模板。
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
|
@ -191,11 +191,11 @@ Template with variables is allowed.
|
||||||
egress_remote_topic {
|
egress_remote_topic {
|
||||||
desc {
|
desc {
|
||||||
en: """
|
en: """
|
||||||
Forward to which topic of the remote broker.</br>
|
Forward to which topic of the remote broker.<br/>
|
||||||
Template with variables is allowed.
|
Template with variables is allowed.
|
||||||
"""
|
"""
|
||||||
zh: """
|
zh: """
|
||||||
转发到远程broker的哪个topic。</br>
|
转发到远程broker的哪个topic。<br/>
|
||||||
允许使用带有变量的模板。
|
允许使用带有变量的模板。
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
|
@ -208,11 +208,11 @@ Template with variables is allowed.
|
||||||
egress_remote_qos {
|
egress_remote_qos {
|
||||||
desc {
|
desc {
|
||||||
en: """
|
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.
|
Template with variables is allowed.
|
||||||
"""
|
"""
|
||||||
zh: """
|
zh: """
|
||||||
待发送 MQTT 消息的 QoS。</br>
|
待发送 MQTT 消息的 QoS。<br/>
|
||||||
允许使用带有变量的模板。
|
允许使用带有变量的模板。
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
|
@ -225,11 +225,11 @@ Template with variables is allowed.
|
||||||
dir {
|
dir {
|
||||||
desc {
|
desc {
|
||||||
en: """
|
en: """
|
||||||
The dir where the replayq file saved.</br>
|
The dir where the replayq file saved.<br/>
|
||||||
Set to 'false' disables the replayq feature.
|
Set to 'false' disables the replayq feature.
|
||||||
"""
|
"""
|
||||||
zh: """
|
zh: """
|
||||||
replayq 文件保存的目录。</br>
|
replayq 文件保存的目录。<br/>
|
||||||
设置为 'false' 会禁用 replayq 功能。
|
设置为 'false' 会禁用 replayq 功能。
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
|
@ -242,12 +242,12 @@ replayq 文件保存的目录。</br>
|
||||||
seg_bytes {
|
seg_bytes {
|
||||||
desc {
|
desc {
|
||||||
en: """
|
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
|
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.
|
(file) will be opened to write.
|
||||||
"""
|
"""
|
||||||
zh: """
|
zh: """
|
||||||
单个段的大小(以字节为单位)。</br>
|
单个段的大小(以字节为单位)。<br/>
|
||||||
一个段映射到 replayq 目录中的一个文件。 如果当前段已满,则新段(文件)将被打开写入。
|
一个段映射到 replayq 目录中的一个文件。 如果当前段已满,则新段(文件)将被打开写入。
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
|
@ -260,12 +260,12 @@ A segment is mapping to a file in the replayq dir. If the current segment is ful
|
||||||
offload {
|
offload {
|
||||||
desc {
|
desc {
|
||||||
en: """
|
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 messages are cached in the memory first, then it writes to the replayq files after the size of
|
||||||
the memory cache reaches 'seg_bytes'.
|
the memory cache reaches 'seg_bytes'.
|
||||||
"""
|
"""
|
||||||
zh: """
|
zh: """
|
||||||
在Offload模式下,磁盘队列仅用于卸载队列尾段。</br>
|
在Offload模式下,磁盘队列仅用于卸载队列尾段。<br/>
|
||||||
消息首先缓存在内存中,然后写入replayq文件。内存缓大小为“seg_bytes” 指定的值。
|
消息首先缓存在内存中,然后写入replayq文件。内存缓大小为“seg_bytes” 指定的值。
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
|
@ -278,11 +278,11 @@ the memory cache reaches 'seg_bytes'.
|
||||||
retain {
|
retain {
|
||||||
desc {
|
desc {
|
||||||
en: """
|
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.
|
Template with variables is allowed.
|
||||||
"""
|
"""
|
||||||
zh: """
|
zh: """
|
||||||
要发送的 MQTT 消息的“保留”标志。</br>
|
要发送的 MQTT 消息的“保留”标志。<br/>
|
||||||
允许使用带有变量的模板。
|
允许使用带有变量的模板。
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
|
@ -295,11 +295,11 @@ Template with variables is allowed.
|
||||||
payload {
|
payload {
|
||||||
desc {
|
desc {
|
||||||
en: """
|
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.
|
Template with variables is allowed.
|
||||||
"""
|
"""
|
||||||
zh: """
|
zh: """
|
||||||
要发送的 MQTT 消息的负载。</br>
|
要发送的 MQTT 消息的负载。<br/>
|
||||||
允许使用带有变量的模板。
|
允许使用带有变量的模板。
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
|
@ -323,13 +323,13 @@ Template with variables is allowed.
|
||||||
desc_ingress {
|
desc_ingress {
|
||||||
desc {
|
desc {
|
||||||
en: """
|
en: """
|
||||||
The ingress config defines how this bridge receive messages from the remote MQTT broker, and then send them to the local broker.</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>
|
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.
|
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: """
|
zh: """
|
||||||
Ingress 模式定义了这个 bridge 如何从远程 MQTT broker 接收消息,然后将它们发送到本地 broker 。</br>
|
Ingress 模式定义了这个 bridge 如何从远程 MQTT broker 接收消息,然后将它们发送到本地 broker 。<br/>
|
||||||
允许带有的模板变量: 'local_topic'、'remote_qos'、'qos'、'retain'、'payload' 。</br>
|
允许带有的模板变量: 'local_topic'、'remote_qos'、'qos'、'retain'、'payload' 。<br/>
|
||||||
注意:如果这个 bridge 被用作规则的输入(emqx 规则引擎),并且还配置了 local_topic,那么从远程 broker 获取的消息将同时被发送到 'local_topic' 和规则引擎。
|
注意:如果这个 bridge 被用作规则的输入(emqx 规则引擎),并且还配置了 local_topic,那么从远程 broker 获取的消息将同时被发送到 'local_topic' 和规则引擎。
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
|
@ -342,13 +342,13 @@ Ingress 模式定义了这个 bridge 如何从远程 MQTT broker 接收消息,
|
||||||
desc_egress {
|
desc_egress {
|
||||||
desc {
|
desc {
|
||||||
en: """
|
en: """
|
||||||
The egress config defines how this bridge forwards messages from the local broker to the remote broker.</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>
|
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.
|
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: """
|
zh: """
|
||||||
Egress 模式定义了 bridge 如何将消息从本地 broker 转发到远程 broker。</br>
|
Egress 模式定义了 bridge 如何将消息从本地 broker 转发到远程 broker。<br/>
|
||||||
允许带有的模板变量: 'remote_topic'、'qos'、'retain'、'payload' 。</br>
|
允许带有的模板变量: 'remote_topic'、'qos'、'retain'、'payload' 。<br/>
|
||||||
注意:如果这个 bridge 作为规则(emqx 规则引擎)的输出,并且还配置了 local_topic,那么从规则引擎中获取的数据和匹配 local_topic 的 MQTT 消息都会被转发到远程 broker 。
|
注意:如果这个 bridge 作为规则(emqx 规则引擎)的输出,并且还配置了 local_topic,那么从规则引擎中获取的数据和匹配 local_topic 的 MQTT 消息都会被转发到远程 broker 。
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,13 +3,13 @@ emqx_connector_mysql {
|
||||||
server {
|
server {
|
||||||
desc {
|
desc {
|
||||||
en: """
|
en: """
|
||||||
The IPv4 or IPv6 address or the hostname to connect to.</br>
|
The IPv4 or IPv6 address or the hostname to connect to.<br/>
|
||||||
A host entry has the following form: `Host[:Port]`.</br>
|
A host entry has the following form: `Host[:Port]`.<br/>
|
||||||
The MySQL default port 3306 is used if `[:Port]` is not specified.
|
The MySQL default port 3306 is used if `[:Port]` is not specified.
|
||||||
"""
|
"""
|
||||||
zh: """
|
zh: """
|
||||||
将要连接的 IPv4 或 IPv6 地址,或者主机名。</br>
|
将要连接的 IPv4 或 IPv6 地址,或者主机名。<br/>
|
||||||
主机名具有以下形式:`Host[:Port]`。</br>
|
主机名具有以下形式:`Host[:Port]`。<br/>
|
||||||
如果未指定 `[:Port]`,则使用 MySQL 默认端口 3306。
|
如果未指定 `[:Port]`,则使用 MySQL 默认端口 3306。
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,13 +3,13 @@ emqx_connector_pgsql {
|
||||||
server {
|
server {
|
||||||
desc {
|
desc {
|
||||||
en: """
|
en: """
|
||||||
The IPv4 or IPv6 address or the hostname to connect to.</br>
|
The IPv4 or IPv6 address or the hostname to connect to.<br/>
|
||||||
A host entry has the following form: `Host[:Port]`.</br>
|
A host entry has the following form: `Host[:Port]`.<br/>
|
||||||
The PostgreSQL default port 5432 is used if `[:Port]` is not specified.
|
The PostgreSQL default port 5432 is used if `[:Port]` is not specified.
|
||||||
"""
|
"""
|
||||||
zh: """
|
zh: """
|
||||||
将要连接的 IPv4 或 IPv6 地址,或者主机名。</br>
|
将要连接的 IPv4 或 IPv6 地址,或者主机名。<br/>
|
||||||
主机名具有以下形式:`Host[:Port]`。</br>
|
主机名具有以下形式:`Host[:Port]`。<br/>
|
||||||
如果未指定 `[:Port]`,则使用 PostgreSQL 默认端口 5432。
|
如果未指定 `[:Port]`,则使用 PostgreSQL 默认端口 5432。
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,13 +47,13 @@ emqx_connector_redis {
|
||||||
server {
|
server {
|
||||||
desc {
|
desc {
|
||||||
en: """
|
en: """
|
||||||
The IPv4 or IPv6 address or the hostname to connect to.</br>
|
The IPv4 or IPv6 address or the hostname to connect to.<br/>
|
||||||
A host entry has the following form: `Host[:Port]`.</br>
|
A host entry has the following form: `Host[:Port]`.<br/>
|
||||||
The Redis default port 6379 is used if `[:Port]` is not specified.
|
The Redis default port 6379 is used if `[:Port]` is not specified.
|
||||||
"""
|
"""
|
||||||
zh: """
|
zh: """
|
||||||
将要连接的 IPv4 或 IPv6 地址,或者主机名。</br>
|
将要连接的 IPv4 或 IPv6 地址,或者主机名。<br/>
|
||||||
主机名具有以下形式:`Host[:Port]`。</br>
|
主机名具有以下形式:`Host[:Port]`。<br/>
|
||||||
如果未指定 `[:Port]`,则使用 MongoDB 默认端口 27017。
|
如果未指定 `[:Port]`,则使用 MongoDB 默认端口 27017。
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,11 +14,11 @@ emqx_connector_schema {
|
||||||
desc_connector {
|
desc_connector {
|
||||||
desc {
|
desc {
|
||||||
en: """
|
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.
|
A connector maintains the data related to the external resources, such as MySQL database.
|
||||||
"""
|
"""
|
||||||
zh: """
|
zh: """
|
||||||
EMQX 连接器的配置。</br>
|
EMQX 连接器的配置。<br/>
|
||||||
连接器维护与外部资源相关的数据,比如 MySQL 数据库。
|
连接器维护与外部资源相关的数据,比如 MySQL 数据库。
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,14 +25,13 @@
|
||||||
-define(PGSQL_DEFAULT_PORT, 5432).
|
-define(PGSQL_DEFAULT_PORT, 5432).
|
||||||
|
|
||||||
-define(SERVERS_DESC,
|
-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: "
|
"For each Node should be: "
|
||||||
).
|
).
|
||||||
|
|
||||||
-define(SERVER_DESC(TYPE, DEFAULT_PORT),
|
-define(SERVER_DESC(TYPE, DEFAULT_PORT),
|
||||||
"\n"
|
"The IPv4 or IPv6 address or the hostname to connect to.<br/>"
|
||||||
"The IPv4 or IPv6 address or the hostname to connect to.</br>\n"
|
"A host entry has the following form: `Host[:Port]`.<br/>"
|
||||||
"A host entry has the following form: `Host[:Port]`.</br>\n"
|
|
||||||
"The " ++ TYPE ++ " default port " ++ DEFAULT_PORT ++ " is used if `[:Port]` is not specified."
|
"The " ++ TYPE ++ " default port " ++ DEFAULT_PORT ++ " is used if `[:Port]` is not specified."
|
||||||
).
|
).
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
%% -*- mode: erlang -*-
|
%% -*- mode: erlang -*-
|
||||||
{application, emqx_connector, [
|
{application, emqx_connector, [
|
||||||
{description, "An OTP application"},
|
{description, "An OTP application"},
|
||||||
{vsn, "0.1.6"},
|
{vsn, "0.1.7"},
|
||||||
{registered, []},
|
{registered, []},
|
||||||
{mod, {emqx_connector_app, []}},
|
{mod, {emqx_connector_app, []}},
|
||||||
{applications, [
|
{applications, [
|
||||||
|
|
|
@ -282,9 +282,9 @@ topic_mappings() ->
|
||||||
ingress_desc() ->
|
ingress_desc() ->
|
||||||
"\n"
|
"\n"
|
||||||
"The ingress config defines how this bridge receive messages from the remote MQTT broker, and then\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"
|
"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"
|
"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"
|
"configured, then messages got from the remote broker will be sent to both the 'local_topic' and\n"
|
||||||
"the rule.\n".
|
"the rule.\n".
|
||||||
|
@ -292,8 +292,8 @@ ingress_desc() ->
|
||||||
egress_desc() ->
|
egress_desc() ->
|
||||||
"\n"
|
"\n"
|
||||||
"The egress config defines how this bridge forwards messages from the local broker to the remote\n"
|
"The egress config defines how this bridge forwards messages from the local broker to the remote\n"
|
||||||
"broker.</br>\n"
|
"broker.<br/>"
|
||||||
"Template with variables is allowed in 'remote_topic', 'qos', 'retain', 'payload'.</br>\n"
|
"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"
|
"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"
|
"is configured, then both the data got from the rule and the MQTT messages that matches\n"
|
||||||
"local_topic will be forwarded.\n".
|
"local_topic will be forwarded.\n".
|
||||||
|
|
|
@ -441,7 +441,7 @@ trans_description(Spec, Hocon) ->
|
||||||
undefined ->
|
undefined ->
|
||||||
Spec;
|
Spec;
|
||||||
Desc ->
|
Desc ->
|
||||||
Desc1 = binary:replace(Desc, [<<"</br>\n">>, <<"\n">>], <<"</br>">>, [global]),
|
Desc1 = binary:replace(Desc, [<<"\n">>], <<"<br/>">>, [global]),
|
||||||
Spec#{description => Desc1}
|
Spec#{description => Desc1}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ emqx_gateway_api_authn {
|
||||||
|
|
||||||
get_authn {
|
get_authn {
|
||||||
desc {
|
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."""
|
Returns 404 when gateway or authentication is not enabled."""
|
||||||
zh: """获取指定网关认证器的配置
|
zh: """获取指定网关认证器的配置
|
||||||
当网关或认证未启用时,返回 404。"""
|
当网关或认证未启用时,返回 404。"""
|
||||||
|
@ -18,11 +18,11 @@ Returns 404 when gateway or authentication is not enabled."""
|
||||||
|
|
||||||
add_authn {
|
add_authn {
|
||||||
desc {
|
desc {
|
||||||
en: """Enables the authenticator for client authentication for the specified gateway. <\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>
|
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."""
|
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>
|
zh: """为指定网关开启认证器实现客户端认证的功能。<br/>
|
||||||
当未配置认证器或关闭认证器时,则认为允许所有客户端的连接。<\br>
|
当未配置认证器或关闭认证器时,则认为允许所有客户端的连接。<br/>
|
||||||
注:在网关中仅支持添加一个认证器,而不是像 MQTT 一样允许配置多个认证器构成认证链。"""
|
注:在网关中仅支持添加一个认证器,而不是像 MQTT 一样允许配置多个认证器构成认证链。"""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,9 +32,9 @@ including current running status, number of connections, listener status, etc.""
|
||||||
|
|
||||||
update_gateway {
|
update_gateway {
|
||||||
desc {
|
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. """
|
Note: The Authentication and Listener configurations should be updated by other special APIs. """
|
||||||
zh: """更新指定网关的基础配置、和启用的状态。</br>
|
zh: """更新指定网关的基础配置、和启用的状态。<br/>
|
||||||
注:认证、和监听器的配置更新需参考对应的 API 接口。"""
|
注:认证、和监听器的配置更新需参考对应的 API 接口。"""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -48,10 +48,10 @@ Note: The Authentication and Listener configurations should be updated by other
|
||||||
|
|
||||||
gateway_name_in_qs {
|
gateway_name_in_qs {
|
||||||
desc {
|
desc {
|
||||||
en: """Gateway Name.</br>
|
en: """Gateway Name.<br/>
|
||||||
It's enum with `stomp`, `mqttsn`, `coap`, `lwm2m`, `exproto`
|
It's enum with `stomp`, `mqttsn`, `coap`, `lwm2m`, `exproto`
|
||||||
"""
|
"""
|
||||||
zh: """网关名称.</br>
|
zh: """网关名称.<br/>
|
||||||
可取值为 `stomp`、`mqttsn`、`coap`、`lwm2m`、`exproto`
|
可取值为 `stomp`、`mqttsn`、`coap`、`lwm2m`、`exproto`
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
|
@ -66,9 +66,9 @@ It's enum with `stomp`, `mqttsn`, `coap`, `lwm2m`, `exproto`
|
||||||
|
|
||||||
gateway_status_in_qs {
|
gateway_status_in_qs {
|
||||||
desc {
|
desc {
|
||||||
en: """Filter gateways by status.</br>
|
en: """Filter gateways by status.<br/>
|
||||||
It is enum with `running`, `stopped`, `unloaded`"""
|
It is enum with `running`, `stopped`, `unloaded`"""
|
||||||
zh: """通过网关状态筛选</br>
|
zh: """通过网关状态筛选<br/>
|
||||||
可选值为 `running`、`stopped`、`unloaded`"""
|
可选值为 `running`、`stopped`、`unloaded`"""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,9 +9,9 @@ emqx_gateway_api_listeners {
|
||||||
|
|
||||||
add_listener {
|
add_listener {
|
||||||
desc {
|
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`."""
|
Note: For listener types not supported by a gateway, this API returns `400: BAD_REQUEST`."""
|
||||||
zh: """为指定网关添加监听器。</br>
|
zh: """为指定网关添加监听器。<br/>
|
||||||
注:对于某网关不支持的监听器类型,该接口会返回 `400: BAD_REQUEST`。"""
|
注:对于某网关不支持的监听器类型,该接口会返回 `400: BAD_REQUEST`。"""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -46,9 +46,9 @@ Note: For listener types not supported by a gateway, this API returns `400: BAD_
|
||||||
|
|
||||||
add_listener_authn {
|
add_listener_authn {
|
||||||
desc {
|
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."""
|
When authenticator is enabled for a listener, all clients connecting to that listener will use that authenticator for authentication."""
|
||||||
zh: """为指定监听器开启认证器以实现客户端认证的能力。</br>
|
zh: """为指定监听器开启认证器以实现客户端认证的能力。<br/>
|
||||||
当某一监听器开启认证后,所有连接到该监听器的客户端会使用该认证器进行认证。"""
|
当某一监听器开启认证后,所有连接到该监听器的客户端会使用该认证器进行认证。"""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -146,7 +146,7 @@ This option specifies the QoS level for the CoAP Client when establishing a subs
|
||||||
"""
|
"""
|
||||||
zh: """客户端订阅请求的默认 QoS 等级。
|
zh: """客户端订阅请求的默认 QoS 等级。
|
||||||
当 CoAP 客户端发起订阅请求时,如果未携带 `qos` 参数则会使用该默认值。默认值可设置为:
|
当 CoAP 客户端发起订阅请求时,如果未携带 `qos` 参数则会使用该默认值。默认值可设置为:
|
||||||
- qos0, qos1, qos2: 设置为固定的 QoS 等级
|
- qos0、 qos1、qos2: 设置为固定的 QoS 等级
|
||||||
- coap: 依据订阅操作的 CoAP 报文类型来动态决定
|
- coap: 依据订阅操作的 CoAP 报文类型来动态决定
|
||||||
* 当订阅请求为 `non-confirmable` 类型时,取值为 qos0
|
* 当订阅请求为 `non-confirmable` 类型时,取值为 qos0
|
||||||
* 当订阅请求为 `confirmable` 类型时,取值为 qos1
|
* 当订阅请求为 `confirmable` 类型时,取值为 qos1
|
||||||
|
@ -165,7 +165,7 @@ This option specifies the QoS level for the CoAP Client when publishing a messag
|
||||||
|
|
||||||
zh: """客户端发布请求的默认 QoS 等级。
|
zh: """客户端发布请求的默认 QoS 等级。
|
||||||
当 CoAP 客户端发起发布请求时,如果未携带 `qos` 参数则会使用该默认值。默认值可设置为:
|
当 CoAP 客户端发起发布请求时,如果未携带 `qos` 参数则会使用该默认值。默认值可设置为:
|
||||||
- qos0, qos1, qos2: 设置为固定的 QoS 等级
|
- qos0、qos1、qos2: 设置为固定的 QoS 等级
|
||||||
- coap: 依据发布操作的 CoAP 报文类型来动态决定
|
- coap: 依据发布操作的 CoAP 报文类型来动态决定
|
||||||
* 当发布请求为 `non-confirmable` 类型时,取值为 qos0
|
* 当发布请求为 `non-confirmable` 类型时,取值为 qos0
|
||||||
* 当发布请求为 `confirmable` 类型时,取值为 qos1
|
* 当发布请求为 `confirmable` 类型时,取值为 qos1
|
||||||
|
@ -175,29 +175,29 @@ This option specifies the QoS level for the CoAP Client when publishing a messag
|
||||||
|
|
||||||
lwm2m {
|
lwm2m {
|
||||||
desc {
|
desc {
|
||||||
en: """The LwM2M Gateway configuration. This gateway only supports the v1.0.1 protocol"""
|
en: """The LwM2M Gateway configuration. This gateway only supports the v1.0.1 protocol."""
|
||||||
zh: """LwM2M 网关配置。仅支持 v1.0.1 协议"""
|
zh: """LwM2M 网关配置。仅支持 v1.0.1 协议。"""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lwm2m_xml_dir {
|
lwm2m_xml_dir {
|
||||||
desc {
|
desc {
|
||||||
en: """The Directory for LwM2M Resource definition"""
|
en: """The Directory for LwM2M Resource definition."""
|
||||||
zh: """LwM2M Resource 定义的 XML 文件目录路径"""
|
zh: """LwM2M Resource 定义的 XML 文件目录路径。"""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lwm2m_lifetime_min {
|
lwm2m_lifetime_min {
|
||||||
desc {
|
desc {
|
||||||
en: """Minimum value of lifetime allowed to be set by the LwM2M client"""
|
en: """Minimum value of lifetime allowed to be set by the LwM2M client."""
|
||||||
zh: """允许 LwM2M 客户端允许设置的心跳最小值"""
|
zh: """允许 LwM2M 客户端允许设置的心跳最小值。"""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lwm2m_lifetime_max {
|
lwm2m_lifetime_max {
|
||||||
desc {
|
desc {
|
||||||
en: """Maximum value of lifetime allowed to be set by the LwM2M client"""
|
en: """Maximum value of lifetime allowed to be set by the LwM2M client."""
|
||||||
zh: """允许 LwM2M 客户端允许设置的心跳最大值"""
|
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."""
|
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网关认为网络链接有效的时间窗口的值。
|
zh: """在QMode模式下,LwM2M网关认为网络链接有效的时间窗口的值。
|
||||||
例如,在收到客户端的更新信息后,在这个时间窗口内的任何信息都会直接发送到LwM2M客户端,而超过这个时间窗口的所有信息都会暂时储存在内存中"""
|
例如,在收到客户端的更新信息后,在这个时间窗口内的任何信息都会直接发送到LwM2M客户端,而超过这个时间窗口的所有信息都会暂时储存在内存中。"""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lwm2m_auto_observe {
|
lwm2m_auto_observe {
|
||||||
desc {
|
desc {
|
||||||
en: """Automatically observe the object list of REGISTER packet"""
|
en: """Automatically observe the object list of REGISTER packet."""
|
||||||
zh: """自动 Observe REGISTER 数据包的 Object 列表"""
|
zh: """自动 Observe REGISTER 数据包的 Object 列表。"""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -226,15 +226,15 @@ For example, after receiving an update message from a client, any messages withi
|
||||||
"""
|
"""
|
||||||
zh: """发布UPDATE事件消息的策略。
|
zh: """发布UPDATE事件消息的策略。
|
||||||
- always: 只要收到 UPDATE 请求,就发送更新事件。
|
- always: 只要收到 UPDATE 请求,就发送更新事件。
|
||||||
- contains_object_list: 仅当 UPDATE 请求携带 Object 列表时才发送更新事件
|
- contains_object_list: 仅当 UPDATE 请求携带 Object 列表时才发送更新事件。
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lwm2m_translators {
|
lwm2m_translators {
|
||||||
desc {
|
desc {
|
||||||
en: """Topic configuration for LwM2M's gateway publishing and subscription"""
|
en: """Topic configuration for LwM2M's gateway publishing and subscription."""
|
||||||
zh: """LwM2M 网关订阅/发布消息的主题映射配置"""
|
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"""
|
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: """下行命令主题。
|
zh: """下行命令主题。
|
||||||
对于每个成功上线的新 LwM2M 客户端,网关会创建一个订阅关系来接收下行消息并将其发送给客户端"""
|
对于每个成功上线的新 LwM2M 客户端,网关会创建一个订阅关系来接收下行消息并将其发送给客户端。"""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lwm2m_translators_response {
|
lwm2m_translators_response {
|
||||||
desc {
|
desc {
|
||||||
en: """The topic for gateway to publish the acknowledge events from LwM2M client"""
|
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"""
|
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 客户端的通知事件的主题。
|
zh: """用于发布来自 LwM2M 客户端的通知事件的主题。
|
||||||
在成功 Observe 到 LwM2M 客户端的资源后,如果客户端报告任何资源状态的变化,网关将通过该主题发送通知事件"""
|
在成功 Observe 到 LwM2M 客户端的资源后,如果客户端报告任何资源状态的变化,网关将通过该主题发送通知事件。"""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lwm2m_translators_register {
|
lwm2m_translators_register {
|
||||||
desc {
|
desc {
|
||||||
en: """The topic for gateway to publish the register events from LwM2M client."""
|
en: """The topic for gateway to publish the register events from LwM2M client."""
|
||||||
zh: """用于发布来自 LwM2M 客户端的注册事件的主题"""
|
zh: """用于发布来自 LwM2M 客户端的注册事件的主题。"""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lwm2m_translators_update {
|
lwm2m_translators_update {
|
||||||
desc {
|
desc {
|
||||||
en: """The topic for gateway to publish the update events from LwM2M client"""
|
en: """The topic for gateway to publish the update events from LwM2M client"""
|
||||||
zh: """用于发布来自LwM2M客户端的更新事件的主题"""
|
zh: """用于发布来自LwM2M客户端的更新事件的主题。"""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
translator {
|
translator {
|
||||||
desc {
|
desc {
|
||||||
en: """MQTT topic that corresponds to a particular type of event."""
|
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 {
|
gateway_common_authentication {
|
||||||
desc {
|
desc {
|
||||||
en: """Default authentication configs for all the gateway listeners. For per-listener overrides see <code>authentication</code>\n in listener configs"""
|
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 {
|
tcp_udp_listeners {
|
||||||
desc {
|
desc {
|
||||||
en: """Settings for the listeners."""
|
en: """Settings for the listeners."""
|
||||||
zh: """监听器配置"""
|
zh: """监听器配置。"""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tcp_listeners {
|
tcp_listeners {
|
||||||
desc {
|
desc {
|
||||||
en: """Settings for the TCP listeners."""
|
en: """Settings for the TCP listeners."""
|
||||||
zh: """配置 TCP 类型的监听器"""
|
zh: """配置 TCP 类型的监听器。"""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
udp_listeners {
|
udp_listeners {
|
||||||
desc {
|
desc {
|
||||||
en: """Settings for the UDP listeners."""
|
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{
|
tcp_listener_tcp_opts{
|
||||||
desc {
|
desc {
|
||||||
en: """Setting the TCP socket options."""
|
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 {
|
ssl_listener_options {
|
||||||
desc {
|
desc {
|
||||||
en: """SSL Socket options."""
|
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 {
|
udp_listener_udp_opts {
|
||||||
desc {
|
desc {
|
||||||
en: """Settings for the UDP sockets."""
|
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 {
|
udp_listener_reuseaddr {
|
||||||
desc {
|
desc {
|
||||||
en: """Allow local reuse of port numbers."""
|
en: """Allow local reuse of port numbers."""
|
||||||
zh: """允许重用本地处于 TIME_WAIT 的端口号"""
|
zh: """允许重用本地处于 TIME_WAIT 的端口号。"""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -118,9 +118,11 @@ list_nodes() ->
|
||||||
Running = mria_mnesia:cluster_nodes(running),
|
Running = mria_mnesia:cluster_nodes(running),
|
||||||
Stopped = mria_mnesia:cluster_nodes(stopped),
|
Stopped = mria_mnesia:cluster_nodes(stopped),
|
||||||
DownNodes = lists:map(fun stopped_node_info/1, 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() ->
|
node_info() ->
|
||||||
{UsedRatio, Total} = get_sys_memory(),
|
{UsedRatio, Total} = get_sys_memory(),
|
||||||
|
@ -152,8 +154,8 @@ get_sys_memory() ->
|
||||||
{0, 0}
|
{0, 0}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
node_info(Node) ->
|
node_info(Nodes) ->
|
||||||
wrap_rpc(emqx_management_proto_v2:node_info(Node)).
|
emqx_rpc:unwrap_erpc(emqx_management_proto_v3:node_info(Nodes)).
|
||||||
|
|
||||||
stopped_node_info(Node) ->
|
stopped_node_info(Node) ->
|
||||||
#{name => Node, node_status => 'stopped'}.
|
#{name => Node, node_status => 'stopped'}.
|
||||||
|
@ -163,17 +165,19 @@ stopped_node_info(Node) ->
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
list_brokers() ->
|
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) ->
|
lookup_broker(Node) ->
|
||||||
broker_info(Node).
|
[Broker] = broker_info([Node]),
|
||||||
|
Broker.
|
||||||
|
|
||||||
broker_info() ->
|
broker_info() ->
|
||||||
Info = maps:from_list([{K, iolist_to_binary(V)} || {K, V} <- emqx_sys: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'}.
|
Info#{node => node(), otp_release => otp_rel(), node_status => 'Running'}.
|
||||||
|
|
||||||
broker_info(Node) ->
|
broker_info(Nodes) ->
|
||||||
wrap_rpc(emqx_management_proto_v2:broker_info(Node)).
|
emqx_rpc:unwrap_erpc(emqx_management_proto_v3:broker_info(Nodes)).
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% Metrics and Stats
|
%% Metrics and Stats
|
||||||
|
@ -183,7 +187,7 @@ get_metrics() ->
|
||||||
nodes_info_count([get_metrics(Node) || Node <- mria_mnesia:running_nodes()]).
|
nodes_info_count([get_metrics(Node) || Node <- mria_mnesia:running_nodes()]).
|
||||||
|
|
||||||
get_metrics(Node) ->
|
get_metrics(Node) ->
|
||||||
wrap_rpc(emqx_proto_v1:get_metrics(Node)).
|
unwrap_rpc(emqx_proto_v1:get_metrics(Node)).
|
||||||
|
|
||||||
get_stats() ->
|
get_stats() ->
|
||||||
GlobalStatsKeys =
|
GlobalStatsKeys =
|
||||||
|
@ -211,7 +215,7 @@ delete_keys(List, [Key | Keys]) ->
|
||||||
delete_keys(proplists:delete(Key, List), Keys).
|
delete_keys(proplists:delete(Key, List), Keys).
|
||||||
|
|
||||||
get_stats(Node) ->
|
get_stats(Node) ->
|
||||||
wrap_rpc(emqx_proto_v1:get_stats(Node)).
|
unwrap_rpc(emqx_proto_v1:get_stats(Node)).
|
||||||
|
|
||||||
nodes_info_count(PropList) ->
|
nodes_info_count(PropList) ->
|
||||||
NodeCount =
|
NodeCount =
|
||||||
|
@ -241,7 +245,7 @@ lookup_client({username, Username}, FormatFun) ->
|
||||||
]).
|
]).
|
||||||
|
|
||||||
lookup_client(Node, Key, {M, F}) ->
|
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} ->
|
||||||
{error, Err};
|
{error, Err};
|
||||||
L ->
|
L ->
|
||||||
|
@ -264,7 +268,7 @@ kickout_client({ClientID, FormatFun}) ->
|
||||||
end.
|
end.
|
||||||
|
|
||||||
kickout_client(Node, ClientId) ->
|
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) ->
|
list_authz_cache(ClientId) ->
|
||||||
call_client(ClientId, list_authz_cache).
|
call_client(ClientId, list_authz_cache).
|
||||||
|
@ -284,14 +288,14 @@ list_client_subscriptions(ClientId) ->
|
||||||
end.
|
end.
|
||||||
|
|
||||||
client_subscriptions(Node, ClientId) ->
|
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) ->
|
clean_authz_cache(ClientId) ->
|
||||||
Results = [clean_authz_cache(Node, ClientId) || Node <- mria_mnesia:running_nodes()],
|
Results = [clean_authz_cache(Node, ClientId) || Node <- mria_mnesia:running_nodes()],
|
||||||
check_results(Results).
|
check_results(Results).
|
||||||
|
|
||||||
clean_authz_cache(Node, ClientId) ->
|
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() ->
|
clean_authz_cache_all() ->
|
||||||
Results = [{Node, clean_authz_cache_all(Node)} || Node <- mria_mnesia:running_nodes()],
|
Results = [{Node, clean_authz_cache_all(Node)} || Node <- mria_mnesia:running_nodes()],
|
||||||
|
@ -308,10 +312,10 @@ wrap_results(Results) ->
|
||||||
end.
|
end.
|
||||||
|
|
||||||
clean_authz_cache_all(Node) ->
|
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) ->
|
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) ->
|
set_ratelimit_policy(ClientId, Policy) ->
|
||||||
call_client(ClientId, {ratelimit, Policy}).
|
call_client(ClientId, {ratelimit, Policy}).
|
||||||
|
@ -357,7 +361,7 @@ do_call_client(ClientId, Req) ->
|
||||||
|
|
||||||
%% @private
|
%% @private
|
||||||
call_client(Node, ClientId, Req) ->
|
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
|
%% Subscriptions
|
||||||
|
@ -376,7 +380,7 @@ do_list_subscriptions() ->
|
||||||
end.
|
end.
|
||||||
|
|
||||||
list_subscriptions(Node) ->
|
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) ->
|
list_subscriptions_via_topic(Topic, FormatFun) ->
|
||||||
lists:append([
|
lists:append([
|
||||||
|
@ -385,7 +389,7 @@ list_subscriptions_via_topic(Topic, FormatFun) ->
|
||||||
]).
|
]).
|
||||||
|
|
||||||
list_subscriptions_via_topic(Node, Topic, _FormatFun = {M, F}) ->
|
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};
|
{error, Reason} -> {error, Reason};
|
||||||
Result -> M:F(Result)
|
Result -> M:F(Result)
|
||||||
end.
|
end.
|
||||||
|
@ -394,7 +398,7 @@ lookup_subscriptions(ClientId) ->
|
||||||
lists:append([lookup_subscriptions(Node, ClientId) || Node <- mria_mnesia:running_nodes()]).
|
lists:append([lookup_subscriptions(Node, ClientId) || Node <- mria_mnesia:running_nodes()]).
|
||||||
|
|
||||||
lookup_subscriptions(Node, ClientId) ->
|
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
|
%% PubSub
|
||||||
|
@ -404,7 +408,7 @@ subscribe(ClientId, TopicTables) ->
|
||||||
subscribe(mria_mnesia:running_nodes(), ClientId, TopicTables).
|
subscribe(mria_mnesia:running_nodes(), ClientId, TopicTables).
|
||||||
|
|
||||||
subscribe([Node | 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);
|
{error, _} -> subscribe(Nodes, ClientId, TopicTables);
|
||||||
{subscribe, Res} -> {subscribe, Res, Node}
|
{subscribe, Res} -> {subscribe, Res, Node}
|
||||||
end;
|
end;
|
||||||
|
@ -431,7 +435,7 @@ unsubscribe(ClientId, Topic) ->
|
||||||
-spec unsubscribe([node()], emqx_types:clientid(), emqx_types:topic()) ->
|
-spec unsubscribe([node()], emqx_types:clientid(), emqx_types:topic()) ->
|
||||||
{unsubscribe, _} | {error, channel_not_found}.
|
{unsubscribe, _} | {error, channel_not_found}.
|
||||||
unsubscribe([Node | Nodes], ClientId, Topic) ->
|
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);
|
{error, _} -> unsubscribe(Nodes, ClientId, Topic);
|
||||||
Re -> Re
|
Re -> Re
|
||||||
end;
|
end;
|
||||||
|
@ -454,7 +458,7 @@ unsubscribe_batch(ClientId, Topics) ->
|
||||||
-spec unsubscribe_batch([node()], emqx_types:clientid(), [emqx_types:topic()]) ->
|
-spec unsubscribe_batch([node()], emqx_types:clientid(), [emqx_types:topic()]) ->
|
||||||
{unsubscribe_batch, _} | {error, channel_not_found}.
|
{unsubscribe_batch, _} | {error, channel_not_found}.
|
||||||
unsubscribe_batch([Node | Nodes], ClientId, Topics) ->
|
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);
|
{error, _} -> unsubscribe_batch(Nodes, ClientId, Topics);
|
||||||
Re -> Re
|
Re -> Re
|
||||||
end;
|
end;
|
||||||
|
@ -477,16 +481,16 @@ get_alarms(Type) ->
|
||||||
[{Node, get_alarms(Node, Type)} || Node <- mria_mnesia:running_nodes()].
|
[{Node, get_alarms(Node, Type)} || Node <- mria_mnesia:running_nodes()].
|
||||||
|
|
||||||
get_alarms(Node, Type) ->
|
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) ->
|
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() ->
|
||||||
[delete_all_deactivated_alarms(Node) || Node <- mria_mnesia:running_nodes()].
|
[delete_all_deactivated_alarms(Node) || Node <- mria_mnesia:running_nodes()].
|
||||||
|
|
||||||
delete_all_deactivated_alarms(Node) ->
|
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) ->
|
add_duration_field(Alarms) ->
|
||||||
Now = erlang:system_time(microsecond),
|
Now = erlang:system_time(microsecond),
|
||||||
|
@ -523,10 +527,9 @@ delete_banned(Who) ->
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% Internal Functions.
|
%% Internal Functions.
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
unwrap_rpc({badrpc, Reason}) ->
|
||||||
wrap_rpc({badrpc, Reason}) ->
|
|
||||||
{error, Reason};
|
{error, Reason};
|
||||||
wrap_rpc(Res) ->
|
unwrap_rpc(Res) ->
|
||||||
Res.
|
Res.
|
||||||
|
|
||||||
otp_rel() ->
|
otp_rel() ->
|
||||||
|
@ -546,7 +549,7 @@ check_row_limit([Tab | Tables], Limit) ->
|
||||||
check_results(Results) ->
|
check_results(Results) ->
|
||||||
case lists:any(fun(Item) -> Item =:= ok end, Results) of
|
case lists:any(fun(Item) -> Item =:= ok end, Results) of
|
||||||
true -> ok;
|
true -> ok;
|
||||||
false -> wrap_rpc(lists:last(Results))
|
false -> unwrap_rpc(lists:last(Results))
|
||||||
end.
|
end.
|
||||||
|
|
||||||
max_row_limit() ->
|
max_row_limit() ->
|
||||||
|
|
|
@ -115,7 +115,7 @@ schema("/configs_reset/:rootname") ->
|
||||||
tags => ?TAGS,
|
tags => ?TAGS,
|
||||||
description =>
|
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 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"
|
"- For a config entry that has no default value, an error 400 will be returned"
|
||||||
>>,
|
>>,
|
||||||
|
|
|
@ -70,8 +70,8 @@ schema("/plugins") ->
|
||||||
'operationId' => list_plugins,
|
'operationId' => list_plugins,
|
||||||
get => #{
|
get => #{
|
||||||
description =>
|
description =>
|
||||||
"List all install plugins.</br>"
|
"List all install plugins.<br/>"
|
||||||
"Plugins are launched in top-down order.</br>"
|
"Plugins are launched in top-down order.<br/>"
|
||||||
"Using `POST /plugins/{name}/move` to change the boot order.",
|
"Using `POST /plugins/{name}/move` to change the boot order.",
|
||||||
tags => ?TAGS,
|
tags => ?TAGS,
|
||||||
responses => #{
|
responses => #{
|
||||||
|
@ -136,9 +136,9 @@ schema("/plugins/:name/:action") ->
|
||||||
'operationId' => update_plugin,
|
'operationId' => update_plugin,
|
||||||
put => #{
|
put => #{
|
||||||
description =>
|
description =>
|
||||||
"start/stop a installed plugin.</br>"
|
"start/stop a installed plugin.<br/>"
|
||||||
"- **start**: start the plugin.</br>"
|
"- **start**: start the plugin.<br/>"
|
||||||
"- **stop**: stop the plugin.</br>",
|
"- **stop**: stop the plugin.<br/>",
|
||||||
tags => ?TAGS,
|
tags => ?TAGS,
|
||||||
parameters => [
|
parameters => [
|
||||||
hoconsc:ref(name),
|
hoconsc:ref(name),
|
||||||
|
@ -272,9 +272,9 @@ fields(running_status) ->
|
||||||
{status,
|
{status,
|
||||||
hoconsc:mk(hoconsc:enum([running, stopped]), #{
|
hoconsc:mk(hoconsc:enum([running, stopped]), #{
|
||||||
desc =>
|
desc =>
|
||||||
"Install plugin status at runtime</br>"
|
"Install plugin status at runtime<br/>"
|
||||||
"1. running: plugin is running.</br>"
|
"1. running: plugin is running.<br/>"
|
||||||
"2. stopped: plugin is stopped.</br>"
|
"2. stopped: plugin is stopped.<br/>"
|
||||||
})}
|
})}
|
||||||
].
|
].
|
||||||
|
|
||||||
|
|
|
@ -45,7 +45,16 @@ running_status() ->
|
||||||
BrokerStatus = broker_status(),
|
BrokerStatus = broker_status(),
|
||||||
AppStatus = application_status(),
|
AppStatus = application_status(),
|
||||||
Body = io_lib:format("Node ~ts is ~ts~nemqx is ~ts", [node(), BrokerStatus, AppStatus]),
|
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 ->
|
false ->
|
||||||
{503, #{<<"retry-after">> => <<"15">>}, <<>>}
|
{503, #{<<"retry-after">> => <<"15">>}, <<>>}
|
||||||
end.
|
end.
|
||||||
|
|
|
@ -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, []).
|
|
@ -113,3 +113,51 @@ t_node_metrics_api(_) ->
|
||||||
{error, {_, 400, _}},
|
{error, {_, 400, _}},
|
||||||
emqx_mgmt_api_test_util:request_api(get, BadNodePath)
|
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}
|
||||||
|
]).
|
||||||
|
|
|
@ -20,6 +20,12 @@
|
||||||
|
|
||||||
-include_lib("eunit/include/eunit.hrl").
|
-include_lib("eunit/include/eunit.hrl").
|
||||||
|
|
||||||
|
-define(HOST, "http://127.0.0.1:18083/").
|
||||||
|
|
||||||
|
%%---------------------------------------------------------------------------------------
|
||||||
|
%% CT boilerplate
|
||||||
|
%%---------------------------------------------------------------------------------------
|
||||||
|
|
||||||
all() ->
|
all() ->
|
||||||
emqx_common_test_helpers:all(?MODULE).
|
emqx_common_test_helpers:all(?MODULE).
|
||||||
|
|
||||||
|
@ -30,8 +36,102 @@ init_per_suite(Config) ->
|
||||||
end_per_suite(_) ->
|
end_per_suite(_) ->
|
||||||
emqx_mgmt_api_test_util:end_suite().
|
emqx_mgmt_api_test_util:end_suite().
|
||||||
|
|
||||||
t_status(_Config) ->
|
init_per_testcase(t_status_not_ok, Config) ->
|
||||||
Path = emqx_mgmt_api_test_util:api_path_without_base_path(["/status"]),
|
ok = application:stop(emqx),
|
||||||
Status = io_lib:format("Node ~ts is ~ts~nemqx is ~ts", [node(), started, running]),
|
Config;
|
||||||
{ok, Status} = emqx_mgmt_api_test_util:request_api(get, Path),
|
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.
|
ok.
|
||||||
|
|
|
@ -2,14 +2,14 @@ emqx_plugins_schema {
|
||||||
plugins {
|
plugins {
|
||||||
desc {
|
desc {
|
||||||
en: """
|
en: """
|
||||||
Manage EMQX plugins.</br>
|
Manage EMQX plugins.<br/>
|
||||||
Plugins can be pre-built as a part of EMQX package,
|
Plugins can be pre-built as a part of EMQX package,
|
||||||
or installed as a standalone package in a location specified by
|
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.
|
The standalone-installed plugins are referred to as 'external' plugins.
|
||||||
"""
|
"""
|
||||||
zh: """管理EMQX插件。</br>
|
zh: """管理EMQX插件。<br/>
|
||||||
插件可以是EMQX安装包中的一部分,也可以是一个独立的安装包。</br>
|
插件可以是EMQX安装包中的一部分,也可以是一个独立的安装包。<br/>
|
||||||
独立安装的插件称为“外部插件”。
|
独立安装的插件称为“外部插件”。
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
|
@ -30,11 +30,11 @@ The standalone-installed plugins are referred to as 'external' plugins.
|
||||||
}
|
}
|
||||||
name_vsn {
|
name_vsn {
|
||||||
desc {
|
desc {
|
||||||
en: """The {name}-{version} of the plugin.</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>
|
It should match the plugin application name-version as the for the plugin release package name<br/>
|
||||||
For example: my_plugin-0.1.0.
|
For example: my_plugin-0.1.0.
|
||||||
"""
|
"""
|
||||||
zh: """插件的名称{name}-{version}。</br>
|
zh: """插件的名称{name}-{version}。<br/>
|
||||||
它应该与插件的发布包名称一致,如my_plugin-0.1.0。"""
|
它应该与插件的发布包名称一致,如my_plugin-0.1.0。"""
|
||||||
}
|
}
|
||||||
label {
|
label {
|
||||||
|
@ -54,7 +54,7 @@ For example: my_plugin-0.1.0.
|
||||||
}
|
}
|
||||||
states {
|
states {
|
||||||
desc {
|
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"""
|
The plugins are started in the defined order"""
|
||||||
zh: """一组插件的状态。插件将按照定义的顺序启动"""
|
zh: """一组插件的状态。插件将按照定义的顺序启动"""
|
||||||
}
|
}
|
||||||
|
@ -69,11 +69,11 @@ The plugins are started in the defined order"""
|
||||||
The installation directory for the external plugins.
|
The installation directory for the external plugins.
|
||||||
The plugin beam files and configuration files should reside in
|
The plugin beam files and configuration files should reside in
|
||||||
the subdirectory named as <code>emqx_foo_bar-0.1.0</code>.
|
the subdirectory named as <code>emqx_foo_bar-0.1.0</code>.
|
||||||
</br>
|
<br/>
|
||||||
NOTE: For security reasons, this directory should **NOT** be writable
|
NOTE: For security reasons, this directory should **NOT** be writable
|
||||||
by anyone except <code>emqx</code> (or any user which runs EMQX).
|
by anyone except <code>emqx</code> (or any user which runs EMQX).
|
||||||
"""
|
"""
|
||||||
zh: "插件安装包的目录, 不要自己创建, 只能由emqx用户创建与修改"
|
zh: "插件安装包的目录,出于安全考虑,该目录应该值允许 <code>emqx</code>,或用于运行 EMQX 服务的用户拥有写入权限。"
|
||||||
}
|
}
|
||||||
label {
|
label {
|
||||||
en: "Install Directory"
|
en: "Install Directory"
|
||||||
|
@ -82,10 +82,10 @@ by anyone except <code>emqx</code> (or any user which runs EMQX).
|
||||||
}
|
}
|
||||||
check_interval {
|
check_interval {
|
||||||
desc {
|
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.
|
if the results of 3 consecutive checks are not consistent, then alarm.
|
||||||
"""
|
"""
|
||||||
zh: """检查间隔:检查集群中插件的状态是否一致,</br>
|
zh: """检查间隔:检查集群中插件的状态是否一致,<br/>
|
||||||
如果连续3次检查结果不一致,则报警。
|
如果连续3次检查结果不一致,则报警。
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
|
|
|
@ -1 +1,2 @@
|
||||||
-define(APP, emqx_prometheus).
|
-define(APP, emqx_prometheus).
|
||||||
|
-define(PROMETHEUS, [prometheus]).
|
||||||
|
|
|
@ -37,18 +37,8 @@
|
||||||
]
|
]
|
||||||
).
|
).
|
||||||
|
|
||||||
-export([
|
|
||||||
update/1,
|
|
||||||
start/0,
|
|
||||||
stop/0,
|
|
||||||
restart/0,
|
|
||||||
% for rpc
|
|
||||||
do_start/0,
|
|
||||||
do_stop/0
|
|
||||||
]).
|
|
||||||
|
|
||||||
%% APIs
|
%% APIs
|
||||||
-export([start_link/1]).
|
-export([start_link/1, info/0]).
|
||||||
|
|
||||||
%% gen_server callbacks
|
%% gen_server callbacks
|
||||||
-export([
|
-export([
|
||||||
|
@ -69,88 +59,69 @@
|
||||||
|
|
||||||
-export([collect/1]).
|
-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(C(K, L), proplists:get_value(K, L, 0)).
|
||||||
|
|
||||||
-define(TIMER_MSG, '#interval').
|
-define(TIMER_MSG, '#interval').
|
||||||
|
|
||||||
-record(state, {push_gateway, timer, interval}).
|
-define(HTTP_OPTIONS, [{autoredirect, true}, {timeout, 60000}]).
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
%% 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.
|
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% APIs
|
%% APIs
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
start_link(Opts) ->
|
start_link([]) ->
|
||||||
gen_server:start_link({local, ?MODULE}, ?MODULE, [Opts], []).
|
gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
|
||||||
|
|
||||||
|
info() ->
|
||||||
|
gen_server:call(?MODULE, info).
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% gen_server callbacks
|
%% gen_server callbacks
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
init([Opts]) ->
|
init([]) ->
|
||||||
Interval = maps:get(interval, Opts),
|
#{interval := Interval} = opts(),
|
||||||
PushGateway = maps:get(push_gateway_server, Opts),
|
{ok, #{timer => ensure_timer(Interval), ok => 0, failed => 0}}.
|
||||||
{ok, ensure_timer(#state{push_gateway = PushGateway, interval = Interval})}.
|
|
||||||
|
|
||||||
|
handle_call(info, _From, State = #{timer := Timer}) ->
|
||||||
|
{reply, State#{opts => opts(), next_push_ms => erlang:read_timer(Timer)}, State};
|
||||||
handle_call(_Msg, _From, State) ->
|
handle_call(_Msg, _From, State) ->
|
||||||
{noreply, State}.
|
{reply, ok, State}.
|
||||||
|
|
||||||
handle_cast(_Msg, State) ->
|
handle_cast(_Msg, State) ->
|
||||||
{noreply, 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()), "@"),
|
[Name, Ip] = string:tokens(atom_to_list(node()), "@"),
|
||||||
Url = lists:concat([Uri, "/metrics/job/", Name, "/instance/", Name, "~", Ip]),
|
Url = lists:concat([Uri, "/metrics/job/", Name, "/instance/", Name, "~", Ip]),
|
||||||
Data = prometheus_text_format:format(),
|
Data = prometheus_text_format:format(),
|
||||||
httpc:request(post, {Url, [], "text/plain", Data}, [{autoredirect, true}], []),
|
case httpc:request(post, {Url, [], "text/plain", Data}, ?HTTP_OPTIONS, []) of
|
||||||
%% Data is too big, hibernate for saving memory and stop system monitor warning.
|
{ok, {{"HTTP/1.1", 200, "OK"}, _Headers, _Body}} ->
|
||||||
{noreply, ensure_timer(State), hibernate};
|
ok;
|
||||||
handle_info(_Msg, State) ->
|
Error ->
|
||||||
{noreply, State}.
|
?SLOG(error, #{
|
||||||
|
msg => "post_to_push_gateway_failed",
|
||||||
|
error => Error,
|
||||||
|
url => Url
|
||||||
|
}),
|
||||||
|
failed
|
||||||
|
end.
|
||||||
|
|
||||||
code_change(_OldVsn, State, _Extra) ->
|
code_change(_OldVsn, State, _Extra) ->
|
||||||
{ok, State}.
|
{ok, State}.
|
||||||
|
@ -158,11 +129,14 @@ code_change(_OldVsn, State, _Extra) ->
|
||||||
terminate(_Reason, _State) ->
|
terminate(_Reason, _State) ->
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
ensure_timer(State = #state{interval = Interval}) ->
|
ensure_timer(Interval) ->
|
||||||
State#state{timer = emqx_misc:start_timer(Interval, ?TIMER_MSG)}.
|
emqx_misc:start_timer(Interval, ?TIMER_MSG).
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% prometheus callbacks
|
%% prometheus callbacks
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
opts() ->
|
||||||
|
emqx_conf:get(?PROMETHEUS).
|
||||||
|
|
||||||
deregister_cleanup(_Registry) ->
|
deregister_cleanup(_Registry) ->
|
||||||
ok.
|
ok.
|
||||||
|
@ -623,3 +597,11 @@ emqx_cluster_data() ->
|
||||||
{nodes_running, length(Running)},
|
{nodes_running, length(Running)},
|
||||||
{nodes_stopped, length(Stopped)}
|
{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).
|
||||||
|
|
|
@ -84,7 +84,7 @@ schema("/prometheus/stats") ->
|
||||||
prometheus(get, _Params) ->
|
prometheus(get, _Params) ->
|
||||||
{200, emqx:get_raw_config([<<"prometheus">>], #{})};
|
{200, emqx:get_raw_config([<<"prometheus">>], #{})};
|
||||||
prometheus(put, #{body := Body}) ->
|
prometheus(put, #{body := Body}) ->
|
||||||
case emqx_prometheus:update(Body) of
|
case emqx_prometheus_config:update(Body) of
|
||||||
{ok, NewConfig} ->
|
{ok, NewConfig} ->
|
||||||
{200, NewConfig};
|
{200, NewConfig};
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
|
@ -120,7 +120,13 @@ prometheus_config_example() ->
|
||||||
#{
|
#{
|
||||||
enable => true,
|
enable => true,
|
||||||
interval => "15s",
|
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() ->
|
prometheus_data_schema() ->
|
||||||
|
|
|
@ -27,17 +27,10 @@
|
||||||
]).
|
]).
|
||||||
|
|
||||||
start(_StartType, _StartArgs) ->
|
start(_StartType, _StartArgs) ->
|
||||||
{ok, Sup} = emqx_prometheus_sup:start_link(),
|
Res = emqx_prometheus_sup:start_link(),
|
||||||
maybe_enable_prometheus(),
|
emqx_prometheus_config:add_handler(),
|
||||||
{ok, Sup}.
|
Res.
|
||||||
|
|
||||||
stop(_State) ->
|
stop(_State) ->
|
||||||
|
emqx_prometheus_config:remove_handler(),
|
||||||
ok.
|
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.
|
|
||||||
|
|
|
@ -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).
|
|
@ -24,12 +24,13 @@
|
||||||
namespace/0,
|
namespace/0,
|
||||||
roots/0,
|
roots/0,
|
||||||
fields/1,
|
fields/1,
|
||||||
desc/1
|
desc/1,
|
||||||
|
translation/1
|
||||||
]).
|
]).
|
||||||
|
|
||||||
namespace() -> "prometheus".
|
namespace() -> "prometheus".
|
||||||
|
|
||||||
roots() -> ["prometheus"].
|
roots() -> [{"prometheus", ?HOCON(?R_REF("prometheus"), #{translate_to => ["prometheus"]})}].
|
||||||
|
|
||||||
fields("prometheus") ->
|
fields("prometheus") ->
|
||||||
[
|
[
|
||||||
|
@ -124,3 +125,7 @@ fields("prometheus") ->
|
||||||
|
|
||||||
desc("prometheus") -> ?DESC(prometheus);
|
desc("prometheus") -> ?DESC(prometheus);
|
||||||
desc(_) -> undefined.
|
desc(_) -> undefined.
|
||||||
|
|
||||||
|
%% for CI test, CI don't load the whole emqx_conf_schema.
|
||||||
|
translation(Name) ->
|
||||||
|
emqx_conf_schema:translation(Name).
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
-export([
|
-export([
|
||||||
start_link/0,
|
start_link/0,
|
||||||
start_child/1,
|
start_child/1,
|
||||||
start_child/2,
|
|
||||||
stop_child/1
|
stop_child/1
|
||||||
]).
|
]).
|
||||||
|
|
||||||
|
@ -40,23 +39,27 @@
|
||||||
start_link() ->
|
start_link() ->
|
||||||
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
|
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) ->
|
start_child(ChildSpec) when is_map(ChildSpec) ->
|
||||||
assert_started(supervisor:start_child(?MODULE, ChildSpec)).
|
assert_started(supervisor:start_child(?MODULE, ChildSpec));
|
||||||
|
start_child(Mod) when is_atom(Mod) ->
|
||||||
-spec start_child(atom(), map()) -> ok.
|
assert_started(supervisor:start_child(?MODULE, ?CHILD(Mod, []))).
|
||||||
start_child(Mod, Opts) when is_atom(Mod) andalso is_map(Opts) ->
|
|
||||||
assert_started(supervisor:start_child(?MODULE, ?CHILD(Mod, Opts))).
|
|
||||||
|
|
||||||
-spec stop_child(any()) -> ok | {error, term()}.
|
-spec stop_child(any()) -> ok | {error, term()}.
|
||||||
stop_child(ChildId) ->
|
stop_child(ChildId) ->
|
||||||
case supervisor:terminate_child(?MODULE, ChildId) of
|
case supervisor:terminate_child(?MODULE, ChildId) of
|
||||||
ok -> supervisor:delete_child(?MODULE, ChildId);
|
ok -> supervisor:delete_child(?MODULE, ChildId);
|
||||||
|
{error, not_found} -> ok;
|
||||||
Error -> Error
|
Error -> Error
|
||||||
end.
|
end.
|
||||||
|
|
||||||
init([]) ->
|
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
|
%% Internal functions
|
||||||
|
@ -64,5 +67,5 @@ init([]) ->
|
||||||
|
|
||||||
assert_started({ok, _Pid}) -> ok;
|
assert_started({ok, _Pid}) -> ok;
|
||||||
assert_started({ok, _Pid, _Info}) -> ok;
|
assert_started({ok, _Pid, _Info}) -> ok;
|
||||||
assert_started({error, {already_tarted, _Pid}}) -> ok;
|
assert_started({error, {already_started, _Pid}}) -> ok;
|
||||||
assert_started({error, Reason}) -> erlang:error(Reason).
|
assert_started({error, Reason}) -> {error, Reason}.
|
||||||
|
|
|
@ -20,13 +20,15 @@
|
||||||
|
|
||||||
-export([
|
-export([
|
||||||
introduced_in/0,
|
introduced_in/0,
|
||||||
|
deprecated_since/0,
|
||||||
start/1,
|
start/1,
|
||||||
stop/1
|
stop/1
|
||||||
]).
|
]).
|
||||||
|
|
||||||
-include_lib("emqx/include/bpapi.hrl").
|
-include_lib("emqx/include/bpapi.hrl").
|
||||||
|
|
||||||
|
deprecated_since() -> "5.0.10".
|
||||||
|
|
||||||
introduced_in() ->
|
introduced_in() ->
|
||||||
"5.0.0".
|
"5.0.0".
|
||||||
|
|
||||||
|
|
|
@ -71,10 +71,14 @@ load_config() ->
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
t_start_stop(_) ->
|
t_start_stop(_) ->
|
||||||
?assertMatch(ok, emqx_prometheus:start()),
|
App = emqx_prometheus,
|
||||||
?assertMatch(ok, emqx_prometheus:stop()),
|
?assertMatch(ok, emqx_prometheus_sup:start_child(App)),
|
||||||
?assertMatch(ok, emqx_prometheus:restart()),
|
%% start twice return ok.
|
||||||
%% wait the interval timer tigger
|
?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).
|
timer:sleep(2000).
|
||||||
|
|
||||||
t_collector_no_crash_test(_) ->
|
t_collector_no_crash_test(_) ->
|
||||||
|
|
|
@ -71,16 +71,27 @@ t_prometheus_api(_) ->
|
||||||
#{
|
#{
|
||||||
<<"push_gateway_server">> := _,
|
<<"push_gateway_server">> := _,
|
||||||
<<"interval">> := _,
|
<<"interval">> := _,
|
||||||
<<"enable">> := _
|
<<"enable">> := _,
|
||||||
|
<<"vm_statistics_collector">> := _,
|
||||||
|
<<"vm_system_info_collector">> := _,
|
||||||
|
<<"vm_memory_collector">> := _,
|
||||||
|
<<"vm_msacc_collector">> := _
|
||||||
},
|
},
|
||||||
Conf
|
Conf
|
||||||
),
|
),
|
||||||
|
#{<<"enable">> := Enable} = Conf,
|
||||||
NewConf = Conf#{<<"interval">> := <<"2s">>},
|
?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),
|
{ok, Response2} = emqx_mgmt_api_test_util:request_api(put, Path, "", Auth, NewConf),
|
||||||
|
|
||||||
Conf2 = emqx_json:decode(Response2, [return_maps]),
|
Conf2 = emqx_json:decode(Response2, [return_maps]),
|
||||||
?assertMatch(NewConf, Conf2),
|
?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.
|
ok.
|
||||||
|
|
||||||
t_stats_api(_) ->
|
t_stats_api(_) ->
|
||||||
|
|
|
@ -16,7 +16,7 @@ The IDs and secrets can be provided from a file which is configurable by the <co
|
||||||
|
|
||||||
PSK 是 “Pre-Shared-Keys” 的缩写。
|
PSK 是 “Pre-Shared-Keys” 的缩写。
|
||||||
|
|
||||||
注意: 确保 SSL 监听器仅启用了 'tlsv1.2', 并且配置了PSK 密码套件,例如 'RSA-PSK-AES256-GCM-SHA384'。
|
注意: 确保 SSL 监听器仅启用了 'tlsv1.2',并且配置了PSK 密码套件,例如 'RSA-PSK-AES256-GCM-SHA384'。
|
||||||
|
|
||||||
可以通过查看监听器中的 SSL 选项,了解更多详细信息。
|
可以通过查看监听器中的 SSL 选项,了解更多详细信息。
|
||||||
|
|
||||||
|
|
|
@ -119,7 +119,7 @@ retainer_indices(type) ->
|
||||||
retainer_indices(desc) ->
|
retainer_indices(desc) ->
|
||||||
"Retainer index specifications: list of arrays of positive ascending integers. "
|
"Retainer index specifications: list of arrays of positive ascending integers. "
|
||||||
"Each array specifies an index. Numbers in an index specification are 1-based "
|
"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 "
|
"For example, it is good to have <code>[2, 4]</code> index to optimize "
|
||||||
"<code>+/X/+/Y/...</code> topic wildcard subscriptions.";
|
"<code>+/X/+/Y/...</code> topic wildcard subscriptions.";
|
||||||
retainer_indices(example) ->
|
retainer_indices(example) ->
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
{application, emqx_rule_engine, [
|
{application, emqx_rule_engine, [
|
||||||
{description, "EMQX Rule Engine"},
|
{description, "EMQX Rule Engine"},
|
||||||
% strict semver, bump manually!
|
% strict semver, bump manually!
|
||||||
{vsn, "5.0.2"},
|
{vsn, "5.0.3"},
|
||||||
{modules, []},
|
{modules, []},
|
||||||
{registered, [emqx_rule_engine_sup, emqx_rule_engine]},
|
{registered, [emqx_rule_engine_sup, emqx_rule_engine]},
|
||||||
{applications, [kernel, stdlib, rulesql, getopt]},
|
{applications, [kernel, stdlib, rulesql, getopt]},
|
||||||
|
|
|
@ -671,8 +671,8 @@ event_info_client_connack() ->
|
||||||
event_info_client_check_authz_complete() ->
|
event_info_client_check_authz_complete() ->
|
||||||
event_info_common(
|
event_info_common(
|
||||||
'client.check_authz_complete',
|
'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\"">>
|
<<"SELECT * FROM \"$events/client_check_authz_complete\"">>
|
||||||
).
|
).
|
||||||
event_info_session_subscribed() ->
|
event_info_session_subscribed() ->
|
||||||
|
|
|
@ -2,14 +2,25 @@
|
||||||
|
|
||||||
## Enhancements
|
## 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).
|
- 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).
|
- 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 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
|
## Bug fixes
|
||||||
|
|
||||||
- Fix error log message when `mechanism` is missing in authentication config [#8924](https://github.com/emqx/emqx/pull/8924).
|
- 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.
|
|
@ -2,14 +2,24 @@
|
||||||
|
|
||||||
## 增强
|
## 增强
|
||||||
|
|
||||||
|
- 提升 `/nodes` API 响应速度 [#9221](https://github.com/emqx/emqx/pull/9221)。
|
||||||
|
|
||||||
- 支持拉黑客户端并从数据库中删除保留和延迟发布的消息 [#9139](https://github.com/emqx/emqx/pull/9139)。
|
- 支持拉黑客户端并从数据库中删除保留和延迟发布的消息 [#9139](https://github.com/emqx/emqx/pull/9139)。
|
||||||
|
|
||||||
- 升级 `gen_rpc` 库到 3.0 [#9187](https://github.com/emqx/emqx/pull/9187)。
|
- 升级 `gen_rpc` 库到 3.0 [#9187](https://github.com/emqx/emqx/pull/9187)。
|
||||||
|
|
||||||
- 在引导 `replicant` 节点时,改善 `core` 节点的内存使用量 [#9236](https://github.com/emqx/emqx/pull/9236)。
|
- 在引导 `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
|
## Bug fixes
|
||||||
|
|
||||||
- 优化认认证配置中 `mechanism` 字段缺失情况下的错误日志 [#8924](https://github.com/emqx/emqx/pull/8924)。
|
- 优化认认证配置中 `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`。
|
2
mix.exs
2
mix.exs
|
@ -616,7 +616,7 @@ defmodule EMQXUmbrella.MixProject do
|
||||||
|
|
||||||
defp jq_dep() do
|
defp jq_dep() do
|
||||||
if enable_jq?(),
|
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: []
|
else: []
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -42,7 +42,7 @@ quicer() ->
|
||||||
{quicer, {git, "https://github.com/emqx/quic.git", {tag, "0.0.16"}}}.
|
{quicer, {git, "https://github.com/emqx/quic.git", {tag, "0.0.16"}}}.
|
||||||
|
|
||||||
jq() ->
|
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(Config) ->
|
||||||
{deps, OldDeps} = lists:keyfind(deps, 1, Config),
|
{deps, OldDeps} = lists:keyfind(deps, 1, Config),
|
||||||
|
|
|
@ -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,
|
HOCON, or Human-Optimized Config Object Notation is a format for human-readable data,
|
||||||
and a superset of JSON.
|
and a superset of JSON.
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ and a superset of JSON.
|
||||||
EMQX configuration consists of 3 layers.
|
EMQX configuration consists of 3 layers.
|
||||||
From bottom up:
|
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.
|
Changes in this layer require a full node restart to take effect.
|
||||||
1. Cluster overrides: `$EMQX_NODE__DATA_DIR/configs/cluster-override.conf`
|
1. Cluster overrides: `$EMQX_NODE__DATA_DIR/configs/cluster-override.conf`
|
||||||
1. Local node overrides: `$EMQX_NODE__DATA_DIR/configs/local-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.
|
or primitive values.
|
||||||
There are quite some different primitive types, to name a few:
|
There are quite some different primitive types, to name a few:
|
||||||
|
|
||||||
* `atom()`
|
* `atom()`.
|
||||||
* `boolean()`
|
* `boolean()`.
|
||||||
* `string()`
|
* `string()`.
|
||||||
* `integer()`
|
* `integer()`.
|
||||||
* `float()`
|
* `float()`.
|
||||||
* `number()`
|
* `number()`.
|
||||||
* `binary()` # another format of string()
|
* `binary()`, another format of string().
|
||||||
* `emqx_schema:duration()` # time duration, another format of integer()
|
* `emqx_schema:duration()`, time duration, another format of integer()
|
||||||
* ...
|
* ...
|
||||||
|
|
||||||
::: tip Tip
|
::: 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"]'
|
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 `:`.
|
characters such as `=` and `:`.
|
||||||
|
|
||||||
For example, a string value `"localhost:1883"` would be
|
For example, a string value `"localhost:1883"` would be
|
||||||
|
@ -248,9 +248,9 @@ authentication=[{enable=true}]
|
||||||
|
|
||||||
#### TLS/SSL ciphers
|
#### 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.
|
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.
|
for servers, or when establishing a TLS connection as a client.
|
||||||
|
|
||||||
Below are the default ciphers selected by EMQX.
|
Below are the default ciphers selected by EMQX.
|
||||||
|
|
|
@ -1,28 +1,28 @@
|
||||||
EMQX的配置文件格式是 [HOCON](https://github.com/emqx/hocon) .
|
EMQX的配置文件格式是 [HOCON](https://github.com/emqx/hocon) 。
|
||||||
HOCON(Human-Optimized Config Object Notation)是一个JSON的超集,非常适用于易于人类读写的配置数据存储。
|
HOCON(Human-Optimized Config Object Notation)是一个JSON的超集,非常适用于易于人类读写的配置数据存储。
|
||||||
|
|
||||||
## 分层结构
|
## 分层结构
|
||||||
|
|
||||||
EMQX的配置文件可分为三层,自底向上依次是:
|
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/cluster-override.conf`
|
||||||
1. 节点本地重载层:`$EMQX_NODE__DATA_DIR/configs/local-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重写。
|
配置文件 `cluster-override.conf` 的内容会在运行时被EMQX重写。
|
||||||
这些重写发生在 dashboard UI,管理HTTP API,或者CLI对集群配置进行修改时。
|
这些重写发生在 dashboard UI,管理HTTP API,或者CLI对集群配置进行修改时。
|
||||||
当EMQX运行在集群中时,一个EMQX节点重启之后,会从集群中其他节点复制该文件内容到本地。
|
当EMQX运行在集群中时,一个EMQX节点重启之后,会从集群中其他节点复制该文件内容到本地。
|
||||||
|
|
||||||
:::tip Tip
|
:::tip Tip
|
||||||
有些配置项是不能被重载的(例如 `node.name`).
|
有些配置项是不能被重载的(例如 `node.name`)。
|
||||||
配置项如果有 `mapping: path.to.boot.config.key` 这个属性,
|
配置项如果有 `mapping: path.to.boot.config.key` 这个属性,
|
||||||
则不能被添加到重载文件中 `*-override.conf` 中。
|
则不能被添加到重载文件 `*-override.conf` 中。
|
||||||
:::
|
:::
|
||||||
|
|
||||||
更多的重载规则,请参考下文 [配置重载规则](#配置重载规则).
|
更多的重载规则,请参考下文 [配置重载规则](#配置重载规则)。
|
||||||
|
|
||||||
## 配置文件语法
|
## 配置文件语法
|
||||||
|
|
||||||
|
@ -70,7 +70,7 @@ EMQX的配置文件中,有4中复杂数据结构类型,它们分别是:
|
||||||
|
|
||||||
1. Struct:结构体都是有类型名称的,结构体中可以有任意多个字段。
|
1. Struct:结构体都是有类型名称的,结构体中可以有任意多个字段。
|
||||||
结构体和字段的名称由不带特殊字符的全小些字母组成,名称中可以带数字,但不得以数字开头,多个单词可用下划线分隔。
|
结构体和字段的名称由不带特殊字符的全小些字母组成,名称中可以带数字,但不得以数字开头,多个单词可用下划线分隔。
|
||||||
1. Map: Map与Struct(结构体)类似,但是内部的字段不是预先定义好的.
|
1. Map: Map 与 Struct(结构体)类似,但是内部的字段不是预先定义好的。
|
||||||
1. Union: 联合 `MemberType1 | MemberType2 | ...`,可以理解为:“不是这个,就是那个”
|
1. Union: 联合 `MemberType1 | MemberType2 | ...`,可以理解为:“不是这个,就是那个”
|
||||||
1. Array: 数组 `[ElementType]`
|
1. Array: 数组 `[ElementType]`
|
||||||
|
|
||||||
|
@ -89,19 +89,19 @@ myarray.2 = 75
|
||||||
复杂类型定义了数据 "盒子",其中可能包含其他复杂数据或原始值。
|
复杂类型定义了数据 "盒子",其中可能包含其他复杂数据或原始值。
|
||||||
有很多不同的原始类型,仅举几个例子。
|
有很多不同的原始类型,仅举几个例子。
|
||||||
|
|
||||||
* 原子 `atom()`
|
* 原子 `atom()`。
|
||||||
* 布尔 `boolean()`.
|
* 布尔 `boolean()`。
|
||||||
* 字符串 `string()'。
|
* 字符串 `string()`。
|
||||||
* 整形 `integer()'。
|
* 整形 `integer()`。
|
||||||
* 浮点数 `float()'.
|
* 浮点数 `float()`。
|
||||||
* 数值 `number()'。
|
* 数值 `number()`。
|
||||||
* 二进制编码的字符串 `binary()` # 是 `string()` 的另一种格式
|
* 二进制编码的字符串 `binary()` 是 `string()` 的另一种格式。
|
||||||
* 时间间隔 `emqx_schema:duration()` # 时间间隔,是 `integer()` 的另一种格式
|
* 时间间隔 `emqx_schema:duration()` 是 `integer()` 的另一种格式。
|
||||||
* ...
|
* ...
|
||||||
|
|
||||||
::: tip Tip
|
::: tip Tip
|
||||||
原始类型的名称大多是自我描述的,所以不需要过多的注释。
|
原始类型的名称大多是自我描述的,所以不需要过多的注释。
|
||||||
但是有一些不是那么直观的数据类型,则需要配合字段的描述文档进行理解
|
但是有一些不是那么直观的数据类型,则需要配合字段的描述文档进行理解。
|
||||||
:::
|
:::
|
||||||
|
|
||||||
|
|
||||||
|
@ -110,7 +110,7 @@ myarray.2 = 75
|
||||||
如果我们把EMQX的配置值理解成一个类似目录树的结构,那么类似于文件系统中使用斜杠或反斜杠进行层级分割,
|
如果我们把EMQX的配置值理解成一个类似目录树的结构,那么类似于文件系统中使用斜杠或反斜杠进行层级分割,
|
||||||
EMQX使用的配置路径的层级分割符是 `'.'`
|
EMQX使用的配置路径的层级分割符是 `'.'`
|
||||||
|
|
||||||
被`'.'`号分割的每一段,则是Struct(结构体)的字段,或Map的key.
|
被 `'.'` 号分割的每一段,则是 Struct(结构体)的字段,或 Map 的 key。
|
||||||
|
|
||||||
下面有几个例子:
|
下面有几个例子:
|
||||||
|
|
||||||
|
@ -122,7 +122,7 @@ authentication.1.enable = true
|
||||||
|
|
||||||
### 环境变量重载
|
### 环境变量重载
|
||||||
|
|
||||||
因为`'.'` 分隔符不能使用于环境变量,所以我们需要使用另一个分割符。EMQX选用的是双下划线`__`。
|
因为 `'.'` 分隔符不能使用于环境变量,所以我们需要使用另一个分割符。EMQX选用的是双下划线 `__`。
|
||||||
为了与其他的环境变量有所区分,EMQX还增加了一个前缀 `EMQX_` 来用作环境变量命名空间。
|
为了与其他的环境变量有所区分,EMQX还增加了一个前缀 `EMQX_` 来用作环境变量命名空间。
|
||||||
|
|
||||||
例如 `node.name` 的重载变量名是 `EMQX_NODE__NAME`。
|
例如 `node.name` 的重载变量名是 `EMQX_NODE__NAME`。
|
||||||
|
@ -154,7 +154,7 @@ EMQX_BRIDGES__MQTT__MYBRIDGE__CONNECTOR_SERVER='"localhost:1883"'
|
||||||
[warning] unknown_env_vars: ["EMQX_AUTHENTICATION__ENABLED"]
|
[warning] unknown_env_vars: ["EMQX_AUTHENTICATION__ENABLED"]
|
||||||
```
|
```
|
||||||
|
|
||||||
这是因为正确的字段名称是 `enable`,而不是 `enabled`.
|
这是因为正确的字段名称是 `enable`,而不是 `enabled`。
|
||||||
:::
|
:::
|
||||||
|
|
||||||
### 配置重载规则
|
### 配置重载规则
|
||||||
|
@ -168,8 +168,7 @@ HOCON的值是分层覆盖的,普遍规则如下:
|
||||||
|
|
||||||
#### 结构体
|
#### 结构体
|
||||||
|
|
||||||
合并覆盖规则。在如下配置中,最后一行的 `debug` 值会覆盖覆盖原先`level`字段的 `error` 值
|
合并覆盖规则。在如下配置中,最后一行的 `debug` 值会覆盖覆盖原先`level`字段的 `error` 值,但是 `enable` 字段保持不变。
|
||||||
但是`enable` 字段保持不变。
|
|
||||||
```
|
```
|
||||||
log {
|
log {
|
||||||
console_handler{
|
console_handler{
|
||||||
|
@ -178,7 +177,7 @@ log {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
## 控制台日志打印先定义为`error`级,后被覆写成`debug`级
|
## 控制台日志打印先定义为 `error` 级,后被覆写成 `debug` 级
|
||||||
|
|
||||||
log.console_handler.level=debug
|
log.console_handler.level=debug
|
||||||
```
|
```
|
||||||
|
@ -186,7 +185,7 @@ log.console_handler.level=debug
|
||||||
#### Map
|
#### Map
|
||||||
|
|
||||||
Map与结构体类似,也是合并覆盖规则。
|
Map与结构体类似,也是合并覆盖规则。
|
||||||
如下例子中,`zone1` 的 `max_packet_size` 可以在文件后面覆写.
|
如下例子中,`zone1` 的 `max_packet_size` 可以在文件后面覆写。
|
||||||
|
|
||||||
```
|
```
|
||||||
zone {
|
zone {
|
||||||
|
|
Loading…
Reference in New Issue