diff options
author | Lukas Larsson <lukas@erlang.org> | 2021-12-22 11:08:33 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-12-22 11:08:33 +0100 |
commit | bfee11fb893266a9476e0e44b637862b2fd1a8dd (patch) | |
tree | 335c29188cca06a4cd83af9fdc081bafee14f246 /lib/sasl | |
parent | d2e67fa7faab2761283db0f8e4d9f12f1d47c74c (diff) | |
parent | 29a7158d57556183fc209ea4115c39d41c0fa326 (diff) | |
download | erlang-bfee11fb893266a9476e0e44b637862b2fd1a8dd.tar.gz |
Merge pull request #5427 from kjellwinblad/kjell/erl/make_installation_location_independentR/OTP-17304
Make Erlang installation file system location independent
Diffstat (limited to 'lib/sasl')
18 files changed, 607 insertions, 89 deletions
diff --git a/lib/sasl/doc/src/release_handler.xml b/lib/sasl/doc/src/release_handler.xml index 55ec4cdb0f..ca6ddd7130 100644 --- a/lib/sasl/doc/src/release_handler.xml +++ b/lib/sasl/doc/src/release_handler.xml @@ -202,6 +202,7 @@ </func> <func> + <name since="OTP @OTP-17730@">create_RELEASES(RelDir, RelFile, AppDirs) -> ok | {error, Reason}</name> <name since="">create_RELEASES(Root, RelDir, RelFile, AppDirs) -> ok | {error, Reason}</name> <fsummary>Creates an initial <c>RELEASES</c> file.</fsummary> <type> @@ -215,12 +216,19 @@ <p>Creates an initial <c>RELEASES</c> file to be used by the release handler. This file must exist to install new releases.</p> - <p><c>Root</c> is the root of the installation (<c>$ROOT</c>) as - described earlier. <c>RelDir</c> is the directory where - the <c>RELEASES</c> file is to be created (normally - <c>$ROOT/releases</c>). <c>RelFile</c> is the name - of the <c>.rel</c> file that describes the initial release, - including the extension <c>.rel</c>.</p> + <p><c>Root</c> is the root of the installation (<c>$ROOT</c>) + as described earlier. <c>RelDir</c> is the directory where the + <c>RELEASES</c> file is to be created (normally + <c>$ROOT/releases</c>). <c>RelFile</c> is the name of the + <c>.rel</c> file that describes the initial release, including + the extension <c>.rel</c>. If <c>Root</c> is not given, + the <c>RELEASES</c> file will be location independent (i.e, it + will not contain absolute paths unless there are absolute + paths in <c>AppDirs</c>). A <c>RELEASES</c> file should be + made location independent if the installation's <c>$ROOT</c> + is unknown. The <c>release_handler</c> module will interpret + relative paths in a running system's <c>RELEASES</c> file as + being relative to <c>$ROOT</c>.</p> <p><c>AppDirs</c> can be used to specify from where the modules for the specified applications are to be loaded. <c>App</c> is the name of an application, <c>Vsn</c> is the version, and diff --git a/lib/sasl/examples/src/target_system.erl b/lib/sasl/examples/src/target_system.erl index b3d6748306..09c9e5254a 100644 --- a/lib/sasl/examples/src/target_system.erl +++ b/lib/sasl/examples/src/target_system.erl @@ -35,9 +35,9 @@ create(RelFileName,SystoolsOpts) -> Dir = filename:dirname(RelFileName), PlainRelFileName = filename:join(Dir,"plain"), PlainRelFile = PlainRelFileName ++ ".rel", - io:fwrite("Reading file: ~tp ...~n", [RelFile]), + io:fwrite("Reading file: ~ts ...~n", [RelFile]), {ok, [RelSpec]} = file:consult(RelFile), - io:fwrite("Creating file: ~tp from ~tp ...~n", + io:fwrite("Creating file: ~ts from ~ts ...~n", [PlainRelFile, RelFile]), {release, {RelName, RelVsn}, @@ -67,32 +67,32 @@ create(RelFileName,SystoolsOpts) -> make_script(RelFileName,SystoolsOpts), TarFileName = RelFileName ++ ".tar.gz", - io:fwrite("Creating tar file ~tp ...~n", [TarFileName]), + io:fwrite("Creating tar file ~ts ...~n", [TarFileName]), make_tar(RelFileName,SystoolsOpts), TmpDir = filename:join(Dir,"tmp"), io:fwrite("Creating directory ~tp ...~n",[TmpDir]), file:make_dir(TmpDir), - io:fwrite("Extracting ~tp into directory ~tp ...~n", [TarFileName,TmpDir]), + io:fwrite("Extracting ~ts into directory ~ts ...~n", [TarFileName,TmpDir]), extract_tar(TarFileName, TmpDir), TmpBinDir = filename:join([TmpDir, "bin"]), ErtsBinDir = filename:join([TmpDir, "erts-" ++ ErtsVsn, "bin"]), - io:fwrite("Deleting \"erl\" and \"start\" in directory ~tp ...~n", + io:fwrite("Deleting \"erl\" and \"start\" in directory ~ts ...~n", [ErtsBinDir]), file:delete(filename:join([ErtsBinDir, "erl"])), file:delete(filename:join([ErtsBinDir, "start"])), - io:fwrite("Creating temporary directory ~tp ...~n", [TmpBinDir]), + io:fwrite("Creating temporary directory ~ts ...~n", [TmpBinDir]), file:make_dir(TmpBinDir), - io:fwrite("Copying file \"~ts.boot\" to ~tp ...~n", + io:fwrite("Copying file \"~ts.boot\" to ~ts ...~n", [PlainRelFileName, filename:join([TmpBinDir, "start.boot"])]), copy_file(PlainRelFileName++".boot",filename:join([TmpBinDir, "start.boot"])), io:fwrite("Copying files \"epmd\", \"run_erl\" and \"to_erl\" from \n" - "~tp to ~tp ...~n", + "~ts to ~ts ...~n", [ErtsBinDir, TmpBinDir]), copy_file(filename:join([ErtsBinDir, "epmd"]), filename:join([TmpBinDir, "epmd"]), [preserve]), @@ -104,15 +104,15 @@ create(RelFileName,SystoolsOpts) -> %% This is needed if 'start' script created from 'start.src' shall %% be used as it points out this directory as log dir for 'run_erl' TmpLogDir = filename:join([TmpDir, "log"]), - io:fwrite("Creating temporary directory ~tp ...~n", [TmpLogDir]), + io:fwrite("Creating temporary directory ~ts ...~n", [TmpLogDir]), ok = file:make_dir(TmpLogDir), StartErlDataFile = filename:join([TmpDir, "releases", "start_erl.data"]), - io:fwrite("Creating ~tp ...~n", [StartErlDataFile]), + io:fwrite("Creating ~ts ...~n", [StartErlDataFile]), StartErlData = io_lib:fwrite("~s ~s~n", [ErtsVsn, RelVsn]), write_file(StartErlDataFile, StartErlData), - io:fwrite("Recreating tar file ~tp from contents in directory ~tp ...~n", + io:fwrite("Recreating tar file ~ts from contents in directory ~ts ...~n", [TarFileName,TmpDir]), {ok, Tar} = erl_tar:open(TarFileName, [write, compressed]), %% {ok, Cwd} = file:get_cwd(), @@ -125,14 +125,14 @@ create(RelFileName,SystoolsOpts) -> erl_tar:add(Tar, filename:join(TmpDir,"log"), "log", []), erl_tar:close(Tar), %% file:set_cwd(Cwd), - io:fwrite("Removing directory ~tp ...~n",[TmpDir]), + io:fwrite("Removing directory ~ts ...~n",[TmpDir]), remove_dir_tree(TmpDir), ok. install(RelFileName, RootDir) -> TarFile = RelFileName ++ ".tar.gz", - io:fwrite("Extracting ~tp ...~n", [TarFile]), + io:fwrite("Extracting ~ts ...~n", [TarFile]), extract_tar(TarFile, RootDir), StartErlDataFile = filename:join([RootDir, "releases", "start_erl.data"]), {ok, StartErlData} = read_txt_file(StartErlDataFile), diff --git a/lib/sasl/src/release_handler.erl b/lib/sasl/src/release_handler.erl index c3053ef84e..3313f08ff0 100644 --- a/lib/sasl/src/release_handler.erl +++ b/lib/sasl/src/release_handler.erl @@ -24,7 +24,7 @@ %% External exports -export([start_link/0, - create_RELEASES/1, create_RELEASES/2, create_RELEASES/4, + create_RELEASES/1, create_RELEASES/2, create_RELEASES/3, create_RELEASES/4, unpack_release/1, check_install_release/1, check_install_release/2, install_release/1, install_release/2, new_emulator_upgrade/2, @@ -43,7 +43,13 @@ -export([do_write_release/3, do_copy_file/2, do_copy_files/2, do_copy_files/1, do_rename_files/1, do_remove_files/1, remove_file/1, do_write_file/2, do_write_file/3, - do_ensure_RELEASES/1]). + do_ensure_RELEASES/1, + consult/2, + root_dir_relative_read_file_info/1, + root_dir_relative_read_file/1, + root_dir_relative_rename_file/2, + root_dir_relative_make_dir/1, + root_dir_relative_ensure_dir/1]). -record(state, {unpurged = [], root, @@ -378,6 +384,8 @@ create_RELEASES([Root, RelFile | LibDirs]) -> create_RELEASES(Root, RelFile) -> create_RELEASES(Root, filename:join(Root, "releases"), RelFile, []). +create_RELEASES(RelDir, RelFile, LibDirs) -> + create_RELEASES("", RelDir, RelFile, LibDirs). create_RELEASES(Root, RelDir, RelFile, LibDirs) -> case catch check_rel(Root, RelFile, LibDirs, false) of {error, Reason } -> @@ -397,7 +405,8 @@ create_RELEASES(Root, RelDir, RelFile, LibDirs) -> %% located under Dir/ebin %% Purpose: Upgrade to the version in Dir according to an appup file %%----------------------------------------------------------------- -upgrade_app(App, NewDir) -> +upgrade_app(App, NewDir1) -> + NewDir = root_dir_relative_path(NewDir1), try upgrade_script(App, NewDir) of {ok, NewVsn, Script} -> eval_appup_script(App, NewVsn, NewDir, Script) @@ -435,7 +444,8 @@ downgrade_app(App, OldVsn, OldDir) -> {error, Reason} end. -upgrade_script(App, NewDir) -> +upgrade_script(App, NewDir1) -> + NewDir = root_dir_relative_path(NewDir1), OldVsn = ensure_running(App), OldDir = code:lib_dir(App), {NewVsn, Script} = find_script(App, NewDir, OldVsn, up), @@ -489,7 +499,8 @@ ensure_running(App) -> end. find_script(App, Dir, OldVsn, UpOrDown) -> - Appup = filename:join([Dir, "ebin", atom_to_list(App)++".appup"]), + Appup1 = filename:join([Dir, "ebin", atom_to_list(App)++".appup"]), + Appup = root_dir_relative_path(Appup1), case file:consult(Appup) of {ok, [{NewVsn, UpFromScripts, DownToScripts}]} -> Scripts = case UpOrDown of @@ -522,7 +533,7 @@ read_app(App, Vsn, Dir) -> read_appspec(App, Dir) -> AppS = atom_to_list(App), - Path = [filename:join(Dir, "ebin")], + Path = [root_dir_relative_path(filename:join(Dir, "ebin"))], case file:path_consult(Path, AppS++".app") of {ok, AppSpecL, _File} -> AppSpecL; @@ -833,7 +844,9 @@ do_unpack_release(Root, RelDir, ReleaseName, Releases) -> Rel = ReleaseName ++ ".rel", _ = extract_rel_file(filename:join("releases", Rel), Tar, Root), RelFile = filename:join(RelDir, Rel), - Release = check_rel(Root, RelFile, false), + %% Send an empty string as Root as the library locations should + %% appear as paths relative to the root + Release = check_rel("", RelFile, false), #release{vsn = Vsn} = Release, case lists:keysearch(Vsn, #release.vsn, Releases) of {value, _} -> throw({error, {existing_release, Vsn}}); @@ -850,8 +863,8 @@ do_unpack_release(Root, RelDir, ReleaseName, Releases) -> copy_file(RelFile, Dir, false), %% Clean release - _ = file:delete(Tar), - _ = file:delete(RelFile), + _ = root_dir_relative_file_delete(Tar), + _ = root_dir_relative_file_delete(RelFile), {ok, NewReleases, Vsn}. @@ -883,7 +896,19 @@ check_rel_data({release, {Name, Vsn}, {erts, EVsn}, Libs}, Root, LibDirs, check_path(Path, Masters), Path; _ -> - filename:join([Root, "lib", LibName]) + %% If Root is an empty string, + %% we assume that the path is + %% relative to code:root_dir() + %% and save a relative + %% path. This is done to make it + %% easy to create a relocatable + %% RELEASES file. + case string:length(Root) of + 0 -> + filename:join("lib", LibName); + _ -> + filename:join([Root, "lib", LibName]) + end end, {Lib, LibVsn, LibDir} end, @@ -894,7 +919,7 @@ check_rel_data(RelData, _Root, _LibDirs, _Masters) -> throw({error, {bad_rel_data, RelData}}). check_path(Path) -> - check_path_response(Path, file:read_file_info(Path)). + check_path_response(Path, root_dir_relative_read_file_info(Path)). check_path(Path, false) -> check_path(Path); check_path(Path, Masters) -> check_path_master(Masters, Path). @@ -904,7 +929,7 @@ check_path(Path, Masters) -> check_path_master(Masters, Path). %% at one node it should not exist at any other node either. %%----------------------------------------------------------------- check_path_master([Master|Ms], Path) -> - case rpc:call(Master, file, read_file_info, [Path]) of + case rpc:call(Master, ?MODULE, root_dir_relative_read_file_info, [Path]) of {badrpc, _} -> consult_master(Ms, Path); Res -> check_path_response(Path, Res) end; @@ -1573,14 +1598,14 @@ memlib(_Lib, []) -> false. %% recursively remove file or directory remove_file(File) -> - case file:read_link_info(File) of + case root_dir_relative_read_link_info(File) of {ok, Info} when Info#file_info.type==directory -> - case file:list_dir(File) of + case root_dir_relative_list_dir(File) of {ok, Files} -> lists:foreach(fun(File2) -> remove_file(filename:join(File,File2)) end, Files), - case file:del_dir(File) of + case root_dir_relative_dir_delete(File) of ok -> ok; {error, Reason} -> throw({error, Reason}) end; @@ -1588,7 +1613,7 @@ remove_file(File) -> throw({error, Reason}) end; {ok, _Info} -> - case file:delete(File) of + case root_dir_relative_file_delete(File) of ok -> ok; {error, Reason} -> throw({error, Reason}) end; @@ -1599,7 +1624,8 @@ remove_file(File) -> do_write_file(File, Str) -> do_write_file(File, Str, []). -do_write_file(File, Str, FileOpts) -> +do_write_file(File1, Str, FileOpts) -> + File = root_dir_relative_path(File1), case file:open(File, [write | FileOpts]) of {ok, Fd} -> io:put_chars(Fd, Str), @@ -1822,13 +1848,13 @@ check_file_masters(_FileName, _Type, []) -> %% Type == regular | directory do_check_file(FileName, Type) -> - case file:read_file_info(FileName) of + case root_dir_relative_read_file_info(FileName) of {ok, Info} when Info#file_info.type==Type -> ok; {error, _Reason} -> throw({error, {no_such_file, FileName}}) end. do_check_file(Master, FileName, Type) -> - case rpc:call(Master, file, read_file_info, [FileName]) of + case rpc:call(Master, ?MODULE, root_dir_relative_read_file_info, [FileName]) of {ok, Info} when Info#file_info.type==Type -> ok; _ -> throw({error, {no_such_file, {Master, FileName}}}) end. @@ -1871,7 +1897,8 @@ write_releases_1(Dir, NewReleases, Masters) -> write_releases_m(Dir, NewReleases, Masters). do_write_release(Dir, RELEASES, NewReleases) -> - case file:open(filename:join(Dir, RELEASES), [write,{encoding,utf8}]) of + ReleasesFile = root_dir_relative_path(filename:join(Dir, RELEASES)), + case file:open(ReleasesFile, [write,{encoding,utf8}]) of {ok, Fd} -> ok = io:format(Fd, "%% ~s~n~tp.~n", [epp:encoding_to_string(utf8),NewReleases]), @@ -1908,7 +1935,8 @@ write_releases_m(Dir, NewReleases, Masters) -> remove_files(all, [Backup, Change], Masters), ok; {error, {Master, R}} -> - takewhile(Master, Masters, file, rename, + takewhile(Master, Masters, ?MODULE, + root_dir_relative_rename_file, [Backup, RelFile]), remove_files(all, [Backup, Change], Masters), throw({error, {Master, R, move_releases}}) @@ -1959,9 +1987,9 @@ do_copy_file(File, Dir) -> do_copy_file1(File, File2). do_copy_file1(File, File2) -> - case file:read_file(File) of + case root_dir_relative_read_file(File) of {ok, Bin} -> - case file:write_file(File2, Bin) of + case root_dir_relative_write_file(File2, Bin) of ok -> ok; {error, Reason} -> {error, {Reason, File2}} @@ -1995,7 +2023,9 @@ do_copy_files([]) -> %%----------------------------------------------------------------- %% Rename each Src file to Dest file in the list of files. %%----------------------------------------------------------------- -do_rename_files([{Src, Dest}|Files]) -> +do_rename_files([{Src1, Dest1}|Files]) -> + Src = root_dir_relative_path(Src1), + Dest = root_dir_relative_path(Dest1), case file:rename(Src, Dest) of ok -> do_rename_files(Files); Error -> Error @@ -2007,7 +2037,7 @@ do_rename_files([]) -> %% Remove a list of files. Ignore failure. %%----------------------------------------------------------------- do_remove_files([File|Files]) -> - _ = file:delete(File), + _ = root_dir_relative_file_delete(File), do_remove_files(Files); do_remove_files([]) -> ok. @@ -2018,7 +2048,7 @@ do_remove_files([]) -> %% If not create an empty RELEASES file. %%----------------------------------------------------------------- do_ensure_RELEASES(RelFile) -> - case file:read_file_info(RelFile) of + case root_dir_relative_read_file_info(RelFile) of {ok, _} -> ok; _ -> do_write_file(RelFile, "[]. ") end. @@ -2026,11 +2056,16 @@ do_ensure_RELEASES(RelFile) -> %%----------------------------------------------------------------- %% Make a directory, ignore failures (captured later). %%----------------------------------------------------------------- -make_dir(Dir, false) -> +make_dir(Dir1, false) -> + Dir = root_dir_relative_path(Dir1), _ = file:make_dir(Dir), ok; make_dir(Dir, Masters) -> - lists:foreach(fun(Master) -> rpc:call(Master, file, make_dir, [Dir]) end, + lists:foreach(fun(Master) -> rpc:call(Master, + ?MODULE, + root_dir_relative_make_dir, + [Dir]) + end, Masters). %%----------------------------------------------------------------- @@ -2068,7 +2103,7 @@ takewhile(Master, Masters, M, F, A) -> end, Masters), ok. -consult(File, false) -> file:consult(File); +consult(File, false) -> file:consult(root_dir_relative_path(File)); consult(File, Masters) -> consult_master(Masters, File). %%----------------------------------------------------------------- @@ -2077,7 +2112,7 @@ consult(File, Masters) -> consult_master(Masters, File). %% not exist at any other node either. %%----------------------------------------------------------------- consult_master([Master|Ms], File) -> - case rpc:call(Master, file, consult, [File]) of + case rpc:call(Master, ?MODULE, consult, [File, false]) of {badrpc, _} -> consult_master(Ms, File); Res -> Res end; @@ -2085,12 +2120,12 @@ consult_master([], _File) -> {error, no_master}. read_file(File, false) -> - file:read_file(File); + root_dir_relative_read_file(File); read_file(File, Masters) -> read_master(Masters, File). write_file(File, Data, false) -> - case file:write_file(File, Data) of + case root_dir_relative_write_file(File, Data) of ok -> ok; Error -> throw(Error) end; @@ -2101,12 +2136,12 @@ write_file(File, Data, Masters) -> end. ensure_dir(File, false) -> - case filelib:ensure_dir(File) of + case root_dir_relative_ensure_dir(File) of ok -> ok; Error -> throw(Error) end; ensure_dir(File, Masters) -> - case at_all_masters(Masters,filelib,ensure_dir,[File]) of + case at_all_masters(Masters,?MODULE,root_dir_relative_ensure_dir,[File]) of ok -> ok; Error -> throw(Error) end. @@ -2130,7 +2165,7 @@ remove_files(Master, Files, Masters) -> %% not exist at any other node either. %%----------------------------------------------------------------- read_master([Master|Ms], File) -> - case rpc:call(Master, file, read_file, [File]) of + case rpc:call(Master, ?MODULE, root_dir_relative_read_file, [File]) of {badrpc, _} -> read_master(Ms, File); Res -> Res end; @@ -2299,3 +2334,47 @@ get_releases_with_status([ {_, _, _, ReleaseStatus } = Head | Tail], get_releases_with_status(Tail, Status, [Head | Acc]); get_releases_with_status([_ | Tail], Status, Acc) -> get_releases_with_status(Tail, Status, Acc). + +root_dir_relative_read_link_info(File) -> + file:read_link_info(root_dir_relative_path(File)). + +root_dir_relative_list_dir(File) -> + file:list_dir(root_dir_relative_path(File)). + +root_dir_relative_file_delete(File) -> + file:delete(root_dir_relative_path(File)). + +root_dir_relative_dir_delete(File) -> + file:del_dir(root_dir_relative_path(File)). + +root_dir_relative_path(Pathname) -> + case filename:pathtype(Pathname) of + relative -> + filename:join(code:root_dir(), Pathname); + _ -> + Pathname + end. + +root_dir_relative_write_file(File, Bin) -> + file:write_file(root_dir_relative_path(File), Bin). + +%% The root_dir_relative* functions below are exported so that they +%% can be called on other nodes with rpc + +root_dir_relative_read_file_info(Path) -> + file:read_file_info(root_dir_relative_path(Path)). + +root_dir_relative_read_file(File) -> + file:read_file(root_dir_relative_path(File)). + +root_dir_relative_rename_file(Source1, Destination1) -> + Source = root_dir_relative_path(Source1), + Destination = root_dir_relative_path(Destination1), + file:rename(Source, Destination). + +root_dir_relative_make_dir(Dir) -> + file:make_dir(root_dir_relative_path(Dir)). + +root_dir_relative_ensure_dir(Dir) -> + filelib:ensure_dir(root_dir_relative_path(Dir)). + diff --git a/lib/sasl/src/release_handler_1.erl b/lib/sasl/src/release_handler_1.erl index ede7df186b..cc46fa5133 100644 --- a/lib/sasl/src/release_handler_1.erl +++ b/lib/sasl/src/release_handler_1.erl @@ -313,7 +313,7 @@ eval({load_object_code, {Lib, LibVsn, Modules}}, EvalState) -> {NewBins, NewVsns} = lists:foldl(fun(Mod, {Bins, Vsns}) -> File = lists:concat([Mod, Ext]), - FName = filename:join([LibDir, "ebin", File]), + FName = root_dir_relative_path(filename:join([LibDir, "ebin", File])), case erl_prim_loader:get_file(FName) of {ok, Bin, FName2} -> NVsns = add_vsns(Mod, Bin, Vsns), @@ -340,14 +340,15 @@ eval(point_of_no_return, EvalState) -> EvalState#eval_state.libdirs end, lists:foreach(fun({Lib, _LibVsn, LibDir}) -> - Ebin = filename:join(LibDir,"ebin"), + Ebin = root_dir_relative_path(filename:join(LibDir,"ebin")), code:replace_path(Lib, Ebin) end, Libs), EvalState; eval({load, {Mod, _PrePurgeMethod, PostPurgeMethod}}, EvalState) -> Bins = EvalState#eval_state.bins, - {value, {_Mod, Bin, File}} = lists:keysearch(Mod, 1, Bins), + {value, {_Mod, Bin, File1}} = lists:keysearch(Mod, 1, Bins), + File = root_dir_relative_path(File1), % load_binary kills all procs running old code % if soft_purge, we know that there are no such procs now {module,_} = code:load_binary(Mod, File, Bin), @@ -804,3 +805,12 @@ get_vsn(Bin) -> Vsn end end. + +root_dir_relative_path(Pathname) -> + case filename:pathtype(Pathname) of + relative -> + filename:join(code:root_dir(), Pathname); + _ -> + Pathname + end. + diff --git a/lib/sasl/test/release_handler_SUITE.erl b/lib/sasl/test/release_handler_SUITE.erl index bb23b03130..78626bbc91 100644 --- a/lib/sasl/test/release_handler_SUITE.erl +++ b/lib/sasl/test/release_handler_SUITE.erl @@ -20,6 +20,8 @@ -module(release_handler_SUITE). -include_lib("common_test/include/ct.hrl"). +-include_lib("stdlib/include/assert.hrl"). +-include_lib("kernel/include/file.hrl"). -compile([export_all, nowarn_export_all]). -export([scheduler_wall_time/0, garbage_collect/0]). %% rpc'ed @@ -59,17 +61,16 @@ win32_cases() -> %% Cases that can be run on all platforms cases() -> - [otp_2740, otp_2760, otp_5761, otp_9402, otp_9417, - otp_9395_check_old_code, otp_9395_check_and_purge, - otp_9395_update_many_mods, otp_9395_rm_many_mods, + [otp_9395_check_old_code, instructions, eval_appup, eval_appup_with_restart, - supervisor_which_children_timeout, - release_handler_which_releases, install_release_syntax_check, - upgrade_supervisor, upgrade_supervisor_fail, otp_9864, - otp_10463_upgrade_script_regexp, no_dot_erlang, unicode_upgrade]. + install_release_syntax_check, + otp_10463_upgrade_script_regexp, no_dot_erlang, move_system, + {group, absolute}, {group, relative}]. groups() -> - [{release,[], + [{absolute,[],root_dir_cases()}, + {relative,[],root_dir_cases()}, + {release,[], [ {group,release_single}, {group,release_gg} @@ -86,6 +87,22 @@ groups() -> upgrade_gg ]}]. +%% Testcases that are to be run with and without an absolute root dir +root_dir_cases() -> + [supervisor_which_children_timeout, + release_handler_which_releases, + otp_2760, + otp_5761, + otp_9402, + otp_9417, + otp_9395_check_and_purge, + otp_9395_update_many_mods, + otp_9395_rm_many_mods, + otp_9864, + upgrade_supervisor, + upgrade_supervisor_fail, + unicode_upgrade]. + %% {group,release} %% Top group for all cases using run_erl init_per_group(release, Config) -> @@ -160,8 +177,10 @@ init_per_group(release_gg, Config0) -> Snames), test_server:timetrap_cancel(Dog), - [{snames,Snames}|Config]. - + [{snames,Snames}|Config]; +init_per_group(Group, Config) when Group =:= absolute; + Group =:= relative -> + [{root_dir, Group}|Config]. end_per_group(release, Config) -> Dog = test_server:timetrap(?default_timeout), @@ -243,6 +262,252 @@ gg_node_snames(Config) -> %%%----------------------------------------------------------------- %%% TEST CASES +%% Test that a release can be location independent (i.e., if all +%% paths related to the release are relative to the ROOTDIR of the +%% release, then one can move the release to a different directory and +%% it should still work). +move_system(Conf) when is_list(Conf) -> + + DataDir = ?config(data_dir, Conf), + TestRootDir = filename:join(priv_dir(Conf), ?FUNCTION_NAME), + ErtsBinDir = filename:join("erts-" ++ find_vsn_app(erts), "bin"), + + %% Remove old test data + file:del_dir_r(filename:join(TestRootDir,"system")), + file:del_dir_r(filename:join(TestRootDir,"system_moved")), + file:del_dir_r(filename:join(TestRootDir,"system_moved_again")), + + %% Create TAR file for release A + ReleaseATarFile = create_release_package(DataDir, "hello_server", "A"), + SystemPath = filename:join(TestRootDir, "system"), + ok = erl_tar:extract(ReleaseATarFile, [{cwd, SystemPath}, compressed]), + RelDir = filename:join(SystemPath, "releases"), + SystemRelFile = filename:join(RelDir, "hello_server-A.rel"), + + %% Create a location independent RELEASES file. Library paths in the releases + %% file are assumed to be relative to the RootDir. + ok = release_handler:create_RELEASES(RelDir, SystemRelFile, []), + + %% Create the bin directory with links (or copies on windows) to the erts directory + file:make_dir(filename:join(SystemPath,"bin")), + case os:type() of + {win32, _} -> + {ok,_} = file:copy( + filelib:wildcard(filename:join([SystemPath,ErtsBinDir,"erl.exe"])), + filename:join([SystemPath,"bin","erl.exe"])); + _ -> + ok = file:make_symlink( + filename:join(["..",ErtsBinDir,"erl"]), + filename:join([SystemPath,"bin","erl"])) + end, + + %% Test that the location independent system can start and run + {ok, Peer, Node} = start_remote_node(SystemPath, "A"), + hello = erpc:call(Node, app_callback_module, get_response, []), + peer:stop(Peer), + + %% Should still work after copying the system and corrupting the source + NewSystemPath = filename:join(TestRootDir, "system_moved"), + copy_r(SystemPath, NewSystemPath), + [file:del_dir_r(F) || F <- filelib:wildcard(filename:join([SystemPath,"lib","stdlib*"]))], + file:del_dir_r(filename:join(SystemPath,"releases")), + {ok, MovedPeer, MovedNode} = start_remote_node(NewSystemPath, "A"), + hello = erpc:call(MovedNode, app_callback_module, get_response, []), + peer:stop(MovedPeer), + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% Let us now try if a system upgrade also works with a location independent system % + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + ReleaseBTarFile = create_release_package(DataDir, "hello_server_new", "B"), + + BPackDest = filename:join([NewSystemPath, "releases", filename:basename(ReleaseBTarFile)]), + {ok, _ } = file:copy(ReleaseBTarFile, BPackDest), + BTarFileName = filename:basename(ReleaseBTarFile), + NameToUnpack = filename:rootname(BTarFileName, ".tar.gz"), + %% Start remote node with release A + {ok, PeerA, NodeA} = start_remote_node(NewSystemPath, "A"), + + %% Set current working directory to something irrelevant as the + %% current working directory should not affect if a system is + %% location independent or not + ok = erpc:call(NodeA, file, set_cwd, ["/"]), + %% Let us check our app + hello = erpc:call(NodeA, app_callback_module, get_response, []), + %% Install the next release + {ok, "B"} = erpc:call(NodeA, release_handler, unpack_release, [NameToUnpack]), + %% We can now create relup file + AppUpSrc = filename:join([DataDir, "relocatable_release", "hello_server_new", + "ebin", "hello_server.appup"]), + AppUpDest = filename:join([NewSystemPath, "lib", "hello_server-B", "ebin", "hello_server.appup"]), + {ok, _} = file:copy(AppUpSrc, AppUpDest), + %% Run command to create the relup file + ok = systools:make_relup( + filename:join([NewSystemPath, "releases", "B", "hello_server-B"]), + [filename:join([NewSystemPath, "releases", "A", "hello_server-A"])], + [filename:join([NewSystemPath, "releases", "A", "hello_server-A"])], + [{outdir,filename:join([NewSystemPath, "releases","B"])}, + {path,[NewSystemPath ++ "/lib/hello_server-A/ebin/", + NewSystemPath ++ "/lib/hello_server-B/ebin/"]}] + ), + %% Install the B version + {ok, "A", _} = erpc:call(NodeA, release_handler, install_release, ["B"]), + %% Check that the releases info looks ok + true = lists:any(fun({"hello_server", "B", _, current}) -> + true; + (_) -> + false + end, + erpc:call(NodeA, release_handler, which_releases, [])), + %% Make sure the old module gets replaced + ok = erpc:call(NodeA, app_callback_module, update, []), + %% Check that the upgrade worked + hej = erpc:call(NodeA, app_callback_module, get_response, []), + + case os:type() of + {win32, _} -> + %% We cannot make release permanent on windows due to + %% not having permissions to edit services. + %% And symlinks to do not on windows, so we don't test + %% anything more there. + peer:stop(PeerA); + _ -> + move_system_unix(NodeA, PeerA, TestRootDir, ErtsBinDir, NewSystemPath) + + end. + +move_system_unix(NodeA, PeerA, TestRootDir, ErtsBinDir, NewSystemPath) -> + %% Make the upgrade permanent + ok = erpc:call(NodeA, release_handler, make_permanent, ["B"]), + %% Check that it still works + hej = erpc:call(NodeA, app_callback_module, get_response, []), + true = lists:any(fun({"hello_server", "B", _, permanent}) -> + true; + (_) -> + false + end, + erpc:call(NodeA, release_handler, which_releases, [])), + ok = peer:stop(PeerA), + + %% We will now move the install and check that everything still seems to be working fine + NewSystemPath2 = filename:join(TestRootDir, "system_moved_again"), + ok = file:rename(NewSystemPath, NewSystemPath2), + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% Create a symlink to moved system and test that if we set the path to + %% contain the symlink it will work. + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + ok = file:make_symlink( + filename:join([NewSystemPath2, ErtsBinDir, "erl"]), + filename:join(TestRootDir, "erl")), + + Name = peer:random_name(), + LinkNode = list_to_atom(Name++"@"++lists:last(string:split(atom_to_list(node()),"@"))), + + %% We cannot use ?CT_PEER here because it uses spawn_executable and that + %% does not search the PATH for which program to run. + Port = open_port( + {spawn,"erl -sname " ++ Name ++ " -boot " ++ + filename:join([NewSystemPath2, "releases", "B", "start"])}, + [{env,[{"PATH",TestRootDir ++ ":" ++ os:getenv("PATH")}]}]), + + %% Wait for node to start + receive _ -> ok end, + + hej = erpc:call(LinkNode, app_callback_module, get_response, []), + + true = catch port_close(Port), + ct:log("~p",[(fun F() -> receive M -> [M | F()] after 0 -> [] end end)()]), + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% Test that we can do a downgrade of the moved system + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + {ok, PeerB, NodeB} = start_remote_node(NewSystemPath2, "B"), + + %% Change current working directory to something irrelevant + ok = erpc:call(NodeB, file, set_cwd, ["/"]), + {ok, "/"} = erpc:call(NodeB, file, get_cwd, []), + %% Check that we are using version B + hej = erpc:call(NodeB, app_callback_module, get_response, []), + %% Downgrade to version A + {ok, "A", _} = erpc:call(NodeB, release_handler, install_release, ["A"]), + true = lists:any(fun({"hello_server", "A", _, current}) -> + true; + (_) -> + false + end, + erpc:call(NodeB, release_handler, which_releases, [])), + %% Make sure that the module is reloaded + ok = erpc:call(NodeB, app_callback_module, update, []), + %% Make sure that we are on version A + hello = erpc:call(NodeB, app_callback_module, get_response, []), + %% Make the downgrade permanent + ok = erpc:call(NodeB, release_handler, make_permanent, ["A"]), + %% Test that remove release works + ok = erpc:call(NodeB, release_handler, remove_release, ["B"]), + %% B should not exist anymore + false = lists:any(fun({"hello_server", "B", _, _}) -> + true; + (_) -> + false + end, + erpc:call(NodeB, release_handler, which_releases, [])), + ok = erpc:call(NodeB, app_callback_module, update, []), + %% We should still get hello + hello = erpc:call(NodeB, app_callback_module, get_response, []), + ok = peer:stop(PeerB), + + ok. + +start_remote_node(SystemPath, RelVsn) -> + SystemErlPath = filename:join([SystemPath, "bin", "erl"]), + ?CT_PEER(#{ exec => SystemErlPath, + args => ["-boot",filename:join([SystemPath,"releases", RelVsn, "start"])]}). + +create_release_package(DataDir, SourceDir, RelVsn) -> + ReleaseSource = filename:join(DataDir, "relocatable_release"), + AppSrc = filename:join(ReleaseSource, SourceDir), + OldCWD = file:get_cwd(), + file:set_cwd(AppSrc), + os:cmd("erl -make"), + file:set_cwd(OldCWD), + RelFileScr = filename:join(ReleaseSource, "hello_server-"++ RelVsn ++".rel.src"), + RelFileDst = filename:join(ReleaseSource, "hello_server-"++ RelVsn ++".rel"), + {ok, RelFileTxt1} = file:read_file(RelFileScr), + RelFileTxt = fix_rel_file_vsns(["erts", "kernel", "stdlib", "sasl"], + RelFileTxt1), + ok = file:write_file(RelFileDst, RelFileTxt), + AppPath = filename:join([ReleaseSource, SourceDir, "ebin"]), + RelFileWithoutEnding = filename:join(ReleaseSource, "hello_server-" ++ RelVsn), + ok = systools:make_script(RelFileWithoutEnding, [local, {path, [AppPath]}]), + ok = systools:make_tar(RelFileWithoutEnding, [{erts, code:root_dir()}, {path, [AppPath]}]), + SystemPath = filename:join(ReleaseSource, "system"), + file:make_dir(SystemPath), + InitialTarPath = filename:join(ReleaseSource, "hello_server-"++ RelVsn ++".tar.gz"), + InitialTarPath. + +fix_rel_file_vsns(Apps, Txt) -> + Res = + lists:foldl( + fun(App, TxtAcc) -> + string:replace(TxtAcc, + "%" ++ App ++ "_VSN" ++ "%" , + find_vsn_app(erlang:list_to_atom(App))) + end, + Txt, + Apps), + erlang:iolist_to_binary(lists:flatten(Res)). + +find_vsn_app(erts) -> + Str = erlang:system_info(system_version), + {match, [{Start, Len} | _]} = re:run(Str, "erts-(\\d\\.?)+"), + ErtsStr = string:substr(Str, Start+1, Len), + [_, Vsn] = string:split(ErtsStr, "-"), + Vsn; +find_vsn_app(App) -> + Apps = application:which_applications(), + [Vsn] = [Vsn || {AppX, _, Vsn} <- Apps, AppX =:= App], + Vsn. + %% Executed instead of release group when no run_erl program exists no_run_erl(Config) when is_list(Config) -> @@ -617,7 +882,7 @@ supervisor_which_children_timeout(Conf) -> DataDir = ?config(data_dir,Conf), LibDir = filename:join([DataDir,release_handler_timeouts]), - Rel1 = create_and_install_fake_first_release(Dir,[{dummy,"0.1",LibDir}]), + Rel1 = create_and_install_fake_first_release(Conf,Dir,[{dummy,"0.1",LibDir}]), {ok, Node} = t_start_node(supervisor_which_children_timeout, Rel1, []), Proc = rpc:call(Node, erlang, whereis, [dummy_sup_2]), @@ -656,7 +921,7 @@ release_handler_which_releases(Conf) -> DataDir = ?config(data_dir,Conf), LibDir = filename:join([DataDir,release_handler_timeouts]), - Rel1 = create_and_install_fake_first_release(Dir,[{dummy,"0.1",LibDir}]), + Rel1 = create_and_install_fake_first_release(Conf,Dir,[{dummy,"0.1",LibDir}]), {ok, Node} = t_start_node(release_handler_which_releases, Rel1, []), Releases0 = rpc:call(Node, release_handler, which_releases, []), @@ -712,7 +977,7 @@ otp_2760(Conf) -> DataDir = ?config(data_dir,Conf), LibDir = filename:join([DataDir,app1_app2,lib1]), - Rel1 = create_and_install_fake_first_release(Dir,[{app1,"1.0",LibDir}]), + Rel1 = create_and_install_fake_first_release(Conf,Dir,[{app1,"1.0",LibDir}]), Rel2 = create_fake_upgrade_release(Dir,"after",[],{[Rel1],[Rel1],[LibDir]}), Rel2Dir = filename:dirname(Rel2), @@ -750,7 +1015,7 @@ otp_5761(Conf) when is_list(Conf) -> LibDir2 = filename:join(RelDir, "lib2"), %% Create the releases - Rel1 = create_and_install_fake_first_release(Dir, + Rel1 = create_and_install_fake_first_release(Conf,Dir, [{app1,"1.0",LibDir1}, {app2,"1.0",LibDir1}]), Rel2 = create_fake_upgrade_release(Dir, @@ -829,7 +1094,7 @@ otp_9402(Conf) when is_list(Conf) -> LibDir = filename:join(?config(data_dir, Conf), "lib"), %% Create the releases - Rel1 = create_and_install_fake_first_release(Dir, + Rel1 = create_and_install_fake_first_release(Conf,Dir, [{a,"1.1",LibDir}]), Rel2 = create_fake_upgrade_release(Dir, "2", @@ -896,7 +1161,7 @@ otp_9417(Conf) when is_list(Conf) -> LibDir = filename:join(?config(data_dir, Conf), "lib"), %% Create the releases - Rel1 = create_and_install_fake_first_release(Dir, + Rel1 = create_and_install_fake_first_release(Conf,Dir, [{b,"1.0",LibDir}]), Rel2 = create_fake_upgrade_release(Dir, "2", @@ -1009,7 +1274,7 @@ otp_9395_check_and_purge(Conf) when is_list(Conf) -> LibDir = filename:join(?config(data_dir, Conf), "lib"), %% Create the releases - Rel1 = create_and_install_fake_first_release(Dir, + Rel1 = create_and_install_fake_first_release(Conf,Dir, [{b,"1.0",LibDir}]), Rel2 = create_fake_upgrade_release(Dir, "2", @@ -1075,7 +1340,7 @@ otp_9395_update_many_mods(Conf) when is_list(Conf) -> LibDir = filename:join(?config(data_dir, Conf), "lib"), %% Create the releases - Rel1 = create_and_install_fake_first_release(Dir, + Rel1 = create_and_install_fake_first_release(Conf,Dir, [{many_mods,"1.0",LibDir}]), Rel2 = create_fake_upgrade_release(Dir, "2", @@ -1190,7 +1455,7 @@ otp_9395_rm_many_mods(Conf) when is_list(Conf) -> LibDir = filename:join(?config(data_dir, Conf), "lib"), %% Create the releases - Rel1 = create_and_install_fake_first_release(Dir, + Rel1 = create_and_install_fake_first_release(Conf,Dir, [{many_mods,"1.0",LibDir}]), Rel2 = create_fake_upgrade_release(Dir, "2", @@ -1302,7 +1567,7 @@ do_otp_9864(Conf) -> LibDir2 = filename:join(Dir, "lib2"), %% Create the releases - Rel1 = create_and_install_fake_first_release(Dir, + Rel1 = create_and_install_fake_first_release(Conf,Dir, [{app1,"1.0",LibDir1}, {app2,"1.0",LibDir1}]), Rel2 = create_fake_upgrade_release(Dir, @@ -1358,7 +1623,7 @@ upgrade_supervisor(Conf) when is_list(Conf) -> %% Create the releases Lib1 = [{a,"1.0",LibDir}], Lib2 = [{a,"9.0",LibDir}], - Rel1 = create_and_install_fake_first_release(Dir,Lib1), + Rel1 = create_and_install_fake_first_release(Conf,Dir,Lib1), Rel2 = create_fake_upgrade_release(Dir,"2",Lib2,{[Rel1],[Rel1],[LibDir]}), Rel1Dir = filename:dirname(Rel1), Rel2Dir = filename:dirname(Rel2), @@ -1415,7 +1680,7 @@ upgrade_supervisor_fail(Conf) when is_list(Conf) -> %% Create the releases Lib1 = [{a,"1.0",LibDir}], Lib2 = [{a,"9.1",LibDir}], - Rel1 = create_and_install_fake_first_release(Dir,Lib1), + Rel1 = create_and_install_fake_first_release(Conf,Dir,Lib1), Rel2 = create_fake_upgrade_release(Dir,"2",Lib2,{[Rel1],[Rel1],[LibDir]}), Rel1Dir = filename:dirname(Rel1), Rel2Dir = filename:dirname(Rel2), @@ -1925,7 +2190,7 @@ unicode_upgrade(Conf) -> %% Create the releases RelName = "unicode_rel_αβ", - Rel1 = create_and_install_fake_first_release(Dir,{RelName,"1"}, + Rel1 = create_and_install_fake_first_release(Conf,Dir,{RelName,"1"}, [{u,"1.0",LibDir}]), Rel2 = create_fake_upgrade_release(Dir, {RelName,"2"}, @@ -2842,9 +3107,9 @@ cover_fun(Node,Func) -> %% current running OTP release. It includes kernel, stdlib and sasl, %% and possibly other applications if they are listed in AppDirs = %% [{App,Vsn,LibDir}] -create_and_install_fake_first_release(Dir,AppDirs) -> - create_and_install_fake_first_release(Dir,init:script_id(),AppDirs). -create_and_install_fake_first_release(Dir,{RelName,RelVsn},AppDirs) -> +create_and_install_fake_first_release(Conf,Dir,AppDirs) -> + create_and_install_fake_first_release(Conf,Dir,init:script_id(),AppDirs). +create_and_install_fake_first_release(Conf,Dir,{RelName,RelVsn},AppDirs) -> {Rel,_} = create_fake_release(Dir,RelName,RelVsn,AppDirs), ReleasesDir = filename:join(Dir, "releases"), RelDir = filename:dirname(Rel), @@ -2857,13 +3122,21 @@ create_and_install_fake_first_release(Dir,{RelName,RelVsn},AppDirs) -> ok = copy_file(Rel++".boot",filename:join(RelVsnDir, "start.boot")), ok = copy_file(filename:join(RelDir,"sys.config"),RelVsnDir), - ok = release_handler:create_RELEASES(code:root_dir(), - ReleasesDir, - Rel++".rel", - AppDirs), - + case proplists:get_value(root_dir, Conf, relative) of + relative -> + ok = release_handler:create_RELEASES( + ReleasesDir, + Rel++".rel", + AppDirs); + absolute -> + ok = release_handler:create_RELEASES( + code:root_dir(), + ReleasesDir, + Rel++".rel", + AppDirs) + end, Rel. - + %% This function create a new release, including a relup file. It can %% be upgraded to from the release created by %% create_and_install_fake_first_release/2. Unpack first by calls to @@ -2958,3 +3231,20 @@ vsn(App,current) -> system_lib(PrivDir) -> filename:join(PrivDir,"system_lib"). + +copy_r(Src, Dst) -> + {ok,S} = file:read_file_info(Src), + case S#file_info.type of + directory -> + {ok,Names} = file:list_dir(Src), + ok = filelib:ensure_dir(Dst), + ok = file:make_dir(Dst), + lists:foreach( + fun(Name) -> + copy_r(filename:join(Src, Name), + filename:join(Dst, Name)) + end, Names); + _ -> + {ok,_NumBytesCopied} = file:copy(Src, Dst), + ok = file:write_file_info(Dst, S) + end. diff --git a/lib/sasl/test/release_handler_SUITE_data/relocatable_release/hello_server-A.rel.src b/lib/sasl/test/release_handler_SUITE_data/relocatable_release/hello_server-A.rel.src new file mode 100644 index 0000000000..8b8ec2eff6 --- /dev/null +++ b/lib/sasl/test/release_handler_SUITE_data/relocatable_release/hello_server-A.rel.src @@ -0,0 +1,8 @@ +{release, + {"hello_server", "A"}, + {erts, "%erts_VSN%"}, + [{kernel, "%kernel_VSN%"}, + {stdlib, "%stdlib_VSN%"}, + {sasl, "%sasl_VSN%"}, + {hello_server, "A"}] +}. diff --git a/lib/sasl/test/release_handler_SUITE_data/relocatable_release/hello_server-B.rel.src b/lib/sasl/test/release_handler_SUITE_data/relocatable_release/hello_server-B.rel.src new file mode 100644 index 0000000000..c966ad48ec --- /dev/null +++ b/lib/sasl/test/release_handler_SUITE_data/relocatable_release/hello_server-B.rel.src @@ -0,0 +1,8 @@ +{release, + {"hello_server", "B"}, + {erts, "%erts_VSN%"}, + [{kernel, "%kernel_VSN%"}, + {stdlib, "%stdlib_VSN%"}, + {sasl, "%sasl_VSN%"}, + {hello_server, "B"}] +}. diff --git a/lib/sasl/test/release_handler_SUITE_data/relocatable_release/hello_server/Emakefile b/lib/sasl/test/release_handler_SUITE_data/relocatable_release/hello_server/Emakefile new file mode 100644 index 0000000000..8e1f951aee --- /dev/null +++ b/lib/sasl/test/release_handler_SUITE_data/relocatable_release/hello_server/Emakefile @@ -0,0 +1,2 @@ +{"src/*", [debug_info, {i,"include/"}, {outdir, "ebin/"}]}. +{"test/*", [debug_info, {i,"include/"}, {outdir, "ebin/"}]}. diff --git a/lib/sasl/test/release_handler_SUITE_data/relocatable_release/hello_server/ebin/.gitignore b/lib/sasl/test/release_handler_SUITE_data/relocatable_release/hello_server/ebin/.gitignore new file mode 100644 index 0000000000..1ef2775ff8 --- /dev/null +++ b/lib/sasl/test/release_handler_SUITE_data/relocatable_release/hello_server/ebin/.gitignore @@ -0,0 +1 @@ +*.beam
\ No newline at end of file diff --git a/lib/sasl/test/release_handler_SUITE_data/relocatable_release/hello_server/ebin/hello_server.app b/lib/sasl/test/release_handler_SUITE_data/relocatable_release/hello_server/ebin/hello_server.app new file mode 100644 index 0000000000..697bd7add4 --- /dev/null +++ b/lib/sasl/test/release_handler_SUITE_data/relocatable_release/hello_server/ebin/hello_server.app @@ -0,0 +1,7 @@ +{application, hello_server, + [{description, "Simple server that sends back hello"}, + {vsn, "A"}, + {modules, [app_callback_module, hello_server]}, + {registered, [hello_server]}, + {applications, [kernel, stdlib, sasl]}, + {mod, {app_callback_module,[]}}]}. diff --git a/lib/sasl/test/release_handler_SUITE_data/relocatable_release/hello_server/src/app_callback_module.erl b/lib/sasl/test/release_handler_SUITE_data/relocatable_release/hello_server/src/app_callback_module.erl new file mode 100644 index 0000000000..0d988ab8f6 --- /dev/null +++ b/lib/sasl/test/release_handler_SUITE_data/relocatable_release/hello_server/src/app_callback_module.erl @@ -0,0 +1,26 @@ +-module(app_callback_module). + +-behaviour(application). + +-export([start/2, stop/1, get_response/0, update/0]). + +start(_Type, _Args) -> + Pid = hello_server:start_server(), + global:register_name(hello_server, Pid), + {ok, Pid}. + +update() -> + global:whereis_name(hello_server) ! update, + ok. + +get_response() -> + global:whereis_name(hello_server) ! self(), + receive + A -> + A + end. + +stop(_State) -> + Pid = global:whereis_name(hello_server), + hello_server:stop(Pid), + ok. diff --git a/lib/sasl/test/release_handler_SUITE_data/relocatable_release/hello_server/src/hello_server.erl b/lib/sasl/test/release_handler_SUITE_data/relocatable_release/hello_server/src/hello_server.erl new file mode 100644 index 0000000000..1008e1f4e2 --- /dev/null +++ b/lib/sasl/test/release_handler_SUITE_data/relocatable_release/hello_server/src/hello_server.erl @@ -0,0 +1,20 @@ +-module(hello_server). + +-export([start_server/0, stop/1, loop/0]). + +start_server() -> + erlang:spawn_link(?MODULE, loop, []). + +stop(Pid) -> + Pid ! stop. + +loop() -> + receive + stop -> + ok; + update -> + ?MODULE:loop(); + Sender -> + Sender ! hello, + loop() + end. diff --git a/lib/sasl/test/release_handler_SUITE_data/relocatable_release/hello_server_new/Emakefile b/lib/sasl/test/release_handler_SUITE_data/relocatable_release/hello_server_new/Emakefile new file mode 100644 index 0000000000..8e1f951aee --- /dev/null +++ b/lib/sasl/test/release_handler_SUITE_data/relocatable_release/hello_server_new/Emakefile @@ -0,0 +1,2 @@ +{"src/*", [debug_info, {i,"include/"}, {outdir, "ebin/"}]}. +{"test/*", [debug_info, {i,"include/"}, {outdir, "ebin/"}]}. diff --git a/lib/sasl/test/release_handler_SUITE_data/relocatable_release/hello_server_new/ebin/.gitignore b/lib/sasl/test/release_handler_SUITE_data/relocatable_release/hello_server_new/ebin/.gitignore new file mode 100644 index 0000000000..1ef2775ff8 --- /dev/null +++ b/lib/sasl/test/release_handler_SUITE_data/relocatable_release/hello_server_new/ebin/.gitignore @@ -0,0 +1 @@ +*.beam
\ No newline at end of file diff --git a/lib/sasl/test/release_handler_SUITE_data/relocatable_release/hello_server_new/ebin/hello_server.app b/lib/sasl/test/release_handler_SUITE_data/relocatable_release/hello_server_new/ebin/hello_server.app new file mode 100644 index 0000000000..1e1426344b --- /dev/null +++ b/lib/sasl/test/release_handler_SUITE_data/relocatable_release/hello_server_new/ebin/hello_server.app @@ -0,0 +1,7 @@ +{application, hello_server, + [{description, "Simple server that sends back hej"}, + {vsn, "B"}, + {modules, [app_callback_module, hello_server]}, + {registered, [hello_server]}, + {applications, [kernel, stdlib, sasl]}, + {mod, {app_callback_module,[]}}]}. diff --git a/lib/sasl/test/release_handler_SUITE_data/relocatable_release/hello_server_new/ebin/hello_server.appup b/lib/sasl/test/release_handler_SUITE_data/relocatable_release/hello_server_new/ebin/hello_server.appup new file mode 100644 index 0000000000..1aa16cd39c --- /dev/null +++ b/lib/sasl/test/release_handler_SUITE_data/relocatable_release/hello_server_new/ebin/hello_server.appup @@ -0,0 +1,3 @@ +{"B", + [{"A", [{load_module, hello_server}]}], + [{"A", [{load_module, hello_server}]}]}. diff --git a/lib/sasl/test/release_handler_SUITE_data/relocatable_release/hello_server_new/src/app_callback_module.erl b/lib/sasl/test/release_handler_SUITE_data/relocatable_release/hello_server_new/src/app_callback_module.erl new file mode 100644 index 0000000000..0d988ab8f6 --- /dev/null +++ b/lib/sasl/test/release_handler_SUITE_data/relocatable_release/hello_server_new/src/app_callback_module.erl @@ -0,0 +1,26 @@ +-module(app_callback_module). + +-behaviour(application). + +-export([start/2, stop/1, get_response/0, update/0]). + +start(_Type, _Args) -> + Pid = hello_server:start_server(), + global:register_name(hello_server, Pid), + {ok, Pid}. + +update() -> + global:whereis_name(hello_server) ! update, + ok. + +get_response() -> + global:whereis_name(hello_server) ! self(), + receive + A -> + A + end. + +stop(_State) -> + Pid = global:whereis_name(hello_server), + hello_server:stop(Pid), + ok. diff --git a/lib/sasl/test/release_handler_SUITE_data/relocatable_release/hello_server_new/src/hello_server.erl b/lib/sasl/test/release_handler_SUITE_data/relocatable_release/hello_server_new/src/hello_server.erl new file mode 100644 index 0000000000..d40309457a --- /dev/null +++ b/lib/sasl/test/release_handler_SUITE_data/relocatable_release/hello_server_new/src/hello_server.erl @@ -0,0 +1,20 @@ +-module(hello_server). + +-export([start_server/0, stop/1, loop/0]). + +start_server() -> + erlang:spawn_link(?MODULE, loop, []). + +stop(Pid) -> + Pid ! stop. + +loop() -> + receive + stop -> + ok; + update -> + ?MODULE:loop(); + Sender -> + Sender ! hej, + loop() + end. |