From 67e3e2de9610e4e0fd8d7a43d8b9c7034a758ec8 Mon Sep 17 00:00:00 2001 From: Thales Macedo Garitezi Date: Thu, 19 May 2022 11:24:57 -0300 Subject: [PATCH 1/2] fix(backup): accept files outside `data/dir` when importing Fixes https://github.com/emqx/emqx/issues/7990 Currently, when importing a data backup using `emqx_ctl data import /some/data.json`, it'll only search in the `data/backup` directory and fail if the file is not inside that dir. --- .../src/emqx_mgmt_data_backup.erl | 5 ++++- apps/emqx_management/test/emqx_mgmt_SUITE.erl | 17 +++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/apps/emqx_management/src/emqx_mgmt_data_backup.erl b/apps/emqx_management/src/emqx_mgmt_data_backup.erl index f5eaaa7ab..5a83528fd 100644 --- a/apps/emqx_management/src/emqx_mgmt_data_backup.erl +++ b/apps/emqx_management/src/emqx_mgmt_data_backup.erl @@ -666,7 +666,10 @@ look_up_file(Filename) -> end, case lists:filter(Filter, backup_files()) of [] -> - {error, not_found}; + case filelib:is_file(Filename) of + true -> {ok, Filename}; + false -> {error, not_found} + end; List -> {ok, hd(List)} end. diff --git a/apps/emqx_management/test/emqx_mgmt_SUITE.erl b/apps/emqx_management/test/emqx_mgmt_SUITE.erl index 45afbd860..48a771d7a 100644 --- a/apps/emqx_management/test/emqx_mgmt_SUITE.erl +++ b/apps/emqx_management/test/emqx_mgmt_SUITE.erl @@ -72,6 +72,13 @@ init_per_testcase(t_plugins_cmd, Config) -> meck:expect(emqx_plugins, reload, fun(_) -> ok end), mock_print(), Config; +init_per_testcase(t_import_outside_backup_dir, Config) -> + RandomName = emqx_guid:to_hexstr(emqx_guid:gen()), + Filepath = "/tmp/" ++ binary_to_list(RandomName) ++ ".json", + FakeData = #{version => "4.4"}, + ok = file:write_file(Filepath, emqx_json:encode(FakeData)), + [ {tmp_file, Filepath} + | Config]; init_per_testcase(_Case, Config) -> mock_print(), Config. @@ -79,6 +86,10 @@ init_per_testcase(_Case, Config) -> end_per_testcase(t_plugins_cmd, _Config) -> meck:unload(emqx_plugins), unmock_print(); +end_per_testcase(t_import_outside_backup_dir, Config) -> + Filepath = ?config(tmp_file, Config), + file:delete(Filepath), + ok; end_per_testcase(_Case, _Config) -> unmock_print(). @@ -384,6 +395,12 @@ t_backup_file(_)-> {error, not_found} = emqx_mgmt_data_backup:delete_backup_file(BadFilename), ok. +t_import_outside_backup_dir(Config) -> + Filepath = ?config(tmp_file, Config), + Env = "{}", + ?assertEqual(ok, emqx_mgmt_data_backup:import(Filepath, Env)), + ok. + mock_print() -> ok = safe_unmeck(emqx_ctl), meck:new(emqx_ctl, [non_strict, passthrough]), From 78c5cb4aacc87ae5ad8d120a24c21afd8e3a48c5 Mon Sep 17 00:00:00 2001 From: Thales Macedo Garitezi Date: Fri, 20 May 2022 09:37:09 -0300 Subject: [PATCH 2/2] refactor: only import checks for external backup file --- .../src/emqx_mgmt_data_backup.erl | 28 +++++++++++++------ 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/apps/emqx_management/src/emqx_mgmt_data_backup.erl b/apps/emqx_management/src/emqx_mgmt_data_backup.erl index 5a83528fd..47b590530 100644 --- a/apps/emqx_management/src/emqx_mgmt_data_backup.erl +++ b/apps/emqx_management/src/emqx_mgmt_data_backup.erl @@ -660,16 +660,19 @@ backup_files(Dir) -> look_up_file(Filename) when is_binary(Filename) -> look_up_file(binary_to_list(Filename)); look_up_file(Filename) -> + DefOnNotFound = fun(_Filename) -> {error, not_found} end, + do_look_up_file(Filename, DefOnNotFound). + +do_look_up_file(Filename, OnNotFound) when is_binary(Filename) -> + do_look_up_file(binary_to_list(Filename), OnNotFound); +do_look_up_file(Filename, OnNotFound) -> Filter = fun(MaybeFile) -> filename:basename(MaybeFile) == Filename end, case lists:filter(Filter, backup_files()) of [] -> - case filelib:is_file(Filename) of - true -> {ok, Filename}; - false -> {error, not_found} - end; + OnNotFound(Filename); List -> {ok, hd(List)} end. @@ -813,19 +816,26 @@ import(Filename, OverridesJson) -> -spec(check_import_json(binary() | string()) -> {ok, map()} | {error, term()}). check_import_json(Filename) -> + OnNotFound = + fun(F) -> + case filelib:is_file(F) of + true -> {ok, F}; + false -> {error, not_found} + end + end, FunList = [ - fun look_up_file/1, + fun(F) -> do_look_up_file(F, OnNotFound) end, fun(F) -> file:read_file(F) end, fun check_json/1 ], - check_import_json(Filename, FunList). + do_check_import_json(Filename, FunList). -check_import_json(Res, []) -> +do_check_import_json(Res, []) -> {ok, Res}; -check_import_json(Acc, [Fun | FunList]) -> +do_check_import_json(Acc, [Fun | FunList]) -> case Fun(Acc) of {ok, Next} -> - check_import_json(Next, FunList); + do_check_import_json(Next, FunList); {error, Reason} -> {error, Reason} end.