Просмотр исходного кода

Merge remote-tracking branch 'origin/master' into fix-buffer-clear-replayq-on-delete-v50

Zaiming (Stone) Shi 3 лет назад
Родитель
Сommit
d4f3b4c8c2
33 измененных файлов с 267 добавлено и 131 удалено
  1. 1 1
      .github/workflows/build_packages.yaml
  2. 1 1
      .github/workflows/build_slim_packages.yaml
  3. 2 2
      .github/workflows/run_fvt_tests.yaml
  4. 11 11
      .github/workflows/run_jmeter_tests.yaml
  5. 1 1
      .github/workflows/run_relup_tests.yaml
  6. 0 8
      apps/emqx/etc/vm.args.cloud
  7. 2 2
      apps/emqx/src/emqx_authentication_config.erl
  8. 10 1
      apps/emqx/src/emqx_misc.erl
  9. 10 1
      apps/emqx_bridge/i18n/emqx_bridge_webhook_schema.conf
  10. 3 1
      apps/emqx_bridge/src/emqx_bridge.erl
  11. 5 2
      apps/emqx_bridge/src/emqx_bridge_resource.erl
  12. 17 10
      apps/emqx_bridge/src/schema/emqx_bridge_mqtt_config.erl
  13. 9 2
      apps/emqx_bridge/src/schema/emqx_bridge_schema.erl
  14. 9 0
      apps/emqx_bridge/src/schema/emqx_bridge_webhook_schema.erl
  15. 1 0
      apps/emqx_bridge/test/emqx_bridge_api_SUITE.erl
  16. 70 14
      apps/emqx_bridge/test/emqx_bridge_mqtt_config_tests.erl
  17. 16 4
      apps/emqx_conf/i18n/emqx_conf_schema.conf
  18. 10 1
      apps/emqx_conf/src/emqx_conf_schema.erl
  19. 5 5
      apps/emqx_dashboard/i18n/emqx_dashboard_api_i18n.conf
  20. 34 27
      apps/emqx_dashboard/i18n/emqx_dashboard_i18n.conf
  21. 2 2
      apps/emqx_dashboard/src/emqx_dashboard_schema.erl
  22. 1 1
      apps/emqx_machine/src/emqx_machine.app.src
  23. 8 0
      apps/emqx_machine/src/user_default.erl
  24. 1 1
      apps/emqx_resource/src/emqx_resource_manager.erl
  25. 3 6
      apps/emqx_resource/src/emqx_resource_worker.erl
  26. 1 0
      changes/v5.0.15/fix-9780.en.md
  27. 1 0
      changes/v5.0.15/fix-9780.zh.md
  28. 1 0
      changes/v5.0.15/fix-9787.en.md
  29. 1 0
      changes/v5.0.15/fix-9787.zh.md
  30. 7 7
      deploy/charts/emqx-enterprise/templates/StatefulSet.yaml
  31. 7 7
      deploy/charts/emqx/templates/StatefulSet.yaml
  32. 12 12
      lib-ee/emqx_ee_bridge/src/emqx_ee_bridge_gcp_pubsub.erl
  33. 5 1
      lib-ee/emqx_ee_bridge/test/emqx_ee_bridge_gcp_pubsub_SUITE.erl

+ 1 - 1
.github/workflows/build_packages.yaml

@@ -101,7 +101,7 @@ jobs:
     - name: unzip source code
       run: Expand-Archive -Path source.zip -DestinationPath ./
     - uses: ilammy/msvc-dev-cmd@v1.12.0
-    - uses: emqx/setup-beam@v1.16.1-emqx
+    - uses: erlef/setup-beam@v1.15.2
       with:
         otp-version: 24.3.4.6
     - name: build

+ 1 - 1
.github/workflows/build_slim_packages.yaml

@@ -94,7 +94,7 @@ jobs:
     steps:
     - uses: actions/checkout@v3
     - uses: ilammy/msvc-dev-cmd@v1.12.0
-    - uses: emqx/setup-beam@v1.16.1-emqx
+    - uses: erlef/setup-beam@v1.15.2
       with:
         otp-version: ${{ matrix.otp }}
     - name: build

+ 2 - 2
.github/workflows/run_fvt_tests.yaml

@@ -57,7 +57,7 @@ jobs:
         arch:
           - amd64
     steps:
-    - uses: emqx/setup-beam@v1.16.1-emqx
+    - uses: erlef/setup-beam@v1.15.2
       with:
         otp-version: 24.3.4.6
     - uses: actions/download-artifact@v3
@@ -132,7 +132,7 @@ jobs:
       # - emqx-enterprise # TODO test enterprise
 
     steps:
-    - uses: emqx/setup-beam@v1.16.1-emqx
+    - uses: erlef/setup-beam@v1.15.2
       with:
         otp-version: 24.3.4.6
     - uses: actions/download-artifact@v3

+ 11 - 11
.github/workflows/run_jmeter_tests.yaml

@@ -14,7 +14,7 @@ jobs:
     outputs:
       version: ${{ steps.build_docker.outputs.version}}
     steps:
-    - uses: emqx/setup-beam@v1.16.1-emqx
+    - uses: erlef/setup-beam@v1.15.2
       with:
         otp-version: 24.3.4.6
     - name: download jmeter
@@ -57,7 +57,7 @@ jobs:
 
     needs: build_emqx_for_jmeter_tests
     steps:
-    - uses: emqx/setup-beam@v1.16.1-emqx
+    - uses: erlef/setup-beam@v1.15.2
       with:
         otp-version: 24.3.4.6
     - uses: actions/checkout@v3
@@ -126,7 +126,7 @@ jobs:
     - name: check logs
       run: |
         if cat jmeter_logs/${{ matrix.scripts_type }}.jtl | grep -e '<failure>true</failure>' > /dev/null 2>&1; then
-          echo "check logs filed"
+          echo "check logs failed"
           exit 1
         fi
     - uses: actions/upload-artifact@v3
@@ -153,7 +153,7 @@ jobs:
 
     needs: build_emqx_for_jmeter_tests
     steps:
-    - uses: emqx/setup-beam@v1.16.1-emqx
+    - uses: erlef/setup-beam@v1.15.2
       with:
         otp-version: 24.3.4.6
     - uses: actions/checkout@v3
@@ -235,7 +235,7 @@ jobs:
     - name: check logs
       run: |
         if cat jmeter_logs/${{ matrix.scripts_type }}_${{ matrix.pgsql_tag }}.jtl | grep -e '<failure>true</failure>' > /dev/null 2>&1; then
-          echo "check logs filed"
+          echo "check logs failed"
           exit 1
         fi
     - uses: actions/upload-artifact@v3
@@ -259,7 +259,7 @@ jobs:
 
     needs: build_emqx_for_jmeter_tests
     steps:
-    - uses: emqx/setup-beam@v1.16.1-emqx
+    - uses: erlef/setup-beam@v1.15.2
       with:
         otp-version: 24.3.4.6
     - uses: actions/checkout@v3
@@ -341,7 +341,7 @@ jobs:
     - name: check logs
       run: |
         if cat jmeter_logs/${{ matrix.scripts_type }}_${{ matrix.mysql_tag }}.jtl | grep -e '<failure>true</failure>' > /dev/null 2>&1; then
-          echo "check logs filed"
+          echo "check logs failed"
           exit 1
         fi
     - uses: actions/upload-artifact@v3
@@ -361,7 +361,7 @@ jobs:
 
     needs: build_emqx_for_jmeter_tests
     steps:
-    - uses: emqx/setup-beam@v1.16.1-emqx
+    - uses: erlef/setup-beam@v1.15.2
       with:
         otp-version: 24.3.4.6
     - uses: actions/checkout@v3
@@ -439,7 +439,7 @@ jobs:
     - name: check logs
       run: |
         if cat jmeter_logs/${{ matrix.scripts_type }}.jtl | grep -e '<failure>true</failure>' > /dev/null 2>&1; then
-          echo "check logs filed"
+          echo "check logs failed"
           exit 1
         fi
     - uses: actions/upload-artifact@v3
@@ -460,7 +460,7 @@ jobs:
 
     needs: build_emqx_for_jmeter_tests
     steps:
-    - uses: emqx/setup-beam@v1.16.1-emqx
+    - uses: erlef/setup-beam@v1.15.2
       with:
         otp-version: 24.3.4.6
     - uses: actions/checkout@v3
@@ -531,7 +531,7 @@ jobs:
     - name: check logs
       run: |
         if cat jmeter_logs/${{ matrix.scripts_type }}_${{ matrix.mysql_tag }}.jtl | grep -e '<failure>true</failure>' > /dev/null 2>&1; then
-          echo "check logs filed"
+          echo "check logs failed"
           exit 1
         fi
     - uses: actions/upload-artifact@v3

+ 1 - 1
.github/workflows/run_relup_tests.yaml

@@ -71,7 +71,7 @@ jobs:
         shell: bash
     steps:
       # setup Erlang to run lux
-    - uses: emqx/setup-beam@v1.16.1-emqx
+    - uses: erlef/setup-beam@v1.15.2
       with:
         otp-version: 24.3.4.6
     - uses: actions/checkout@v3

+ 0 - 8
apps/emqx/etc/vm.args.cloud

@@ -24,9 +24,6 @@
 ## Sets the maximum number of atoms the virtual machine can handle.
 #+t 1048576
 
-## Set the location of crash dumps
-#-env ERL_CRASH_DUMP {{ platform_log_dir }}/crash.dump
-
 ## Set how many times generational garbages collections can be done without
 ## forcing a fullsweep collection.
 -env ERL_FULLSWEEP_AFTER 1000
@@ -40,11 +37,6 @@
 ## Prevent user from accidentally calling a function from the prompt that could harm a running system.
 -stdlib restricted_shell emqx_restricted_shell
 
-## Specifies the net_kernel tick time in seconds.
-## This is the approximate time a connected node may be unresponsive until
-## it is considered down and thereby disconnected.
--kernel net_ticktime 120
-
 ## Sets the distribution buffer busy limit (dist_buf_busy_limit).
 ## Preferably set in `emqx.conf`,
 #+zdbbl 8192

+ 2 - 2
apps/emqx/src/emqx_authentication_config.erl

@@ -327,9 +327,9 @@ atom(Bin) -> binary_to_existing_atom(Bin, utf8).
 certs_dir(ChainName, ConfigOrID) ->
     DirName = dir(ChainName, ConfigOrID),
     SubDir = iolist_to_binary(filename:join(["authn", DirName])),
-    binary:replace(SubDir, <<":">>, <<"-">>, [global]).
+    emqx_misc:safe_filename(SubDir).
 
 dir(ChainName, ID) when is_binary(ID) ->
-    binary:replace(iolist_to_binary([to_bin(ChainName), "-", ID]), <<":">>, <<"-">>);
+    emqx_misc:safe_filename(iolist_to_binary([to_bin(ChainName), "-", ID]));
 dir(ChainName, Config) when is_map(Config) ->
     dir(ChainName, authenticator_id(Config)).

+ 10 - 1
apps/emqx/src/emqx_misc.erl

@@ -55,7 +55,8 @@
     readable_error_msg/1,
     safe_to_existing_atom/1,
     safe_to_existing_atom/2,
-    pub_props_to_packet/1
+    pub_props_to_packet/1,
+    safe_filename/1
 ]).
 
 -export([
@@ -708,3 +709,11 @@ pub_props_to_packet(Properties) ->
             true
     end,
     maps:filtermap(F, Properties).
+
+%% fix filename by replacing characters which could be invalid on some filesystems
+%% with safe ones
+-spec safe_filename(binary() | unicode:chardata()) -> binary() | [unicode:chardata()].
+safe_filename(Filename) when is_binary(Filename) ->
+    binary:replace(Filename, <<":">>, <<"-">>, [global]);
+safe_filename(Filename) when is_list(Filename) ->
+    string:replace(Filename, ":", "-", all).

+ 10 - 1
apps/emqx_bridge/i18n/emqx_bridge_webhook_schema.conf

@@ -10,7 +10,16 @@ emqx_bridge_webhook_schema {
                            zh: "启用/禁用 Bridge"
                           }
                   }
-
+   config_direction {
+                   desc {
+                         en: """Deprecated, The direction of this bridge, MUST be 'egress'"""
+                         zh: """已废弃,Bridge 的方向,必须是 egress"""
+                        }
+                   label: {
+                           en: "Bridge Direction"
+                           zh: "Bridge 方向"
+                          }
+                  }
     config_url {
                    desc {
                          en: """

+ 3 - 1
apps/emqx_bridge/src/emqx_bridge.erl

@@ -235,7 +235,9 @@ lookup(Type, Name, RawConf) ->
     end.
 
 maybe_upgrade(mqtt, Config) ->
-    emqx_bridge_mqtt_config:maybe_upgrade(Config);
+    emqx_bridge_compatible_config:maybe_upgrade(Config);
+maybe_upgrade(webhook, Config) ->
+    emqx_bridge_compatible_config:webhook_maybe_upgrade(Config);
 maybe_upgrade(_Other, Config) ->
     Config.
 

+ 5 - 2
apps/emqx_bridge/src/emqx_bridge_resource.erl

@@ -216,7 +216,8 @@ recreate(Type, Name, Conf, Opts) ->
     ).
 
 create_dry_run(Type, Conf0) ->
-    TmpPath = iolist_to_binary(["bridges-create-dry-run:", emqx_misc:gen_id(8)]),
+    TmpPath0 = iolist_to_binary(["bridges-create-dry-run:", emqx_misc:gen_id(8)]),
+    TmpPath = emqx_misc:safe_filename(TmpPath0),
     Conf = emqx_map_lib:safe_atom_key_map(Conf0),
     case emqx_connector_ssl:convert_certs(TmpPath, Conf) of
         {error, Reason} ->
@@ -251,7 +252,9 @@ maybe_clear_certs(TmpPath, #{ssl := SslConf} = Conf) ->
     case is_tmp_path_conf(TmpPath, SslConf) of
         true -> emqx_connector_ssl:clear_certs(TmpPath, Conf);
         false -> ok
-    end.
+    end;
+maybe_clear_certs(_TmpPath, _ConfWithoutSsl) ->
+    ok.
 
 is_tmp_path_conf(TmpPath, #{certfile := Certfile}) ->
     is_tmp_path(TmpPath, Certfile);

+ 17 - 10
apps/emqx_bridge/src/schema/emqx_bridge_mqtt_config.erl

@@ -15,22 +15,23 @@
 %%--------------------------------------------------------------------
 
 %% @doc This module was created to convert old version (from v5.0.0 to v5.0.11)
-%% mqtt connector configs to newer version (developed for enterprise edition).
--module(emqx_bridge_mqtt_config).
+%% mqtt/webhook connector configs to newer version (developed for enterprise edition).
+-module(emqx_bridge_compatible_config).
 
 -export([
-    upgrade_pre_ee/1,
-    maybe_upgrade/1
+    upgrade_pre_ee/2,
+    maybe_upgrade/1,
+    webhook_maybe_upgrade/1
 ]).
 
-upgrade_pre_ee(undefined) ->
+upgrade_pre_ee(undefined, _UpgradeFunc) ->
     undefined;
-upgrade_pre_ee(Conf0) when is_map(Conf0) ->
-    maps:from_list(upgrade_pre_ee(maps:to_list(Conf0)));
-upgrade_pre_ee([]) ->
+upgrade_pre_ee(Conf0, UpgradeFunc) when is_map(Conf0) ->
+    maps:from_list(upgrade_pre_ee(maps:to_list(Conf0), UpgradeFunc));
+upgrade_pre_ee([], _UpgradeFunc) ->
     [];
-upgrade_pre_ee([{Name, Config} | Bridges]) ->
-    [{Name, maybe_upgrade(Config)} | upgrade_pre_ee(Bridges)].
+upgrade_pre_ee([{Name, Config} | Bridges], UpgradeFunc) ->
+    [{Name, UpgradeFunc(Config)} | upgrade_pre_ee(Bridges, UpgradeFunc)].
 
 maybe_upgrade(#{<<"connector">> := _} = Config0) ->
     Config1 = up(Config0),
@@ -39,6 +40,12 @@ maybe_upgrade(#{<<"connector">> := _} = Config0) ->
 maybe_upgrade(NewVersion) ->
     NewVersion.
 
+webhook_maybe_upgrade(#{<<"direction">> := _} = Config0) ->
+    Config1 = maps:remove(<<"direction">>, Config0),
+    Config1#{<<"resource_opts">> => default_resource_opts()};
+webhook_maybe_upgrade(NewVersion) ->
+    NewVersion.
+
 binary_key({K, V}) ->
     {atom_to_binary(K, utf8), V}.
 

+ 9 - 2
apps/emqx_bridge/src/schema/emqx_bridge_schema.erl

@@ -121,7 +121,12 @@ fields(bridges) ->
                 hoconsc:map(name, ref(emqx_bridge_webhook_schema, "config")),
                 #{
                     desc => ?DESC("bridges_webhook"),
-                    required => false
+                    required => false,
+                    converter => fun(X, _HoconOpts) ->
+                        emqx_bridge_compatible_config:upgrade_pre_ee(
+                            X, fun emqx_bridge_compatible_config:webhook_maybe_upgrade/1
+                        )
+                    end
                 }
             )},
         {mqtt,
@@ -131,7 +136,9 @@ fields(bridges) ->
                     desc => ?DESC("bridges_mqtt"),
                     required => false,
                     converter => fun(X, _HoconOpts) ->
-                        emqx_bridge_mqtt_config:upgrade_pre_ee(X)
+                        emqx_bridge_compatible_config:upgrade_pre_ee(
+                            X, fun emqx_bridge_compatible_config:maybe_upgrade/1
+                        )
                     end
                 }
             )}

+ 9 - 0
apps/emqx_bridge/src/schema/emqx_bridge_webhook_schema.erl

@@ -81,6 +81,15 @@ request_config() ->
                     desc => ?DESC("config_url")
                 }
             )},
+        {direction,
+            mk(
+                egress,
+                #{
+                    desc => ?DESC("config_direction"),
+                    required => {false, recursively},
+                    deprecated => {since, "5.0.12"}
+                }
+            )},
         {local_topic,
             mk(
                 binary(),

+ 1 - 0
apps/emqx_bridge/test/emqx_bridge_api_SUITE.erl

@@ -86,6 +86,7 @@ init_per_testcase(_, Config) ->
     {ok, _} = emqx_cluster_rpc:start_link(node(), emqx_cluster_rpc, 1000),
     {Port, Sock, Acceptor} = start_http_server(fun handle_fun_200_ok/2),
     [{port, Port}, {sock, Sock}, {acceptor, Acceptor} | Config].
+
 end_per_testcase(_, Config) ->
     Sock = ?config(sock, Config),
     Acceptor = ?config(acceptor, Config),

+ 70 - 14
apps/emqx_bridge/test/emqx_bridge_mqtt_config_tests.erl

@@ -13,7 +13,7 @@
 %% limitations under the License.
 %%--------------------------------------------------------------------
 
--module(emqx_bridge_mqtt_config_tests).
+-module(emqx_bridge_compatible_config_tests).
 
 -include_lib("eunit/include/eunit.hrl").
 
@@ -26,30 +26,54 @@ empty_config_test() ->
 
 %% ensure webhook config can be checked
 webhook_config_test() ->
-    Conf = parse(webhook_v5011_hocon()),
+    Conf1 = parse(webhook_v5011_hocon()),
+    Conf2 = parse(full_webhook_v5011_hocon()),
+
     ?assertMatch(
         #{
-            <<"bridges">> :=
-                #{
-                    <<"webhook">> := #{
-                        <<"the_name">> :=
-                            #{
-                                <<"method">> := get,
-                                <<"body">> := <<"${payload}">>
-                            }
-                    }
+            <<"bridges">> := #{
+                <<"webhook">> := #{
+                    <<"the_name">> :=
+                        #{
+                            <<"method">> := get,
+                            <<"body">> := <<"${payload}">>
+                        }
                 }
+            }
         },
-        check(Conf)
+        check(Conf1)
     ),
+
+    ?assertMatch(
+        #{
+            <<"bridges">> := #{
+                <<"webhook">> := #{
+                    <<"the_name">> :=
+                        #{
+                            <<"method">> := get,
+                            <<"body">> := <<"${payload}">>
+                        }
+                }
+            }
+        },
+        check(Conf2)
+    ),
+
     ok.
 
 up(#{<<"bridges">> := Bridges0} = Conf0) ->
     Bridges = up(Bridges0),
     Conf0#{<<"bridges">> := Bridges};
 up(#{<<"mqtt">> := MqttBridges0} = Bridges) ->
-    MqttBridges = emqx_bridge_mqtt_config:upgrade_pre_ee(MqttBridges0),
-    Bridges#{<<"mqtt">> := MqttBridges}.
+    MqttBridges = emqx_bridge_compatible_config:upgrade_pre_ee(
+        MqttBridges0, fun emqx_bridge_compatible_config:maybe_upgrade/1
+    ),
+    Bridges#{<<"mqtt">> := MqttBridges};
+up(#{<<"webhook">> := WebhookBridges0} = Bridges) ->
+    WebhookBridges = emqx_bridge_compatible_config:upgrade_pre_ee(
+        WebhookBridges0, fun emqx_bridge_compatible_config:webhook_maybe_upgrade/1
+    ),
+    Bridges#{<<"webhook">> := WebhookBridges}.
 
 parse(HOCON) ->
     {ok, Conf} = hocon:binary(HOCON),
@@ -108,6 +132,38 @@ bridges{
 }
 """.
 
+full_webhook_v5011_hocon() ->
+    ""
+    "\n"
+    "bridges{\n"
+    "  webhook {\n"
+    "    the_name{\n"
+    "      body = \"${payload}\"\n"
+    "      connect_timeout = \"5s\"\n"
+    "      direction = \"egress\"\n"
+    "      enable_pipelining = 100\n"
+    "      headers {\"content-type\" = \"application/json\"}\n"
+    "      max_retries = 3\n"
+    "      method = \"get\"\n"
+    "      pool_size = 4\n"
+    "      pool_type = \"random\"\n"
+    "      request_timeout = \"5s\"\n"
+    "      ssl {\n"
+    "        ciphers = \"\"\n"
+    "        depth = 10\n"
+    "        enable = false\n"
+    "        reuse_sessions = true\n"
+    "        secure_renegotiate = true\n"
+    "        user_lookup_fun = \"emqx_tls_psk:lookup\"\n"
+    "        verify = \"verify_peer\"\n"
+    "        versions = [\"tlsv1.3\", \"tlsv1.2\", \"tlsv1.1\", \"tlsv1\"]\n"
+    "      }\n"
+    "      url = \"http://localhost:8080\"\n"
+    "    }\n"
+    "  }\n"
+    "}\n"
+    "".
+
 %% erlfmt-ignore
 %% this is a generated from v5.0.11
 mqtt_v5011_hocon() ->

+ 16 - 4
apps/emqx_conf/i18n/emqx_conf_schema.conf

@@ -480,8 +480,16 @@ the old dir should be deleted first.<br/>
 
   node_crash_dump_seconds {
     desc {
-      en: """The number of seconds that the broker is allowed to spend writing a crash dump."""
-      zh: """保存崩溃文件最大允许时间,如果文件太大,在规则时间内没有保存完成,则会直接结束。"""
+      en: """This variable gives the number of seconds that the emulator is allowed to spend writing a crash dump. When the given number of seconds have elapsed, the emulator is terminated.
+- If setting to 0 seconds, the runtime system does not even attempt to write the crash dump file. It only terminates.
+- If setting to a positive value S, wait for S seconds to complete the crash dump file and then terminates the runtime system with a SIGALRM signal.
+- A negative value causes the termination of the runtime system to wait indefinitely until the crash dump file has been completely written.
+ """
+      zh: """该配置给出了运行时系统允许花费的写入崩溃转储的秒数。当给定的秒数已经过去,运行时系统将被终止。
+- 如果设置为0秒,运行时会立即终止,不会尝试写入崩溃转储文件。
+- 如果设置为一个正数 S,节点会等待 S 秒来完成崩溃转储文件,然后用SIGALRM信号终止运行时系统。
+- 如果设置为一个负值导致运行时系统的终止等待无限期地直到崩溃转储文件已经完全写入。
+"""
     }
     label {
       en: "Crash Dump Seconds"
@@ -491,10 +499,14 @@ the old dir should be deleted first.<br/>
 
   node_crash_dump_bytes {
     desc {
-      en: """The maximum size of a crash dump file in bytes."""
+      en: """This variable sets the maximum size of a crash dump file in bytes.
+The crash dump will be truncated if this limit is exceeded.
+If setting it to 0, the runtime system does not even attempt to write a crash dump file.
+"""
       zh: """限制崩溃文件的大小,当崩溃时节点内存太大,
 如果为了保存现场,需要全部存到崩溃文件中,此处限制最多能保存多大的文件。
-          """
+如果超过此限制,崩溃转储将被截断。如果设置为0,系统不会尝试写入崩溃转储文件。
+"""
     }
     label {
       en: "Crash Dump Bytes"

+ 10 - 1
apps/emqx_conf/src/emqx_conf_schema.erl

@@ -487,7 +487,7 @@ fields("node") ->
                 #{
                     mapping => "vm_args.-env ERL_CRASH_DUMP",
                     desc => ?DESC(node_crash_dump_file),
-                    default => "log/erl_crash.dump",
+                    default => crash_dump_file_default(),
                     'readOnly' => true
                 }
             )},
@@ -1296,6 +1296,15 @@ sort_log_levels(Levels) ->
         Levels
     ).
 
+crash_dump_file_default() ->
+    case os:getenv("RUNNER_LOG_DIR") of
+        false ->
+            %% testing, or running emqx app as deps
+            "log/erl_crash.dump";
+        Dir ->
+            [filename:join([Dir, "erl_crash.dump"])]
+    end.
+
 %% utils
 -spec conf_get(string() | [string()], hocon:config()) -> term().
 conf_get(Key, Conf) ->

+ 5 - 5
apps/emqx_dashboard/i18n/emqx_dashboard_api_i18n.conf

@@ -31,7 +31,7 @@ emqx_dashboard_api {
     license {
         desc {
             en: """EMQX License. opensource or enterprise"""
-            zh: """EMQX 许可。开源版本 或者企业版"""
+            zh: """EMQX 许可类型。可为 opensource 或 enterprise"""
         }
     }
 
@@ -44,15 +44,15 @@ emqx_dashboard_api {
 
     login_api {
         desc {
-            en: """Dashboard Auth. Get Token"""
-            zh: """Dashboard 认证。获取 Token"""
+            en: """Get Dashboard Auth Token."""
+            zh: """获取 Dashboard 认证 Token"""
         }
     }
 
     login_success {
         desc {
-            en: """Dashboard Auth. Success"""
-            zh: """Dashboard 认证成功"""
+            en: """Dashboard Auth Success"""
+            zh: """Dashboard 认证成功"""
         }
     }
 

+ 34 - 27
apps/emqx_dashboard/i18n/emqx_dashboard_i18n.conf

@@ -8,7 +8,10 @@ For example, an HTTP listener can listen on all configured IP addresses
 on a given port for a machine by specifying the IP address 0.0.0.0.
 Alternatively, the HTTP listener can specify a unique IP address for each listener,
 but use the same port."""
-      zh: """仪表盘监听器设置。"""
+      zh: """Dashboard 监听器设置。监听器必须有唯一的端口号和IP地址的组合。
+例如,可以通过指定IP地址 0.0.0.0 来监听机器上给定端口上的所有配置的IP地址。
+或者,可以为每个监听器指定唯一的IP地址,但使用相同的端口。
+"""
     }
     label {
       en: "Listeners"
@@ -18,14 +21,14 @@ but use the same port."""
   sample_interval {
     desc {
       en: """How often to update metrics displayed in the dashboard.
-Note: `sample_interval` should be a divisor of 60."""
-      zh: """更新仪表板中显示的指标的时间间隔。必须小于60,且被60的整除。"""
+Note: `sample_interval` should be a divisor of 60, default is 10s."""
+      zh: """Dashboard 中图表指标的时间间隔。必须小于60,且被60的整除,默认设置 10s。"""
     }
   }
   token_expired_time {
     desc {
-      en: "JWT token expiration time."
-      zh: "JWT token 过期时间"
+      en: "JWT token expiration time. Default is 60 minutes"
+      zh: "JWT token 过期时间。默认设置为 60 分钟。"
     }
     label {
       en: "Token expired time"
@@ -34,8 +37,8 @@ Note: `sample_interval` should be a divisor of 60."""
   }
   num_acceptors {
     desc {
-      en: "Socket acceptor pool size for TCP protocols."
-      zh: "TCP协议的Socket acceptor池大小"
+      en: "Socket acceptor pool size for TCP protocols. Default is the number of schedulers online"
+      zh: "TCP协议的Socket acceptor池大小, 默认设置在线的调度器数量(通常为 CPU 核数)"
     }
     label {
       en: "Number of acceptors"
@@ -45,7 +48,7 @@ Note: `sample_interval` should be a divisor of 60."""
   max_connections {
     desc {
       en: "Maximum number of simultaneous connections."
-      zh: "同时处理的最大连接数"
+      zh: "同时处理的最大连接数"
     }
     label {
       en: "Maximum connections"
@@ -55,7 +58,7 @@ Note: `sample_interval` should be a divisor of 60."""
   backlog {
     desc {
       en: "Defines the maximum length that the queue of pending connections can grow to."
-      zh: "排队等待连接的队列的最大长度"
+      zh: "排队等待连接的队列的最大长度"
     }
     label {
       en: "Backlog"
@@ -65,7 +68,7 @@ Note: `sample_interval` should be a divisor of 60."""
   send_timeout {
     desc {
       en: "Send timeout for the socket."
-      zh: "Socket发送超时时间"
+      zh: "Socket发送超时时间"
     }
     label {
       en: "Send timeout"
@@ -75,7 +78,7 @@ Note: `sample_interval` should be a divisor of 60."""
   inet6 {
     desc {
       en: "Enable IPv6 support, default is false, which means IPv4 only."
-      zh: "启用IPv6, 如果机器不支持IPv6,请关闭此选项,否则会导致仪表盘无法使用。"
+      zh: "启用IPv6, 如果机器不支持IPv6,请关闭此选项,否则会导致 Dashboard 无法使用。"
     }
     label {
       en: "IPv6"
@@ -84,7 +87,8 @@ Note: `sample_interval` should be a divisor of 60."""
   }
   ipv6_v6only {
     desc {
-      en: "Disable IPv4-to-IPv6 mapping for the listener."
+      en: """Disable IPv4-to-IPv6 mapping for the listener.
+The configuration is only valid when the inet6 is true."""
       zh: "当开启 inet6 功能的同时禁用 IPv4-to-IPv6 映射。该配置仅在 inet6 功能开启时有效。"
     }
     label {
@@ -95,17 +99,17 @@ Note: `sample_interval` should be a divisor of 60."""
   desc_dashboard {
     desc {
       en: "Configuration for EMQX dashboard."
-      zh: "EMQX仪表板配置"
+      zh: "EMQX Dashboard 配置。"
     }
     label {
       en: "Dashboard"
-      zh: "仪表板"
+      zh: "Dashboard"
     }
   }
   desc_listeners {
     desc {
       en: "Configuration for the dashboard listener."
-      zh: "仪表板监听器配置"
+      zh: "Dashboard 监听器配置。"
     }
     label {
       en: "Listeners"
@@ -115,7 +119,7 @@ Note: `sample_interval` should be a divisor of 60."""
   desc_http {
     desc {
       en: "Configuration for the dashboard listener (plaintext)."
-      zh: "仪表板监听器(HTTP)配置"
+      zh: "Dashboard 监听器(HTTP)配置。"
     }
     label {
       en: "HTTP"
@@ -125,7 +129,7 @@ Note: `sample_interval` should be a divisor of 60."""
   desc_https {
     desc {
       en: "Configuration for the dashboard listener (TLS)."
-      zh: "仪表板监听器(HTTPS)配置"
+      zh: "Dashboard 监听器(HTTPS)配置。"
     }
     label {
       en: "HTTPS"
@@ -135,7 +139,7 @@ Note: `sample_interval` should be a divisor of 60."""
   listener_enable {
     desc {
         en: "Ignore or enable this listener"
-        zh: "忽略或启用该监听器配置"
+        zh: "忽略或启用该监听器"
     }
     label {
         en: "Enable"
@@ -145,7 +149,7 @@ Note: `sample_interval` should be a divisor of 60."""
   bind {
     desc {
       en: "Port without IP(18083) or port with specified IP(127.0.0.1:18083)."
-      zh: "监听的地址与端口,在dashboard更新此配置时,会重启dashboard服务。"
+      zh: "监听地址和端口,热更新此配置时,会重启 Dashboard 服务。"
     }
     label {
       en: "Bind"
@@ -155,7 +159,7 @@ Note: `sample_interval` should be a divisor of 60."""
   default_username {
     desc {
       en: "The default username of the automatically created dashboard user."
-      zh: "默认的仪表板用户名"
+      zh: "Dashboard 的默认用户名"
     }
     label {
       en: "Default username"
@@ -165,9 +169,12 @@ Note: `sample_interval` should be a divisor of 60."""
   default_password {
     desc {
       en: """The initial default password for dashboard 'admin' user.
-For safety, it should be changed as soon as possible."""
-      zh: """默认的仪表板用户密码
-为了安全,应该尽快修改密码。"""
+For safety, it should be changed as soon as possible.
+This value is not valid when you log in to Dashboard for the first time via the web
+and change to a complex password as prompted.
+"""
+      zh: """Dashboard 的默认密码,为了安全,应该尽快修改密码。
+当通过网页首次登录 Dashboard 并按提示修改成复杂密码后,此值就会失效。"""
     }
     label {
       en: "Default password"
@@ -179,7 +186,7 @@ For safety, it should be changed as soon as possible."""
       en: """Support Cross-Origin Resource Sharing (CORS).
 Allows a server to indicate any origins (domain, scheme, or port) other than
 its own from which a browser should permit loading resources."""
-      zh: """支持跨域资源共享(CORS)
+      zh: """支持跨域资源共享(CORS)
 允许服务器指示任何来源(域名、协议或端口),除了本服务器之外的任何浏览器应允许加载资源。"""
     }
     label {
@@ -190,7 +197,7 @@ its own from which a browser should permit loading resources."""
   i18n_lang {
     desc {
       en: "Internationalization language support."
-      zh: "swagger多语言支持"
+      zh: "设置 Swagger 多语言的版本,可为 en 或 zh。"
     }
     label {
       en: "I18n language"
@@ -199,8 +206,8 @@ its own from which a browser should permit loading resources."""
   }
   bootstrap_users_file {
     desc {
-      en: "Deprecated, use api_key.bootstrap_file"
-      zh: "已废弃,请使用 api_key.bootstrap_file"
+      en: "Deprecated, use api_key.bootstrap_file."
+      zh: "已废弃,请使用 api_key.bootstrap_file"
     }
     label {
       en: """Deprecated"""

+ 2 - 2
apps/emqx_dashboard/src/emqx_dashboard_schema.erl

@@ -117,7 +117,7 @@ common_listener_fields() ->
             ?HOCON(
                 integer(),
                 #{
-                    default => 4,
+                    default => erlang:system_info(schedulers_online),
                     desc => ?DESC(num_acceptors)
                 }
             )},
@@ -141,7 +141,7 @@ common_listener_fields() ->
             ?HOCON(
                 emqx_schema:duration(),
                 #{
-                    default => "5s",
+                    default => "10s",
                     desc => ?DESC(send_timeout)
                 }
             )},

+ 1 - 1
apps/emqx_machine/src/emqx_machine.app.src

@@ -3,7 +3,7 @@
     {id, "emqx_machine"},
     {description, "The EMQX Machine"},
     % strict semver, bump manually!
-    {vsn, "0.1.2"},
+    {vsn, "0.1.3"},
     {modules, []},
     {registered, []},
     {applications, [kernel, stdlib]},

+ 8 - 0
apps/emqx_machine/src/user_default.erl

@@ -26,6 +26,14 @@
 
 %% API
 -export([lock/0, unlock/0]).
+-export([t/1, t2/1, t/2, t2/2, t/3, t2/3]).
 
 lock() -> emqx_restricted_shell:lock().
 unlock() -> emqx_restricted_shell:unlock().
+
+t(M) -> recon_trace:calls({M, '_', return_trace}, 300).
+t2(M) -> recon_trace:calls({M, '_', return_trace}, 300, [{args, arity}]).
+t(M, F) -> recon_trace:calls({M, F, return_trace}, 300).
+t2(M, F) -> recon_trace:calls({M, F, return_trace}, 300, [{args, arity}]).
+t(M, F, A) -> recon_trace:calls({M, F, A}, 300).
+t2(M, F, A) -> recon_trace:calls({M, F, A}, 300, [{args, arity}]).

+ 1 - 1
apps/emqx_resource/src/emqx_resource_manager.erl

@@ -171,7 +171,7 @@ create_dry_run(ResourceType, Config) ->
     ok = emqx_resource_manager_sup:ensure_child(
         MgrId, ResId, <<"dry_run">>, ResourceType, Config, #{}
     ),
-    case wait_for_ready(ResId, 15000) of
+    case wait_for_ready(ResId, 5000) of
         ok ->
             remove(ResId);
         {error, Reason} ->

+ 3 - 6
apps/emqx_resource/src/emqx_resource_worker.erl

@@ -1167,12 +1167,9 @@ queue_count(Q) ->
     replayq:count(Q).
 
 disk_queue_dir(Id, Index) ->
-    QDir0 = binary_to_list(Id) ++ "_" ++ integer_to_list(Index),
-    QDir = sanitize_file_path(QDir0),
-    filename:join([emqx:data_dir(), "bufs", node(), QDir]).
-
-sanitize_file_path(Filepath) ->
-    iolist_to_binary(string:replace(Filepath, ":", "_", all)).
+    QDir0 = binary_to_list(Id) ++ ":" ++ integer_to_list(Index),
+    QDir = filename:join([emqx:data_dir(), "bufs", node(), QDir0]),
+    emqx_misc:safe_filename(QDir).
 
 clear_disk_queue_dir(Id, Index) ->
     ReplayQDir = disk_queue_dir(Id, Index),

+ 1 - 0
changes/v5.0.15/fix-9780.en.md

@@ -0,0 +1 @@
+When creating disk queue directory for resource worker, substitute ':' with '-' in worker id.

+ 1 - 0
changes/v5.0.15/fix-9780.zh.md

@@ -0,0 +1 @@
+在为资源缓存进程创建磁盘队列目录时,在ID中用 '-' 代替 ':'。

+ 1 - 0
changes/v5.0.15/fix-9787.en.md

@@ -0,0 +1 @@
+Fix a compatible problem for the `webhook` bridge configuration which was created before the v5.0.12.

+ 1 - 0
changes/v5.0.15/fix-9787.zh.md

@@ -0,0 +1 @@
+修复对在 v5.0.12 之前创建的 `webhook` 桥接配置的兼容问题。

+ 7 - 7
deploy/charts/emqx-enterprise/templates/StatefulSet.yaml

@@ -98,15 +98,15 @@ spec:
           {{- end }}
           ports:
           - name: mqtt
-            containerPort: {{ .Values.emqxConfig.EMQX_LISTENERS__TCP__DEFAULT | default 1883 }}
+            containerPort: {{ .Values.emqxConfig.EMQX_LISTENERS__TCP__DEFAULT__BIND | default 1883 }}
           - name: mqttssl
-            containerPort: {{ .Values.emqxConfig.EMQX_LISTENERS__SSL__DEFAULT | default 8883 }}
+            containerPort: {{ .Values.emqxConfig.EMQX_LISTENERS__SSL__DEFAULT__BIND | default 8883 }}
           - name: ws
-            containerPort: {{ .Values.emqxConfig.EMQX_LISTENERS__WS__DEFAULT | default 8083 }}
+            containerPort: {{ .Values.emqxConfig.EMQX_LISTENERS__WS__DEFAULT__BIND | default 8083 }}
           - name: wss
-            containerPort: {{ .Values.emqxConfig.EMQX_LISTENERS__WSS__DEFAULT | default 8084 }}
+            containerPort: {{ .Values.emqxConfig.EMQX_LISTENERS__WSS__DEFAULT__BIND | default 8084 }}
           - name: dashboard
-            containerPort: {{ .Values.emqxConfig.EMQX_DASHBOARD__LISTENER__HTTP | default 18083 }}
+            containerPort: {{ .Values.emqxConfig.EMQX_DASHBOARD__LISTENER__HTTP__BIND | default 18083 }}
           {{- if not (empty .Values.emqxConfig.EMQX_LISTENERS__TCP__DEFAULT) }}
           - name: internalmqtt
             containerPort: {{ .Values.emqxConfig.EMQX_LISTENERS__TCP__DEFAULT }}
@@ -143,14 +143,14 @@ spec:
           readinessProbe:
             httpGet:
               path: /status
-              port: {{ .Values.emqxConfig.EMQX_DASHBOARD__LISTENER__HTTP | default 18083 }}
+              port: {{ .Values.emqxConfig.EMQX_DASHBOARD__LISTENER__HTTP__BIND | default 18083 }}
             initialDelaySeconds: 10
             periodSeconds: 5
             failureThreshold: 30
           livenessProbe:
             httpGet:
               path: /status
-              port: {{ .Values.emqxConfig.EMQX_DASHBOARD__LISTENER__HTTP | default 18083 }}
+              port: {{ .Values.emqxConfig.EMQX_DASHBOARD__LISTENER__HTTP__BIND | default 18083 }}
             initialDelaySeconds: 60
             periodSeconds: 30
             failureThreshold: 10

+ 7 - 7
deploy/charts/emqx/templates/StatefulSet.yaml

@@ -98,15 +98,15 @@ spec:
           {{- end }}
           ports:
           - name: mqtt
-            containerPort: {{ .Values.emqxConfig.EMQX_LISTENERS__TCP__DEFAULT | default 1883 }}
+            containerPort: {{ .Values.emqxConfig.EMQX_LISTENERS__TCP__DEFAULT__BIND | default 1883 }}
           - name: mqttssl
-            containerPort: {{ .Values.emqxConfig.EMQX_LISTENERS__SSL__DEFAULT | default 8883 }}
+            containerPort: {{ .Values.emqxConfig.EMQX_LISTENERS__SSL__DEFAULT__BIND | default 8883 }}
           - name: ws
-            containerPort: {{ .Values.emqxConfig.EMQX_LISTENERS__WS__DEFAULT | default 8083 }}
+            containerPort: {{ .Values.emqxConfig.EMQX_LISTENERS__WS__DEFAULT__BIND | default 8083 }}
           - name: wss
-            containerPort: {{ .Values.emqxConfig.EMQX_LISTENERS__WSS__DEFAULT | default 8084 }}
+            containerPort: {{ .Values.emqxConfig.EMQX_LISTENERS__WSS__DEFAULT__BIND | default 8084 }}
           - name: dashboard
-            containerPort: {{ .Values.emqxConfig.EMQX_DASHBOARD__LISTENER__HTTP | default 18083 }}
+            containerPort: {{ .Values.emqxConfig.EMQX_DASHBOARD__LISTENER__HTTP__BIND | default 18083 }}
           {{- if not (empty .Values.emqxConfig.EMQX_LISTENERS__TCP__DEFAULT) }}
           - name: internalmqtt
             containerPort: {{ .Values.emqxConfig.EMQX_LISTENERS__TCP__DEFAULT }}
@@ -143,14 +143,14 @@ spec:
           readinessProbe:
             httpGet:
               path: /status
-              port: {{ .Values.emqxConfig.EMQX_DASHBOARD__LISTENER__HTTP | default 18083 }}
+              port: {{ .Values.emqxConfig.EMQX_DASHBOARD__LISTENER__HTTP__BIND | default 18083 }}
             initialDelaySeconds: 10
             periodSeconds: 5
             failureThreshold: 30
           livenessProbe:
             httpGet:
               path: /status
-              port: {{ .Values.emqxConfig.EMQX_DASHBOARD__LISTENER__HTTP | default 18083 }}
+              port: {{ .Values.emqxConfig.EMQX_DASHBOARD__LISTENER__HTTP__BIND | default 18083 }}
             initialDelaySeconds: 60
             periodSeconds: 30
             failureThreshold: 10

+ 12 - 12
lib-ee/emqx_ee_bridge/src/emqx_ee_bridge_gcp_pubsub.erl

@@ -149,31 +149,31 @@ values(get) ->
     maps:merge(values(post), ?METRICS_EXAMPLE);
 values(post) ->
     #{
-        <<"pubsub_topic">> => <<"mytopic">>,
-        <<"service_account_json">> =>
+        pubsub_topic => <<"mytopic">>,
+        service_account_json =>
             #{
-                <<"auth_provider_x509_cert_url">> =>
+                auth_provider_x509_cert_url =>
                     <<"https://www.googleapis.com/oauth2/v1/certs">>,
-                <<"auth_uri">> =>
+                auth_uri =>
                     <<"https://accounts.google.com/o/oauth2/auth">>,
-                <<"client_email">> =>
+                client_email =>
                     <<"test@myproject.iam.gserviceaccount.com">>,
-                <<"client_id">> => <<"123812831923812319190">>,
-                <<"client_x509_cert_url">> =>
+                client_id => <<"123812831923812319190">>,
+                client_x509_cert_url =>
                     <<
                         "https://www.googleapis.com/robot/v1/"
                         "metadata/x509/test%40myproject.iam.gserviceaccount.com"
                     >>,
-                <<"private_key">> =>
+                private_key =>
                     <<
                         "-----BEGIN PRIVATE KEY-----\n"
                         "MIIEvQI..."
                     >>,
-                <<"private_key_id">> => <<"kid">>,
-                <<"project_id">> => <<"myproject">>,
-                <<"token_uri">> =>
+                private_key_id => <<"kid">>,
+                project_id => <<"myproject">>,
+                token_uri =>
                     <<"https://oauth2.googleapis.com/token">>,
-                <<"type">> => <<"service_account">>
+                type => <<"service_account">>
             }
     };
 values(put) ->

+ 5 - 1
lib-ee/emqx_ee_bridge/test/emqx_ee_bridge_gcp_pubsub_SUITE.erl

@@ -198,13 +198,17 @@ create_bridge_http(Config, GCPPubSubConfigOverrides) ->
     Params = GCPPubSubConfig#{<<"type">> => TypeBin, <<"name">> => Name},
     Path = emqx_mgmt_api_test_util:api_path(["bridges"]),
     AuthHeader = emqx_mgmt_api_test_util:auth_header_(),
+    ProbePath = emqx_mgmt_api_test_util:api_path(["bridges_probe"]),
+    ProbeResult = emqx_mgmt_api_test_util:request_api(post, ProbePath, "", AuthHeader, Params),
     ct:pal("creating bridge (via http): ~p", [Params]),
+    ct:pal("probe result: ~p", [ProbeResult]),
     Res =
         case emqx_mgmt_api_test_util:request_api(post, Path, "", AuthHeader, Params) of
             {ok, Res0} -> {ok, emqx_json:decode(Res0, [return_maps])};
             Error -> Error
         end,
     ct:pal("bridge creation result: ~p", [Res]),
+    ?assertEqual(element(1, ProbeResult), element(1, Res)),
     Res.
 
 create_rule_and_action_http(Config) ->
@@ -681,7 +685,7 @@ t_create_via_http(Config) ->
         create_bridge_http(Config),
         fun(Res, Trace) ->
             ?assertMatch({ok, _}, Res),
-            ?assertMatch([_], ?of_kind(gcp_pubsub_bridge_jwt_created, Trace)),
+            ?assertMatch([_, _], ?of_kind(gcp_pubsub_bridge_jwt_created, Trace)),
             ok
         end
     ),