fix(relup): download to 4.4.0 failed with error bad_lib_vsn

This commit is contained in:
Shawn 2022-03-01 01:58:55 +08:00
parent bcd56d3db2
commit a7791b6c58
3 changed files with 112 additions and 75 deletions

View File

@ -129,7 +129,7 @@ prod_overrides() ->
[{add, [ {erl_opts, [deterministic]}]}]. [{add, [ {erl_opts, [deterministic]}]}].
relup_deps(Profile, Vsn) -> relup_deps(Profile, Vsn) ->
InjectCmd = "scripts/inject-relup.escript " ++ filename:join(["_build", Profile, "rel", "emqx", "releases", Vsn]), InjectCmd = "scripts/inject-relup.escript " ++ filename:join(["_build", Profile, "rel", "emqx"]) ++ " " ++ Vsn,
{post_hooks, {post_hooks,
[ {"(linux|darwin|solaris|freebsd|netbsd|openbsd)", relup, InjectCmd} [ {"(linux|darwin|solaris|freebsd|netbsd|openbsd)", relup, InjectCmd}
] ]

View File

@ -4,88 +4,123 @@
-mode(compile). -mode(compile).
-define(ERROR(FORMAT, ARGS), io:format(standard_error, "[inject-relup] " ++ FORMAT ++"~n", ARGS)). -define(ERROR(FORMAT, ARGS), io:format(standard_error, "[inject-relup] " ++ FORMAT ++ "~n", ARGS)).
-define(INFO(FORMAT, ARGS), io:format(user, "[inject-relup] " ++ FORMAT ++"~n", ARGS)). -define(INFO(FORMAT, ARGS), io:format(user, "[inject-relup] " ++ FORMAT ++ "~n", ARGS)).
usage() -> usage() ->
"Usage: " ++ escript:script_name() ++ " <path-to-relup-file-or-dir>". "Usage: " ++ escript:script_name() ++ " <path-to-release-dir> <release-vsn>".
main([DirOrFile]) -> main([RelRootDir, CurrRelVsn]) ->
case filelib:is_dir(DirOrFile) of case filelib:is_dir(filename:join([RelRootDir, "releases"])) andalso
true -> ok = inject_dir(DirOrFile); filelib:is_dir(filename:join([RelRootDir, "lib"])) of
false -> true ->
case filelib:is_regular(DirOrFile) of EmqxAppVsns = get_emqx_app_vsns(RelRootDir),
true -> inject_file(DirOrFile); ok = inject_relup_file(RelRootDir, CurrRelVsn, EmqxAppVsns);
false -> false ->
?ERROR("not a valid file: ~p", [DirOrFile]), ?ERROR("not a valid root dir of release: ~p, for example: _build/emqx/rel/emqx",
erlang:halt(1) [RelRootDir]),
end erlang:halt(1)
end; end;
main(_Args) -> main(_Args) ->
?ERROR("~s", [usage()]), ?ERROR("~s", [usage()]),
erlang:halt(1). erlang:halt(1).
inject_dir(Dir) -> inject_relup_file(RelRootDir, CurrRelVsn, EmqxAppVsns) ->
RelupFiles = filelib:wildcard(filename:join([Dir, "**", "relup"])), RelupFile = filename:join([RelRootDir, "releases", CurrRelVsn, "relup"]),
lists:foreach(fun inject_file/1, RelupFiles). inject_file(RelupFile, EmqxAppVsns).
inject_file(File) -> inject_file(File, EmqxAppVsns) ->
EmqxVsn = emqx_vsn_from_rel_file(File), case file:script(File) of
case file:script(File) of {ok, {CurrRelVsn, UpVsnRUs, DnVsnRUs}} ->
{ok, {CurrRelVsn, UpVsnRUs, DnVsnRUs}} -> ?INFO("injecting instructions to: ~p", [File]),
?INFO("injecting instructions to: ~p", [File]), UpdatedContent = {CurrRelVsn,
UpdatedContent = {CurrRelVsn, inject_relup_instrs(up, EmqxVsn, CurrRelVsn, UpVsnRUs), inject_relup_instrs(up, EmqxAppVsns, CurrRelVsn, UpVsnRUs),
inject_relup_instrs(down, EmqxVsn, CurrRelVsn, DnVsnRUs)}, inject_relup_instrs(down, EmqxAppVsns, CurrRelVsn, DnVsnRUs)},
ok = file:write_file(File, term_to_text(UpdatedContent)); file:write_file(File, term_to_text(UpdatedContent));
{ok, _BadFormat} -> {ok, _BadFormat} ->
?ERROR("bad formatted relup file: ~p", [File]), ?ERROR("bad formatted relup file: ~p", [File]),
error({bad_relup_format, File}); error({bad_relup_format, File});
{error, Reason} -> {error, enoent} ->
?ERROR("read relup file ~p failed: ~p", [File, Reason]), ?INFO("relup file not found: ~p", [File]),
error({read_relup_error, Reason}) ok;
end. {error, Reason} ->
?ERROR("read relup file ~p failed: ~p", [File, Reason]),
error({read_relup_error, Reason})
end.
inject_relup_instrs(Type, EmqxVsn, CurrRelVsn, RUs) -> inject_relup_instrs(Type, EmqxAppVsns, CurrRelVsn, RUs) ->
[{Vsn, Desc, append_emqx_relup_instrs(Type, EmqxVsn, CurrRelVsn, Vsn, Instrs)} lists:map(fun
|| {Vsn, Desc, Instrs} <- RUs]. ({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)}
end, RUs).
%% The `{apply, emqx_relup, post_release_upgrade, []}` will be appended to the end of %% The `{apply, emqx_relup, post_release_upgrade, []}` will be appended to the end of
%% the instruction lists. %% the instruction lists.
append_emqx_relup_instrs(Type, EmqxVsn, CurrRelVsn, Vsn, Instrs) -> append_emqx_relup_instrs(up, EmqxAppVsns, CurrRelVsn, FromRelVsn, Instrs) ->
CallbackFun = relup_callback_func(Type), {EmqxVsn, true} = maps:get(CurrRelVsn, EmqxAppVsns),
Extra = #{}, %% we may need some extended args Extra = #{}, %% we may need some extended args
case lists:reverse(Instrs) of %% we have to put 'load_object_code' before 'point_of_no_return'
[{apply, {emqx_relup, CallbackFun, _}} | _] -> %% so here we simply put it to the beginning
Instrs; Instrs0 = [ {load_object_code, {emqx, EmqxVsn, [emqx_relup]}}
RInstrs -> | Instrs],
Instrs2 = lists:reverse( Instrs0 ++
[ {apply, {emqx_relup, CallbackFun, [CurrRelVsn, Vsn, Extra]}} [ {load, {emqx_relup, brutal_purge, soft_purge}}
, {load, {emqx_relup, brutal_purge, soft_purge}} , {apply, {emqx_relup, post_release_upgrade, [FromRelVsn, Extra]}}
| RInstrs]), ];
%% we have to put 'load_object_code' before 'point_of_no_return'
%% so here we simply put it to the beginning
[{load_object_code, {emqx, EmqxVsn, [emqx_relup]}} | Instrs2]
end.
relup_callback_func(up) -> post_release_upgrade; append_emqx_relup_instrs(down, EmqxAppVsns, _CurrRelVsn, ToRelVsn, Instrs) ->
relup_callback_func(down) -> post_release_downgrade. Extra = #{}, %% we may need some extended args
case maps:get(ToRelVsn, EmqxAppVsns) of
{EmqxVsn, true} ->
Instrs0 = [ {load_object_code, {emqx, EmqxVsn, [emqx_relup]}}
| Instrs],
Instrs0 ++
[ {apply, {emqx_relup, post_release_downgrade, [ToRelVsn, Extra]}}
, {load, {emqx_relup, brutal_purge, soft_purge}}
];
{_EmqxVsn, false} ->
Instrs ++
[ {apply, {emqx_relup, post_release_downgrade, [ToRelVsn, Extra]}}
, {remove, {emqx_relup, brutal_purge, soft_purge}}
]
end.
emqx_vsn_from_rel_file(RelupFile) -> get_emqx_app_vsns(RelRootDir) ->
RelDir = filename:dirname(RelupFile), RelFiles = filelib:wildcard(filename:join([RelRootDir, "releases", "*", "emqx.rel"])),
RelFile = filename:join([RelDir, "emqx.rel"]), lists:foldl(fun(RelFile, AppVsns) ->
case file:script(RelFile) of {ok, RelVsn, EmqxVsn} = read_emqx_vsn_from_rel_file(RelFile),
{ok, {release, {_RelName, _RelVsn}, _Erts, Apps}} -> AppVsns#{RelVsn => {EmqxVsn, has_relup_module(RelRootDir, EmqxVsn)}}
case lists:keysearch(emqx, 1, Apps) of end, #{}, RelFiles).
{value, {emqx, EmqxVsn}} ->
EmqxVsn; read_emqx_vsn_from_rel_file(RelFile) ->
false -> case file:script(RelFile) of
error({emqx_vsn_cannot_found, RelFile}) {ok, {release, {_RelName, RelVsn}, _Erts, Apps}} ->
end; case lists:keysearch(emqx, 1, Apps) of
{ok, _BadFormat} -> {value, {emqx, EmqxVsn}} ->
?ERROR("bad formatted .rel file: ~p", [RelFile]); {ok, RelVsn, EmqxVsn};
{error, Reason} -> false ->
?ERROR("read .rel file ~p failed: ~p", [RelFile, Reason]) error({emqx_vsn_cannot_found, RelFile})
end. end;
{ok, _BadFormat} ->
?ERROR("bad formatted .rel file: ~p", [RelFile]);
{error, Reason} ->
?ERROR("read .rel file ~p failed: ~p", [RelFile, Reason])
end.
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.
term_to_text(Term) -> term_to_text(Term) ->
io_lib:format("~p.", [Term]). io_lib:format("~p.", [Term]).

View File

@ -1,13 +1,15 @@
-module(emqx_relup). -module(emqx_relup).
-export([ post_release_upgrade/3 -export([ post_release_upgrade/2
, post_release_downgrade/3 , post_release_downgrade/2
]). ]).
post_release_upgrade(_CurrRelVsn, _FromVsn, _) -> %% what to do after upgraded from a old release vsn.
post_release_upgrade(_FromRelVsn, _) ->
reload_components(). reload_components().
post_release_downgrade(_CurrRelVsn, _ToVsn, _) -> %% what to do after downgraded to a old release vsn.
post_release_downgrade(_ToRelVsn, _) ->
reload_components(). reload_components().
-ifdef(EMQX_ENTERPRISE). -ifdef(EMQX_ENTERPRISE).