From 41afbd2b13ddcbd77c911b9193c4cfa7a7e2f1d4 Mon Sep 17 00:00:00 2001 From: Shawn <506895667@qq.com> Date: Tue, 1 Mar 2022 22:01:00 +0800 Subject: [PATCH] refactor(relup): don't collect relvsn -> appvsn mappings --- build | 3 + .../src/emqx_dashboard.appup.src | 2 +- rebar.config.erl | 11 -- scripts/inject-relup.escript | 165 +++++++----------- src/emqx.appup.src | 14 +- src/emqx_relup.erl | 30 +++- 6 files changed, 107 insertions(+), 118 deletions(-) diff --git a/build b/build index b4c9d0548..8bf435357 100755 --- a/build +++ b/build @@ -136,6 +136,9 @@ make_zip() { local tarball="${relpath}/${tarname}" local target_zip="${pkgpath}/${pkgname}" tar zxf "${tarball}" -C "${tard}/emqx" + if ! [[ $SYSTEM == windows* ]]; then + ./scripts/inject-relup.escript "${tard}/emqx/releases/${PKG_VSN}/relup" + fi cp_dyn_libs "${tard}/emqx" pushd "${tard}" >/dev/null case "$SYSTEM" in diff --git a/lib-ce/emqx_dashboard/src/emqx_dashboard.appup.src b/lib-ce/emqx_dashboard/src/emqx_dashboard.appup.src index 270c65b5e..513757418 100644 --- a/lib-ce/emqx_dashboard/src/emqx_dashboard.appup.src +++ b/lib-ce/emqx_dashboard/src/emqx_dashboard.appup.src @@ -8,4 +8,4 @@ [ {restart_application, emqx_dashboard} ]} ] -}. \ No newline at end of file +}. diff --git a/rebar.config.erl b/rebar.config.erl index 32e3444d1..492707867 100644 --- a/rebar.config.erl +++ b/rebar.config.erl @@ -128,34 +128,23 @@ prod_compile_opts() -> prod_overrides() -> [{add, [ {erl_opts, [deterministic]}]}]. -relup_deps(Profile, Vsn) -> - InjectCmd = "scripts/inject-relup.escript " ++ filename:join(["_build", Profile, "rel", "emqx"]) ++ " " ++ Vsn, - {post_hooks, - [ {"(linux|darwin|solaris|freebsd|netbsd|openbsd)", relup, InjectCmd} - ] - }. - profiles() -> Vsn = get_vsn(), [ {'emqx', [ {erl_opts, prod_compile_opts()} , {relx, relx(Vsn, cloud, bin)} , {overrides, prod_overrides()} - , relup_deps('emqx', Vsn) ]} , {'emqx-pkg', [ {erl_opts, prod_compile_opts()} , {relx, relx(Vsn, cloud, pkg)} , {overrides, prod_overrides()} - , relup_deps('emqx-pkg', Vsn) ]} , {'emqx-edge', [ {erl_opts, prod_compile_opts()} , {relx, relx(Vsn, edge, bin)} , {overrides, prod_overrides()} - , relup_deps('emqx-edge', Vsn) ]} , {'emqx-edge-pkg', [ {erl_opts, prod_compile_opts()} , {relx, relx(Vsn, edge, pkg)} , {overrides, prod_overrides()} - , relup_deps('emqx-edge-pkg', Vsn) ]} , {check, [ {erl_opts, common_compile_opts()} ]} diff --git a/scripts/inject-relup.escript b/scripts/inject-relup.escript index 3a779d239..93fe34a90 100755 --- a/scripts/inject-relup.escript +++ b/scripts/inject-relup.escript @@ -8,34 +8,27 @@ -define(INFO(FORMAT, ARGS), io:format(user, "[inject-relup] " ++ FORMAT ++ "~n", ARGS)). usage() -> - "Usage: " ++ escript:script_name() ++ " ". + "Usage: " ++ escript:script_name() ++ " ". -main([RelRootDir, CurrRelVsn]) -> - case filelib:is_dir(filename:join([RelRootDir, "releases"])) andalso - filelib:is_dir(filename:join([RelRootDir, "lib"])) of +main([RelupFile]) -> + case filelib:is_regular(RelupFile) of true -> - EmqxAppVsns = get_emqx_app_vsns(RelRootDir), - ok = inject_relup_file(RelRootDir, CurrRelVsn, EmqxAppVsns); + ok = inject_relup_file(RelupFile); false -> - ?ERROR("not a valid root dir of release: ~p, for example: _build/emqx/rel/emqx", - [RelRootDir]), + ?ERROR("not a valid file: ~p", [RelupFile]), erlang:halt(1) end; main(_Args) -> ?ERROR("~s", [usage()]), erlang:halt(1). -inject_relup_file(RelRootDir, CurrRelVsn, EmqxAppVsns) -> - RelupFile = filename:join([RelRootDir, "releases", CurrRelVsn, "relup"]), - inject_file(RelupFile, EmqxAppVsns). - -inject_file(File, EmqxAppVsns) -> +inject_relup_file(File) -> case file:script(File) of {ok, {CurrRelVsn, UpVsnRUs, DnVsnRUs}} -> ?INFO("injecting instructions to: ~p", [File]), UpdatedContent = {CurrRelVsn, - inject_relup_instrs(up, EmqxAppVsns, CurrRelVsn, UpVsnRUs), - inject_relup_instrs(down, EmqxAppVsns, CurrRelVsn, DnVsnRUs)}, + inject_relup_instrs(up, UpVsnRUs), + inject_relup_instrs(down, DnVsnRUs)}, file:write_file(File, term_to_text(UpdatedContent)); {ok, _BadFormat} -> ?ERROR("bad formatted relup file: ~p", [File]), @@ -48,101 +41,77 @@ inject_file(File, EmqxAppVsns) -> error({read_relup_error, Reason}) end. -inject_relup_instrs(Type, EmqxAppVsns, CurrRelVsn, RUs) -> - lists:map(fun - ({Vsn, "(relup-injected) " ++ _ = Desc, Instrs}) -> %% already injected - {Vsn, Desc, Instrs}; - ({Vsn, Desc, Instrs}) -> - {Vsn, "(relup-injected) " ++ Desc, - append_emqx_relup_instrs(Type, EmqxAppVsns, CurrRelVsn, Vsn, Instrs)} +inject_relup_instrs(Type, RUs) -> + lists:map(fun({Vsn, Desc, Instrs}) -> + {Vsn, Desc, append_emqx_relup_instrs(Type, Vsn, Instrs)} end, RUs). %% The `{apply, emqx_relup, post_release_upgrade, []}` will be appended to the end of %% the instruction lists. -append_emqx_relup_instrs(up, EmqxAppVsns, CurrRelVsn, FromRelVsn, Instrs0) -> - {EmqxVsn, true} = maps:get(CurrRelVsn, EmqxAppVsns), +append_emqx_relup_instrs(up, FromRelVsn, Instrs0) -> Extra = #{}, %% we may need some extended args - LoadObjEmqxMods = {load_object_code, {emqx, EmqxVsn, [emqx_relup, emqx_app]}}, - LoadCodeEmqxRelup = {load, {emqx_relup, brutal_purge, soft_purge}}, - LoadCodeEmqxApp = {load, {emqx_app, brutal_purge, soft_purge}}, - ApplyEmqxRelup = {apply, {emqx_relup, post_release_upgrade, [FromRelVsn, Extra]}}, - Instrs1 = Instrs0 -- [LoadCodeEmqxRelup, LoadCodeEmqxApp], - %% we have to put 'load_object_code' before 'point_of_no_return' - %% so here we simply put them to the beginning of the instruction list - Instrs2 = [ LoadObjEmqxMods - | Instrs1], - %% the `load` must be put after the 'point_of_no_return' - Instrs2 ++ - [ LoadCodeEmqxRelup - , LoadCodeEmqxApp - , ApplyEmqxRelup + filter_and_check_instrs(up, Instrs0) ++ + [ {load, {emqx_app, brutal_purge, soft_purge}} + , {load, {emqx_relup, brutal_purge, soft_purge}} + , {apply, {emqx_relup, post_release_upgrade, [FromRelVsn, Extra]}} ]; -append_emqx_relup_instrs(down, EmqxAppVsns, _CurrRelVsn, ToRelVsn, Instrs0) -> +append_emqx_relup_instrs(down, ToRelVsn, Instrs0) -> Extra = #{}, %% we may need some extended args - ApplyEmqxRelup = {apply, {emqx_relup, post_release_downgrade, [ToRelVsn, Extra]}}, - case maps:get(ToRelVsn, EmqxAppVsns) of - {EmqxVsn, true} -> - LoadObjEmqxMods = {load_object_code, {emqx, EmqxVsn, [emqx_relup, emqx_app]}}, - LoadCodeEmqxRelup = {load, {emqx_relup, brutal_purge, soft_purge}}, - LoadCodeEmqxApp = {load, {emqx_app, brutal_purge, soft_purge}}, - Instrs1 = Instrs0 -- [LoadCodeEmqxRelup, LoadCodeEmqxApp, ApplyEmqxRelup], - Instrs2 = [ LoadObjEmqxMods - | Instrs1], - %% NOTE: We apply emqx_relup:post_release_downgrade/2 first, and then reload - %% the old vsn code of emqx_relup. - Instrs2 ++ - [ LoadCodeEmqxApp - , ApplyEmqxRelup - , LoadCodeEmqxRelup - ]; - {EmqxVsn, false} -> - LoadObjEmqxApp = {load_object_code, {emqx, EmqxVsn, [emqx_app]}}, - LoadCodeEmqxApp = {load, {emqx_app, brutal_purge, soft_purge}}, - RemoveCodeEmqxRelup = {remove, {emqx_relup, brutal_purge, soft_purge}}, - Instrs1 = Instrs0 -- [LoadCodeEmqxApp, RemoveCodeEmqxRelup, ApplyEmqxRelup], - Instrs2 = [ LoadObjEmqxApp - | Instrs1], - Instrs2 ++ - [ LoadCodeEmqxApp - , ApplyEmqxRelup - , RemoveCodeEmqxRelup - ] + %% NOTE: When downgrading, we apply emqx_relup:post_release_downgrade/2 before reloading + %% or removing the emqx_relup module. + Instrs1 = filter_and_check_instrs(down, Instrs0) ++ + [ {load, {emqx_app, brutal_purge, soft_purge}} + , {apply, {emqx_relup, post_release_downgrade, [ToRelVsn, Extra]}} + ], + %% emqx_relup does not exist before release "4.4.2" + LoadInsts = + case ToRelVsn of + ToRelVsn when ToRelVsn =:= "4.4.1"; ToRelVsn =:= "4.4.0" -> + [{remove, {emqx_relup, brutal_purge, brutal_purge}}]; + _ -> + [{load, {emqx_relup, brutal_purge, soft_purge}}] + end, + Instrs1 ++ LoadInsts. + +filter_and_check_instrs(Type, Instrs) -> + case take_emqx_vsn_and_modules(Instrs) of + {EmqxAppVsn, EmqxMods, RemainInstrs} when EmqxAppVsn =/= not_found, EmqxMods =/= [] -> + assert_mandatory_modules(Type, EmqxMods), + [{load_object_code, {emqx, EmqxAppVsn, EmqxMods}} | RemainInstrs]; + {_, _, _} -> + ?ERROR("cannot found 'load_module' instructions for app emqx", []), + error({instruction_not_found, load_object_code}) end. -get_emqx_app_vsns(RelRootDir) -> - RelFiles = filelib:wildcard(filename:join([RelRootDir, "releases", "*", "emqx.rel"])), - lists:foldl(fun(RelFile, AppVsns) -> - {ok, RelVsn, EmqxVsn} = read_emqx_vsn_from_rel_file(RelFile), - AppVsns#{RelVsn => {EmqxVsn, has_relup_module(RelRootDir, EmqxVsn)}} - end, #{}, RelFiles). +take_emqx_vsn_and_modules(Instrs) -> + lists:foldl(fun + ({load_object_code, {emqx, AppVsn, Mods}}, {_EmqxAppVsn, EmqxMods, RemainInstrs}) -> + {AppVsn, EmqxMods ++ Mods, RemainInstrs}; + ({load, {Mod, _, _}}, {EmqxAppVsn, EmqxMods, RemainInstrs}) + when Mod =:= emqx_relup; Mod =:= emqx_app -> + {EmqxAppVsn, EmqxMods, RemainInstrs}; + ({remove, {emqx_relup, _, _}}, {EmqxAppVsn, EmqxMods, RemainInstrs}) -> + {EmqxAppVsn, EmqxMods, RemainInstrs}; + ({apply, {emqx_relup, _, _}}, {EmqxAppVsn, EmqxMods, RemainInstrs}) -> + {EmqxAppVsn, EmqxMods, RemainInstrs}; + (Instr, {EmqxAppVsn, EmqxMods, RemainInstrs}) -> + {EmqxAppVsn, EmqxMods, RemainInstrs ++ [Instr]} + end, {not_found, [], []}, Instrs). -read_emqx_vsn_from_rel_file(RelFile) -> - case file:script(RelFile) of - {ok, {release, {_RelName, RelVsn}, _Erts, Apps}} -> - case lists:keysearch(emqx, 1, Apps) of - {value, {emqx, EmqxVsn}} -> - {ok, RelVsn, EmqxVsn}; - false -> - error({emqx_vsn_cannot_found, RelFile}) - end; - {ok, _BadFormat} -> - ?ERROR("bad formatted .rel file: ~p", [RelFile]); - {error, Reason} -> - ?ERROR("read .rel file ~p failed: ~p", [RelFile, Reason]) - end. +assert_mandatory_modules(up, Mods) -> + assert(lists:member(emqx_relup, Mods) andalso lists:member(emqx_app, Mods), + "cannot found 'load_module' instructions for emqx_app and emqx_rel: ~p", [Mods]); -has_relup_module(RelRootDir, EmqxVsn) -> - AppFile = filename:join([RelRootDir, "lib", "emqx-" ++ EmqxVsn, "ebin", "emqx.app"]), - case file:script(AppFile) of - {ok, {application, emqx, AppInfo}} -> - {value, {_, EmqxVsn}} = lists:keysearch(vsn, 1, AppInfo), %% assert - {value, {_, Modules}} = lists:keysearch(modules, 1, AppInfo), - lists:member(emqx_relup, Modules); - {error, Reason} -> - ?ERROR("read .app file ~p failed: ~p", [AppFile, Reason]), - error({read_app_file_error, AppFile, Reason}) - end. +assert_mandatory_modules(down, Mods) -> + assert(lists:member(emqx_app, Mods), + "cannot found 'load_module' instructions for emqx_app", []). + +assert(true, _, _) -> + ok; +assert(false, Msg, Args) -> + ?ERROR(Msg, Args), + error(assert_failed). term_to_text(Term) -> io_lib:format("~p.", [Term]). diff --git a/src/emqx.appup.src b/src/emqx.appup.src index b9d4f5a16..53b4a9ff7 100644 --- a/src/emqx.appup.src +++ b/src/emqx.appup.src @@ -1,7 +1,9 @@ %% -*- mode: erlang -*- {VSN, [{"4.4.1", - [{load_module,emqx_os_mon,brutal_purge,soft_purge,[]}, + [{load_module,emqx_app,brutal_purge,soft_purge,[]}, + {add_module,emqx_relup}, + {load_module,emqx_os_mon,brutal_purge,soft_purge,[]}, {load_module,emqx_pmon,brutal_purge,soft_purge,[]}, {load_module,emqx_cm,brutal_purge,soft_purge,[]}, {load_module,emqx_sys_mon,brutal_purge,soft_purge,[]}, @@ -10,7 +12,8 @@ {load_module,emqx_ctl,brutal_purge,soft_purge,[]}, {load_module,emqx_channel,brutal_purge,soft_purge,[]}]}, {"4.4.0", - [{load_module,emqx_pmon,brutal_purge,soft_purge,[]}, + [{add_module,emqx_relup}, + {load_module,emqx_pmon,brutal_purge,soft_purge,[]}, {load_module,emqx_cm,brutal_purge,soft_purge,[]}, {load_module,emqx_sys_mon,brutal_purge,soft_purge,[]}, {load_module,emqx_vm_mon,brutal_purge,soft_purge,[]}, @@ -31,7 +34,9 @@ {load_module,emqx_limiter,brutal_purge,soft_purge,[]}]}, {<<".*">>,[]}], [{"4.4.1", - [{load_module,emqx_os_mon,brutal_purge,soft_purge,[]}, + [{load_module,emqx_app,brutal_purge,soft_purge,[]}, + {delete_module,emqx_relup}, + {load_module,emqx_os_mon,brutal_purge,soft_purge,[]}, {load_module,emqx_pmon,brutal_purge,soft_purge,[]}, {load_module,emqx_cm,brutal_purge,soft_purge,[]}, {load_module,emqx_sys_mon,brutal_purge,soft_purge,[]}, @@ -40,7 +45,8 @@ {load_module,emqx_ctl,brutal_purge,soft_purge,[]}, {load_module,emqx_channel,brutal_purge,soft_purge,[]}]}, {"4.4.0", - [{load_module,emqx_pmon,brutal_purge,soft_purge,[]}, + [{delete_module,emqx_relup}, + {load_module,emqx_pmon,brutal_purge,soft_purge,[]}, {load_module,emqx_cm,brutal_purge,soft_purge,[]}, {load_module,emqx_sys_mon,brutal_purge,soft_purge,[]}, {load_module,emqx_vm_mon,brutal_purge,soft_purge,[]}, diff --git a/src/emqx_relup.erl b/src/emqx_relup.erl index cb71c6305..dc443947a 100644 --- a/src/emqx_relup.erl +++ b/src/emqx_relup.erl @@ -1,5 +1,25 @@ +%%-------------------------------------------------------------------- +%% Copyright (c) 2017-2021 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_relup). +%% NOTE: DO NOT remove this `-include`. +%% We use this to forece this module to upgraded every release. +-include("emqx_release.hrl"). + -export([ post_release_upgrade/2 , post_release_downgrade/2 ]). @@ -8,13 +28,15 @@ -define(INFO(FORMAT, ARGS), io:format("[emqx_relup] " ++ FORMAT ++ "~n", ARGS)). %% what to do after upgraded from a old release vsn. -post_release_upgrade(_FromRelVsn, _) -> - ?INFO("emqx has been upgraded to ~s", [emqx_app:get_release()]), +post_release_upgrade(FromRelVsn, _) -> + {_, CurrRelVsn} = ?EMQX_RELEASE, + ?INFO("emqx has been upgraded to from ~s to ~s!", [FromRelVsn, CurrRelVsn]), reload_components(). %% what to do after downgraded to a old release vsn. -post_release_downgrade(_ToRelVsn, _) -> - ?INFO("emqx has been downgrade to ~s", [emqx_app:get_release()]), +post_release_downgrade(ToRelVsn, _) -> + {_, CurrRelVsn} = ?EMQX_RELEASE, + ?INFO("emqx has been downgraded to from ~s to ~s!", [CurrRelVsn, ToRelVsn]), reload_components(). -ifdef(EMQX_ENTERPRISE).