diff --git a/apps/emqx_conf/src/emqx_conf_app.erl b/apps/emqx_conf/src/emqx_conf_app.erl index 43a468762..20e1444ba 100644 --- a/apps/emqx_conf/src/emqx_conf_app.erl +++ b/apps/emqx_conf/src/emqx_conf_app.erl @@ -62,10 +62,11 @@ sync_data_from_node() -> TargetDirs = lists:filter(fun(Type) -> filelib:is_dir(filename:join(Dir, Type)) end, [ "authz", "certs" ]), - {ok, Zip} = zip:zip(atom_to_list(node()) ++ "_data.zip", TargetDirs, [{cwd, Dir}]), - Res = {ok, _Bin} = file:read_file(Zip), - _ = file:delete(Zip), - Res. + Name = "data.zip", + case zip:zip(Name, TargetDirs, [memory, {cwd, Dir}]) of + {ok, {Name, Bin}} -> {ok, Bin}; + {error, Reason} -> {error, Reason} + end. %% ------------------------------------------------------------------------------ %% Internal functions @@ -195,8 +196,12 @@ conf_sort({ok, _}, {ok, _}) -> sync_data_from_node(Node) -> case emqx_conf_proto_v2:sync_data_from_node(Node) of {ok, DataBin} -> - {ok, Files} = zip:unzip(DataBin, [{cwd, emqx:data_dir()}]), - ?SLOG(debug, #{node => Node, msg => "sync_data_from_node_ok", files => Files}), + case zip:unzip(DataBin, [{cwd, emqx:data_dir()}]) of + {ok, []} -> + ?SLOG(debug, #{node => Node, msg => "sync_data_from_node_ignore"}); + {ok, Files} -> + ?SLOG(debug, #{node => Node, msg => "sync_data_from_node_ok", files => Files}) + end, ok; Error -> ?SLOG(emergency, #{node => Node, msg => "sync_data_from_node_failed", reason => Error}), diff --git a/apps/emqx_conf/test/emqx_conf_app_SUITE.erl b/apps/emqx_conf/test/emqx_conf_app_SUITE.erl index f10e42759..a3787fe6e 100644 --- a/apps/emqx_conf/test/emqx_conf_app_SUITE.erl +++ b/apps/emqx_conf/test/emqx_conf_app_SUITE.erl @@ -54,10 +54,78 @@ t_copy_conf_override_on_restarts(_Config) -> stop_cluster(Nodes) end. +t_copy_data_dir(_Config) -> + net_kernel:start(['master1@127.0.0.1', longnames]), + ct:timetrap({seconds, 120}), + snabbkaffe:fix_ct_logging(), + Cluster = cluster([{core, copy1}, {core, copy2}, {core, copy3}]), + + %% 1. Start all nodes + [First | Rest] = Nodes = start_cluster(Cluster), + try + assert_config_load_done(Nodes), + rpc:call(First, ?MODULE, create_data_dir, []), + {[ok, ok, ok], []} = rpc:multicall(Nodes, application, stop, [emqx_conf]), + {[ok, ok, ok], []} = rpc:multicall(Nodes, ?MODULE, set_data_dir_env, []), + ok = rpc:call(First, application, start, [emqx_conf]), + {[ok, ok], []} = rpc:multicall(Rest, application, start, [emqx_conf]), + + assert_data_copy_done(Nodes), + stop_cluster(Nodes), + ok + after + stop_cluster(Nodes) + end. + %%------------------------------------------------------------------------------ %% Helper functions %%------------------------------------------------------------------------------ +create_data_dir() -> + Node = atom_to_list(node()), + ok = filelib:ensure_dir(Node ++ "/certs/"), + ok = filelib:ensure_dir(Node ++ "/authz/"), + ok = filelib:ensure_dir(Node ++ "/configs/"), + ok = file:write_file(Node ++ "/certs/fake-cert", list_to_binary(Node)), + ok = file:write_file(Node ++ "/authz/fake-authz", list_to_binary(Node)), + Telemetry = <<"telemetry.enable = false">>, + ok = file:write_file(Node ++ "/configs/cluster-override.conf", Telemetry). + +set_data_dir_env() -> + Node = atom_to_list(node()), + %% will create certs and authz dir + ok = filelib:ensure_dir(Node ++ "/configs/"), + application:set_env(emqx, data_dir, Node), + application:set_env(emqx, cluster_override_conf_file, Node ++ "/configs/cluster-override.conf"), + ok. + +assert_data_copy_done([First0 | Rest]) -> + First = atom_to_list(First0), + {ok, FakeCertFile} = file:read_file(First ++ "/certs/fake-cert"), + {ok, FakeAuthzFile} = file:read_file(First ++ "/authz/fake-authz"), + {ok, FakeOverrideFile} = file:read_file(First ++ "/configs/cluster-override.conf"), + lists:foreach( + fun(Node0) -> + Node = atom_to_list(Node0), + ?assertEqual( + {ok, FakeCertFile}, + file:read_file(Node ++ "/certs/fake-cert"), + #{node => Node} + ), + ?assertEqual( + {ok, FakeOverrideFile}, + file:read_file(Node ++ "/configs/cluster-override.conf"), + #{node => Node} + ), + ?assertEqual( + {ok, FakeAuthzFile}, + file:read_file(Node ++ "/authz/fake-authz"), + #{node => Node} + ) + end, + Rest + ). + assert_config_load_done(Nodes) -> lists:foreach( fun(Node) -> @@ -96,6 +164,7 @@ cluster(Specs) -> {env_handler, fun (emqx) -> application:set_env(emqx, boot_modules, []), + io:format("~p~p~n", [node(), application:get_all_env(emqx)]), ok; (_) -> ok diff --git a/changes/v5.0.12-en.md b/changes/v5.0.12-en.md index d811bf042..f3a1dbbab 100644 --- a/changes/v5.0.12-en.md +++ b/changes/v5.0.12-en.md @@ -13,6 +13,8 @@ - Add `limiter` update API [#9133](https://github.com/emqx/emqx/pull/9133). +- Avoid creating temporary zip files when syncing data directory during cluster startup [#9429](https://github.com/emqx/emqx/pull/9429). + ## Bug fixes - Fix that the obsolete SSL files aren't deleted after the ExHook config update [#9432](https://github.com/emqx/emqx/pull/9432). diff --git a/changes/v5.0.12-zh.md b/changes/v5.0.12-zh.md index 5129821cd..3dfbb026e 100644 --- a/changes/v5.0.12-zh.md +++ b/changes/v5.0.12-zh.md @@ -13,6 +13,8 @@ - 添加 `limiter` 更新 API [#9133](https://github.com/emqx/emqx/pull/9133)。 +- EMQX 集群启动时同步 data 目录不需要在磁盘上产生临时的zip文件 [#9429](https://github.com/emqx/emqx/pull/9429)。 + ## 修复 - 修复 ExHook 更新 SSL 相关配置后,过时的 SSL 文件没有被删除的问题 [#9432](https://github.com/emqx/emqx/pull/9432)。