From 19a46c5c9f4ed3f0f2bfb149fc1feb0b93d55379 Mon Sep 17 00:00:00 2001 From: Siri Hansen Date: Thu, 8 Sep 2011 10:14:10 +0200 Subject: Restart emulator before running upgrade script when erts is upgraded If the version of erts differs between two releases, the release handler automatically adds a 'restart_new_emulator' instruction to the upgrade script (relup). Earlier, this instruction was always added at the end of the upgrade script, causing the following sequence of operations during an upgrade (a bit simplified): 1. suspend processes 2. load new code 3. execute code_change functions 4. resume processes 5. restart emulator with new erts version Obviously, this caused the new code to be loaded into the old emulator and this would fail if the beam format had been changed in the new version of the emulator. To overcome this problem, this commit changes the order of the instructions, so for upgrade with changed erts version we now have: 1. restart emulator with new erts, kernel, stdlib and sasl versions, but old versions of all other applications. 2. suspend processes 3. load new code 4. execute code_change functions 5. resume processes This is implemented by creating a temporary release, including new erts, kernel, stdlib and sasl from the new release and all other applications from the old release. A new boot file for this temporary release is created, which includes a new 'apply' instruction to run release_handler:new_emulator_upgrade/2. Then the emulator is restarted using this boot file - and release_handler:new_emulator_upgrade/2 executes the rest of the upgrade script. For downgrade, the order will be as before: 1. suspend processes 2. execute code_change functions with 'down'-indication 3. load old code 4. resume processes 5. restart emulator with old erts version --- lib/sasl/src/release_handler.erl | 288 +++++++++-- lib/sasl/src/release_handler_1.erl | 34 +- lib/sasl/src/systools_make.erl | 114 +++++ lib/sasl/src/systools_rc.erl | 25 +- lib/sasl/src/systools_relup.erl | 17 +- lib/sasl/test/Makefile | 4 +- lib/sasl/test/installer.erl | 562 ++++++++++++++++----- lib/sasl/test/release_handler_SUITE.erl | 318 ++++++++---- .../lib/a-1.1/ebin/a.appup | 2 +- .../release_handler_SUITE_data/lib/a-1.1/src/a.erl | 4 +- lib/sasl/test/systools_SUITE.erl | 271 +++++++++- .../systools_SUITE_data/lib/sasl/ebin/sasl.app | 6 + .../systools_SUITE_data/lib/sasl/ebin/sasl.appup | 12 + lib/sasl/test/test_lib.hrl | 3 + 14 files changed, 1352 insertions(+), 308 deletions(-) create mode 100644 lib/sasl/test/systools_SUITE_data/lib/sasl/ebin/sasl.app create mode 100644 lib/sasl/test/systools_SUITE_data/lib/sasl/ebin/sasl.appup create mode 100644 lib/sasl/test/test_lib.hrl (limited to 'lib/sasl') diff --git a/lib/sasl/src/release_handler.erl b/lib/sasl/src/release_handler.erl index bc08f94dff..38aee9ecde 100644 --- a/lib/sasl/src/release_handler.erl +++ b/lib/sasl/src/release_handler.erl @@ -26,7 +26,8 @@ create_RELEASES/1, create_RELEASES/2, create_RELEASES/4, unpack_release/1, check_install_release/1, check_install_release/2, - install_release/1, install_release/2, remove_release/1, + install_release/1, install_release/2, + new_emulator_upgrade/2, remove_release/1, which_releases/0, make_permanent/1, reboot_old_release/1, set_unpacked/2, set_removed/1, install_file/2]). -export([upgrade_app/2, downgrade_app/2, downgrade_app/3, @@ -40,7 +41,7 @@ %% Internal exports, a client release_handler may call this functions. -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, - do_write_file/2, do_ensure_RELEASES/1]). + remove_file/1, do_write_file/2, do_ensure_RELEASES/1]). -record(state, {unpurged = [], root, @@ -61,10 +62,11 @@ %% remove - %% current make_permanent permanent %% install other old +%% restart node unpacked %% remove - %% permanent make other permanent old %% install permanent -%% old reboot permanen +%% old reboot_old permanent %% install current %% remove - %%----------------------------------------------------------------- @@ -73,6 +75,14 @@ -define(timeout, 10000). +%%----------------------------------------------------------------- +%% The version set on the temporary release that will be used when the +%% emulator is upgraded. +-define(tmp_vsn(__BaseVsn__), "__new_emulator__"++__BaseVsn__). + + + + %%----------------------------------------------------------------- %% Assumes the following file structure: %% root --- lib --- Appl-Vsn1 --- @@ -229,6 +239,21 @@ check_timeout(infinity) -> true; check_timeout(Int) when is_integer(Int), Int > 0 -> true; check_timeout(_Else) -> false. +%%----------------------------------------------------------------- +%% Purpose: Called by boot script after emulator is restarted due to +%% new erts version. +%% Returns: Same as install_release/2 +%% If this crashes, the emulator restart will fail +%% (since the function is called from the boot script) +%% and there will be a rollback. +%%----------------------------------------------------------------- +new_emulator_upgrade(Vsn, Opts) -> + Result = call({install_release, Vsn, reboot, Opts}), + error_logger:info_msg( + "~p:install_release(~p,~p) completed after node restart " + "with new emulator version~nResult: ~p~n",[?MODULE,Vsn,Opts,Result]), + Result. + %%----------------------------------------------------------------- %% Purpose: Makes the specified release version be the one that is %% used when the system starts (or restarts). @@ -578,7 +603,7 @@ handle_call({check_install_release, Vsn, Purge}, _From, S) -> handle_call({install_release, Vsn, ErrorAction, Opts}, From, S) -> NS = resend_sync_nodes(S), case catch do_install_release(S, Vsn, Opts) of - {ok, NewReleases, CurrentVsn, Descr} -> + {ok, NewReleases, [], CurrentVsn, Descr} -> {reply, {ok, CurrentVsn, Descr}, NS#state{releases=NewReleases}}; {ok, NewReleases, Unpurged, CurrentVsn, Descr} -> Timer = @@ -597,6 +622,10 @@ handle_call({install_release, Vsn, ErrorAction, Opts}, From, S) -> gen_server:reply(From, {ok, CurrentVsn, Descr}), init:reboot(), {noreply, NS}; + {restart_new_emulator_then_continue, CurrentVsn, Descr} -> + gen_server:reply(From, {continue_after_restart, CurrentVsn, Descr}), + init:reboot(), + {noreply, NS}; {'EXIT', Reason} -> io:format("release_handler:" "install_release(Vsn=~p Opts=~p) failed, " @@ -941,7 +970,36 @@ do_install_release(#state{start_prg = StartPrg, {value, Release} -> LatestRelease = get_latest_release(Releases), case get_rh_script(LatestRelease, Release, RelDir, Masters) of + {ok, {_CurrentVsn, _Descr, [restart_new_emulator|_Script]}} + when Static == true -> + throw(static_emulator); + {ok, {CurrentVsn, Descr, [restart_new_emulator|_Script]}} -> + %% This will only happen if the upgrade includes + %% an emulator upgrade (and it is not a downgrade) + %% - then the new emulator must be started before + %% new code can be loaded. + %% Create a temporary release which includes new + %% emulator, kernel, stdlib and sasl - and old + %% versions of other applications. + {TmpVsn,TmpRelease} = + new_emulator_make_tmp_release(LatestRelease,Release, + RelDir,Opts,Masters), + NReleases = [TmpRelease|Releases], + + %% Then uppgrade to the temporary release. + %% The rest of the upgrade will continue after the restart + prepare_restart_new_emulator(StartPrg, RootDir, + RelDir, TmpVsn, TmpRelease, + NReleases, Masters), + {restart_new_emulator_then_continue, CurrentVsn, Descr}; {ok, {CurrentVsn, Descr, Script}} -> + %% In case there has been an emulator upgrade, + %% remove the temporary release + NReleases = + new_emulator_rm_tmp_release(LatestRelease#release.vsn, + RelDir,Releases,Masters), + + %% Then execute the relup script mon_nodes(true), EnvBefore = application_controller:prep_config_change(), Apps = change_appl_data(RelDir, Release, Masters), @@ -949,30 +1007,18 @@ do_install_release(#state{start_prg = StartPrg, NewLibs = get_new_libs(LatestRelease#release.libs, Release#release.libs), case eval_script(Script, Apps, LibDirs, NewLibs, Opts) of - {ok, []} -> - application_controller:config_change(EnvBefore), - mon_nodes(false), - NewReleases = set_status(Vsn, current, Releases), - {ok, NewReleases, CurrentVsn, Descr}; {ok, Unpurged} -> application_controller:config_change(EnvBefore), mon_nodes(false), - NewReleases = set_status(Vsn, current, Releases), - {ok, NewReleases, Unpurged, CurrentVsn, Descr}; + NReleases1 = set_status(Vsn, current, NReleases), + {ok, NReleases1, Unpurged, CurrentVsn, Descr}; restart_new_emulator when Static == true -> throw(static_emulator); restart_new_emulator -> mon_nodes(false), - {value, PermanentRelease} = - lists:keysearch(permanent, #release.status, - Releases), - NReleases = set_status(Vsn, current, Releases), - NReleases2 = set_status(Vsn,tmp_current,NReleases), - write_releases(RelDir, NReleases2, Masters), prepare_restart_new_emulator(StartPrg, RootDir, - RelDir, Release, - PermanentRelease, - Masters), + RelDir, Vsn, Release, + NReleases, Masters), {restart_new_emulator, CurrentVsn, Descr}; Else -> application_controller:config_change(EnvBefore), @@ -986,6 +1032,68 @@ do_install_release(#state{start_prg = StartPrg, {error, {no_such_release, Vsn}} end. +new_emulator_make_tmp_release(CurrentRelease,ToRelease,RelDir,Opts,Masters) -> + CurrentVsn = CurrentRelease#release.vsn, + ToVsn = ToRelease#release.vsn, + TmpVsn = ?tmp_vsn(CurrentVsn), + BaseApps = [kernel,stdlib,sasl], + BaseLibs = [{App,Vsn,Lib} || {App,Vsn,Lib} <- ToRelease#release.libs, + lists:member(App,BaseApps)], + check_base_libs(BaseLibs,ToVsn), + OldBaseLibs = [{App,Vsn,Lib} || {App,Vsn,Lib} <- CurrentRelease#release.libs, + lists:member(App,BaseApps)], + check_base_libs(OldBaseLibs,CurrentVsn), + RestLibs = [{App,Vsn,Lib} || {App,Vsn,Lib} <- CurrentRelease#release.libs, + not lists:member(App,BaseApps)], + TmpRelease = CurrentRelease#release{vsn=TmpVsn, + erts_vsn=ToRelease#release.erts_vsn, + libs = BaseLibs ++ RestLibs, + status = unpacked}, + new_emulator_make_boot_hybrid(CurrentVsn,ToVsn,TmpVsn,BaseLibs, + RelDir,Opts,Masters), + SysConfig = filename:join([RelDir,CurrentVsn,"sys.config"]), + copy_file(SysConfig,filename:join(RelDir,TmpVsn),Masters), + {TmpVsn,TmpRelease}. + +check_base_libs([_,_,_]=BaseLibs,_Vsn) -> + [Kernel,Sasl,Stdlib] = lists:keysort(1,BaseLibs), + [Kernel,Stdlib,Sasl]; +check_base_libs(SomeMissing,Vsn) -> + find_missing(SomeMissing,[kernel,stdlib,sasl],Vsn). + +find_missing(SomeMissing,[H|T],Vsn) -> + case lists:keymember(H,1,SomeMissing) of + true -> + find_missing(SomeMissing,T,Vsn); + false -> + throw({error,{missing_base_app,Vsn,H}}) + end. + +new_emulator_make_boot_hybrid(CurrentVsn,ToVsn,TmpVsn,BaseLibs,RelDir,Opts,Masters) -> + FromBootFile = filename:join([RelDir,CurrentVsn,"start.boot"]), + ToBootFile = filename:join([RelDir,ToVsn,"start.boot"]), + TmpBootFile = filename:join([RelDir,TmpVsn,"start.boot"]), + ensure_dir(TmpBootFile,Masters), + Args = [ToVsn,Opts], + {ok,FromBoot} = read_file(FromBootFile,Masters), + {ok,ToBoot} = read_file(ToBootFile,Masters), + [KernelPath,SaslPath,StdlibPath] = + [filename:join(Path,ebin) || {_,_,Path} <- lists:keysort(1,BaseLibs)], + Paths = {KernelPath,StdlibPath,SaslPath}, + case systools_make:make_boot_hybrid(TmpVsn,FromBoot,ToBoot,Paths,Args) of + {ok,TmpBoot} -> + write_file(TmpBootFile,TmpBoot,Masters); + {error,Reason} -> + throw({error,{could_not_create_hybrid_boot,Reason}}) + end. + +new_emulator_rm_tmp_release(?tmp_vsn(_)=TmpVsn,RelDir,Releases,Masters) -> + remove_dir(filename:join(RelDir,TmpVsn),Masters), + lists:keydelete(TmpVsn,#release.vsn,Releases); +new_emulator_rm_tmp_release(_,_,Releases,_) -> + Releases. + + %%% This code chunk updates the services in one of two ways, %%% Either the emulator is restarted, in which case the old service %%% is to be removed and the new enabled, or the emulator is NOT restarted @@ -1260,21 +1368,31 @@ do_set_removed(RelDir, Vsn, Releases, Masters) -> %% corresponding relup instructions, we check if it's possible to %% downgrade from CurrentVsn to ToVsn. %%----------------------------------------------------------------- +get_rh_script(#release{vsn = ?tmp_vsn(CurrentVsn)}, + #release{vsn = ToVsn}, + RelDir, + Masters) -> + {ok,{Vsn,Descr,[restart_new_emulator|Script]}} = + do_get_rh_script(CurrentVsn,ToVsn,RelDir,Masters), + {ok,{Vsn,Descr,Script}}; get_rh_script(#release{vsn = CurrentVsn}, - #release{vsn = Vsn}, + #release{vsn = ToVsn}, RelDir, Masters) -> - Relup = filename:join([RelDir, Vsn, "relup"]), - case try_upgrade(Vsn, CurrentVsn, Relup, Masters) of + do_get_rh_script(CurrentVsn,ToVsn,RelDir,Masters). + +do_get_rh_script(CurrentVsn, ToVsn, RelDir, Masters) -> + Relup = filename:join([RelDir, ToVsn, "relup"]), + case try_upgrade(ToVsn, CurrentVsn, Relup, Masters) of {ok, RhScript} -> {ok, RhScript}; _ -> Relup2 = filename:join([RelDir, CurrentVsn,"relup"]), - case try_downgrade(Vsn, CurrentVsn, Relup2, Masters) of + case try_downgrade(ToVsn, CurrentVsn, Relup2, Masters) of {ok, RhScript} -> {ok, RhScript}; _ -> - throw({error, {no_matching_relup, Vsn, CurrentVsn}}) + throw({error, {no_matching_relup, ToVsn, CurrentVsn}}) end end. @@ -1486,6 +1604,15 @@ prepare_restart_nt(#release{erts_vsn = EVsn, vsn = Vsn}, %% Set things up for restarting the new emulator. The actual %% restart is performed by calling init:reboot() higher up. %%----------------------------------------------------------------- +prepare_restart_new_emulator(StartPrg, RootDir, RelDir, + Vsn, Release, Releases, Masters) -> + {value, PRelease} = lists:keysearch(permanent, #release.status,Releases), + NReleases1 = set_status(Vsn, current, Releases), + NReleases2 = set_status(Vsn,tmp_current,NReleases1), + write_releases(RelDir, NReleases2, Masters), + prepare_restart_new_emulator(StartPrg, RootDir, RelDir, + Release, PRelease, Masters). + prepare_restart_new_emulator(StartPrg, RootDir, RelDir, Release, PRelease, Masters) -> #release{erts_vsn = EVsn, vsn = Vsn} = Release, @@ -1512,19 +1639,10 @@ check_start_prg({do_check, StartPrg}, Masters) -> check_start_prg({_, StartPrg}, _) -> StartPrg. -write_new_start_erl(Data, RelDir, false) -> - DataFile = filename:join([RelDir, "new_start_erl.data"]), - case do_write_file(DataFile, Data) of - ok -> DataFile; - Error -> throw(Error) - end; write_new_start_erl(Data, RelDir, Masters) -> DataFile = filename:join([RelDir, "new_start_erl.data"]), - case at_all_masters(Masters, ?MODULE, do_write_file, - [DataFile, Data]) of - ok -> DataFile; - Error -> throw(Error) - end. + write_file(DataFile, Data, Masters), + DataFile. %%----------------------------------------------------------------- %% When a new emulator shall be restarted, the current release @@ -1538,27 +1656,41 @@ write_new_start_erl(Data, RelDir, Masters) -> %% If the release is made permanent, this is written to disk. %%----------------------------------------------------------------- transform_release(ReleaseDir, Releases, Masters) -> - F = fun(Release) when Release#release.status == tmp_current -> - Release#release{status = unpacked}; - (Release) -> Release - end, - case lists:map(F, Releases) of - Releases -> - Releases; - DReleases -> + case init:script_id() of + {Name, ?tmp_vsn(_)=TmpVsn} -> + %% This is was a reboot due to a new emulator version. The + %% current release is a temporary internal release, which + %% must be removed. It is the "real new release" that is + %% set to unpacked on disk and current in memory. + DReleases = lists:keydelete(TmpVsn,#release.vsn,Releases), write_releases(ReleaseDir, DReleases, Masters), - F1 = fun(Release) when Release#release.status == tmp_current -> - case init:script_id() of - {_Name, Vsn} when Release#release.vsn == Vsn -> - Release#release{status = current}; - _ -> - Release#release{status = unpacked} - end; - (Release) -> Release - end, - lists:map(F1, Releases) + set_current({Name,TmpVsn},Releases); + ScriptId -> + F = fun(Release) when Release#release.status == tmp_current -> + Release#release{status = unpacked}; + (Release) -> Release + end, + case lists:map(F, Releases) of + Releases -> + Releases; + DReleases -> + write_releases(ReleaseDir, DReleases, Masters), + set_current(ScriptId, Releases) + end end. +set_current(ScriptId, Releases) -> + F1 = fun(Release) when Release#release.status == tmp_current -> + case ScriptId of + {_Name,Vsn} when Release#release.vsn == Vsn -> + Release#release{status = current}; + _ -> + Release#release{status = unpacked} + end; + (Release) -> Release + end, + lists:map(F1, Releases). + %%----------------------------------------------------------------- %% Functions handling files, RELEASES, start_erl.data etc. %% This functions consider if the release_handler is a client and @@ -1617,12 +1749,25 @@ extract_tar(Root, Tar) -> throw({error, {cannot_extract_file, Name, Reason}}) end. -write_releases(Dir, NewReleases, false) -> +write_releases(Dir, Releases, Masters) -> + %% We must never write 'current' to disk, since this will confuse + %% us after a node restart - since we would then have a permanent + %% release running, but state set to current for a non-running + %% release. + NewReleases = lists:zf(fun(Release) when Release#release.status == current -> + {true, Release#release{status = unpacked}}; + (_) -> + true + end, Releases), + write_releases_1(Dir, NewReleases, Masters). + + +write_releases_1(Dir, NewReleases, false) -> case do_write_release(Dir, "RELEASES", NewReleases) of ok -> ok; Error -> throw(Error) end; -write_releases(Dir, NewReleases, Masters) -> +write_releases_1(Dir, NewReleases, Masters) -> all_masters(Masters), write_releases_m(Dir, NewReleases, Masters). @@ -1844,6 +1989,37 @@ read_file(File, false) -> read_file(File, Masters) -> read_master(Masters, File). +write_file(File, Data, false) -> + case file:write_file(File, Data) of + ok -> ok; + Error -> throw(Error) + end; +write_file(File, Data, Masters) -> + case at_all_masters(Masters, file, write_file, [File, Data]) of + ok -> ok; + Error -> throw(Error) + end. + +ensure_dir(File, false) -> + case filelib:ensure_dir(File) of + ok -> ok; + Error -> throw(Error) + end; +ensure_dir(File, Masters) -> + case at_all_masters(Masters,filelib,ensure_dir,[File]) of + ok -> ok; + Error -> throw(Error) + end. + +remove_dir(Dir, false) -> + remove_file(Dir); +remove_dir(Dir, Masters) -> + case at_all_masters(Masters,?MODULE,remove_file,[Dir]) of + ok -> ok; + Error -> throw(Error) + end. + + %% Ignore status of each delete ! remove_files(Master, Files, Masters) -> takewhile(Master, Masters, ?MODULE, do_remove_files, [Files]). diff --git a/lib/sasl/src/release_handler_1.erl b/lib/sasl/src/release_handler_1.erl index 8d0baf3ab1..4a776fd18b 100644 --- a/lib/sasl/src/release_handler_1.erl +++ b/lib/sasl/src/release_handler_1.erl @@ -47,26 +47,34 @@ %%%----------------------------------------------------------------- %%% This is a low-level release handler. %%%----------------------------------------------------------------- +check_script([restart_new_emulator|Script], LibDirs) -> + %% There is no need to check for old processes, since the node + %% will be restarted before anything else happens. + do_check_script(Script, LibDirs, []); check_script(Script, LibDirs) -> case catch check_old_processes(Script,soft_purge) of {ok, PurgeMods} -> - {Before, _After} = split_instructions(Script), - case catch lists:foldl(fun(Instruction, EvalState1) -> - eval(Instruction, EvalState1) - end, - #eval_state{libdirs = LibDirs}, - Before) of - EvalState2 when is_record(EvalState2, eval_state) -> - {ok,PurgeMods}; - {error, Error} -> - {error, Error}; - Other -> - {error, Other} - end; + do_check_script(Script, LibDirs, PurgeMods); {error, Mod} -> {error, {old_processes, Mod}} end. +do_check_script(Script, LibDirs, PurgeMods) -> + {Before, _After} = split_instructions(Script), + case catch lists:foldl(fun(Instruction, EvalState1) -> + eval(Instruction, EvalState1) + end, + #eval_state{libdirs = LibDirs}, + Before) of + EvalState2 when is_record(EvalState2, eval_state) -> + {ok,PurgeMods}; + {error, Error} -> + {error, Error}; + Other -> + {error, Other} + end. + + %% eval_script/1 - For testing only - no apps added, just testing instructions eval_script(Script) -> eval_script(Script, [], [], [], []). diff --git a/lib/sasl/src/systools_make.erl b/lib/sasl/src/systools_make.erl index 7f400f5cce..42b528540e 100644 --- a/lib/sasl/src/systools_make.erl +++ b/lib/sasl/src/systools_make.erl @@ -31,6 +31,8 @@ -export([read_application/4]). +-export([make_boot_hybrid/5]). + -import(lists, [filter/2, keysort/2, keysearch/3, map/2, reverse/1, append/1, foldl/3, member/2, foreach/2]). @@ -162,6 +164,118 @@ return({error,Mod,Error},_,Flags) -> error end. + +%%----------------------------------------------------------------- +%% Make hybrid boot file for upgrading emulator. The resulting boot +%% file is a combination of the two input files, where kernel, stdlib +%% and sasl versions are taken from the second file (the boot file of +%% the new release), and all other application versions from the first +%% file (the boot file of the old release). +%% +%% The most important thing that can fail here is that the input boot +%% files do not contain all three base applications - kernel, stdlib +%% and sasl. +%% +%% TmpVsn = string(), +%% Paths = {KernelPath,StdlibPath,SaslPath} +%% Returns {ok,Boot} | {error,Reason} +%% Boot1 = Boot2 = Boot = binary() +%% Reason = {app_not_found,App} | {app_not_replaced,App} +%% App = kernel | stdlib | sasl +make_boot_hybrid(TmpVsn, Boot1, Boot2, Paths, Args) -> + catch do_make_boot_hybrid(TmpVsn, Boot1, Boot2, Paths, Args). +do_make_boot_hybrid(TmpVsn, Boot1, Boot2, Paths, Args) -> + {script,{_RelName1,_RelVsn1},Script1} = binary_to_term(Boot1), + {script,{RelName2,_RelVsn2},Script2} = binary_to_term(Boot2), + MatchPaths = get_regexp_path(Paths), + NewScript1 = replace_paths(Script1,MatchPaths), + {Kernel,Stdlib,Sasl} = get_apps(Script2,undefined,undefined,undefined), + NewScript2 = replace_apps(NewScript1,Kernel,Stdlib,Sasl), + NewScript3 = add_apply_upgrade(NewScript2,Args), + Boot = term_to_binary({script,{RelName2,TmpVsn},NewScript3}), + {ok,Boot}. + +%% For each app, compile a regexp that can be used for finding its path +get_regexp_path({KernelPath,StdlibPath,SaslPath}) -> + {ok,KernelMP} = re:compile("kernel-[0-9\.]+",[unicode]), + {ok,StdlibMP} = re:compile("stdlib-[0-9\.]+",[unicode]), + {ok,SaslMP} = re:compile("sasl-[0-9\.]+",[unicode]), + [{KernelMP,KernelPath},{StdlibMP,StdlibPath},{SaslMP,SaslPath}]. + +%% For each path in the script, check if it matches any of the MPs +%% found above, and if so replace it with the correct new path. +replace_paths([{path,Path}|Script],MatchPaths) -> + [{path,replace_path(Path,MatchPaths)}|replace_paths(Script,MatchPaths)]; +replace_paths([Stuff|Script],MatchPaths) -> + [Stuff|replace_paths(Script,MatchPaths)]; +replace_paths([],_) -> + []. + +replace_path([Path|Paths],MatchPaths) -> + [do_replace_path(Path,MatchPaths)|replace_path(Paths,MatchPaths)]; +replace_path([],_) -> + []. + +do_replace_path(Path,[{MP,ReplacePath}|MatchPaths]) -> + case re:run(Path,MP,[{capture,none}]) of + nomatch -> do_replace_path(Path,MatchPaths); + match -> ReplacePath + end; +do_replace_path(Path,[]) -> + Path. + +%% Return the entries for loading the three base applications +get_apps([{kernelProcess,application_controller, + {application_controller,start,[{application,kernel,_}]}}=Kernel| + Script],_,Stdlib,Sasl) -> + get_apps(Script,Kernel,Stdlib,Sasl); +get_apps([{apply,{application,load,[{application,stdlib,_}]}}=Stdlib|Script], + Kernel,_,Sasl) -> + get_apps(Script,Kernel,Stdlib,Sasl); +get_apps([{apply,{application,load,[{application,sasl,_}]}}=Sasl|_Script], + Kernel,Stdlib,_) -> + {Kernel,Stdlib,Sasl}; +get_apps([_|Script],Kernel,Stdlib,Sasl) -> + get_apps(Script,Kernel,Stdlib,Sasl); +get_apps([],undefined,_,_) -> + throw({error,{app_not_found,kernel}}); +get_apps([],_,undefined,_) -> + throw({error,{app_not_found,stdlib}}); +get_apps([],_,_,undefined) -> + throw({error,{app_not_found,sasl}}). + + +%% Replace the entries for loading the base applications +replace_apps([{kernelProcess,application_controller, + {application_controller,start,[{application,kernel,_}]}}| + Script],Kernel,Stdlib,Sasl) -> + [Kernel|replace_apps(Script,undefined,Stdlib,Sasl)]; +replace_apps([{apply,{application,load,[{application,stdlib,_}]}}|Script], + Kernel,Stdlib,Sasl) -> + [Stdlib|replace_apps(Script,Kernel,undefined,Sasl)]; +replace_apps([{apply,{application,load,[{application,sasl,_}]}}|Script], + _Kernel,_Stdlib,Sasl) -> + [Sasl|Script]; +replace_apps([Stuff|Script],Kernel,Stdlib,Sasl) -> + [Stuff|replace_apps(Script,Kernel,Stdlib,Sasl)]; +replace_apps([],undefined,undefined,_) -> + throw({error,{app_not_replaced,sasl}}); +replace_apps([],undefined,_,_) -> + throw({error,{app_not_replaced,stdlib}}); +replace_apps([],_,_,_) -> + throw({error,{app_not_replaced,kernel}}). + + +%% Finally add an apply of release_handler:new_emulator_upgrade - which will +%% complete the execution of the upgrade script (relup). +add_apply_upgrade(Script,Args) -> + [{progress, started} | RevScript] = lists:reverse(Script), + lists:reverse([{progress,started}, + {apply,{release_handler,new_emulator_upgrade,Args}} | + RevScript]). + + + %%----------------------------------------------------------------- %% Create a release package from a release file. %% Options is a list of {path, Path} | silent | diff --git a/lib/sasl/src/systools_rc.erl b/lib/sasl/src/systools_rc.erl index daadb79967..6f01901fbc 100644 --- a/lib/sasl/src/systools_rc.erl +++ b/lib/sasl/src/systools_rc.erl @@ -144,7 +144,10 @@ translate_merged_script(Mode, Script, Appls, PreAppls) -> {Before2, After2} = translate_dependent_instrs(Mode, Before1, After1, Appls), Before3 = merge_load_object_code(Before2), - NewScript = Before3 ++ [point_of_no_return | After2], + + {Before4,After4} = sort_restart_new_emulator(Mode,Before3,After2), + NewScript = Before4 ++ [point_of_no_return | After4], + check_syntax(NewScript), {ok, NewScript}. @@ -698,6 +701,25 @@ mlo([{load_object_code, {Lib, LibVsn, Mods}} | T]) -> [{load_object_code, {Lib, LibVsn, OCode1}} | mlo(Other)]; mlo([]) -> []. +%%----------------------------------------------------------------- +%% RESTART DIFF EMULATOR +%% ----------------------------------------------------------------- +%% ----------------------------------------------------------------- +%% Check if a diff_vsn_restart_new_emulator instruction exists (i.e. if the +%% emulator version is changed). If so, this must be done first for +%% upgrade and last for downgrade. +%% ----------------------------------------------------------------- +sort_restart_new_emulator(Mode,Before,After) -> + case lists:delete(diff_vsn_restart_new_emulator,After) of + After -> + {Before,After}; + NewAfter when Mode==up -> + {[restart_new_emulator|Before],NewAfter}; + NewAfter when Mode==dn -> + {Before,NewAfter++[restart_new_emulator]} + end. + + %%----------------------------------------------------------------- %% SYNTAX CHECK %%----------------------------------------------------------------- @@ -817,6 +839,7 @@ check_op({apply, {M, F, A}}) -> check_func(F), check_args(A); check_op(restart_new_emulator) -> ok; +check_op(diff_vsn_restart_new_emulator) -> ok; check_op(X) -> throw({error, {bad_instruction, X}}). check_mod(Mod) when is_atom(Mod) -> ok; diff --git a/lib/sasl/src/systools_relup.erl b/lib/sasl/src/systools_relup.erl index 6d9e922900..682f5f5cc9 100644 --- a/lib/sasl/src/systools_relup.erl +++ b/lib/sasl/src/systools_relup.erl @@ -263,7 +263,7 @@ foreach_baserel_up(TopRel, TopApps, [BaseRelDc|BaseRelDcs], Path, Opts, {RUs3, Ws3} = create_remove_app_scripts(BaseRel, TopRel, RUs2, Ws2), - {RUs4, Ws4} = + {RUs4, Ws4} = check_for_emulator_restart(TopRel, BaseRel, RUs3, Ws3, Opts), BaseApps = @@ -343,9 +343,20 @@ foreach_baserel_dn( _, _, [], _, _, Ws, Acc) -> %% check_for_emulator_restart(#release{erts_vsn = Vsn1, name = N1}, #release{erts_vsn = Vsn2, name = N2}, RUs, Ws, - _Opts) when Vsn1 /= Vsn2 -> - {RUs++[[restart_new_emulator]], [{erts_vsn_changed, {N1, N2}} | Ws]}; + Opts) when Vsn1 /= Vsn2 -> + %% The diff_vsn_restart_new_emulator instruction will be replaced + %% by a restart_new_emulator instruction in systools_rc, and + %% placed in the proper order according to mode (up or dn). + %% We will also allow an extra restart of emulator (specified by + %% the restart_emulator option) at the end of the upgrade, for + %% application specific purposes. + NewRUs = [[diff_vsn_restart_new_emulator]|RUs], + NewWs = [{erts_vsn_changed, {N1, N2}} | Ws], + check_for_restart_emulator_opt(NewRUs, NewWs, Opts); check_for_emulator_restart(_, _, RUs, Ws, Opts) -> + check_for_restart_emulator_opt(RUs, Ws, Opts). + +check_for_restart_emulator_opt(RUs, Ws, Opts) -> case get_opt(restart_emulator, Opts) of true -> {RUs++[[restart_new_emulator]], Ws}; _ -> {RUs, Ws} diff --git a/lib/sasl/test/Makefile b/lib/sasl/test/Makefile index 65be134462..91a8c42484 100644 --- a/lib/sasl/test/Makefile +++ b/lib/sasl/test/Makefile @@ -36,6 +36,8 @@ MODULES= \ ERL_FILES= $(MODULES:%=%.erl) +HRL_FILES= test_lib.hrl + TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR)) INSTALL_PROGS= $(TARGET_FILES) @@ -84,7 +86,7 @@ release_spec: opt release_tests_spec: make_emakefile $(INSTALL_DIR) $(RELSYSDIR) - $(INSTALL_DATA) $(ERL_FILES) $(RELSYSDIR) + $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(RELSYSDIR) $(INSTALL_DATA) sasl.spec sasl.cover $(EMAKEFILE) $(RELSYSDIR) chmod -R u+w $(RELSYSDIR) @tar cfh - *_SUITE_data | (cd $(RELSYSDIR); tar xf -) diff --git a/lib/sasl/test/installer.erl b/lib/sasl/test/installer.erl index f5ceab0dc4..d77b0e8538 100644 --- a/lib/sasl/test/installer.erl +++ b/lib/sasl/test/installer.erl @@ -19,20 +19,32 @@ -module(installer). +-include("test_lib.hrl"). + %%-compile(export_all). -export([install_1/2]). -export([install_2/1]). -export([install_3/2]). --export([install_3a/1]). +-export([install_6a/1]). -export([install_4/1]). -export([install_5/1]). -export([install_5a/1]). -export([install_6/1]). -export([install_7/1]). +-export([install_7a/1]). -export([install_8/1]). +-export([install_8a/1]). -export([install_9/1]). -export([install_10/1]). -export([install_11/1]). +-export([install_12/1]). +-export([install_13/1]). +-export([install_14/1]). +-export([upgrade_restart_1/2]). +-export([upgrade_restart_1a/1]). +-export([upgrade_restart_2/1]). +-export([upgrade_restart_2a/1]). +-export([upgrade_restart_3/1]). -export([client1_1/4]). -export([client2/3]). -export([stop/1]). @@ -46,28 +58,35 @@ -define(fail(Term), exit({?MODULE, ?LINE, Term})). -define(fail_line(Line,Term), exit({?MODULE, Line, Term})). --define(check_release(Vsn,Status,Apps), - check_release(TestNode,node(),Vsn,Status,Apps,?LINE)). --define(check_release_client(Node,Vsn,Status,Apps), - check_release(TestNode,Node,Vsn,Status,Apps,?LINE)). +-define(check_release_states(States), + check_release_states(TestNode,node(),States,?LINE)). +-define(check_release_states_client(Node,States), + check_release_states(TestNode,Node,States,?LINE)). + +-define(check_release_lib(Vsn,Apps), + check_release_lib(TestNode,node(),Vsn,Apps,?LINE)). +-define(check_release_lib_client(Node,Vsn,Apps), + check_release_lib(TestNode,Node,Vsn,Apps,?LINE)). -define(check_running_app(App,Vsn), check_running_app(TestNode,node(),App,Vsn,?LINE)). -define(check_running_app_client(Node,App,Vsn), check_running_app(TestNode,Node,App,Vsn,?LINE)). +-define(check_disallowed_calls,check_disallowed_calls(TestNode,?LINE)). + install_1(TestNode,PrivDir) -> ?print([TestNode]), ?print(["install_1 start"]), + ?check_release_states([permanent]), % Unpack and install P1H {ok, "P1H"} = unpack_release(PrivDir,"rel1"), - ?print(["unpack_release P1H ok"]), - ?check_release("P1H",unpacked,["a-1.0"]), + ?check_release_states([permanent,unpacked]), + ?check_release_lib("P1H",["a-1.0"]), {ok,"P1G",[new_appl]} = release_handler:install_release("P1H"), - ?print(["install_release P1H ok"]), - ?check_release("P1H",current,["a-1.0"]), + ?check_release_states([permanent,current]), ?check_running_app(a,"1.0"), X = a:a(), ?print(["X", X]), @@ -81,172 +100,337 @@ install_2(TestNode) -> ?print(["install_2 start"]), % Check that P1H is still unpacked, install it and make_permanent - ?check_release("P1H",unpacked,["a-1.0"]), - ?print(["install_2 P1H unpacked"]), + ?check_release_states([permanent,unpacked]), {ok,"P1G",[new_appl]} = release_handler:install_release("P1H"), ?print(["install_2 install_release ok"]), - ?check_release("P1H",current,["a-1.0"]), + ?check_release_states([permanent,current]), + ?check_running_app(a,"1.0"), + ok = release_handler:make_permanent("P1H"), + ?print(["install_2 make permanent P1H ok"]), + ?check_release_states([old,permanent]), ?check_running_app(a,"1.0"), - ok = release_handler:make_permanent("P1H"). + ok. % release_handler_SUITE will reboot this node now! install_3(TestNode,PrivDir) -> ?print(["install_3 start"]), % Check that P1H is permanent - ?check_release("P1H",permanent,["a-1.0"]), + ?check_release_states([old,permanent]), + ?check_running_app(a,"1.0"), X = a:a(), {key2, val2} = lists:keyfind(key2, 1, X), {key1, val1} = lists:keyfind(key1, 1, X), % Unpack and install P1I {ok, "P1I"} = unpack_release(PrivDir,"rel2"), - ?print(["install_3 unpack_release P1I ok"]), - ?check_release("P1I",unpacked,["a-1.1"]), + ?check_release_states([old,permanent,unpacked]), + ?check_release_lib("P1I",["a-1.1"]), {ok,"P1H",[{extra, gott}]} = release_handler:check_install_release("P1I"), + ?print(["install_3 check_install_release P1I ok"]), {error,_} = release_handler:check_install_release("P1J"), + ?print(["install_3 check_install_release P1J fails - ok"]), {ok,"P1H",[{extra, gott}]} = release_handler:install_release("P1I"), - ?print(["install_3 install_release P1I ok"]), - ?check_release("P1I",current,["a-1.1"]), + ?check_release_states([old,permanent,current]), ?check_running_app(a,"1.1"), X2 = a:a(), {key2, newval2} = lists:keyfind(key2, 1, X2), {key1, val1} = lists:keyfind(key1, 1, X2), {ok, bval} = a:b(), + ?print(["install_3 env ok"]), - % Unpack and install P2A + % Unpack P2A {ok, "P2A"} = unpack_release(PrivDir,"rel3"), - ?print(["install_3 unpack_release P2A ok"]), - ?check_release("P2A",unpacked,["a-1.1"]), + ?check_release_states([old,permanent,current,unpacked]), + ?check_release_lib("P2A",["a-1.1"]), {ok, "P1I", [new_emu]} = release_handler:check_install_release("P2A"), ?print(["install_3 check_install_release P2A ok"]), - ok = release_handler:make_permanent("P1I"), - ?print(["install_3 make_permanent P1I ok"]), - ?check_release("P1I",permanent,["a-1.1"]), ok. + % release_handler_SUITE will reboot this node now! + +install_4(TestNode) -> + ?print(["install_4 start"]), -install_3a(TestNode) -> - {ok, "P1I", [new_emu]} = release_handler:install_release("P2A"), + %% Check that P1H is the one that is used + ?check_release_states([old,permanent,unpacked,unpacked]), + ?check_running_app(a,"1.0"), + + %% Install P2A + {continue_after_restart, "P1H", [new_emu,new_appl]} = + release_handler:install_release("P2A"), %% Node is rebooted by the release_handler:install_release %% (init:reboot) because P2A includes a new erts vsn and the relup %% file contains a 'restart_new_emulator' instruction. - ?print(["install_3 P2A installed"]), + ?print(["install_4 P2A installed"]), ok. +install_5(TestNode) -> + ?print(["install_5 start"]), -install_4(TestNode) -> - ?print(["install_4 start"]), + %% Check that the upgrade was done via a temporary release due to + %% new emulator version. + {"SASL-test","__new_emulator__P1H"} = init:script_id(), + + %% Check that P2A is in use. + ?check_release_states([old,permanent,unpacked,current]), + ?check_running_app(a,"1.1"), + X = a:a(), + {key2, newval2} = lists:keyfind(key2, 1, X), + {key1, val1} = lists:keyfind(key1, 1, X), + {ok, bval} = a:b(), + ?print(["install_5 check env ok"]), + ok. + +install_5a(TestNode) -> + ?print(["install_5a start"]), + + %% Install P1I (this will be a downgrade) + {ok, "P1I", [old_emu]} = release_handler:install_release("P1I"), + %% Node is rebooted by the release_handler:install_release + %% (init:reboot) because P2A includes a new erts vsn and the relup + %% file contains a 'restart_new_emulator' instruction. + ?print(["install_5a P1I installed"]), + ok. + +install_6(TestNode) -> + ?print(["install_6 start"]), + + %% Check that P1I is used + ?check_release_states([old,permanent,current,old]), + ?check_running_app(a,"1.1"), + + %% Make P1I permanent + ok = release_handler:make_permanent("P1I"), + ?check_release_states([old,old,permanent,old]), + ?check_running_app(a,"1.1"), + ok. + +install_6a(TestNode) -> + %% Install P2A + {continue_after_restart, "P1I", [new_emu]} = + release_handler:install_release("P2A"), + %% Node is rebooted by the release_handler:install_release + %% (init:reboot) because P2A includes a new erts vsn and the relup + %% file contains a 'restart_new_emulator' instruction. + ?print(["install_6a P2A installed"]), + ok. + +install_7(TestNode) -> + ?print(["install_7 start"]), + + %% Check that the upgrade was done via a temporary release due to + %% new emulator version. + {"SASL-test","__new_emulator__P1I"} = init:script_id(), % Check that P2A is in use. - ?check_release("P2A",current,["a-1.1"]), + ?check_release_states([old,old,permanent,current]), ?check_running_app(a,"1.1"), X = a:a(), {key2, newval2} = lists:keyfind(key2, 1, X), {key1, val1} = lists:keyfind(key1, 1, X), {ok, bval} = a:b(), + ?print(["install_7 check env ok"]), ok. - % release_handler_SUITE will reboot this node now! -install_5(TestNode) -> - ?print(["install_5 start"]), +install_7a(TestNode) -> + %% Install P1H (this will be a downgrade) + {ok, "P1H", [old_emu,old_appl]} = release_handler:install_release("P1H"), + %% Node is rebooted by the release_handler:install_release + %% (init:reboot) because P2A includes a new erts vsn and the relup + %% file contains a 'restart_new_emulator' instruction. + ?print(["install_7a P1H installed"]), + ok. - % Check that P1I is used - {ok, "P1I", [new_emu]} = release_handler:check_install_release("P2A"), +install_8(TestNode) -> + ?print(["install_8 start"]), + + %% Check that P1H is used + ?check_release_states([old,current,permanent,old]), + ?check_running_app(a,"1.0"), + {ok,"P1H",[new_emu,new_appl]} = release_handler:check_install_release("P2A"), + ?print(["install_8 check_install_release P2A ok"]), + + %% Install P1I and check that it is permanent + {ok,"P1H",[{extra, gott}]} = release_handler:install_release("P1I"), + ?check_release_states([old,old,permanent,old]), + ?check_running_app(a,"1.1"), ok. -install_5a(TestNode) -> +install_8a(TestNode) -> % Install P2A again - {ok, "P1I", [new_emu]} = release_handler:install_release("P2A"), + {continue_after_restart, "P1I", [new_emu]} = + release_handler:install_release("P2A"), %% Node is rebooted by the release_handler:install_release %% (init:reboot) because P2A includes a new erts vsn and the relup %% file contains a 'restart_new_emulator' instruction. - ?print(["install_5 P2A installed"]), + ?print(["install_8a P2A installed"]), ok. -install_6(TestNode) -> - ?print(["install_6 start"]), +install_9(TestNode) -> + ?print(["install_9 start"]), + + %% Check that the upgrade was done via a temporary release due to + %% new emulator version. + {"SASL-test","__new_emulator__P1I"} = init:script_id(), % Check that P2A is used - ?check_release("P2A",current,["a-1.1"]), + ?check_release_states([old,old,permanent,current]), ?check_running_app(a,"1.1"), X = a:a(), {key2, newval2} = lists:keyfind(key2, 1, X), {key1, val1} = lists:keyfind(key1, 1, X), {ok, bval} = a:b(), - ok = release_handler:make_permanent("P2A"). + ?print(["install_9 check env ok"]), + ok = release_handler:make_permanent("P2A"), + ?check_release_states([old,old,old,permanent]), + ?check_running_app(a,"1.1"), + ok. % release_handler_SUITE will reboot this node now! -install_7(TestNode) -> - ?print(["install_7 start"]), +install_10(TestNode) -> + ?print(["install_10 start"]), % Check that P2A is used - ?check_release("P2A",permanent,["a-1.1"]), + ?check_release_states([old,old,old,permanent]), + ?check_running_app(a,"1.1"), % Install old P1H ok = release_handler:reboot_old_release("P1H"), + ?print(["install_10 reboot_old ok"]), ok. -install_8(TestNode) -> - ?print(["install_8 start"]), + +install_11(TestNode) -> + ?print(["install_11 start"]), % Check that P1H is permanent - ?check_release("P1H",permanent,["a-1.0"]), + ?check_release_states([old,permanent,old,old]), + ?check_running_app(a,"1.0"), X = a:a(), {key2, val2} = lists:keyfind(key2, 1, X), {key1, val1} = lists:keyfind(key1, 1, X), + ?print(["install_11 check env ok"]), %% Remove P1I and P2A and check that a-1.1 and erts- are removed ok = release_handler:remove_release("P2A"), + ?check_release_states([old,permanent,old]), ok = release_handler:remove_release("P1I"), + ?check_release_states([old,permanent]), {ok, Libs} = file:list_dir(code:lib_dir()), {_,_,StdlibVsn} = lists:keyfind(stdlib,1,application:which_applications()), true = lists:member("stdlib-"++StdlibVsn, Libs), true = lists:member("a-1.0", Libs), false = lists:member("a-1.1", Libs), {ok, Dirs} = file:list_dir(code:root_dir()), - ["erts-4.4"] = lists:filter(fun(Dir) -> lists:prefix("erts-",Dir) end, Dirs), + ErtsDir = "erts-"++?ertsvsn, + [ErtsDir] = lists:filter(fun(Dir) -> lists:prefix("erts-",Dir) end, Dirs), + ?print(["install_11 file checks ok"]), ok. % release_handler_SUITE will reboot this node now! -install_9(TestNode) -> - ?print(["install_9 start"]), +install_12(TestNode) -> + ?print(["install_12 start"]), % Check that P1H is permanent - ?check_release("P1H",permanent,["a-1.0"]), + ?check_release_states([old,permanent]), + ?check_running_app(a,"1.0"), X = a:a(), {key2, val2} = lists:keyfind(key2, 1, X), {key1, val1} = lists:keyfind(key1, 1, X), + ?print(["install_12 check env ok"]), % Install old P1G ok = release_handler:reboot_old_release("P1G"), + ?print(["install_12 reboot_old ok"]), ok. -install_10(TestNode) -> - ?print(["install_10 start"]), +install_13(TestNode) -> + ?print(["install_13 start"]), % Check that P1G is permanent - ?check_release("P1G",permanent,[]), - ?check_release("P1H",old,["a-1.0"]), + ?check_release_states([permanent,old]), + false = lists:keysearch(a,1,application:loaded_applications()), + ?print(["install_13 no a application found - ok"]), %% Remove P1H and check that both versions of application a is removed ok = release_handler:remove_release("P1H"), + ?check_release_states([permanent]), {ok, Libs} = file:list_dir(code:lib_dir()), {_,_,StdlibVsn} = lists:keyfind(stdlib,1,application:which_applications()), true = lists:member("stdlib-"++StdlibVsn, Libs), false = lists:member("a-1.0", Libs), false = lists:member("a-1.1", Libs), + ?print(["install_13 file checks ok"]), ok. % release_handler_SUITE will reboot this node now! -install_11(TestNode) -> - ?print(["install_11 start"]), +install_14(TestNode) -> + ?print(["install_14 start"]), % Check that P1G is permanent - ?check_release("P1G",permanent,[]), + ?check_release_states([permanent]), + false = lists:keysearch(a,1,application:loaded_applications()), + ?print(["install_13 no a application found - ok"]), + ok. + + +%%%----------------------------------------------------------------- +%%% Ths test checks that an upgrade which both upgrades to a new +%%% emulator version, and had a restart_emulator option to +%%% systools:make_relup will be restarted twice on upgrade. +%%% (On downgrade it will happen only once.) +upgrade_restart_1(TestNode,PrivDir) -> + ?print([TestNode]), + ?print(["upgrade_restart_1 start"]), + ?check_release_states([permanent]), + + {ok, "P2B"} = unpack_release(PrivDir,"rel4"), + ?check_release_states([permanent,unpacked]), + ?check_release_lib("P2B",["a-1.1"]), + ok. + +upgrade_restart_1a(TestNode) -> + ?print(["upgrade_restart_1a start"]), + + {continue_after_restart,"P1G",[new_emu,add_appl]} = + release_handler:install_release("P2B"), + ?print(["upgrade_restart_1a P2B installed"]), + ok. + +upgrade_restart_2(TestNode) -> + ?print(["upgrade_restart_2 start"]), + + %% Check that the node has been restarted once more after the tmp release + {"SASL-test","P2B"} = init:script_id(), + ?check_release_states([permanent,current]), + ?check_running_app(a,"1.1"), + + ok = release_handler:make_permanent("P2B"), + ?check_release_states([old,permanent]), + ok. +upgrade_restart_2a(TestNode) -> + ?print(["upgrade_restart_2a start"]), + + {ok,"P1G",[old_emu,rm_appl]} = release_handler:install_release("P1G"), + ?print(["upgrade_restart_2a P1G installed"]), + ok. + +upgrade_restart_3(TestNode) -> + ?print(["upgrade_restart_3 start"]), + + %% Ideally we should test that the node has only been restarted + %% once... but that's not so easy. Let's just check that P1G is running. + ?check_release_states([current,permanent]), + false = lists:keysearch(a,1,application:loaded_applications()), + ?print(["upgrade_restart_3 no a application found - ok"]), + + ok. + + %%----------------------------------------------------------------- @@ -272,6 +456,8 @@ client1_1(TestNode,PrivDir,MasterDir,ClientSname) -> Node = start_client(TestNode,client1,ClientSname), trace_disallowed_calls(Node), + ?check_release_states_client(Node,[permanent]), + %% Check env var for SASL on client node SaslEnv = rpc:call(Node, application, get_all_env, [sasl]), ?print([{client1_1,sasl_env},SaslEnv]), @@ -300,13 +486,14 @@ client1_1(TestNode,PrivDir,MasterDir,ClientSname) -> %% as default. But it is given here in order to force hitting the %% release_handler:check_path function so it can be checked that %% it does not use file:read_file_info on the client node, see - %% trace_disallowed_calls/1 and check_disallowed_calls/0 below. + %% trace_disallowed_calls/1 and check_disallowed_calls/2 below. %% (OTP-9142) {ok, "P1H"} = rpc:call(Node, release_handler, set_unpacked, [filename:join(P1HDir, "rel1.rel"), [{a,"1.0",filename:join(MasterDir,lib)}]]), - ?check_release_client(Node,"P1H",unpacked,["a-1.0"]), + ?check_release_states_client(Node,[permanent,unpacked]), + ?check_release_lib_client(Node,"P1H",["a-1.0"]), ok = rpc:call(Node, release_handler, install_file, ["P1H", filename:join(P1HDir, "start.boot")]), @@ -323,13 +510,16 @@ client1_1(TestNode,PrivDir,MasterDir,ClientSname) -> {ok,"P1G",[new_appl]} = rpc:call(Node, release_handler, install_release, ["P1H"]), + ?check_release_states_client(Node,[permanent,current]), + ?check_running_app_client(Node,a,"1.0"), + Apps = rpc:call(Node, application, which_applications, []), {a,"A CXC 138 11","1.0"} = lists:keyfind(a, 1, Apps), X = rpc:call(Node, a, a, []), {key2, val2} = lists:keyfind(key2, 1, X), {key1, val1} = lists:keyfind(key1, 1, X), - check_disallowed_calls(), + ?check_disallowed_calls, reboot(TestNode,Node), trace_disallowed_calls(Node), @@ -339,17 +529,17 @@ client1_2(TestNode,PrivDir,Node) -> ?print(["client1_2 start"]), %% Check that P1H is still unpacked, install it and make_permanent - ?check_release_client(Node,"P1H",unpacked,["a-1.0"]), + ?check_release_states_client(Node,[permanent,unpacked]), {ok,"P1G",[new_appl]} = rpc:call(Node, release_handler, install_release, ["P1H"]), - ?check_release_client(Node,"P1H",current,["a-1.0"]), + ?check_release_states_client(Node,[permanent,current]), ?check_running_app_client(Node,a,"1.0"), ok = rpc:call(Node, release_handler, make_permanent, ["P1H"]), - ?check_release_client(Node,"P1H",permanent,["a-1.0"]), + ?check_release_states_client(Node,[old,permanent]), - check_disallowed_calls(), + ?check_disallowed_calls, reboot(TestNode,Node), trace_disallowed_calls(Node), @@ -359,10 +549,8 @@ client1_3(TestNode,PrivDir,Node) -> ?print(["client1_3 start"]), %% Check that P1H is permanent - ?check_release_client(Node,"P1H",permanent,["a-1.0"]), - X = rpc:call(Node, a, a, []), - {key2, val2} = lists:keyfind(key2, 1, X), - {key1, val1} = lists:keyfind(key1, 1, X), + ?check_release_states_client(Node,[old,permanent]), + ?check_running_app_client(Node,a,"1.0"), %% Unpack P1I on master {ok, "P1I"} = unpack_release(PrivDir,"rel2"), @@ -374,7 +562,8 @@ client1_3(TestNode,PrivDir,Node) -> {ok, "P1I"} = rpc:call(Node, release_handler, set_unpacked, [filename:join(P1IDir, "rel2.rel"),[]]), - ?check_release_client(Node,"P1I",unpacked,["a-1.1"]), + ?check_release_states_client(Node,[old,permanent,unpacked]), + ?check_release_lib_client(Node,"P1I",["a-1.1"]), ok = rpc:call(Node, release_handler, install_file, ["P1I", filename:join(P1IDir, "start.boot")]), @@ -389,6 +578,7 @@ client1_3(TestNode,PrivDir,Node) -> {ok,"P1H",[{extra, gott}]} = rpc:call(Node, release_handler, install_release, ["P1I"]), + ?check_release_states_client(Node,[old,permanent,current]), ?check_running_app_client(Node,a,"1.1"), X2 = rpc:call(Node, a, a, []), {key2, newval2} = lists:keyfind(key2, 1, X2), @@ -404,6 +594,9 @@ client1_3(TestNode,PrivDir,Node) -> rpc:call(Node, release_handler, set_unpacked, [filename:join(P2ADir, "rel3.rel"),[]]), + ?check_release_states_client(Node,[old,permanent,current,unpacked]), + ?check_release_lib_client(Node,"P2A",["a-1.1"]), + ok = rpc:call(Node, release_handler, install_file, ["P2A", filename:join(P2ADir, "start.boot")]), ok = rpc:call(Node, release_handler, install_file, @@ -413,66 +606,136 @@ client1_3(TestNode,PrivDir,Node) -> {ok, "P1I", [new_emu]} = rpc:call(Node, release_handler, check_install_release, ["P2A"]), + + %% Reboot from P1H + ?check_disallowed_calls, + reboot(TestNode,Node), + trace_disallowed_calls(Node), + + client1_4(TestNode,Node). + +client1_4(TestNode,Node) -> + ?print(["client1_4 start"]), + + %% check that P1H is used + ?check_release_states_client(Node,[old,permanent,unpacked,unpacked]), + + %% since the install_release below reboot the node... + ?check_disallowed_calls, + cover_client(TestNode,Node,stop_cover), + + {continue_after_restart, "P1H", [new_emu,new_appl]} = + rpc:call(Node, release_handler, install_release, ["P2A"]), + %% Reboots the client ! + + check_reboot(TestNode,Node), + trace_disallowed_calls(Node), + + client1_5(TestNode,Node). + +client1_5(TestNode,Node) -> + ?print(["client1_5 start"]), + + %% Check that P2A is in use. + ?check_release_states_client(Node,[old,permanent,unpacked,current]), + ?check_running_app_client(Node,a,"1.1"), + X = rpc:call(Node, a, a, []), + {key2, newval2} = lists:keyfind(key2, 1, X), + {key1, val1} = lists:keyfind(key1, 1, X), + {ok, bval} = rpc:call(Node, a, b, []), + + %% since the install_release below reboot the node... + ?check_disallowed_calls, + cover_client(TestNode,Node,stop_cover), + + {ok,"P1I",[old_emu]} = + rpc:call(Node, release_handler, install_release, ["P1I"]), + + check_reboot(TestNode,Node), + trace_disallowed_calls(Node), + + client1_6(TestNode,Node). + +client1_6(TestNode,Node) -> + ?print(["client1_6 start"]), + + ?check_release_states_client(Node,[old,permanent,current,old]), + ?check_running_app_client(Node,a,"1.1"), + ok = rpc:call(Node, release_handler, make_permanent, ["P1I"]), - ?check_release_client(Node,"P1I",permanent,["a-1.1"]), + ?check_release_states_client(Node,[old,old,permanent,old]), %% since the install_release below reboot the node... - check_disallowed_calls(), + ?check_disallowed_calls, cover_client(TestNode,Node,stop_cover), - {ok, "P1I", [new_emu]} = + {continue_after_restart, "P1I", [new_emu]} = rpc:call(Node, release_handler, install_release, ["P2A"]), %% Reboots the client ! check_reboot(TestNode,Node), trace_disallowed_calls(Node), - client1_4(TestNode,Node). + client1_7(TestNode,Node). -client1_4(TestNode,Node) -> - ?print(["client1_4 start"]), +client1_7(TestNode,Node) -> + ?print(["client1_7 start"]), %% Check that P2A is in use. - ?check_release_client(Node,"P2A",current,["a-1.1"]), + ?check_release_states_client(Node,[old,old,permanent,current]), ?check_running_app_client(Node,a,"1.1"), X = rpc:call(Node, a, a, []), {key2, newval2} = lists:keyfind(key2, 1, X), {key1, val1} = lists:keyfind(key1, 1, X), {ok, bval} = rpc:call(Node, a, b, []), - %% Reboot from P1I - check_disallowed_calls(), - reboot(TestNode,Node), + %% since the install_release below reboot the node... + ?check_disallowed_calls, + cover_client(TestNode,Node,stop_cover), + + {ok,"P1H",[old_emu,old_appl]} = + rpc:call(Node, release_handler, install_release, ["P1H"]), + + check_reboot(TestNode,Node), trace_disallowed_calls(Node), - client1_5(TestNode,Node). + client1_8(TestNode,Node). -client1_5(TestNode,Node) -> - ?print(["client1_5 start"]), +client1_8(TestNode,Node) -> + ?print(["client1_8 start"]), - %% Check that P1I is used - {ok, "P1I", [new_emu]} = + %% Check that P1H is used + ?check_release_states_client(Node,[old,current,permanent,old]), + ?check_running_app_client(Node,a,"1.0"), + {ok, "P1H", [new_emu,new_appl]} = rpc:call(Node, release_handler, check_install_release, ["P2A"]), + + {ok,"P1H",[{extra, gott}]} = + rpc:call(Node, release_handler, install_release, ["P1I"]), + ?check_release_states_client(Node,[old,old,permanent,old]), + ?check_running_app_client(Node,a,"1.1"), + + %% since the install_release below will reboot the node... - check_disallowed_calls(), + ?check_disallowed_calls, cover_client(TestNode,Node,stop_cover), %% Install P2A again - {ok, "P1I", [new_emu]} = + {continue_after_restart, "P1I", [new_emu]} = rpc:call(Node, release_handler, install_release, ["P2A"]), %% We are rebooted again. check_reboot(TestNode,Node), trace_disallowed_calls(Node), - client1_6(TestNode,Node). + client1_9(TestNode,Node). -client1_6(TestNode,Node) -> - ?print(["client1_6 start"]), +client1_9(TestNode,Node) -> + ?print(["client1_9 start"]), %% Check that P2A is used - ?check_release_client(Node,"P2A",current,["a-1.1"]), + ?check_release_states_client(Node,[old,old,permanent,current]), ?check_running_app_client(Node,a,"1.1"), X = rpc:call(Node, a, a, []), {key2, newval2} = lists:keyfind(key2, 1, X), @@ -481,22 +744,23 @@ client1_6(TestNode,Node) -> %% Make P2A permanent ok = rpc:call(Node, release_handler, make_permanent, ["P2A"]), + ?check_release_states_client(Node,[old,old,old,permanent]), %% Reboot from P2A - check_disallowed_calls(), + ?check_disallowed_calls, reboot(TestNode,Node), trace_disallowed_calls(Node), - client1_7(TestNode,Node). + client1_10(TestNode,Node). -client1_7(TestNode,Node) -> - ?print(["client1_7 start"]), +client1_10(TestNode,Node) -> + ?print(["client1_10 start"]), %% Check that P2A is used - ?check_release_client(Node,"P2A",permanent,["a-1.1"]), + ?check_release_states_client(Node,[old,old,old,permanent]), %% since the reboot_old_release below will reboot the node - check_disallowed_calls(), + ?check_disallowed_calls, cover_client(TestNode,Node,stop_cover), %% Install old P1H @@ -505,41 +769,45 @@ client1_7(TestNode,Node) -> check_reboot(TestNode,Node), trace_disallowed_calls(Node), - client1_8(TestNode,Node). + client1_11(TestNode,Node). -client1_8(TestNode,Node) -> - ?print(["client1_8 start"]), +client1_11(TestNode,Node) -> + ?print(["client1_11 start"]), %% Check that P1H is permanent - ?check_release_client(Node,"P1H",permanent,["a-1.0"]), + ?check_release_states_client(Node,[old,permanent,old,old]), + ?check_running_app_client(Node,a,"1.0"), X = rpc:call(Node, a, a, []), {key2, val2} = lists:keyfind(key2, 1, X), {key1, val1} = lists:keyfind(key1, 1, X), - %% Remove P1I and P2I from client + %% Remove P1I and P2A from client ok = rpc:call(Node, release_handler, set_removed, ["P2A"]), + ?check_release_states_client(Node,[old,permanent,old]), ok = rpc:call(Node, release_handler, set_removed, ["P1I"]), + ?check_release_states_client(Node,[old,permanent]), - check_disallowed_calls(), - reboot(TestNode,Node), - trace_disallowed_calls(Node), - - client1_9(TestNode,Node). - -client1_9(TestNode,Node) -> - ?print(["client1_9 start"]), - - %% Check that P2A and P1I does not exists and that PiH is permanent. + %% Check that P2A and P1I does not exists Rels = rpc:call(Node, release_handler, which_releases, []), false = lists:keysearch("P2A", 2, Rels), false = lists:keysearch("P1I", 2, Rels), - ?check_release_client(Node,"P1H",permanent,["a-1.0"]), X = rpc:call(Node, a, a, []), {key2, val2} = lists:keyfind(key2, 1, X), {key1, val1} = lists:keyfind(key1, 1, X), + ?check_disallowed_calls, + reboot(TestNode,Node), + trace_disallowed_calls(Node), + + client1_12(TestNode,Node). + +client1_12(TestNode,Node) -> + ?print(["client1_12 start"]), + + ?check_release_states_client(Node,[old,permanent]), + %% since the reboot_old_release below will reboot the node - check_disallowed_calls(), + ?check_disallowed_calls, cover_client(TestNode,Node,stop_cover), %% Install old P1G @@ -548,33 +816,34 @@ client1_9(TestNode,Node) -> check_reboot(TestNode,Node), trace_disallowed_calls(Node), - client1_10(TestNode,Node). + client1_13(TestNode,Node). -client1_10(TestNode,Node) -> - ?print(["client1_10 start"]), +client1_13(TestNode,Node) -> + ?print(["client1_13 start"]), %% Check that P1G is permanent - ?check_release_client(Node,"P1G",permanent,[]), - ?check_release_client(Node,"P1H",old,["a-1.0"]), + ?check_release_states_client(Node,[permanent,old]), {error,client_node} = rpc:call(Node,release_handler,remove_release,["P1H"]), ok = rpc:call(Node, release_handler, set_removed, ["P1H"]), + ?check_release_states_client(Node,[permanent]), - check_disallowed_calls(), + ?check_disallowed_calls, reboot(TestNode,Node), trace_disallowed_calls(Node), - client1_11(TestNode,Node). + client1_14(TestNode,Node). -client1_11(TestNode,Node) -> - ?print(["client1_11 start"]), +client1_14(TestNode,Node) -> + ?print(["client1_14 start"]), %% Check that P1G is permanent - ?check_release_client(Node,"P1G",permanent,[]), + ?check_release_states_client(Node,[permanent]), - check_disallowed_calls(), + ?check_disallowed_calls, stop_client(TestNode,Node), %% TEST IS OK !! net_kernel:monitor_nodes(false), + %% Remove releases from master ok = release_handler:remove_release("P2A"), ok = release_handler:remove_release("P1I"), ok = release_handler:remove_release("P1H"), @@ -595,9 +864,10 @@ trace_disallowed_calls(Node) -> rpc:call(Node,dbg,p,[all,call]), rpc:call(Node,dbg,tp,[file,[{'_',[],[{message,{caller}}]}]]). -check_disallowed_calls() -> +check_disallowed_calls(TestNode,Line) -> receive Trace when element(1,Trace)==trace -> + ?print_line(Line,["Disallowed function called",Trace]), exit({disallowed_function_call,Trace}) after 0 -> ok @@ -628,7 +898,7 @@ start_client_unix(TestNode,Sname,Node) -> start_client_win32(TestNode,Client,ClientSname) -> Name = atom_to_list(ClientSname) ++ "_P1G", RootDir = code:root_dir(), - ErtsBinDir = filename:join(RootDir,"erts-4.4/bin"), + ErtsBinDir = filename:join([RootDir,"erts-"++?ertsvsn,"bin"]), {ClientArgs,RelClientDir} = rh_test_lib:get_client_args(Client,ClientSname, RootDir), @@ -729,8 +999,10 @@ client2(TestNode,PrivDir,ClientSname) -> ok end, + %% Unpack P1H on master {ok, "P1H"} = unpack_release(PrivDir,"rel1"), + %% Try to set P1H unpacked on client Root = code:root_dir(), {error,{bad_masters,[Master2]}} = rpc:call(Node, release_handler, set_unpacked, @@ -755,15 +1027,17 @@ stop(Now) -> unpack_p1h(TestNode,PrivDir) -> {ok, "P1H"} = unpack_release(PrivDir,"rel1"), - ?check_release("P1H",unpacked,["a-1.0"]), + ?check_release_states([permanent,unpacked]), + ?check_release_lib("P1H",["a-1.0"]), ok. permanent_p1h(TestNode) -> - ?check_release("P1H",unpacked,["a-1.0"]), + ?check_release_states([permanent,unpacked]), + ?check_release_lib("P1H",["a-1.0"]), {ok,"P1G",[new_appl]} = release_handler:install_release("P1H"), - ?check_release("P1H",current,["a-1.0"]), + ?check_release_states([permanent,current]), ok = release_handler:make_permanent("P1H"), - ?check_release("P1H",permanent,["a-1.0"]), + ?check_release_states([old,permanent]), ok. @@ -779,24 +1053,38 @@ registered_loop(_Name) -> exit(killed) end. -check_release(TestNode,Node,Vsn,Status,Apps,Line) -> +%% Checks that the list of states for all releases (sorted on vsn) +%% equals the input States +check_release_states(TestNode,Node,States,Line) -> + case rpc:call(Node,release_handler,which_releases,[]) of + {badrpc,_}=Error -> + ?fail_line(Line,{check_release_states,Node,States,Error}); + Rels -> + ?print_line(Line,["check_release_states:", Rels]), + States = [Status || {_,_,_,Status} <- lists:keysort(2,Rels)], + ok + end. + +%% Check that the given release (Vsn) sees the correct vsn of App. +check_release_lib(TestNode,Node,Vsn,Apps,Line) -> case rpc:call(Node,release_handler,which_releases,[]) of {badrpc,_}=Error -> - ?fail_line(Line,{check_release,Node,Vsn,Status,Error}); + ?fail_line(Line,{check_release_lib,Node,Vsn,Apps,Error}); Rels -> - ?print_line(Line,["check_release:", Rels]), - {"SASL-test", Vsn, Libs, Status} = lists:keyfind(Vsn, 2, Rels), + ?print_line(Line,["check_release_lib:", Rels]), + {"SASL-test", Vsn, Libs, _Status} = lists:keyfind(Vsn, 2, Rels), true = lists:all(fun(App) -> lists:member(App,Libs) end,Apps), ok end. +%% Check that the given Vsn of App is executed check_running_app(TestNode,Node,App,Vsn,Line) -> case rpc:call(Node,application,which_applications,[]) of {badrpc,_}=Error -> ?fail_line(Line,{check_running_app,Node,App,Vsn,Error}); Apps -> ?print_line(Line,["check_running_app:", Apps]), - {App, _, Vsn} = lists:keyfind(a, 1, Apps), + {App, _, Vsn} = lists:keyfind(App, 1, Apps), ok end. diff --git a/lib/sasl/test/release_handler_SUITE.erl b/lib/sasl/test/release_handler_SUITE.erl index af2183bfff..c2930b1039 100644 --- a/lib/sasl/test/release_handler_SUITE.erl +++ b/lib/sasl/test/release_handler_SUITE.erl @@ -19,6 +19,7 @@ -module(release_handler_SUITE). -include_lib("common_test/include/ct.hrl"). +-include("test_lib.hrl"). -compile(export_all). @@ -30,6 +31,7 @@ suite() -> [{ct_hooks, [ts_install_cth]}]. init_per_suite(Config) -> + init_priv_dir(Config), application:start(sasl), Config. @@ -69,6 +71,7 @@ groups() -> {release_single,[], [ upgrade, + upgrade_restart, client1, client2 ]}, @@ -82,7 +85,7 @@ groups() -> init_per_group(release, Config) -> Dog = ?t:timetrap(?default_timeout), P1gInstall = filename:join(priv_dir(Config),p1g_install), - ok = do_create_p1g(Config,P1gInstall), + ok = create_p1g(Config,P1gInstall), ok = create_p1h(Config), ?t:timetrap_cancel(Dog); @@ -95,6 +98,7 @@ init_per_group(release_single, Config) -> %% Create some more releases to upgrade to ok = create_p1i(Config), ok = create_p2a(Config), + ok = create_p2b(Config), ?t:timetrap_cancel(Dog); @@ -155,7 +159,7 @@ end_per_group(release, Config) -> {win32,_} -> delete_all_services(); _ -> ok end, - delete_release(Config), + clean_priv_dir(Config,true), ?t:timetrap_cancel(Dog), Config; end_per_group(_GroupName, Config) -> @@ -191,7 +195,10 @@ end_per_testcase(Case, Config) -> FailDir = filename:join(SaveDir,lists:concat(["failed-",Case])), ok = filelib:ensure_dir(filename:join(FailDir,"*")), - LogDirs = filelib:wildcard(filename:join([PrivDir,"*",log])), + LogDirs = + filelib:wildcard(filename:join([PrivDir,"*",log])) ++ + filelib:wildcard(filename:join([PrivDir,"*",clients, + type1,"*",log])), lists:foreach( fun(LogDir) -> @@ -236,7 +243,7 @@ break(Config) -> ?t:break(priv_dir(Config)), ok. -%% Test upgrade and downgrade of erts +%% Test upgrade and downgrade of erts and other apps on embedded node upgrade(Conf) when is_list(Conf) -> reg_print_proc(), %% starts a printer process on test_server node ?t:format("upgrade ~p~n",[reg_print_proc]), @@ -259,54 +266,75 @@ upgrade(Conf) when is_list(Conf) -> stop_cover(TestNode), reboot_and_wait(TestNode,"install_2",[a]), - %% check that P1H is permanent, unpack and install P1I, unpack and install P2A - TestNodeInit1 = rpc:call(TestNode,erlang,whereis,[init]), + %% check that P1H is permanent, unpack and install P1I, unpack P2A ok = rpc_inst(TestNode, install_3, [PrivDir]), stop_cover(TestNode), - ok = rpc_inst(TestNode, install_3a, []), - wait_nodes_up([{TestNode,TestNodeInit1}],"install_3",[a]), + reboot_and_wait(TestNode,"install_3",[a]), - %% check that P2A is used, reboot from P1I - ok = rpc_inst(TestNode, install_4, []), + %% check that P1H is used, install P2A + TestNodeInit1 = rpc:call(TestNode,erlang,whereis,[init]), stop_cover(TestNode), - reboot_and_wait(TestNode,"install_4",[a]), + ok = rpc_inst(TestNode, install_4, []), + wait_nodes_up([{TestNode,TestNodeInit1}],"install_4",[a]), - %% check that P1I, reinstall P2A + %% check that P2A is used, then downgrade to P1I TestNodeInit2 = rpc:call(TestNode,erlang,whereis,[init]), ok = rpc_inst(TestNode, install_5, []), stop_cover(TestNode), ok = rpc_inst(TestNode, install_5a, []), wait_nodes_up([{TestNode,TestNodeInit2}],"install_5",[a]), - %% check that P2A is used, make P2A permanent + %% Check that P1I is used, then make P1I permanent and install P2A + TestNodeInit3 = rpc:call(TestNode,erlang,whereis,[init]), ok = rpc_inst(TestNode, install_6, []), stop_cover(TestNode), - reboot_and_wait(TestNode,"install_6",[a]), + ok = rpc_inst(TestNode, install_6a, []), + wait_nodes_up([{TestNode,TestNodeInit3}],"install_6",[a]), - %% check that P2A is permanent, install old P1H - TestNodeInit3 = rpc:call(TestNode,erlang,whereis,[init]), - stop_cover(TestNode), + %% check that P2A is used, then downgrade to P1H + TestNodeInit4 = rpc:call(TestNode,erlang,whereis,[init]), ok = rpc_inst(TestNode, install_7, []), - wait_nodes_up([{TestNode,TestNodeInit3}],"install_7",[a]), + stop_cover(TestNode), + ok = rpc_inst(TestNode, install_7a, []), + wait_nodes_up([{TestNode,TestNodeInit4}],"install_7",[a]), - %% check that P1H is permanent, remove P1I and P2A + %% check that P1H is used, then install P1I and check that it is permanent + %% then reinstall P2A + TestNodeInit5 = rpc:call(TestNode,erlang,whereis,[init]), ok = rpc_inst(TestNode, install_8, []), stop_cover(TestNode), - reboot_and_wait(TestNode,"install_8",[a]), + ok = rpc_inst(TestNode, install_8a, []), + wait_nodes_up([{TestNode,TestNodeInit5}],"install_8",[a]), + + %% check that P2A is used, make P2A permanent + ok = rpc_inst(TestNode, install_9, []), + stop_cover(TestNode), + reboot_and_wait(TestNode,"install_9",[a]), + + %% check that P2A is permanent, reboot to old P1H + TestNodeInit6 = rpc:call(TestNode,erlang,whereis,[init]), + stop_cover(TestNode), + ok = rpc_inst(TestNode, install_10, []), + wait_nodes_up([{TestNode,TestNodeInit6}],"install_10",[a]), + + %% check that P1H is permanent, remove P1I and P2A + ok = rpc_inst(TestNode, install_11, []), + stop_cover(TestNode), + reboot_and_wait(TestNode,"install_11",[a]), %% check that P1H is permanent, reboot old P1G - TestNodeInit4 = rpc:call(TestNode,erlang,whereis,[init]), + TestNodeInit7 = rpc:call(TestNode,erlang,whereis,[init]), stop_cover(TestNode), - ok = rpc_inst(TestNode, install_9, []), - wait_nodes_up([{TestNode,TestNodeInit4}],"install_9"), + ok = rpc_inst(TestNode, install_12, []), + wait_nodes_up([{TestNode,TestNodeInit7}],"install_12"), %% check that P1G is permanent, remove P1H - ok = rpc_inst(TestNode, install_10, []), + ok = rpc_inst(TestNode, install_13, []), stop_cover(TestNode), - reboot_and_wait(TestNode,"install_10"), + reboot_and_wait(TestNode,"install_13"), %% check that P1G is permanent - ok = rpc_inst(TestNode, install_11, []), + ok = rpc_inst(TestNode, install_14, []), ok. @@ -323,6 +351,46 @@ reboot_and_wait(Node,Tag,Apps) -> wait_nodes_up([{Node,InitPid}],Tag,Apps). +%% Test upgrade and downgrade of erts in combination with the +%% restart_emulator option to systools:make_relup. For upgrade, this +%% should cause one restart before the upgrade code, and one +%% after. For downgrade, there will be one restart only - at the end. +upgrade_restart(Conf) when is_list(Conf) -> + reg_print_proc(), %% starts a printer process on test_server node + ?t:format("upgrade_restart ~p~n",[reg_print_proc]), + PrivDir = priv_dir(Conf), + Sname = tc_sname(Conf), % nodename for use in this testcase + + %% Copy the P1G release to a directory for use in this testcase + ok = copy_installed(Conf,p1g_install,[Sname]), + + %% start the test node + [TestNode] = start_nodes(Conf,[Sname],"upgrade_restart start"), + + %% unpack and install P2B + TestNodeInit1 = rpc:call(TestNode,erlang,whereis,[init]), + ok = rpc_inst(TestNode, upgrade_restart_1, [PrivDir]), + stop_cover(TestNode), + ok = rpc_inst(TestNode, upgrade_restart_1a, []), + wait_nodes_up([{TestNode,TestNodeInit1}],"upgrade_restart_1",[a]), + + %% install P1G + TestNodeInit2 = rpc:call(TestNode,erlang,whereis,[init]), + ok = rpc_inst(TestNode, upgrade_restart_2, []), + stop_cover(TestNode), + ok = rpc_inst(TestNode, upgrade_restart_2a, []), + wait_nodes_up([{TestNode,TestNodeInit2}],"upgrade_restart_2",[]), + + %% Check that P1G is going again + ok = rpc_inst(TestNode, upgrade_restart_3, []), + + ok. + +upgrade_restart(cleanup,Config) -> + TestNode = tc_full_node_name(Config), + ok = stop_nodes([TestNode]). + + %% Test upgrade and downgrade of erts, diskless client1(Conf) when is_list(Conf) -> reg_print_proc(), %% starts a printer process on test_server node @@ -1147,11 +1215,10 @@ target_system(Conf) when is_list(Conf) -> %% Create the .rel file - ErtsVsn = erlang:system_info(version), RelName = filename:join(TargetCreateDir,"ts-1.0"), RelFile = RelName++".rel", RelVsn = "R1A", - create_rel_file(RelFile,RelName,RelVsn,ErtsVsn,[{a, "1.0"}]), + create_rel_file(RelFile,RelName,RelVsn,current,[{a, "1.0"}]), %% Build the target_system module ExamplesEbin = filename:join([code:lib_dir(sasl),examples,ebin]), @@ -1179,11 +1246,12 @@ target_system(Conf) when is_list(Conf) -> code:del_path(TSPath), %% Check that all files exist in installation - true = filelib:is_dir(filename:join(TargetInstallDir,"erts-"++ErtsVsn)), + ErtsDir = app_dir(erts,current), + true = filelib:is_dir(filename:join(TargetInstallDir,ErtsDir)), LibDir = filename:join(TargetInstallDir,lib), - {ok,KernelVsn} = application:get_key(kernel,vsn), - {ok,StdlibVsn} = application:get_key(stdlib,vsn), - {ok,SaslVsn} = application:get_key(sasl,vsn), + KernelVsn = vsn(kernel,current), + StdlibVsn = vsn(stdlib,current), + SaslVsn = vsn(sasl,current), true = filelib:is_dir(filename:join(LibDir,"kernel-"++KernelVsn)), true = filelib:is_dir(filename:join(LibDir,"stdlib-"++StdlibVsn)), true = filelib:is_dir(filename:join(LibDir,"sasl-"++SaslVsn)), @@ -1205,6 +1273,7 @@ target_system(Conf) when is_list(Conf) -> true = filelib:is_regular(filename:join(BinDir,to_erl)), %% Check content of files + ErtsVsn = vsn(erts,current), {ok,SED} = file:read_file(filename:join(RelDir,"start_erl.data")), [ErtsVsn,RelVsn] = string:tokens(binary_to_list(SED),"\s\n"), ok. @@ -1456,7 +1525,7 @@ copy_client(Conf,Master,Sname,Client) -> ok. -delete_release(Conf) -> +clean_priv_dir(Conf,Save) -> PrivDir = priv_dir(Conf), {ok, OrigWd} = file:get_cwd(), @@ -1466,7 +1535,7 @@ delete_release(Conf) -> {ok, Dirs} = file:list_dir(PrivDir), ?t:format("======== deleting ~p~n",[Dirs]), - ok = delete_release_os(Dirs--["save"]), + ok = clean_dirs_os(Dirs,Save), {ok,Remaining} = file:list_dir(PrivDir), ?t:format("======== remaining ~p~n",[Remaining]), @@ -1474,7 +1543,7 @@ delete_release(Conf) -> [] -> ok; _ -> - delete_release_os(Remaining), + clean_dirs_os(Remaining,Save), Remaining2 = file:list_dir(PrivDir), ?t:format("======== remaining after second try ~p~n",[Remaining2]) end, @@ -1483,22 +1552,22 @@ delete_release(Conf) -> ok. -delete_release_os(Dirs) -> +clean_dirs_os(Dirs,Save) -> case os:type() of {unix, _} -> - delete_release_unix(Dirs); + clean_dirs_unix(Dirs,Save); {win32, _} -> - delete_release_win32(Dirs); + clean_dirs_win32(Dirs,Save); Os -> test_server:fail({error, {not_yet_implemented_os, Os}}) end. -delete_release_unix([]) -> +clean_dirs_unix([],_) -> ok; -delete_release_unix(["save"|Dirs]) -> - delete_release_unix(Dirs); -delete_release_unix([Dir|Dirs]) -> +clean_dirs_unix(["save"|Dirs],Save) when Save -> + clean_dirs_unix(Dirs,Save); +clean_dirs_unix([Dir|Dirs],Save) -> Rm = string:concat("rm -rf ", Dir), ?t:format("============== COMMAND ~p~n",[Rm]), case file:list_dir(Dir) of @@ -1515,13 +1584,13 @@ delete_release_unix([Dir|Dirs]) -> ?t:format("------- ls -al ~p~n",[os:cmd("ls -al " ++ Dir)]) end, - delete_release_unix(Dirs). + clean_dirs_unix(Dirs,Save). -delete_release_win32([]) -> +clean_dirs_win32([],_) -> ok; -delete_release_win32(["save"|Dirs]) -> - delete_release_win32(Dirs); -delete_release_win32([Dir|Dirs]) -> +clean_dirs_win32(["save"|Dirs],Save) when Save -> + clean_dirs_win32(Dirs,Save); +clean_dirs_win32([Dir|Dirs],Save) -> Rm = case filelib:is_dir(Dir) of true -> @@ -1531,7 +1600,7 @@ delete_release_win32([Dir|Dirs]) -> end, ?t:format("============== COMMAND ~p~n",[Rm]), [] = os:cmd(Rm), - delete_release_win32(Dirs). + clean_dirs_win32(Dirs,Save). node_name(Sname) when is_atom(Sname) -> @@ -1657,9 +1726,17 @@ priv_dir(Conf) -> %% filename:absname(?config(priv_dir, Conf)). % Get rid of trailing slash %% Due to problem with long paths on windows => creating a new %% priv_dir under data_dir + filename:absname(filename:join(?config(data_dir, Conf),priv_dir)). + +init_priv_dir(Conf) -> Dir = filename:absname(filename:join(?config(data_dir, Conf),priv_dir)), - filelib:ensure_dir(filename:join(Dir,"*")), - Dir. + case filelib:is_dir(Dir) of + true -> + clean_priv_dir(Conf,false); + false -> + ok + end, + filelib:ensure_dir(filename:join(Dir,"*")). latest_version(Dir) -> List = filelib:wildcard(Dir ++ "*"), @@ -1694,14 +1771,22 @@ stop_print_proc() -> %% Create the first target release, vsn P1G. This release is used for %% all test cases in {group,release} -create_p1g(Conf,Sname) -> - do_create_p1g(Conf,filename:join(priv_dir(Conf),Sname)). - -do_create_p1g(Conf,TargetDir) -> - PrivDir = priv_dir(Conf), +create_p1g(Conf,TargetDir) -> DataDir = ?config(data_dir,Conf), - ErtsVsn = "4.4", - ErtsDir = "erts-"++ErtsVsn, + PrivDir = priv_dir(Conf), + ErtsDir = app_dir(erts,old), + KernelDir = app_dir(kernel,old), + StdlibDir = app_dir(stdlib,old), + + %% Fake earlier version of kernel and stdlib + SystemLib = system_lib(PrivDir), + ok = filelib:ensure_dir(filename:join(SystemLib,"*")), + KernelLib = code:lib_dir(kernel), + StdlibLib = code:lib_dir(stdlib), + ok = copy_tree(Conf,KernelLib,KernelDir,SystemLib), + ok = copy_tree(Conf,StdlibLib,StdlibDir,SystemLib), + fix_version(SystemLib,kernel), + fix_version(SystemLib,stdlib), %% Create dirs BinDir = filename:join(TargetDir,bin), @@ -1745,17 +1830,15 @@ do_create_p1g(Conf,TargetDir) -> RelFileName = filename:join(RelDir,RelName), RelFile = RelFileName ++ ".rel", ok = filelib:ensure_dir(RelFile), - LibPath = filename:join([DataDir,lib,"*",ebin]), - TarFile = create_basic_release(Conf, RelFile, RelVsn, {ErtsVsn,false}, - LibPath, [], [], [], []), + TarFile = create_basic_release(Conf,RelFile,RelVsn,{old,false}), %% Extract tar file in target directory (i.e. same directory as erts etc.) ok = erl_tar:extract(TarFile, [{cwd, TargetDir}, compressed]), %% Create start_erl.data StartErlDataFile = filename:join([ReleasesDir, "start_erl.data"]), - StartErlData = io_lib:fwrite("~s ~s~n", [ErtsVsn, RelVsn]), + StartErlData = io_lib:fwrite("~s ~s~n", [vsn(erts,old), RelVsn]), ok = file:write_file(StartErlDataFile, StartErlData), %% Create RELEASES @@ -1763,60 +1846,98 @@ do_create_p1g(Conf,TargetDir) -> ok. +fix_version(SystemLib,App) -> + FromVsn = vsn(App,current), + ToVsn = vsn(App,old), + Rootname = filename:join([SystemLib,app_dir(App,old),ebin,atom_to_list(App)]), + + AppFile = Rootname ++ ".app", + {ok,OrigApp} = file:read_file(AppFile), + ok = file:write_file(AppFile,re:replace(OrigApp,FromVsn,ToVsn, + [{return,binary}])), + AppupFile = Rootname ++ ".appup", + {ok,OrigAppup} = file:read_file(AppupFile), + ok = file:write_file(AppupFile,re:replace(OrigAppup,FromVsn,ToVsn, + [{return,binary}])). + + %% Create version P1H - which is P1G + a-1.0 %% Must have run create_p1g first!! create_p1h(Conf) -> - create_upgrade_release(Conf,"rel1","P1H",{"4.4",false},[{a,"1.0"}], - [{a,[{key2,val2}]}],{"rel0",[new_appl]}). + create_upgrade_release(Conf,"rel1","P1H",{old,false},[{a,"1.0"}], + [{a,[{key2,val2}]}],[{"rel0",[new_appl]}]). %% Create version P1I - which is P1H, but with application a upgraded to a-1.1 %% Must have run create_p1h first!! create_p1i(Conf) -> - create_upgrade_release(Conf,"rel2","P1I",{"4.4",false},[{a,"1.1"}], + create_upgrade_release(Conf,"rel2","P1I",{old,false},[{a,"1.1"}], [{a,[{key2,newval2}]}], - {"rel1",[{extra,gott}]}). + [{"rel1",[{extra,gott}]}]). %% Create version P2A - which is P1I, but with erts- %% Must have run create_p1i first!! create_p2a(Conf) -> - ErtsVsn = erlang:system_info(version), - create_upgrade_release(Conf,"rel3","P2A",{ErtsVsn,code:root_dir()}, + create_upgrade_release(Conf,"rel3","P2A",{current,code:root_dir()}, + [{a,"1.1"}],[{a,[{key2,newval2}]}], + [{"rel1",[new_emu,new_appl]},{"rel2",[new_emu]}], + [{"rel1",[old_emu,old_appl]},{"rel2",[old_emu]}]). + +%% Create version P2B - which is P2A, but with relup containing an +%% extra reboot. +%% Can be upgraded to from P1G - so must have run create_p1g first!! +create_p2b(Conf) -> + create_upgrade_release(Conf,"rel4","P2B",{current,code:root_dir()}, [{a,"1.1"}],[{a,[{key2,newval2}]}], - {"rel2",[new_emu]}). + [{"rel0",[new_emu,add_appl]}], + [{"rel0",[old_emu,rm_appl]}], + [restart_emulator]). %% Create a release tar package which can be installed on top of P1G -create_upgrade_release(Conf,RelName,RelVsn,Erts,Apps,Config,{UpFromName,Descr}) -> +create_upgrade_release(Conf,RelName,RelVsn,Erts,Apps,Config,UpFrom) -> + create_upgrade_release(Conf,RelName,RelVsn,Erts,Apps,Config,UpFrom,[]). +create_upgrade_release(Conf,RelName,RelVsn,Erts,Apps,Config,UpFrom,DownTo) -> + create_upgrade_release(Conf,RelName,RelVsn,Erts,Apps,Config,UpFrom,DownTo,[]). +create_upgrade_release(Conf,RelName,RelVsn,Erts,Apps,Config,UpFrom0,DownTo0,RelupOpts) -> PrivDir = priv_dir(Conf), - DataDir = ?config(data_dir,Conf), - RelDir = filename:join(PrivDir,RelName), RelFileName = filename:join(RelDir,RelName), RelFile = RelFileName ++ ".rel", ok = filelib:ensure_dir(RelFile), - LibPath = filename:join([DataDir,lib,"*",ebin]), - UpFrom = [{filename:join([PrivDir,UpFromName,UpFromName]),Descr}], + UpFrom = [{filename:join([PrivDir,UpFromName,UpFromName]),Descr} || + {UpFromName,Descr} <- UpFrom0], + DownTo = [{filename:join([PrivDir,DownToName,DownToName]),Descr} || + {DownToName,Descr} <- DownTo0], - create_basic_release(Conf, RelFile, RelVsn, Erts, LibPath, - Apps, Config, UpFrom, []), + create_basic_release(Conf,RelFile,RelVsn,Erts,Apps,Config, + UpFrom,DownTo,RelupOpts), ok. %% Create .rel, .script, .boot, sys.config and tar -create_basic_release(Conf, RelFile,RelVsn,{ErtsVsn,ErtsDir},LibPath,ExtraApps,Config,UpFrom,DownTo) -> +create_basic_release(Conf,RelFile,RelVsn,{Erts,ErtsDir}) -> + create_basic_release(Conf, RelFile,RelVsn,{Erts,ErtsDir},[],[],[],[],[]). +create_basic_release(Conf,RelFile,RelVsn,{Erts,ErtsDir},ExtraApps,Config,UpFrom,DownTo,RelupOpts) -> + DataDir = ?config(data_dir,Conf), + PrivDir = priv_dir(Conf), + SystemLib = system_lib(PrivDir), + LibPath = [filename:join([SystemLib,"*",ebin]), + filename:join([DataDir,lib,"*",ebin])], + RelDir = filename:dirname(RelFile), RelFileName = filename:rootname(RelFile), %% Create .rel file - create_installer_rel_file(RelFile,RelVsn,ErtsVsn,ExtraApps), + create_installer_rel_file(RelFile,RelVsn,Erts,ExtraApps), %% Generate .script and .boot ok = systools:make_script(RelFileName, - [{path,[LibPath]}, + [{path,LibPath}, {outdir,RelDir}]), %% Generate relup - ok = systools:make_relup(RelFileName,UpFrom,DownTo,[{path,[LibPath]}, - {outdir,RelDir}]), + ok = systools:make_relup(RelFileName,UpFrom,DownTo,[{path,LibPath}, + {outdir,RelDir} | + RelupOpts]), %% Create sys.config ok = write_term_file(filename:join(RelDir,"sys.config"),Config), @@ -1824,7 +1945,7 @@ create_basic_release(Conf, RelFile,RelVsn,{ErtsVsn,ErtsDir},LibPath,ExtraApps,Co %% Create tar file (i.e. collect all lib/app-*/* and system files) ok = systools:make_tar(RelFileName, - [{path,[LibPath]}, + [{path,LibPath}, {outdir,RelDir} | case ErtsDir of false -> []; @@ -1841,18 +1962,19 @@ create_basic_release(Conf, RelFile,RelVsn,{ErtsVsn,ErtsDir},LibPath,ExtraApps,Co TarFileName. %% Create a .rel file -create_installer_rel_file(RelFile,RelVsn,ErtsVsn,ExtraApps) -> - create_rel_file(RelFile,"SASL-test",RelVsn,ErtsVsn, +create_installer_rel_file(RelFile,RelVsn,Erts,ExtraApps) -> + create_rel_file(RelFile,"SASL-test",RelVsn,Erts, [{installer,"1.0"}|ExtraApps]). -create_rel_file(RelFile,RelName,RelVsn,ErtsVsn,ExtraApps) -> - {ok,KernelVsn} = application:get_key(kernel,vsn), - {ok,StdlibVsn} = application:get_key(stdlib,vsn), - {ok,SaslVsn} = application:get_key(sasl,vsn), +create_rel_file(RelFile,RelName,RelVsn,Erts,ExtraApps) -> + ErtsVsn = vsn(erts,Erts), + KernelVsn = vsn(kernel,Erts), + StdlibVsn = vsn(stdlib,Erts), + SaslVsn = vsn(sasl,current), application:load(tools), - {ok,ToolsVsn} = application:get_key(tools,vsn), + ToolsVsn = vsn(tools,current), application:load(runtime_tools), - {ok,RuntimeToolsVsn} = application:get_key(runtime_tools,vsn), + RuntimeToolsVsn = vsn(runtime_tools,current), RelFileContent = {release, {RelName, RelVsn}, @@ -2033,7 +2155,7 @@ start_node_unix(Sname,NodeDir) -> start_node_win32(Sname,NodeDir) -> Name = atom_to_list(Sname) ++ "_P1G", - ErtsBinDir = filename:join(NodeDir,"erts-4.4/bin"), + ErtsBinDir = filename:join([NodeDir,app_dir(erts,old),"bin"]), StartErlArgs = rh_test_lib:get_start_erl_args(NodeDir), ServiceArgs = rh_test_lib:get_service_args(NodeDir, Sname, StartErlArgs), @@ -2158,7 +2280,6 @@ create_fake_release(Dir,RelName,RelVsn,AppDirs) -> RelDir = filename:join(Dir,"rel_" ++ RelVsn), Rel = filename:join([RelDir,"rel_" ++ RelVsn]), ok = filelib:ensure_dir(Rel), - ErtsVsn = erlang:system_info(version), {Apps,Paths} = lists:foldl(fun({App,Vsn,Lib},{As,Ps}) -> @@ -2168,7 +2289,7 @@ create_fake_release(Dir,RelName,RelVsn,AppDirs) -> {[],[]}, AppDirs), - create_rel_file(Rel++".rel",RelName,RelVsn,ErtsVsn,Apps), + create_rel_file(Rel++".rel",RelName,RelVsn,current,Apps), %% Generate boot scripts ok = systools:make_script(Rel,[local, @@ -2217,3 +2338,16 @@ modify_tar_win32(Conf, TarFileName) -> [ok = erl_tar:add(T,filename:join(TmpDir,F),F,[]) || F <- Fs], ok = erl_tar:close(T), ok. + +app_dir(App,Vsn) -> + atom_to_list(App) ++ "-" ++ vsn(App,Vsn). +vsn(erts,old) -> ?ertsvsn; +vsn(kernel,old) -> ?kernelvsn; +vsn(stdlib,old) -> ?stdlibvsn; +vsn(erts,current) -> erlang:system_info(version); +vsn(App,current) -> + {ok,Vsn} = application:get_key(App,vsn), + Vsn. + +system_lib(PrivDir) -> + filename:join(PrivDir,"system_lib"). diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/a-1.1/ebin/a.appup b/lib/sasl/test/release_handler_SUITE_data/lib/a-1.1/ebin/a.appup index 05db4cb541..6ef67b869e 100644 --- a/lib/sasl/test/release_handler_SUITE_data/lib/a-1.1/ebin/a.appup +++ b/lib/sasl/test/release_handler_SUITE_data/lib/a-1.1/ebin/a.appup @@ -1,3 +1,3 @@ {"1.1", [{"1.0",[{update,a,{advanced,extra_par}}]}], - []}. + [{"1.0",[{update,a,{advanced,extra_par}}]}]}. diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/a-1.1/src/a.erl b/lib/sasl/test/release_handler_SUITE_data/lib/a-1.1/src/a.erl index c082ad5339..1050e53f35 100644 --- a/lib/sasl/test/release_handler_SUITE_data/lib/a-1.1/src/a.erl +++ b/lib/sasl/test/release_handler_SUITE_data/lib/a-1.1/src/a.erl @@ -51,4 +51,6 @@ terminate(_Reason, _State) -> ok. code_change(1, Extra, State) -> - {ok, {state, bval}}. + {ok, {state, bval}}; +code_change({down,1},Extra,State) -> + {ok, state}. diff --git a/lib/sasl/test/systools_SUITE.erl b/lib/sasl/test/systools_SUITE.erl index e352247d44..a3e97c4543 100644 --- a/lib/sasl/test/systools_SUITE.erl +++ b/lib/sasl/test/systools_SUITE.erl @@ -51,8 +51,8 @@ exref_tar/1, link_tar/1, otp_9507/1]). -export([ normal_relup/1, abnormal_relup/1, no_appup_relup/1, bad_appup_relup/1, app_start_type_relup/1, otp_3065/1]). --export([ - otp_6226/1]). +-export([otp_6226/1]). +-export([normal_hybrid/1,hybrid_no_old_sasl/1,hybrid_no_new_sasl/1]). -export([init_per_suite/1, end_per_suite/1, init_per_testcase/2, end_per_testcase/2]). @@ -67,7 +67,7 @@ suite() -> [{ct_hooks, [ts_install_cth]}]. all() -> - [{group, script}, {group, tar}, {group, relup}, + [{group, script}, {group, tar}, {group, relup}, {group, hybrid}, {group, tickets}]. groups() -> @@ -85,6 +85,7 @@ groups() -> {relup, [], [normal_relup, abnormal_relup, no_appup_relup, bad_appup_relup, app_start_type_relup]}, + {hybrid, [], [normal_hybrid,hybrid_no_old_sasl,hybrid_no_new_sasl]}, {tickets, [], [otp_6226]}]. init_per_group(_GroupName, Config) -> @@ -1143,6 +1144,8 @@ normal_relup(Config) when is_list(Config) -> ?line {LatestDir,LatestName} = create_script(latest0,Config), ?line {_LatestDir1,LatestName1} = create_script(latest1,Config), ?line {_LatestDir2,LatestName2} = create_script(latest2,Config), + ?line {_LatestDir1CurrErts,LatestName1CurrErts} = + create_script(latest1_current_erts,Config), ?line DataDir = filename:absname(?copydir), ?line LibDir = [fname([DataDir, d_normal, lib])], @@ -1160,6 +1163,31 @@ normal_relup(Config) when is_list(Config) -> ?line ok = check_relup([{db, "2.1"}], [{db, "1.0"}]), ?line ok = check_restart_emulator(), + %% Check that new erts version generates a restart_new_emulator + %% instruction + %% (One erts_vsn_changed warning for upgrade and one for downgrade) + ?line {ok, _ , _, [{erts_vsn_changed,_},{erts_vsn_changed,_}]} = + systools:make_relup(LatestName, + [LatestName1CurrErts], + [LatestName1CurrErts], + [{path, P},silent]), + ?line ok = check_relup([{db, "2.1"}], [{db, "1.0"}]), + ?line ok = check_restart_emulator_diff_erts(), + + + %% Check that new erts version generates a restart_new_emulator + %% instruction, and can be combined with restart_emulator opt. + %% (One erts_vsn_changed warning for upgrade and one for downgrade) + ?line {ok, _ , _, [{erts_vsn_changed,_},{erts_vsn_changed,_}]} = + systools:make_relup(LatestName, + [LatestName1CurrErts], + [LatestName1CurrErts], + [{path, P},restart_emulator,silent]), + ?line ok = check_relup([{db, "2.1"}], [{db, "1.0"}]), + ?line ok = check_restart_emulator(), + ?line ok = check_restart_emulator_diff_erts(), + + %% This is the ultra normal case ?line ok = systools:make_relup(LatestName, [LatestName1], [LatestName1], [{path, P}]), @@ -1222,6 +1250,12 @@ check_restart_emulator() -> restart_new_emulator = lists:last(Dn), ok. +check_restart_emulator_diff_erts() -> + {ok, [{_V1, [{_, _, Up}], [{_, _, Dn}]}]} = file:consult(relup), + [restart_new_emulator|_] = Up, + restart_new_emulator = lists:last(Dn), + ok. + %% make_relup %% no_appup_relup(suite) -> []; @@ -1371,6 +1405,168 @@ app_start_type_relup(Config) when is_list(Config) -> ok. +%% For upgrade of erts - create a boot file which is a hybrid between +%% old and new release - i.e. starts erts, kernel, stdlib, sasl from +%% new release, all other apps from old release. +normal_hybrid(Config) -> + ?line {ok, OldDir} = file:get_cwd(), + ?line {Dir1,Name1} = create_script(latest1_sasl,Config), + ?line {_Dir2,Name2} = create_script(current_all_sasl,Config), + + ?line DataDir = filename:absname(?copydir), + ?line LibDir = [fname([DataDir, d_normal, lib])], + ?line P = [fname([LibDir, '*', ebin]), + fname([DataDir, lib, kernel, ebin]), + fname([DataDir, lib, stdlib, ebin]), + fname([DataDir, lib, sasl, ebin])], + + ?line ok = file:set_cwd(Dir1), + + ?line {ok, _ , []} = systools:make_script(Name1,[{path, P},silent]), + ?line {ok, _ , []} = systools:make_script(Name2,[{path, P},silent]), + ?line {ok,Boot1} = file:read_file(Name1 ++ ".boot"), + ?line {ok,Boot2} = file:read_file(Name2 ++ ".boot"), + + ?line ok = file:set_cwd(OldDir), + + ?line BasePaths = {"testkernelpath","teststdlibpath","testsaslpath"}, + ?line {ok,Hybrid} = systools_make:make_boot_hybrid("tmp_vsn",Boot1,Boot2, + BasePaths, [dummy,args]), + + ?line {script,{"Test release 4","tmp_vsn"},Script} = binary_to_term(Hybrid), + ct:log("~p.~n",[Script]), + + %% Check that all paths to base apps are replaced by paths from BaseLib + Boot1Str = io_lib:format("~p~n",[binary_to_term(Boot1)]), + HybridStr = io_lib:format("~p~n",[binary_to_term(Hybrid)]), + ReOpts = [global,{capture,first,list},unicode], + ?line {match,OldKernelMatch} = re:run(Boot1Str,"kernel-[0-9\.]+",ReOpts), + ?line {match,OldStdlibMatch} = re:run(Boot1Str,"stdlib-[0-9\.]+",ReOpts), + ?line {match,OldSaslMatch} = re:run(Boot1Str,"sasl-[0-9\.]+",ReOpts), + + ?line nomatch = re:run(HybridStr,"kernel-[0-9\.]+",ReOpts), + ?line nomatch = re:run(HybridStr,"stdlib-[0-9\.]+",ReOpts), + ?line nomatch = re:run(HybridStr,"sasl-[0-9\.]+",ReOpts), + ?line {match,NewKernelMatch} = re:run(HybridStr,"testkernelpath",ReOpts), + ?line {match,NewStdlibMatch} = re:run(HybridStr,"teststdlibpath",ReOpts), + ?line {match,NewSaslMatch} = re:run(HybridStr,"testsaslpath",ReOpts), + + NewKernelN = length(NewKernelMatch), + ?line NewKernelN = length(OldKernelMatch), + NewStdlibN = length(NewStdlibMatch), + ?line NewStdlibN = length(OldStdlibMatch), + NewSaslN = length(NewSaslMatch), + ?line NewSaslN = length(OldSaslMatch), + + %% Check that application load instruction has correct versions + Apps = application:loaded_applications(), + {_,_,KernelVsn} = lists:keyfind(kernel,1,Apps), + {_,_,StdlibVsn} = lists:keyfind(stdlib,1,Apps), + {_,_,SaslVsn} = lists:keyfind(sasl,1,Apps), + + ?line [KernelInfo] = [I || {kernelProcess,application_controller, + {application_controller,start, + [{application,kernel,I}]}} <- Script], + ?line [StdlibInfo] = [I || {apply, + {application,load, + [{application,stdlib,I}]}} <- Script], + ?line [SaslInfo] = [I || {apply, + {application,load, + [{application,sasl,I}]}} <- Script], + + ?line {vsn,KernelVsn} = lists:keyfind(vsn,1,KernelInfo), + ?line {vsn,StdlibVsn} = lists:keyfind(vsn,1,StdlibInfo), + ?line {vsn,SaslVsn} = lists:keyfind(vsn,1,SaslInfo), + + %% Check that new_emulator_upgrade call is added + ?line [_,{apply,{release_handler,new_emulator_upgrade,[dummy,args]}}|_] = + lists:reverse(Script), + + %% Check that db-1.0 and fe-3.1 are used (i.e. vsns from old release) + %% And that fe is in there (it exists in old rel but not in new) + ?line {match,DbMatch} = re:run(HybridStr,"db-[0-9\.]+",ReOpts), + ?line {match,[_|_]=FeMatch} = re:run(HybridStr,"fe-[0-9\.]+",ReOpts), + ?line true = lists:all(fun(["db-1.0"]) -> true; + (_) -> false + end, + DbMatch), + ?line true = lists:all(fun(["fe-3.1"]) -> true; + (_) -> false + end, + FeMatch), + + %% Check that script has same length as old script, plus one (the + %% new_emulator_upgrade apply) + {_,_,Old} = binary_to_term(Boot1), + OldLength = length(Old), + NewLength = length(Script), + ?line NewLength = OldLength + 1, + + ok. + +%% Check that systools_make:make_boot_hybrid fails with a meaningful +%% error message if the FromBoot does not include the sasl +%% application. +hybrid_no_old_sasl(Config) -> + ?line {ok, OldDir} = file:get_cwd(), + ?line {Dir1,Name1} = create_script(latest1,Config), + ?line {_Dir2,Name2} = create_script(current_all_sasl,Config), + + ?line DataDir = filename:absname(?copydir), + ?line LibDir = [fname([DataDir, d_normal, lib])], + ?line P = [fname([LibDir, '*', ebin]), + fname([DataDir, lib, kernel, ebin]), + fname([DataDir, lib, stdlib, ebin]), + fname([DataDir, lib, sasl, ebin])], + + ?line ok = file:set_cwd(Dir1), + + ?line {ok, _ , []} = systools:make_script(Name1,[{path, P},silent]), + ?line {ok, _ , []} = systools:make_script(Name2,[{path, P},silent]), + ?line {ok,Boot1} = file:read_file(Name1 ++ ".boot"), + ?line {ok,Boot2} = file:read_file(Name2 ++ ".boot"), + + ?line BasePaths = {"testkernelpath","teststdlibpath","testsaslpath"}, + ?line {error,{app_not_replaced,sasl}} = + systools_make:make_boot_hybrid("tmp_vsn",Boot1,Boot2, + BasePaths,[dummy,args]), + + ?line ok = file:set_cwd(OldDir), + ok. + + +%% Check that systools_make:make_boot_hybrid fails with a meaningful +%% error message if the ToBoot does not include the sasl +%% application. +hybrid_no_new_sasl(Config) -> + ?line {ok, OldDir} = file:get_cwd(), + ?line {Dir1,Name1} = create_script(latest1_sasl,Config), + ?line {_Dir2,Name2} = create_script(current_all_no_sasl,Config), + + ?line DataDir = filename:absname(?copydir), + ?line LibDir = [fname([DataDir, d_normal, lib])], + ?line P = [fname([LibDir, '*', ebin]), + fname([DataDir, lib, kernel, ebin]), + fname([DataDir, lib, stdlib, ebin]), + fname([DataDir, lib, sasl, ebin])], + + ?line ok = file:set_cwd(Dir1), + + ?line {ok, _ , []} = systools:make_script(Name1,[{path, P},silent]), + ?line {ok, _ , []} = systools:make_script(Name2,[{path, P},silent]), + ?line {ok,Boot1} = file:read_file(Name1 ++ ".boot"), + ?line {ok,Boot2} = file:read_file(Name2 ++ ".boot"), + + ?line BasePaths = {"testkernelpath","teststdlibpath","testsaslpath"}, + ?line {error,{app_not_found,sasl}} = + systools_make:make_boot_hybrid("tmp_vsn",Boot1,Boot2, + BasePaths,[dummy,args]), + + ?line ok = file:set_cwd(OldDir), + ok. + + + otp_6226(suite) -> []; otp_6226(doc) -> @@ -1709,6 +1905,36 @@ create_script(latest1,Config) -> []), ?line ok = file:close(Fd), {filename:dirname(Name), filename:basename(Name)}; +create_script(latest1_sasl,Config) -> + ?line PrivDir = ?privdir, + ?line Name = fname(PrivDir, latest_sasl), + ?line {ok,Fd} = file:open(Name++".rel",write), + ?line RelfileContent = + {release,{"Test release 2", "LATEST1_SASL"}, + {erts,"4.4"}, + [{kernel,"1.0"}, + {stdlib,"1.0"}, + {sasl,"1.0"}, + {db,"1.0"}, + {fe,"3.1"}]}, + ?line io:format(Fd,"~p.~n",[RelfileContent]), + ?line ok = file:close(Fd), + {filename:dirname(Name), filename:basename(Name)}; +create_script(latest1_current_erts,Config) -> + ?line PrivDir = ?privdir, + ?line Name = fname(PrivDir, 'latest_current_erts'), + ?line ErtsVer = erlang:system_info(version), + ?line {ok,Fd} = file:open(Name++".rel",write), + ?line RelfileContent = + {release,{"Test release 2", "LATEST1_CURRENT_ERTS"}, + {erts,ErtsVer}, + [{kernel,"1.0"}, % fake - will never happen for real that + {stdlib,"1.0"}, % erts changes verson but not kernel and stdlib. + {db,"1.0"}, + {fe,"3.1"}]}, + ?line io:format(Fd,"~p.~n",[RelfileContent]), + ?line ok = file:close(Fd), + {filename:dirname(Name), filename:basename(Name)}; create_script(latest2,Config) -> ?line PrivDir = ?privdir, ?line Name = fname(PrivDir, 'latest-2'), @@ -1813,8 +2039,47 @@ create_script(latest_app_start_type2,Config) -> {stdlib,StdlibVer} | OtherAppsRel]}, ?line io:format(Fd,"~p.~n",[RelfileContent]), ?line ok = file:close(Fd), + {filename:dirname(Name), filename:basename(Name)}; +create_script(current_all_no_sasl,Config) -> + ?line PrivDir = ?privdir, + ?line Name = fname(PrivDir, 'current_all_no_sasl'), + ?line ErtsVer = erlang:system_info(version), + ?line Apps = application_controller:which_applications(), + ?line {value,{_,_,KernelVer}} = lists:keysearch(kernel,1,Apps), + ?line {value,{_,_,StdlibVer}} = lists:keysearch(stdlib,1,Apps), + ?line {ok,Fd} = file:open(Name++".rel",write), + ?line RelfileContent = + {release,{"Test release 4", "CURRENT_ALL_NO_SASL"}, + {erts,ErtsVer}, + [{kernel,KernelVer}, + {stdlib,StdlibVer}, + {db,"2.1"}, + {fe,"3.1"}]}, + ?line io:format(Fd,"~p.~n",[RelfileContent]), + ?line ok = file:close(Fd), + {filename:dirname(Name), filename:basename(Name)}; +create_script(current_all_sasl,Config) -> + ?line PrivDir = ?privdir, + ?line Name = fname(PrivDir, 'current_all_sasl'), + ?line ErtsVer = erlang:system_info(version), + ?line application:load(sasl), + ?line Apps = application_controller:loaded_applications(), + ?line {value,{_,_,KernelVer}} = lists:keysearch(kernel,1,Apps), + ?line {value,{_,_,StdlibVer}} = lists:keysearch(stdlib,1,Apps), + ?line {value,{_,_,SaslVer}} = lists:keysearch(sasl,1,Apps), + ?line {ok,Fd} = file:open(Name++".rel",write), + ?line RelfileContent = + {release,{"Test release 4", "CURRENT_ALL_SASL"}, + {erts,ErtsVer}, + [{kernel,KernelVer}, + {stdlib,StdlibVer}, + {sasl,SaslVer}, + {db,"2.1"}]},% fe left out here on purpose - for normal_hybrid test + ?line io:format(Fd,"~p.~n",[RelfileContent]), + ?line ok = file:close(Fd), {filename:dirname(Name), filename:basename(Name)}. + create_include_files(inc1, Config) -> ?line PrivDir = ?privdir, ?line Name = fname(PrivDir, inc1), diff --git a/lib/sasl/test/systools_SUITE_data/lib/sasl/ebin/sasl.app b/lib/sasl/test/systools_SUITE_data/lib/sasl/ebin/sasl.app new file mode 100644 index 0000000000..aaeb37fa4d --- /dev/null +++ b/lib/sasl/test/systools_SUITE_data/lib/sasl/ebin/sasl.app @@ -0,0 +1,6 @@ +{application, sasl, + [{description, "FAKE SASL"}, + {vsn, "1.0"}, + {modules, []}, + {registered, []}, + {applications, []}]}. diff --git a/lib/sasl/test/systools_SUITE_data/lib/sasl/ebin/sasl.appup b/lib/sasl/test/systools_SUITE_data/lib/sasl/ebin/sasl.appup new file mode 100644 index 0000000000..796a1e7368 --- /dev/null +++ b/lib/sasl/test/systools_SUITE_data/lib/sasl/ebin/sasl.appup @@ -0,0 +1,12 @@ +%% +%% Fake release upgrade script for sasl +%% + +{ + "1.0", + [ + ], + + [ + ] +}. diff --git a/lib/sasl/test/test_lib.hrl b/lib/sasl/test/test_lib.hrl new file mode 100644 index 0000000000..eeef721647 --- /dev/null +++ b/lib/sasl/test/test_lib.hrl @@ -0,0 +1,3 @@ +-define(ertsvsn,"4.4"). +-define(kernelvsn,"2.14.3"). +-define(stdlibvsn,"1.17.3"). -- cgit v1.2.3 From 8a013f1f16fd4730c24839127afdf46f96a45b0b Mon Sep 17 00:00:00 2001 From: Siri Hansen Date: Mon, 10 Oct 2011 11:30:17 +0200 Subject: Allow regexp for version in .appup In order to avoid duplication of upgrade instructions in .appup files, we now allow regular expressions to specify the UpFrom and DownTo versions. To be considered a regular expression, the version identifier must be specified as a binary, e.g. <<"2\\.1\\.[0-9]+">> will match versions 2.1.x, where x is any number. --- lib/sasl/src/systools_relup.erl | 22 ++++++- lib/sasl/test/systools_SUITE.erl | 72 +++++++++++++++++++++- .../d_regexp_appup/lib/fe-2.1.1/ebin/fe.app | 8 +++ .../d_regexp_appup/lib/fe-2.1/ebin/fe.app | 8 +++ .../d_regexp_appup/lib/fe-3.1/ebin/fe.app | 7 +++ .../d_regexp_appup/lib/fe-3.1/ebin/fe.appup | 28 +++++++++ 6 files changed, 140 insertions(+), 5 deletions(-) create mode 100644 lib/sasl/test/systools_SUITE_data/d_regexp_appup/lib/fe-2.1.1/ebin/fe.app create mode 100644 lib/sasl/test/systools_SUITE_data/d_regexp_appup/lib/fe-2.1/ebin/fe.app create mode 100644 lib/sasl/test/systools_SUITE_data/d_regexp_appup/lib/fe-3.1/ebin/fe.app create mode 100644 lib/sasl/test/systools_SUITE_data/d_regexp_appup/lib/fe-3.1/ebin/fe.appup (limited to 'lib/sasl') diff --git a/lib/sasl/src/systools_relup.erl b/lib/sasl/src/systools_relup.erl index 682f5f5cc9..5cfbc3aadf 100644 --- a/lib/sasl/src/systools_relup.erl +++ b/lib/sasl/src/systools_relup.erl @@ -451,13 +451,29 @@ get_script_from_appup(Mode, TopApp, BaseVsn, Ws, RUs) -> %% XXX Why is this a warning only? [{bad_vsn, {TopVsn, TopApp#application.vsn}}| Ws] end, - case lists:keysearch(BaseVsn, 1, VsnRUs) of - {value, {_, RU}} -> + case search_for_version(BaseVsn, length(BaseVsn), VsnRUs) of + {ok, RU} -> {RUs ++ [RU], Ws1}; - _ -> + error -> throw({error, ?MODULE, {no_relup, FName, TopApp, BaseVsn}}) end. +search_for_version(BaseVsn,_,[{BaseVsn,RU}|_]) -> + {ok,RU}; +search_for_version(BaseVsn,Size,[{Vsn,RU}|VsnRUs]) when is_binary(Vsn) -> + case re:run(BaseVsn,Vsn,[unicode,{capture,first,index}]) of + {match,[{0,Size}]} -> + {ok, RU}; + _ -> + search_for_version(BaseVsn,Size,VsnRUs) + end; +search_for_version(BaseVsn,Size,[_|VsnRUs]) -> + search_for_version(BaseVsn,Size,VsnRUs); +search_for_version(_,_,[]) -> + error. + + + %% Primitives for the "lists of release names" that we upgrade from %% and to. diff --git a/lib/sasl/test/systools_SUITE.erl b/lib/sasl/test/systools_SUITE.erl index a3e97c4543..960ba3cc21 100644 --- a/lib/sasl/test/systools_SUITE.erl +++ b/lib/sasl/test/systools_SUITE.erl @@ -50,7 +50,7 @@ src_tests_tar/1, shadow_tar/1, var_tar/1, exref_tar/1, link_tar/1, otp_9507/1]). -export([ normal_relup/1, abnormal_relup/1, no_appup_relup/1, - bad_appup_relup/1, app_start_type_relup/1, otp_3065/1]). + bad_appup_relup/1, app_start_type_relup/1, regexp_relup/1, otp_3065/1]). -export([otp_6226/1]). -export([normal_hybrid/1,hybrid_no_old_sasl/1,hybrid_no_new_sasl/1]). -export([init_per_suite/1, end_per_suite/1, @@ -84,7 +84,8 @@ groups() -> exref_tar, link_tar, otp_9507]}, {relup, [], [normal_relup, abnormal_relup, no_appup_relup, - bad_appup_relup, app_start_type_relup]}, + bad_appup_relup, app_start_type_relup, regexp_relup + ]}, {hybrid, [], [normal_hybrid,hybrid_no_old_sasl,hybrid_no_new_sasl]}, {tickets, [], [otp_6226]}]. @@ -1244,12 +1245,26 @@ check_relup(UpVsnL, DnVsnL) -> [{App, Vsn} || {load_object_code,{App,Vsn,_}} <- Dn]), ok. +check_relup_up_only(UpVsnL) -> + {ok, [{_V1, [{_, _, Up}], []}]} = file:consult(relup), + [] = foldl(fun(X, Acc) -> + true = lists:member(X, Acc), + lists:delete(X, Acc) end, + UpVsnL, + [{App, Vsn} || {load_object_code,{App,Vsn,_}} <- Up]), + ok. + check_restart_emulator() -> {ok, [{_V1, [{_, _, Up}], [{_, _, Dn}]}]} = file:consult(relup), restart_new_emulator = lists:last(Up), restart_new_emulator = lists:last(Dn), ok. +check_restart_emulator_up_only() -> + {ok, [{_V1, [{_, _, Up}], []}]} = file:consult(relup), + restart_new_emulator = lists:last(Up), + ok. + check_restart_emulator_diff_erts() -> {ok, [{_V1, [{_, _, Up}], [{_, _, Dn}]}]} = file:consult(relup), [restart_new_emulator|_] = Up, @@ -1405,6 +1420,47 @@ app_start_type_relup(Config) when is_list(Config) -> ok. +%% regexp_relup +regexp_relup(Config) -> + ?line {ok, OldDir} = file:get_cwd(), + + ?line {LatestDir,LatestName} = create_script(latest_small,Config), + ?line {_LatestDir0,LatestName0} = create_script(latest_small0,Config), + ?line {_LatestDir1,LatestName1} = create_script(latest_small2,Config), + + ?line DataDir = filename:absname(?copydir), + ?line P = [fname([DataDir, d_regexp_appup, lib, '*', ebin]), + fname([DataDir, lib, kernel, ebin]), + fname([DataDir, lib, stdlib, ebin])], + + ?line ok = file:set_cwd(LatestDir), + + %% Upgrade fe 2.1 -> 3.1, and downgrade 2.1 -> 3.1 + %% Shall match the first entry if fe-3.1 appup. + ?line {ok, _, _, []} = + systools:make_relup(LatestName, [LatestName0], [LatestName0], + [{path, P}, silent]), + ?line ok = check_relup([{fe, "3.1"}], [{fe, "2.1"}]), + + %% Upgrade fe 2.1.1 -> 3.1 + %% Shall match the second entry in fe-3.1 appup. Have added a + %% restart_new_emulator instruction there to distinguish it from + %% the first entry... + ?line {ok, _, _, []} = + systools:make_relup(LatestName, [LatestName1], [], [{path, P}, silent]), + ?line ok = check_relup_up_only([{fe, "3.1"}]), + ?line ok = check_restart_emulator_up_only(), + + %% Attempt downgrade fe 3.1 -> 2.1.1 + %% Shall not match any entry!! + ?line {error,systools_relup,{no_relup,_,_,_}} = + systools:make_relup(LatestName, [], [LatestName1], [{path, P}, silent]), + + ?line ok = file:set_cwd(OldDir), + + ok. + + %% For upgrade of erts - create a boot file which is a hybrid between %% old and new release - i.e. starts erts, kernel, stdlib, sasl from %% new release, all other apps from old release. @@ -1983,6 +2039,18 @@ create_script(latest_small1,Config) -> []), ?line ok = file:close(Fd), {filename:dirname(Name), filename:basename(Name)}; +create_script(latest_small2,Config) -> + ?line PrivDir = ?privdir, + ?line Name = fname(PrivDir, 'latest-small2'), + ?line {ok,Fd} = file:open(Name++".rel",write), + ?line io:format(Fd, + "{release, {\"Test release 2\", \"LATEST_SMALL2\"}, \n" + " {erts, \"4.4\"}, \n" + " [{kernel, \"1.0\"}, {stdlib, \"1.0\"}, \n" + " {fe, \"2.1.1\"}]}.\n", + []), + ?line ok = file:close(Fd), + {filename:dirname(Name), filename:basename(Name)}; create_script(latest_nokernel,Config) -> ?line PrivDir = ?privdir, ?line Name = fname(PrivDir, 'latest-nokernel'), diff --git a/lib/sasl/test/systools_SUITE_data/d_regexp_appup/lib/fe-2.1.1/ebin/fe.app b/lib/sasl/test/systools_SUITE_data/d_regexp_appup/lib/fe-2.1.1/ebin/fe.app new file mode 100644 index 0000000000..c7ba1dfe91 --- /dev/null +++ b/lib/sasl/test/systools_SUITE_data/d_regexp_appup/lib/fe-2.1.1/ebin/fe.app @@ -0,0 +1,8 @@ +{application, fe, + [{description, "ERICSSON NR FOR FE"}, + {vsn, "2.1.1"}, + {modules, [{fe1, "1.0"}, {fe2, "1.0"}, {fe3, "2.0"}]}, + {registered, []}, + {applications, []}, + {env, []}, + {start, {fe2, start, []}}]}. diff --git a/lib/sasl/test/systools_SUITE_data/d_regexp_appup/lib/fe-2.1/ebin/fe.app b/lib/sasl/test/systools_SUITE_data/d_regexp_appup/lib/fe-2.1/ebin/fe.app new file mode 100644 index 0000000000..47ea248720 --- /dev/null +++ b/lib/sasl/test/systools_SUITE_data/d_regexp_appup/lib/fe-2.1/ebin/fe.app @@ -0,0 +1,8 @@ +{application, fe, + [{description, "ERICSSON NR FOR FE"}, + {vsn, "2.1"}, + {modules, [{fe1, "1.0"}, {fe2, "1.0"}, {fe3, "2.0"}]}, + {registered, []}, + {applications, []}, + {env, []}, + {start, {fe2, start, []}}]}. diff --git a/lib/sasl/test/systools_SUITE_data/d_regexp_appup/lib/fe-3.1/ebin/fe.app b/lib/sasl/test/systools_SUITE_data/d_regexp_appup/lib/fe-3.1/ebin/fe.app new file mode 100644 index 0000000000..0696e2494c --- /dev/null +++ b/lib/sasl/test/systools_SUITE_data/d_regexp_appup/lib/fe-3.1/ebin/fe.app @@ -0,0 +1,7 @@ +{application, fe, + [{description, "ERICSSON NR FOR FE"}, + {vsn, "3.1"}, + {modules, [{fe1, "1.0"}, {fe2, "1.0"}, {fe3, "2.0"}]}, + {registered, []}, + {applications, []}, + {mod, {fe1, []}}]}. diff --git a/lib/sasl/test/systools_SUITE_data/d_regexp_appup/lib/fe-3.1/ebin/fe.appup b/lib/sasl/test/systools_SUITE_data/d_regexp_appup/lib/fe-3.1/ebin/fe.appup new file mode 100644 index 0000000000..53d54735e5 --- /dev/null +++ b/lib/sasl/test/systools_SUITE_data/d_regexp_appup/lib/fe-3.1/ebin/fe.appup @@ -0,0 +1,28 @@ +%% -*- erlang -*- +%% Release upgrade script for fe (front end) +%% + +{ + "3.1", + %% Upgrade from: + [ + {<<"2\\.[0-9]+">>, % matches 2.X in full length and 2.X.Y... only partly + [{update, fe1, soft, soft_purge, soft_purge, []}, + {update, fe2, soft, soft_purge, soft_purge, [fe1]}, + {update, fe3, {advanced, extra}, soft_purge, soft_purge, [fe1, fe2]} + ]}, + {<<"2(\\.[0-9]+)+">>, % matches 2.X.Y... in full length + [{update, fe1, soft, soft_purge, soft_purge, []}, + {update, fe2, soft, soft_purge, soft_purge, [fe1]}, + {update, fe3, {advanced, extra}, soft_purge, soft_purge,[fe1, fe2]}, + restart_new_emulator]} + ], + + %% Downgrade to: + [ + {<<"2\\.[0-9]+">>, % matches 2.X in full length and 2.X.Y... only partly + [{update, fe2, soft, soft_purge, soft_purge, []}, + {update, fe3, {advanced, extra}, soft_purge, soft_purge, [fe2]} + ]} + ] +}. -- cgit v1.2.3 From 1dec251ad333045847b75b8ee75d4bff4237108e Mon Sep 17 00:00:00 2001 From: Siri Hansen Date: Tue, 11 Oct 2011 10:58:47 +0200 Subject: Upgrade erts: merge sys.config for tmp release instead of using old The sys.config file used for the temporary release in an erts upgrade is now a hybrid where kernel, stdlib and sasl configuration is taken from the new release, and other configuration is taken from the old release. I.e. similar to how the temporary boot file is created. --- lib/sasl/src/release_handler.erl | 53 ++++++++++++++++++++++++++++++++++++---- lib/sasl/src/systools_make.erl | 8 +++--- lib/sasl/test/systools_SUITE.erl | 10 ++++---- 3 files changed, 57 insertions(+), 14 deletions(-) (limited to 'lib/sasl') diff --git a/lib/sasl/src/release_handler.erl b/lib/sasl/src/release_handler.erl index 38aee9ecde..931347bde2 100644 --- a/lib/sasl/src/release_handler.erl +++ b/lib/sasl/src/release_handler.erl @@ -1049,10 +1049,9 @@ new_emulator_make_tmp_release(CurrentRelease,ToRelease,RelDir,Opts,Masters) -> erts_vsn=ToRelease#release.erts_vsn, libs = BaseLibs ++ RestLibs, status = unpacked}, - new_emulator_make_boot_hybrid(CurrentVsn,ToVsn,TmpVsn,BaseLibs, + new_emulator_make_hybrid_boot(CurrentVsn,ToVsn,TmpVsn,BaseLibs, RelDir,Opts,Masters), - SysConfig = filename:join([RelDir,CurrentVsn,"sys.config"]), - copy_file(SysConfig,filename:join(RelDir,TmpVsn),Masters), + new_emulator_make_hybrid_config(CurrentVsn,ToVsn,TmpVsn,RelDir,Masters), {TmpVsn,TmpRelease}. check_base_libs([_,_,_]=BaseLibs,_Vsn) -> @@ -1069,7 +1068,7 @@ find_missing(SomeMissing,[H|T],Vsn) -> throw({error,{missing_base_app,Vsn,H}}) end. -new_emulator_make_boot_hybrid(CurrentVsn,ToVsn,TmpVsn,BaseLibs,RelDir,Opts,Masters) -> +new_emulator_make_hybrid_boot(CurrentVsn,ToVsn,TmpVsn,BaseLibs,RelDir,Opts,Masters) -> FromBootFile = filename:join([RelDir,CurrentVsn,"start.boot"]), ToBootFile = filename:join([RelDir,ToVsn,"start.boot"]), TmpBootFile = filename:join([RelDir,TmpVsn,"start.boot"]), @@ -1080,13 +1079,57 @@ new_emulator_make_boot_hybrid(CurrentVsn,ToVsn,TmpVsn,BaseLibs,RelDir,Opts,Maste [KernelPath,SaslPath,StdlibPath] = [filename:join(Path,ebin) || {_,_,Path} <- lists:keysort(1,BaseLibs)], Paths = {KernelPath,StdlibPath,SaslPath}, - case systools_make:make_boot_hybrid(TmpVsn,FromBoot,ToBoot,Paths,Args) of + case systools_make:make_hybrid_boot(TmpVsn,FromBoot,ToBoot,Paths,Args) of {ok,TmpBoot} -> write_file(TmpBootFile,TmpBoot,Masters); {error,Reason} -> throw({error,{could_not_create_hybrid_boot,Reason}}) end. +new_emulator_make_hybrid_config(CurrentVsn,ToVsn,TmpVsn,RelDir,Masters) -> + FromFile = filename:join([RelDir,CurrentVsn,"sys.config"]), + ToFile = filename:join([RelDir,ToVsn,"sys.config"]), + TmpFile = filename:join([RelDir,TmpVsn,"sys.config"]), + + FromConfig = + case consult(FromFile,Masters) of + {ok,[FC]} -> + FC; + {error,Error1} -> + io:format("Warning: ~p can not read ~p: ~p~n", + [?MODULE,FromFile,Error1]), + [] + end, + + [Kernel,Stdlib,Sasl] = + case consult(ToFile,Masters) of + {ok,[ToConfig]} -> + [lists:keyfind(App,1,ToConfig) || App <- [kernel,stdlib,sasl]]; + {error,Error2} -> + io:format("Warning: ~p can not read ~p: ~p~n", + [?MODULE,ToFile,Error2]), + [false,false,false] + end, + + Config1 = replace_config(kernel,FromConfig,Kernel), + Config2 = replace_config(stdlib,Config1,Stdlib), + Config3 = replace_config(sasl,Config2,Sasl), + + ConfigStr = io_lib:format("~p.~n",[Config3]), + write_file(TmpFile,ConfigStr,Masters). + +%% Take the configuration for application App from the new config and +%% insert in the old config. +%% If no entry exists in the new config, then delete the entry (if it exists) +%% from the old config. +%% If entry exists in the new config, but not in the old config, then +%% add the entry. +replace_config(App,Config,false) -> + lists:keydelete(App,1,Config); +replace_config(App,Config,AppConfig) -> + lists:keystore(App,1,Config,AppConfig). + +%% Remove all files related to the temporary release new_emulator_rm_tmp_release(?tmp_vsn(_)=TmpVsn,RelDir,Releases,Masters) -> remove_dir(filename:join(RelDir,TmpVsn),Masters), lists:keydelete(TmpVsn,#release.vsn,Releases); diff --git a/lib/sasl/src/systools_make.erl b/lib/sasl/src/systools_make.erl index 42b528540e..33bd51ecbb 100644 --- a/lib/sasl/src/systools_make.erl +++ b/lib/sasl/src/systools_make.erl @@ -31,7 +31,7 @@ -export([read_application/4]). --export([make_boot_hybrid/5]). +-export([make_hybrid_boot/5]). -import(lists, [filter/2, keysort/2, keysearch/3, map/2, reverse/1, append/1, foldl/3, member/2, foreach/2]). @@ -182,9 +182,9 @@ return({error,Mod,Error},_,Flags) -> %% Boot1 = Boot2 = Boot = binary() %% Reason = {app_not_found,App} | {app_not_replaced,App} %% App = kernel | stdlib | sasl -make_boot_hybrid(TmpVsn, Boot1, Boot2, Paths, Args) -> - catch do_make_boot_hybrid(TmpVsn, Boot1, Boot2, Paths, Args). -do_make_boot_hybrid(TmpVsn, Boot1, Boot2, Paths, Args) -> +make_hybrid_boot(TmpVsn, Boot1, Boot2, Paths, Args) -> + catch do_make_hybrid_boot(TmpVsn, Boot1, Boot2, Paths, Args). +do_make_hybrid_boot(TmpVsn, Boot1, Boot2, Paths, Args) -> {script,{_RelName1,_RelVsn1},Script1} = binary_to_term(Boot1), {script,{RelName2,_RelVsn2},Script2} = binary_to_term(Boot2), MatchPaths = get_regexp_path(Paths), diff --git a/lib/sasl/test/systools_SUITE.erl b/lib/sasl/test/systools_SUITE.erl index 960ba3cc21..5b3abad219 100644 --- a/lib/sasl/test/systools_SUITE.erl +++ b/lib/sasl/test/systools_SUITE.erl @@ -1486,7 +1486,7 @@ normal_hybrid(Config) -> ?line ok = file:set_cwd(OldDir), ?line BasePaths = {"testkernelpath","teststdlibpath","testsaslpath"}, - ?line {ok,Hybrid} = systools_make:make_boot_hybrid("tmp_vsn",Boot1,Boot2, + ?line {ok,Hybrid} = systools_make:make_hybrid_boot("tmp_vsn",Boot1,Boot2, BasePaths, [dummy,args]), ?line {script,{"Test release 4","tmp_vsn"},Script} = binary_to_term(Hybrid), @@ -1560,7 +1560,7 @@ normal_hybrid(Config) -> ok. -%% Check that systools_make:make_boot_hybrid fails with a meaningful +%% Check that systools_make:make_hybrid_boot fails with a meaningful %% error message if the FromBoot does not include the sasl %% application. hybrid_no_old_sasl(Config) -> @@ -1584,14 +1584,14 @@ hybrid_no_old_sasl(Config) -> ?line BasePaths = {"testkernelpath","teststdlibpath","testsaslpath"}, ?line {error,{app_not_replaced,sasl}} = - systools_make:make_boot_hybrid("tmp_vsn",Boot1,Boot2, + systools_make:make_hybrid_boot("tmp_vsn",Boot1,Boot2, BasePaths,[dummy,args]), ?line ok = file:set_cwd(OldDir), ok. -%% Check that systools_make:make_boot_hybrid fails with a meaningful +%% Check that systools_make:make_hybrid_boot fails with a meaningful %% error message if the ToBoot does not include the sasl %% application. hybrid_no_new_sasl(Config) -> @@ -1615,7 +1615,7 @@ hybrid_no_new_sasl(Config) -> ?line BasePaths = {"testkernelpath","teststdlibpath","testsaslpath"}, ?line {error,{app_not_found,sasl}} = - systools_make:make_boot_hybrid("tmp_vsn",Boot1,Boot2, + systools_make:make_hybrid_boot("tmp_vsn",Boot1,Boot2, BasePaths,[dummy,args]), ?line ok = file:set_cwd(OldDir), -- cgit v1.2.3 From be04ed7beceeb4bcf5db7807e86df87e28c9f4b9 Mon Sep 17 00:00:00 2001 From: Siri Hansen Date: Thu, 13 Oct 2011 11:53:51 +0200 Subject: Distinguish restart_new_emulator from restart_emulator in upgrade instructions Earlier, there was only one valid instruction to restart the emulator in an appup/relup script, 'restart_new_emulator'. A new instuction, 'restart_emulator', is now added, and the meaning is as follows: 'restart_new_emulator' is mainly for the core applications (erts, kernel, stdlib and sasl), and it indicates that there is new core functionality in the release and the emulator needs to be restarted before executing the upgrade scripts. If this instruction exists, a temporary release will be created which consists of the new version erts, kernel, stdlib and sasl, and the old versions of all other applications. After restarting the emulator with this temporary release, the rest of the upgrade instructions are executed, including loading of new versions. 'restart_emulator' can be used by any application if a restart of the emulator is needed after the upgrade instructions have been executed. In this case, the emulator will be restarted with the new release (i.e. not a tempoarary one) after all other upgrade instructions for all applications have been excecuted. --- lib/sasl/src/release_handler.erl | 18 ++--- lib/sasl/src/release_handler_1.erl | 10 +-- lib/sasl/src/systools_rc.erl | 45 +++++++---- lib/sasl/src/systools_relup.erl | 13 +-- lib/sasl/test/systools_SUITE.erl | 12 +-- .../d_regexp_appup/lib/fe-3.1/ebin/fe.appup | 2 +- lib/sasl/test/systools_rc_SUITE.erl | 92 +++++++++++++++++++++- 7 files changed, 146 insertions(+), 46 deletions(-) (limited to 'lib/sasl') diff --git a/lib/sasl/src/release_handler.erl b/lib/sasl/src/release_handler.erl index 931347bde2..abe6d6bee6 100644 --- a/lib/sasl/src/release_handler.erl +++ b/lib/sasl/src/release_handler.erl @@ -338,7 +338,7 @@ check_script(Script, LibDirs) -> %%----------------------------------------------------------------- %% eval_script(Script, Apps, LibDirs, NewLibs, Opts) -> %% {ok, UnPurged} | -%% restart_new_emulator | +%% restart_emulator | %% {error, Error} %% {'EXIT', Reason} %% If sync_nodes is present, the calling process must have called @@ -375,7 +375,7 @@ create_RELEASES(Root, RelDir, RelFile, LibDirs) -> %%----------------------------------------------------------------- %% Func: upgrade_app(App, Dir) -> {ok, Unpurged} -%% | restart_new_emulator +%% | restart_emulator %% | {error, Error} %% Types: %% App = atom() @@ -395,7 +395,7 @@ upgrade_app(App, NewDir) -> %%----------------------------------------------------------------- %% Func: downgrade_app(App, Dir) %% downgrade_app(App, Vsn, Dir) -> {ok, Unpurged} -%% | restart_new_emulator +%% | restart_emulator %% | {error, Error} %% Types: %% App = atom() @@ -618,11 +618,11 @@ handle_call({install_release, Vsn, ErrorAction, Opts}, From, S) -> {reply, {ok, CurrentVsn, Descr}, NewS}; {error, Reason} -> {reply, {error, Reason}, NS}; - {restart_new_emulator, CurrentVsn, Descr} -> + {restart_emulator, CurrentVsn, Descr} -> gen_server:reply(From, {ok, CurrentVsn, Descr}), init:reboot(), {noreply, NS}; - {restart_new_emulator_then_continue, CurrentVsn, Descr} -> + {restart_new_emulator, CurrentVsn, Descr} -> gen_server:reply(From, {continue_after_restart, CurrentVsn, Descr}), init:reboot(), {noreply, NS}; @@ -991,7 +991,7 @@ do_install_release(#state{start_prg = StartPrg, prepare_restart_new_emulator(StartPrg, RootDir, RelDir, TmpVsn, TmpRelease, NReleases, Masters), - {restart_new_emulator_then_continue, CurrentVsn, Descr}; + {restart_new_emulator, CurrentVsn, Descr}; {ok, {CurrentVsn, Descr, Script}} -> %% In case there has been an emulator upgrade, %% remove the temporary release @@ -1012,14 +1012,14 @@ do_install_release(#state{start_prg = StartPrg, mon_nodes(false), NReleases1 = set_status(Vsn, current, NReleases), {ok, NReleases1, Unpurged, CurrentVsn, Descr}; - restart_new_emulator when Static == true -> + restart_emulator when Static == true -> throw(static_emulator); - restart_new_emulator -> + restart_emulator -> mon_nodes(false), prepare_restart_new_emulator(StartPrg, RootDir, RelDir, Vsn, Release, NReleases, Masters), - {restart_new_emulator, CurrentVsn, Descr}; + {restart_emulator, CurrentVsn, Descr}; Else -> application_controller:config_change(EnvBefore), mon_nodes(false), diff --git a/lib/sasl/src/release_handler_1.erl b/lib/sasl/src/release_handler_1.erl index 4a776fd18b..3a64e10185 100644 --- a/lib/sasl/src/release_handler_1.erl +++ b/lib/sasl/src/release_handler_1.erl @@ -99,8 +99,8 @@ eval_script(Script, Apps, LibDirs, NewLibs, Opts) -> After) of EvalState4 when is_record(EvalState4, eval_state) -> {ok, EvalState4#eval_state.unpurged}; - restart_new_emulator -> - restart_new_emulator; + restart_emulator -> + restart_emulator; Error -> {'EXIT', Error} end; @@ -251,7 +251,7 @@ do_check_old_code(Mod,Procs) -> %% must also exectue the same line. Waits for all these nodes to get %% to this line. %% point_of_no_return -%% restart_new_emulator +%% restart_emulator %% {stop_application, Appl} - Impl with apply %% {unload_application, Appl} - Impl with {remove..} %% {load_application, Appl} - Impl with {load..} @@ -410,8 +410,8 @@ eval({sync_nodes, Id, Nodes}, EvalState) -> eval({apply, {M, F, A}}, EvalState) -> apply(M, F, A), EvalState; -eval(restart_new_emulator, _EvalState) -> - throw(restart_new_emulator). +eval(restart_emulator, _EvalState) -> + throw(restart_emulator). get_opt(Tag, EvalState, Default) -> case lists:keysearch(Tag, 1, EvalState#eval_state.opts) of diff --git a/lib/sasl/src/systools_rc.erl b/lib/sasl/src/systools_rc.erl index 6f01901fbc..c16f6aa845 100644 --- a/lib/sasl/src/systools_rc.erl +++ b/lib/sasl/src/systools_rc.erl @@ -54,6 +54,7 @@ %% {sync_nodes, Id, Nodes} %% {apply, {M, F, A}} %% restart_new_emulator +%% restart_emulator %%----------------------------------------------------------------- %% High-level instructions that contain dependencies @@ -145,7 +146,7 @@ translate_merged_script(Mode, Script, Appls, PreAppls) -> Appls), Before3 = merge_load_object_code(Before2), - {Before4,After4} = sort_restart_new_emulator(Mode,Before3,After2), + {Before4,After4} = sort_emulator_restart(Mode,Before3,After2), NewScript = Before4 ++ [point_of_no_return | After4], check_syntax(NewScript), @@ -702,23 +703,37 @@ mlo([{load_object_code, {Lib, LibVsn, Mods}} | T]) -> mlo([]) -> []. %%----------------------------------------------------------------- -%% RESTART DIFF EMULATOR +%% RESTART EMULATOR %% ----------------------------------------------------------------- %% ----------------------------------------------------------------- -%% Check if a diff_vsn_restart_new_emulator instruction exists (i.e. if the -%% emulator version is changed). If so, this must be done first for -%% upgrade and last for downgrade. +%% Check if there are any 'restart_new_emulator' instructions (i.e. if +%% the emulator or core application version is changed). If so, this +%% must be done first for upgrade and last for downgrade. +%% Check if there are any 'restart_emulator' instructions, if so +%% remove all and place one the end. %% ----------------------------------------------------------------- -sort_restart_new_emulator(Mode,Before,After) -> - case lists:delete(diff_vsn_restart_new_emulator,After) of - After -> - {Before,After}; - NewAfter when Mode==up -> - {[restart_new_emulator|Before],NewAfter}; - NewAfter when Mode==dn -> - {Before,NewAfter++[restart_new_emulator]} - end. +sort_emulator_restart(Mode,Before,After) -> + {Before1,After1} = + case filter_out(restart_new_emulator, After) of + After -> + {Before,After}; + A1 when Mode==up -> + {[restart_new_emulator|Before],A1}; + A1 when Mode==dn -> + {Before,A1++[restart_emulator]} + end, + After2 = + case filter_out(restart_emulator, After1) of + After1 -> + After1; + A2 -> + A2++[restart_emulator] + end, + {Before1,After2}. + +filter_out(What,List) -> + lists:filter(fun(X) when X=:=What -> false; (_) -> true end, List). %%----------------------------------------------------------------- %% SYNTAX CHECK @@ -839,7 +854,7 @@ check_op({apply, {M, F, A}}) -> check_func(F), check_args(A); check_op(restart_new_emulator) -> ok; -check_op(diff_vsn_restart_new_emulator) -> ok; +check_op(restart_emulator) -> ok; check_op(X) -> throw({error, {bad_instruction, X}}). check_mod(Mod) when is_atom(Mod) -> ok; diff --git a/lib/sasl/src/systools_relup.erl b/lib/sasl/src/systools_relup.erl index 5cfbc3aadf..b750e86e29 100644 --- a/lib/sasl/src/systools_relup.erl +++ b/lib/sasl/src/systools_relup.erl @@ -263,8 +263,7 @@ foreach_baserel_up(TopRel, TopApps, [BaseRelDc|BaseRelDcs], Path, Opts, {RUs3, Ws3} = create_remove_app_scripts(BaseRel, TopRel, RUs2, Ws2), - {RUs4, Ws4} = - check_for_emulator_restart(TopRel, BaseRel, RUs3, Ws3, Opts), + {RUs4, Ws4} = check_for_emulator_restart(TopRel, BaseRel, RUs3, Ws3, Opts), BaseApps = case systools_make:get_release(BaseRelFile, Path) of @@ -321,8 +320,7 @@ foreach_baserel_dn(TopRel, TopApps, [BaseRelDc|BaseRelDcs], Path, Opts, {RUs4, Ws4} = create_remove_app_scripts(TopRel, BaseRel, RUs3, Ws3), - {RUs5, Ws5} = check_for_emulator_restart(TopRel, BaseRel, - RUs4, Ws4, Opts), + {RUs5, Ws5} = check_for_emulator_restart(TopRel, BaseRel, RUs4, Ws4, Opts), case systools_rc:translate_scripts(dn, RUs5, BaseApps, TopApps) of {ok, RUs} -> @@ -350,7 +348,7 @@ check_for_emulator_restart(#release{erts_vsn = Vsn1, name = N1}, %% We will also allow an extra restart of emulator (specified by %% the restart_emulator option) at the end of the upgrade, for %% application specific purposes. - NewRUs = [[diff_vsn_restart_new_emulator]|RUs], + NewRUs = [[restart_new_emulator]|RUs], NewWs = [{erts_vsn_changed, {N1, N2}} | Ws], check_for_restart_emulator_opt(NewRUs, NewWs, Opts); check_for_emulator_restart(_, _, RUs, Ws, Opts) -> @@ -358,10 +356,13 @@ check_for_emulator_restart(_, _, RUs, Ws, Opts) -> check_for_restart_emulator_opt(RUs, Ws, Opts) -> case get_opt(restart_emulator, Opts) of - true -> {RUs++[[restart_new_emulator]], Ws}; + true -> {RUs++[[restart_emulator]], Ws}; _ -> {RUs, Ws} end. + + + %% collect_appup_scripts(Mode, TopApps, BaseRel, Ws, RUs) -> {NRUs, NWs} %% Mode = up | dn %% TopApps = [#application] diff --git a/lib/sasl/test/systools_SUITE.erl b/lib/sasl/test/systools_SUITE.erl index 5b3abad219..4cf6aefea9 100644 --- a/lib/sasl/test/systools_SUITE.erl +++ b/lib/sasl/test/systools_SUITE.erl @@ -1157,7 +1157,7 @@ normal_relup(Config) when is_list(Config) -> ?line ok = file:set_cwd(LatestDir), %% OTP-2561: Check that the option 'restart_emulator' generates a - %% "restart_new_emulator" instruction. + %% "restart_emulator" instruction. ?line {ok, _ , _, []} = systools:make_relup(LatestName, [LatestName1], [LatestName1], [{path, P},restart_emulator,silent]), @@ -1256,19 +1256,19 @@ check_relup_up_only(UpVsnL) -> check_restart_emulator() -> {ok, [{_V1, [{_, _, Up}], [{_, _, Dn}]}]} = file:consult(relup), - restart_new_emulator = lists:last(Up), - restart_new_emulator = lists:last(Dn), + restart_emulator = lists:last(Up), + restart_emulator = lists:last(Dn), ok. check_restart_emulator_up_only() -> {ok, [{_V1, [{_, _, Up}], []}]} = file:consult(relup), - restart_new_emulator = lists:last(Up), + restart_emulator = lists:last(Up), ok. check_restart_emulator_diff_erts() -> {ok, [{_V1, [{_, _, Up}], [{_, _, Dn}]}]} = file:consult(relup), [restart_new_emulator|_] = Up, - restart_new_emulator = lists:last(Dn), + restart_emulator = lists:last(Dn), ok. %% make_relup @@ -1444,7 +1444,7 @@ regexp_relup(Config) -> %% Upgrade fe 2.1.1 -> 3.1 %% Shall match the second entry in fe-3.1 appup. Have added a - %% restart_new_emulator instruction there to distinguish it from + %% restart_emulator instruction there to distinguish it from %% the first entry... ?line {ok, _, _, []} = systools:make_relup(LatestName, [LatestName1], [], [{path, P}, silent]), diff --git a/lib/sasl/test/systools_SUITE_data/d_regexp_appup/lib/fe-3.1/ebin/fe.appup b/lib/sasl/test/systools_SUITE_data/d_regexp_appup/lib/fe-3.1/ebin/fe.appup index 53d54735e5..6b99c47e53 100644 --- a/lib/sasl/test/systools_SUITE_data/d_regexp_appup/lib/fe-3.1/ebin/fe.appup +++ b/lib/sasl/test/systools_SUITE_data/d_regexp_appup/lib/fe-3.1/ebin/fe.appup @@ -15,7 +15,7 @@ [{update, fe1, soft, soft_purge, soft_purge, []}, {update, fe2, soft, soft_purge, soft_purge, [fe1]}, {update, fe3, {advanced, extra}, soft_purge, soft_purge,[fe1, fe2]}, - restart_new_emulator]} + restart_emulator]} ], %% Downgrade to: diff --git a/lib/sasl/test/systools_rc_SUITE.erl b/lib/sasl/test/systools_rc_SUITE.erl index bb93f38fa7..2ab9e269f9 100644 --- a/lib/sasl/test/systools_rc_SUITE.erl +++ b/lib/sasl/test/systools_rc_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2010. All Rights Reserved. +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -21,14 +21,15 @@ -include_lib("test_server/include/test_server.hrl"). -include_lib("sasl/src/systools.hrl"). -export([all/0,groups/0,init_per_group/2,end_per_group/2, - syntax_check/1, translate/1, translate_app/1]). + syntax_check/1, translate/1, translate_app/1, + translate_emulator_restarts/1]). %%----------------------------------------------------------------- %% erl -compile systools_rc_SUITE @i ../src/ @i ../../test_server/include/ %% c(systools_rc_SUITE, [{i, "../src"}, {i, "../../test_server/include"}]). %%----------------------------------------------------------------- all() -> - [syntax_check, translate, translate_app]. + [syntax_check, translate, translate_app, translate_emulator_restarts]. groups() -> []. @@ -87,7 +88,8 @@ syntax_check(Config) when is_list(Config) -> {sync_nodes, id1, {m, f, [a]}}, {sync_nodes, id2, [cp1, cp2]}, {apply, {m,f,[a]}}, - restart_new_emulator + restart_new_emulator, + restart_emulator ], ?line {ok, _} = systools_rc:translate_scripts([S2], Apps, []), S3 = [{apply, {m, f, a}}], @@ -486,3 +488,85 @@ io:format("X2=~p~n", [X2]), {purge,[pelle,kalle]}, {apply,{application,unload,[pelle]}}] = X3, ?line ok. + + +translate_emulator_restarts(_Config) -> + Apps = + [#application{name = test, + description = "TEST", + vsn = "1.0", + modules = [{foo,1},{bar,1},{baz,1}], + regs = [], + mod = {sasl, []}}, + #application{name = test, + description = "TEST2", + vsn = "1.0", + modules = [{x,1},{y,1},{z,1}], + regs = [], + mod = {sasl, []}}], + %% restart_new_emulator + Up1 = [{update, foo, soft, soft_purge, soft_purge, []},restart_new_emulator], + ?line {ok, X1} = systools_rc:translate_scripts([Up1], Apps, []), + ?line [restart_new_emulator, + {load_object_code, {test,"1.0",[foo]}}, + point_of_no_return, + {suspend,[foo]}, + {load,{foo,soft_purge,soft_purge}}, + {resume,[foo]}] = X1, + + %% restart_emulator + Up2 = [{update, foo, soft, soft_purge, soft_purge, []},restart_emulator], + ?line {ok, X2} = systools_rc:translate_scripts([Up2], Apps, []), + ?line [{load_object_code, {test,"1.0",[foo]}}, + point_of_no_return, + {suspend,[foo]}, + {load,{foo,soft_purge,soft_purge}}, + {resume,[foo]}, + restart_emulator] = X2, + + %% restart_emulator + restart_new_emulator + Up3 = [{update, foo, soft, soft_purge, soft_purge, []}, + restart_emulator, + restart_new_emulator], + ?line {ok, X3} = systools_rc:translate_scripts([Up3], Apps, []), + ?line [restart_new_emulator, + {load_object_code, {test,"1.0",[foo]}}, + point_of_no_return, + {suspend,[foo]}, + {load,{foo,soft_purge,soft_purge}}, + {resume,[foo]}, + restart_emulator] = X3, + + %% restart_emulator + restart_new_emulator + Up4a = [{update, foo, soft, soft_purge, soft_purge, []}, + restart_emulator, + restart_new_emulator], + Up4b = [restart_new_emulator, + {update, x, soft, soft_purge, soft_purge, []}, + restart_emulator, + restart_emulator], + ?line {ok, X4} = systools_rc:translate_scripts([Up4a,Up4b], Apps, []), + ?line [restart_new_emulator, + {load_object_code, {test,"1.0",[foo,x]}}, + point_of_no_return, + {suspend,[foo]}, + {load,{foo,soft_purge,soft_purge}}, + {resume,[foo]}, + {suspend,[x]}, + {load,{x,soft_purge,soft_purge}}, + {resume,[x]}, + restart_emulator] = X4, + + %% only restart_new_emulator + Up5 = [restart_new_emulator], + ?line {ok, X5} = systools_rc:translate_scripts([Up5], Apps, []), + ?line [restart_new_emulator, + point_of_no_return] = X5, + + %% only restart_emulator + Up6 = [restart_emulator], + ?line {ok, X6} = systools_rc:translate_scripts([Up6], Apps, []), + ?line [point_of_no_return, + restart_emulator] = X6, + + ok. -- cgit v1.2.3 From d221b34133a8da8d62bdc57ebb724f86d7cd2fc0 Mon Sep 17 00:00:00 2001 From: Siri Hansen Date: Fri, 14 Oct 2011 12:34:08 +0200 Subject: Add restart_new_emulator instruction to kernel, stdlib and sasl appups The appup files for kernel, stdlib and sasl did not contain any UpFromVsn and DownToVsn. This means that it was not possible to create a relup file with systool:make_relup if any of these applications had changed. This commit adds entries in the appup files for a maximum of two major releases back - all with only one upgrade instruction: restart_new_emulator. The point is to allow relups to be generated, but ensure that no soft upgrade is done for these three applications - i.e. they will always cause a restart of the emulator prior to all other upgrade instructions from other applications. Test cases (appup_test) are added to kernel_SUITE, stdlib_SUITE and sasl_SUITE. These all check that expected versions are matched in the appups, and illegal versions (older than two major releases, or in any other way illegal) do not match. The test is written in a general way where it is assumed that the version of these applications are stepped according the the rule that major releases step the second number, maintenance releases step the third number and patches step the fourth number. --- lib/sasl/src/sasl.appup.src | 26 ++++++----- lib/sasl/src/systools_relup.erl | 21 ++++++--- lib/sasl/test/sasl_SUITE.erl | 99 ++++++++++++++++++++++++++++++++++++++++- 3 files changed, 126 insertions(+), 20 deletions(-) (limited to 'lib/sasl') diff --git a/lib/sasl/src/sasl.appup.src b/lib/sasl/src/sasl.appup.src index 64c653a4e5..ce4aa1f8f8 100644 --- a/lib/sasl/src/sasl.appup.src +++ b/lib/sasl/src/sasl.appup.src @@ -1,25 +1,27 @@ -%% +%% -*- erlang -*- %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1999-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 1999-2011. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% -%% %CopyrightEnd% %% - +%% %CopyrightEnd% {"%VSN%", - [{"2.1.4", [{load_module, release_handler}, - {load_module, systools_relup}]}], - [{"2.1.4", [{load_module, release_handler}, - {load_module, systools_relup}]}] + %% Up from - max two major revisions back + [{<<"2\\.2(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R15 + {<<"2\\.1\\.10(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R14B04 (and later?) + {<<"2\\.1\\.[6-9](\\.[0-9]+)*">>,[restart_new_emulator]}],%% R13B-R14B03 + %% Down to - max two major revisions back + [{<<"2\\.2(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R15 + {<<"2\\.1\\.10(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R14B04 (and later?) + {<<"2\\.1\\.[6-9](\\.[0-9]+)*">>,[restart_new_emulator]}] %% R13B-R14B03 }. diff --git a/lib/sasl/src/systools_relup.erl b/lib/sasl/src/systools_relup.erl index b750e86e29..27960e9938 100644 --- a/lib/sasl/src/systools_relup.erl +++ b/lib/sasl/src/systools_relup.erl @@ -112,6 +112,10 @@ -export([mk_relup/3, mk_relup/4, format_error/1, format_warning/1]). -include("systools.hrl"). + +%% For test purposes only - used by kernel, stdlib and sasl tests +-export([appup_search_for_version/2]). + %%----------------------------------------------------------------- %% mk_relup(TopRelFile, BaseUpRelDcs, BaseDnRelDcs) %% mk_relup(TopRelFile, BaseUpRelDcs, BaseDnRelDcs, Opts) -> Ret @@ -452,25 +456,28 @@ get_script_from_appup(Mode, TopApp, BaseVsn, Ws, RUs) -> %% XXX Why is this a warning only? [{bad_vsn, {TopVsn, TopApp#application.vsn}}| Ws] end, - case search_for_version(BaseVsn, length(BaseVsn), VsnRUs) of + case appup_search_for_version(BaseVsn, VsnRUs) of {ok, RU} -> {RUs ++ [RU], Ws1}; error -> throw({error, ?MODULE, {no_relup, FName, TopApp, BaseVsn}}) end. -search_for_version(BaseVsn,_,[{BaseVsn,RU}|_]) -> +appup_search_for_version(BaseVsn, VsnRUs) -> + appup_search_for_version(BaseVsn, length(BaseVsn), VsnRUs). + +appup_search_for_version(BaseVsn,_,[{BaseVsn,RU}|_]) -> {ok,RU}; -search_for_version(BaseVsn,Size,[{Vsn,RU}|VsnRUs]) when is_binary(Vsn) -> +appup_search_for_version(BaseVsn,Size,[{Vsn,RU}|VsnRUs]) when is_binary(Vsn) -> case re:run(BaseVsn,Vsn,[unicode,{capture,first,index}]) of {match,[{0,Size}]} -> {ok, RU}; _ -> - search_for_version(BaseVsn,Size,VsnRUs) + appup_search_for_version(BaseVsn,Size,VsnRUs) end; -search_for_version(BaseVsn,Size,[_|VsnRUs]) -> - search_for_version(BaseVsn,Size,VsnRUs); -search_for_version(_,_,[]) -> +appup_search_for_version(BaseVsn,Size,[_|VsnRUs]) -> + appup_search_for_version(BaseVsn,Size,VsnRUs); +appup_search_for_version(_,_,[]) -> error. diff --git a/lib/sasl/test/sasl_SUITE.erl b/lib/sasl/test/sasl_SUITE.erl index 454095db6a..195324daa0 100644 --- a/lib/sasl/test/sasl_SUITE.erl +++ b/lib/sasl/test/sasl_SUITE.erl @@ -30,10 +30,11 @@ % Test cases must be exported. -export([app_test/1, + appup_test/1, log_mf_h_env/1]). all() -> - [app_test, log_mf_h_env]. + [app_test, appup_test, log_mf_h_env]. groups() -> []. @@ -57,6 +58,102 @@ app_test(Config) when is_list(Config) -> ?line ?t:app_test(sasl, allow), ok. +%% Test that appup allows upgrade from/downgrade to a maximum of two +%% major releases back. +appup_test(_Config) -> + application:load(sasl), + {sasl,_,SaslVsn} = lists:keyfind(sasl,1,application:loaded_applications()), + Ebin = filename:join(code:lib_dir(sasl),ebin), + {ok,[{SaslVsn,UpFrom,DownTo}=Appup]} = + file:consult(filename:join(Ebin,"sasl.appup")), + ct:log("~p~n",[Appup]), + ?line {OkVsns,NokVsns} = create_test_vsns(SaslVsn), + ?line check_appup(OkVsns,UpFrom,{ok,[restart_new_emulator]}), + ?line check_appup(OkVsns,DownTo,{ok,[restart_new_emulator]}), + ?line check_appup(NokVsns,UpFrom,error), + ?line check_appup(NokVsns,DownTo,error), + ok. + + +%% For sasl, the versions up to R14B03 were not according to the rule +%% used for other core applications - i.e. to change the second number +%% at major releases, the third at maintenance releases and the fourth +%% for patches - therefore test versions up to and including R16 are +%% hardcoded. +%% (All versions below are not necessarily existing.) +-define(r12_vsns,["2.1.5"]). +-define(r13_vsns,["2.1.6","2.1.7.1","2.1.9","2.1.9.1.2"]). +-define(r14_vsns,["2.1.9.2","2.1.9.2.20","2.1.9.4","2.1.10"]). +-define(r15_major,"2.2"). +-define(r16_major,"2.3"). +-define(r17_major,"2.4"). +create_test_vsns(?r15_major ++ Rest) -> + R15Vsns = + case string:tokens(Rest,".") of + [] -> []; + ["1"] -> [?r15_major]; + _ -> [?r15_major,?r15_major++".1"] + end, + OkVsns = ?r13_vsns ++ ?r14_vsns ++ R15Vsns, + NokVsns = ?r12_vsns ++ [?r15_major++",1", ?r16_major], + {OkVsns,NokVsns}; +create_test_vsns(?r16_major ++ Rest) -> + R16Vsns = + case string:tokens(Rest,".") of + [] -> []; + ["1"] -> [?r16_major]; + _ -> [?r16_major,?r16_major++".1"] + end, + OkVsns = ?r14_vsns ++ [?r15_major, ?r15_major ++ ".1.4"] ++ R16Vsns, + NokVsns = ?r13_vsns ++ [?r16_major++",1", ?r17_major], + {OkVsns,NokVsns}; +%% Normal erts case - i.e. for versions that comply to the erts standard +create_test_vsns(Current) -> + [XStr,YStr|Rest] = string:tokens(Current,"."), + X = list_to_integer(XStr), + Y = list_to_integer(YStr), + SecondMajor = vsn(X,Y-2), + SecondMinor = SecondMajor ++ ".1.3", + FirstMajor = vsn(X,Y-1), + FirstMinor = FirstMajor ++ ".57", + ThisMajor = vsn(X,Y), + This = + case Rest of + [] -> + []; + ["1"] -> + [ThisMajor]; + _ -> + ThisMinor = ThisMajor ++ ".1", + [ThisMajor,ThisMinor] + end, + OkVsns = This ++ [FirstMajor, FirstMinor, SecondMajor, SecondMinor], + + ThirdMajor = vsn(X,Y-3), + ThirdMinor = ThirdMajor ++ ".10.12", + Illegal = ThisMajor ++ ",1", + Newer1Major = vsn(X,Y+1), + Newer1Minor = Newer1Major ++ ".1", + Newer2Major = ThisMajor ++ "1", + NokVsns = [ThirdMajor,ThirdMinor, + Illegal, + Newer1Major,Newer1Minor, + Newer2Major], + {OkVsns,NokVsns}. + +vsn(X,Y) -> + integer_to_list(X) ++ "." ++ integer_to_list(Y). + +check_appup([Vsn|Vsns],Instrs,Expected) -> + case systools_relup:appup_search_for_version(Vsn, Instrs) of + Expected -> check_appup(Vsns,Instrs,Expected); + Other -> ct:fail({unexpected_result_for_vsn,Vsn,Other}) + end; +check_appup([],_,_) -> + ok. + + + %% OTP-9185 - fail sasl start if some but not all log_mf_h env vars %% are given. log_mf_h_env(Config) -> -- cgit v1.2.3 From 1e344f34bf9f3fcc0a75b2980ab79e60d4cd71fc Mon Sep 17 00:00:00 2001 From: Siri Hansen Date: Mon, 17 Oct 2011 15:47:05 +0200 Subject: Wait for two restarts in upgrade_restart test This is an attempt to correct a failing test case. It the test fails on having restarted only once, we give it another try to see if the second restart will happen. --- lib/sasl/test/installer.erl | 20 +++++++++++++++++--- lib/sasl/test/release_handler_SUITE.erl | 13 ++++++++++--- 2 files changed, 27 insertions(+), 6 deletions(-) (limited to 'lib/sasl') diff --git a/lib/sasl/test/installer.erl b/lib/sasl/test/installer.erl index d77b0e8538..6942ec21ea 100644 --- a/lib/sasl/test/installer.erl +++ b/lib/sasl/test/installer.erl @@ -44,6 +44,7 @@ -export([upgrade_restart_1a/1]). -export([upgrade_restart_2/1]). -export([upgrade_restart_2a/1]). +-export([upgrade_restart_2b/1]). -export([upgrade_restart_3/1]). -export([client1_1/4]). -export([client2/3]). @@ -403,7 +404,20 @@ upgrade_restart_2(TestNode) -> ?print(["upgrade_restart_2 start"]), %% Check that the node has been restarted once more after the tmp release + case init:script_id() of + {"SASL-test","P2B"} -> + upgrade_restart_2a(TestNode); + {"SASL-test","__new_emulator__P1G"} -> + %% catched the node too early - give it another try + {wait,whereis(init)} + end. + +upgrade_restart_2a(TestNode) -> + ?print(["upgrade_restart_2a start"]), + + %% This time we must be there, else something is definitely wrong {"SASL-test","P2B"} = init:script_id(), + ?check_release_states([permanent,current]), ?check_running_app(a,"1.1"), @@ -412,11 +426,11 @@ upgrade_restart_2(TestNode) -> ok. -upgrade_restart_2a(TestNode) -> - ?print(["upgrade_restart_2a start"]), +upgrade_restart_2b(TestNode) -> + ?print(["upgrade_restart_2b start"]), {ok,"P1G",[old_emu,rm_appl]} = release_handler:install_release("P1G"), - ?print(["upgrade_restart_2a P1G installed"]), + ?print(["upgrade_restart_2b P1G installed"]), ok. upgrade_restart_3(TestNode) -> diff --git a/lib/sasl/test/release_handler_SUITE.erl b/lib/sasl/test/release_handler_SUITE.erl index c2930b1039..958f6bbfc9 100644 --- a/lib/sasl/test/release_handler_SUITE.erl +++ b/lib/sasl/test/release_handler_SUITE.erl @@ -375,11 +375,18 @@ upgrade_restart(Conf) when is_list(Conf) -> wait_nodes_up([{TestNode,TestNodeInit1}],"upgrade_restart_1",[a]), %% install P1G + case rpc_inst(TestNode, upgrade_restart_2, []) of + ok -> + ok; + {wait,TestNodeInit2a} -> + %% We catched the node too early - it was supposed to + %% restart twice, so let's wait for one more restart. + wait_nodes_up([{TestNode,TestNodeInit2a}],"upgrade_restart_2a",[]) + end, TestNodeInit2 = rpc:call(TestNode,erlang,whereis,[init]), - ok = rpc_inst(TestNode, upgrade_restart_2, []), stop_cover(TestNode), - ok = rpc_inst(TestNode, upgrade_restart_2a, []), - wait_nodes_up([{TestNode,TestNodeInit2}],"upgrade_restart_2",[]), + ok = rpc_inst(TestNode, upgrade_restart_2b, []), + wait_nodes_up([{TestNode,TestNodeInit2}],"upgrade_restart_2b",[]), %% Check that P1G is going again ok = rpc_inst(TestNode, upgrade_restart_3, []), -- cgit v1.2.3 From 281fb9929e2cdcfdaf95e0b90b3b690b78535ddb Mon Sep 17 00:00:00 2001 From: Siri Hansen Date: Mon, 24 Oct 2011 14:25:15 +0200 Subject: Document upgrade instructions restart_new_emulator and restart_emulator --- lib/sasl/doc/src/appup.xml | 37 ++++++++++++++++++++++++++++++------ lib/sasl/doc/src/release_handler.xml | 16 +++++++++++++--- lib/sasl/src/release_handler.erl | 6 +++++- 3 files changed, 49 insertions(+), 10 deletions(-) (limited to 'lib/sasl') diff --git a/lib/sasl/doc/src/appup.xml b/lib/sasl/doc/src/appup.xml index 89bcf23b5e..195f9fe1d3 100644 --- a/lib/sasl/doc/src/appup.xml +++ b/lib/sasl/doc/src/appup.xml @@ -319,12 +319,37 @@ point_of_no_return
 restart_new_emulator
     
-

Shuts down the current emulator and starts a ne one. All - processes are terminated gracefully. The new release must still - be made permanent when the new emulator is up and running. - Otherwise, the old emulator is started in case of a emulator - restart. This instruction should be used when a new emulator is - introduced, or if a complete reboot of the system should be done.

+

This instruction is used when erts, kernel, stdlib or sasl is + upgraded. It shuts down the current emulator and starts a new + one. All processes are terminated gracefully, and the new + version of erts, kernel, stdlib and sasl are used when the + emulator restarts. Only one restart_new_emulator + instruction is allowed in the relup, and it shall be placed + first. systools:make_relup3,4 + will ensure this when the relup is generated. The rest of the + relup script is executed after the restart as a part of the boot + script.

+

An info report will be written when the upgrade is + completed. To programatically find out if the upgrade is + complete, + call + release_handler:which_releases and check if the + expected release has status current.

+

The new release must still be made permanent after the upgrade + is completed. Otherwise, the old emulator is started in case of + an emulator restart.

+
+restart_emulator
+    
+

This instruction is similar to restart_new_emulator, + except it shall be placed at the end of the relup script. It is + not related to an upgrade of the emulator or the core + applications, but can be used by any application when a complete + reboot of the system is reqiured. When generating the + relup, systools:make_relup/3,4 + ensures that there is only one restart_emulator + instruction and that it is the last instruction of the + relup.

diff --git a/lib/sasl/doc/src/release_handler.xml b/lib/sasl/doc/src/release_handler.xml index 5ac0dc1acc..c625b40c9d 100644 --- a/lib/sasl/doc/src/release_handler.xml +++ b/lib/sasl/doc/src/release_handler.xml @@ -238,7 +238,7 @@ old reboot_old permanent install_release(Vsn) -> {ok, OtherVsn, Descr} | {error, Reason} - install_release(Vsn, [Opt]) -> {ok, OtherVsn, Descr} | {error, Reason} + install_release(Vsn, [Opt]) -> {ok, OtherVsn, Descr} | {continue_after_restart, OtherVsn, Descr} | {error, Reason} Install a release in the system. Vsn = OtherVsn = string() @@ -248,7 +248,8 @@ old reboot_old permanent  Timeout = default | infinity | int()>0  Bool = boolean() Descr = term() - Reason = {illegal_option, Opt} | {already_installed, Vsn} | {change_appl_data, term()} | term() + Reason = {illegal_option, Opt} | {already_installed, Vsn} | {change_appl_data, term()} | {missing_base_app, OtherVsn, App} | {could_not_create_hybrid_boot, term()} | term() + App = atom()

Installs the specified version Vsn of the release. @@ -268,6 +269,15 @@ old reboot_old permanent OtherVsn and Descr are the version (UpFromVsn or Vsn) and description (Descr1 or Descr2) as specified in the script.

+

If {continue_after_restart,OtherVsn,Descr} is + returned, it means that the emulator will be restarted + before the upgrade instructions are executed. This will + happen if the emulator or any of the applications kernel, + stdlib or sasl are updated. The new version of the emulator + and these core applications will execute after the restart, + but for all other applications the old versions will be + started and the upgrade will be performed as normal by + executing the upgrade instructions.

If a recoverable error occurs, the function returns {error,Reason} and the original application specifications are restored. If a non-recoverable error @@ -442,7 +452,7 @@ release_handler:set_unpacked(RelFile, [{myapp,"1.0","/home/user"},...]). and evaluated exactly in the same way as release_handler does.

-

These function is primarily intended for simplified testing of +

These functions are primarily intended for simplified testing of .appup files. They are not run within the context of the release_handler process. They must therefore not be used together with calls to diff --git a/lib/sasl/src/release_handler.erl b/lib/sasl/src/release_handler.erl index abe6d6bee6..87660db3e3 100644 --- a/lib/sasl/src/release_handler.erl +++ b/lib/sasl/src/release_handler.erl @@ -193,11 +193,15 @@ check_check_install_options([],Purge) -> %%----------------------------------------------------------------- %% Purpose: Executes the relup script for the specified version. %% The release must be unpacked. -%% Returns: {ok, FromVsn, Descr} | {error, Reason} +%% Returns: {ok, FromVsn, Descr} | +%% {continue_after_restart, FromVsn, Descr} | +%% {error, Reason} %% Reason = {already_installed, Vsn} | %% {bad_relup_file, RelFile} | %% {no_such_release, Vsn} | %% {no_such_from_vsn, Vsn} | +%% {could_not_create_hybrid_boot,Why} | +%% {missing_base_app,Vsn,App} | %% {illegal_option, Opt}} | %% exit_reason() %%----------------------------------------------------------------- -- cgit v1.2.3 From 93495eaf90e4ea862a9ea1c5df2d4cb6b8a413eb Mon Sep 17 00:00:00 2001 From: Siri Hansen Date: Wed, 26 Oct 2011 14:25:37 +0200 Subject: Step version of sasl to 2.2 for R15 This is needed for sasl_SUITE:appup_test to work, therefore we do not wait until release time. --- lib/sasl/vsn.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/sasl') diff --git a/lib/sasl/vsn.mk b/lib/sasl/vsn.mk index 2db134af48..23694f1399 100644 --- a/lib/sasl/vsn.mk +++ b/lib/sasl/vsn.mk @@ -1 +1 @@ -SASL_VSN = 2.1.10 +SASL_VSN = 2.2 -- cgit v1.2.3 From aef75ca63752f65299e95c12b67870f1debea7ff Mon Sep 17 00:00:00 2001 From: Siri Hansen Date: Tue, 1 Nov 2011 12:32:38 +0100 Subject: Handle upgrade from pre R15 to post R15 sasl New emulator upgrade mechanism introduced in R15 can only work if the sasl version to upgrade from is 2.2 or later. I.e. if we are already running at least R15. This commit adds backwards compatiblity for upgrades from earlier versions, meaning that the new code is loaded into the old emulator and code_change is executed - then after all application code is updated, the emulator is restarted with the new erts version. Note that this might cause problems if the new code is compiled with the new emulator and there have been updates to the beam format. If this happens, the workaround is to compile the new code with the old emulator. --- lib/sasl/doc/src/release_handler.xml | 12 + lib/sasl/src/systools_relup.erl | 40 +++- lib/sasl/test/systools_SUITE.erl | 259 +++++++++++++++------ .../systools_SUITE_data/lib/sasl-9.9/ebin/sasl.app | 6 + .../lib/sasl-9.9/ebin/sasl.appup | 12 + 5 files changed, 244 insertions(+), 85 deletions(-) create mode 100644 lib/sasl/test/systools_SUITE_data/lib/sasl-9.9/ebin/sasl.app create mode 100644 lib/sasl/test/systools_SUITE_data/lib/sasl-9.9/ebin/sasl.appup (limited to 'lib/sasl') diff --git a/lib/sasl/doc/src/release_handler.xml b/lib/sasl/doc/src/release_handler.xml index c625b40c9d..bd24b2d963 100644 --- a/lib/sasl/doc/src/release_handler.xml +++ b/lib/sasl/doc/src/release_handler.xml @@ -335,6 +335,18 @@ release_handler:set_unpacked(RelFile, [{myapp,"1.0","/home/user"},...]). upgrade, but it will allow checks and purge to be executed in the background before the real upgrade is started.

+ +

When upgrading the emulator from a version older than OTP + R15, there will be an attempt to load new application beam + code into the old emulator. In some cases, the new beam + format can not be read by the old emulator, and so the code + loading will fail and terminate the complete upgrade. To + overcome this problem, the new application code should be + compiled with the old emulator. See Design + Principles for more information about emulator + upgrade from pre OTP R15 versions.

+
diff --git a/lib/sasl/src/systools_relup.erl b/lib/sasl/src/systools_relup.erl index 27960e9938..5346538dc8 100644 --- a/lib/sasl/src/systools_relup.erl +++ b/lib/sasl/src/systools_relup.erl @@ -112,6 +112,7 @@ -export([mk_relup/3, mk_relup/4, format_error/1, format_warning/1]). -include("systools.hrl"). +-define(R15_SASL_VSN,"2.2"). %% For test purposes only - used by kernel, stdlib and sasl tests -export([appup_search_for_version/2]). @@ -269,20 +270,25 @@ foreach_baserel_up(TopRel, TopApps, [BaseRelDc|BaseRelDcs], Path, Opts, {RUs4, Ws4} = check_for_emulator_restart(TopRel, BaseRel, RUs3, Ws3, Opts), - BaseApps = + {BaseNameVsns,BaseApps} = case systools_make:get_release(BaseRelFile, Path) of {ok, _, NameVsnApps, _Warns} -> - lists:map(fun({_,App}) -> App end, NameVsnApps); + %% NameVsnApps = [{{Name,Vsn},#application}] + %% Gives two lists - [{Name,Vsn}] and [#application] + lists:unzip(NameVsnApps); Other1 -> throw(Other1) end, case systools_rc:translate_scripts(up, RUs4, TopApps, BaseApps) of - {ok, RUs} -> + {ok, RUs5} -> + + {RUs, Ws5} = fix_r15_sasl_upgrade(RUs5,Ws4,BaseNameVsns), + VDR = {BaseRel#release.vsn, extract_description(BaseRelDc), RUs}, foreach_baserel_up(TopRel, TopApps, BaseRelDcs, Path, - Opts, Ws4, [VDR| Acc]); + Opts, Ws5, [VDR| Acc]); XXX -> throw(XXX) end; @@ -346,12 +352,9 @@ foreach_baserel_dn( _, _, [], _, _, Ws, Acc) -> check_for_emulator_restart(#release{erts_vsn = Vsn1, name = N1}, #release{erts_vsn = Vsn2, name = N2}, RUs, Ws, Opts) when Vsn1 /= Vsn2 -> - %% The diff_vsn_restart_new_emulator instruction will be replaced - %% by a restart_new_emulator instruction in systools_rc, and - %% placed in the proper order according to mode (up or dn). - %% We will also allow an extra restart of emulator (specified by - %% the restart_emulator option) at the end of the upgrade, for - %% application specific purposes. + %% Automatically insert a restart_new_emulator instruction when + %% erts version is changed. Also allow extra restart at the end of + %% the upgrade if restart_emulator option is given. NewRUs = [[restart_new_emulator]|RUs], NewWs = [{erts_vsn_changed, {N1, N2}} | Ws], check_for_restart_emulator_opt(NewRUs, NewWs, Opts); @@ -365,6 +368,23 @@ check_for_restart_emulator_opt(RUs, Ws, Opts) -> end. +%% Special handling of the upgrade from pre R15 to post R15. In R15, +%% upgrade of the emulator was improved by moving the restart of the +%% emulator before the rest of the upgrade instructions. However, it +%% can only work if the release_handler is already upgraded to a post +%% R15 version. If not, the upgrade instructions must be backwards +%% compatible - i.e. restart_new_emulator will be the last +%% instruction, executed after all code loading, code_change etc. +fix_r15_sasl_upgrade([restart_new_emulator | RestRUs]=RUs, Ws, BaseApps) -> + case lists:keyfind(sasl,1,BaseApps) of + {sasl,Vsn} when Vsn < ?R15_SASL_VSN -> + {lists:delete(restart_emulator,RestRUs) ++ [restart_new_emulator], + [pre_R15_emulator_upgrade|Ws]}; + _ -> + {RUs,Ws} + end; +fix_r15_sasl_upgrade(RUs, Ws, _BaseApps) -> + {RUs,Ws}. %% collect_appup_scripts(Mode, TopApps, BaseRel, Ws, RUs) -> {NRUs, NWs} diff --git a/lib/sasl/test/systools_SUITE.erl b/lib/sasl/test/systools_SUITE.erl index 4cf6aefea9..e06a26828c 100644 --- a/lib/sasl/test/systools_SUITE.erl +++ b/lib/sasl/test/systools_SUITE.erl @@ -49,7 +49,7 @@ -export([ tar_options/1, normal_tar/1, no_mod_vsn_tar/1, variable_tar/1, src_tests_tar/1, shadow_tar/1, var_tar/1, exref_tar/1, link_tar/1, otp_9507/1]). --export([ normal_relup/1, abnormal_relup/1, no_appup_relup/1, +-export([ normal_relup/1, restart_relup/1, abnormal_relup/1, no_appup_relup/1, bad_appup_relup/1, app_start_type_relup/1, regexp_relup/1, otp_3065/1]). -export([otp_6226/1]). -export([normal_hybrid/1,hybrid_no_old_sasl/1,hybrid_no_new_sasl/1]). @@ -83,7 +83,7 @@ groups() -> src_tests_tar, shadow_tar, var_tar, exref_tar, link_tar, otp_9507]}, {relup, [], - [normal_relup, abnormal_relup, no_appup_relup, + [normal_relup, restart_relup, abnormal_relup, no_appup_relup, bad_appup_relup, app_start_type_relup, regexp_relup ]}, {hybrid, [], [normal_hybrid,hybrid_no_old_sasl,hybrid_no_new_sasl]}, @@ -1145,50 +1145,16 @@ normal_relup(Config) when is_list(Config) -> ?line {LatestDir,LatestName} = create_script(latest0,Config), ?line {_LatestDir1,LatestName1} = create_script(latest1,Config), ?line {_LatestDir2,LatestName2} = create_script(latest2,Config), - ?line {_LatestDir1CurrErts,LatestName1CurrErts} = - create_script(latest1_current_erts,Config), ?line DataDir = filename:absname(?copydir), ?line LibDir = [fname([DataDir, d_normal, lib])], ?line P = [fname([LibDir, '*', ebin]), fname([DataDir, lib, kernel, ebin]), - fname([DataDir, lib, stdlib, ebin])], + fname([DataDir, lib, stdlib, ebin]), + fname([DataDir, lib, sasl, ebin])], ?line ok = file:set_cwd(LatestDir), - %% OTP-2561: Check that the option 'restart_emulator' generates a - %% "restart_emulator" instruction. - ?line {ok, _ , _, []} = - systools:make_relup(LatestName, [LatestName1], [LatestName1], - [{path, P},restart_emulator,silent]), - ?line ok = check_relup([{db, "2.1"}], [{db, "1.0"}]), - ?line ok = check_restart_emulator(), - - %% Check that new erts version generates a restart_new_emulator - %% instruction - %% (One erts_vsn_changed warning for upgrade and one for downgrade) - ?line {ok, _ , _, [{erts_vsn_changed,_},{erts_vsn_changed,_}]} = - systools:make_relup(LatestName, - [LatestName1CurrErts], - [LatestName1CurrErts], - [{path, P},silent]), - ?line ok = check_relup([{db, "2.1"}], [{db, "1.0"}]), - ?line ok = check_restart_emulator_diff_erts(), - - - %% Check that new erts version generates a restart_new_emulator - %% instruction, and can be combined with restart_emulator opt. - %% (One erts_vsn_changed warning for upgrade and one for downgrade) - ?line {ok, _ , _, [{erts_vsn_changed,_},{erts_vsn_changed,_}]} = - systools:make_relup(LatestName, - [LatestName1CurrErts], - [LatestName1CurrErts], - [{path, P},restart_emulator,silent]), - ?line ok = check_relup([{db, "2.1"}], [{db, "1.0"}]), - ?line ok = check_restart_emulator(), - ?line ok = check_restart_emulator_diff_erts(), - - %% This is the ultra normal case ?line ok = systools:make_relup(LatestName, [LatestName1], [LatestName1], [{path, P}]), @@ -1229,6 +1195,91 @@ normal_relup(Config) when is_list(Config) -> ok. +restart_relup(suite) -> []; +restart_relup(doc) -> + ["Test relup which includes emulator restart"]; +restart_relup(Config) when is_list(Config) -> + ?line {ok, OldDir} = file:get_cwd(), + + ?line {LatestDir,LatestName} = create_script(latest0,Config), + ?line {_LatestDir1,LatestName1} = create_script(latest1,Config), + ?line {_LatestDir0CurrErts,LatestName0CurrErts} = + create_script(latest0_current_erts,Config), + ?line {_CurrentAllDir,CurrentAllName} = create_script(current_all,Config), + ?line {_CurrentAllFutErtsDir,CurrentAllFutErtsName} = + create_script(current_all_future_erts,Config), + ?line {_CurrentAllFutSaslDir,CurrentAllFutSaslName} = + create_script(current_all_future_sasl,Config), + + ?line DataDir = filename:absname(?copydir), + ?line LibDir = [fname([DataDir, d_normal, lib])], + ?line P = [fname([LibDir, '*', ebin]), + fname([DataDir, lib, kernel, ebin]), + fname([DataDir, lib, stdlib, ebin]), + fname([DataDir, lib, sasl, ebin]), + fname([DataDir, lib, 'sasl-9.9', ebin])], + + ?line ok = file:set_cwd(LatestDir), + + %% OTP-2561: Check that the option 'restart_emulator' generates a + %% "restart_emulator" instruction. + ?line {ok, _ , _, []} = + systools:make_relup(LatestName, [LatestName1], [LatestName1], + [{path, P},restart_emulator,silent]), + ?line ok = check_relup([{db, "2.1"}], [{db, "1.0"}]), + ?line ok = check_restart_emulator(), + + + %% Pre-R15 to Post-R15 upgrade + ?line {ok, _ , _, Ws} = + systools:make_relup(LatestName0CurrErts, + [LatestName1], + [LatestName1], + [{path, P},silent]), + ?line ok = check_relup([{db,"2.1"}], [{db, "1.0"}]), + ?line ok = check_pre_to_post_r15_restart_emulator(), + ?line ok = check_pre_to_post_r15_warnings(Ws), + + + %% Check that new sasl version generates a restart_new_emulator + %% instruction + ?line {ok, _ , _, []} = + systools:make_relup(CurrentAllFutSaslName, + [CurrentAllName], + [CurrentAllName], + [{path, P},silent]), + ?line ok = check_relup([{fe, "3.1"}], []), + ?line ok = check_restart_emulator_diff_coreapp(), + + + %% Check that new erts version generates a restart_new_emulator + %% instruction, if FromSaslVsn >= R15SaslVsn + %% (One erts_vsn_changed warning for upgrade and one for downgrade) + ?line {ok, _ , _, [{erts_vsn_changed,_},{erts_vsn_changed,_}]} = + systools:make_relup(CurrentAllFutErtsName, + [CurrentAllName], + [CurrentAllName], + [{path, P},silent]), + ?line ok = check_relup([{fe, "3.1"}], []), + ?line ok = check_restart_emulator_diff_coreapp(), + + + %% Check that new erts version generates a restart_new_emulator + %% instruction, and can be combined with restart_emulator opt. + %% (One erts_vsn_changed warning for upgrade and one for downgrade) + ?line {ok, _ , _, [{erts_vsn_changed,_},{erts_vsn_changed,_}]} = + systools:make_relup(CurrentAllFutErtsName, + [CurrentAllName], + [CurrentAllName], + [{path, P},restart_emulator,silent]), + ?line ok = check_relup([{fe, "3.1"}], []), + ?line ok = check_restart_emulator(), + ?line ok = check_restart_emulator_diff_coreapp(), + + ?line ok = file:set_cwd(OldDir), + ok. + + %% This test fails if wrong version numbers are seen in the relup file %% or if any application is missing. This was triggered by OTP-1360. check_relup(UpVsnL, DnVsnL) -> @@ -1265,12 +1316,22 @@ check_restart_emulator_up_only() -> restart_emulator = lists:last(Up), ok. -check_restart_emulator_diff_erts() -> +check_restart_emulator_diff_coreapp() -> {ok, [{_V1, [{_, _, Up}], [{_, _, Dn}]}]} = file:consult(relup), [restart_new_emulator|_] = Up, restart_emulator = lists:last(Dn), ok. +check_pre_to_post_r15_restart_emulator() -> + {ok, [{_V1, [{_, _, Up}], [{_, _, Dn}]}]} = file:consult(relup), + restart_new_emulator = lists:last(Up), + restart_emulator = lists:last(Dn), + ok. + +check_pre_to_post_r15_warnings(Ws) -> + true = lists:member(pre_R15_emulator_upgrade,Ws), + ok. + %% make_relup %% no_appup_relup(suite) -> []; @@ -1362,7 +1423,8 @@ abnormal_relup(Config) when is_list(Config) -> ?line P = [fname([DataDir, d_bad_app_vsn, lib, 'db-2.1', ebin]), fname([DataDir, d_bad_app_vsn, lib, 'fe-3.1', ebin]), fname([DataDir, lib, kernel, ebin]), - fname([DataDir, lib, stdlib, ebin])], + fname([DataDir, lib, stdlib, ebin]), + fname([DataDir, lib, sasl, ebin])], ?line ok = file:set_cwd(LatestDir), @@ -1466,8 +1528,8 @@ regexp_relup(Config) -> %% new release, all other apps from old release. normal_hybrid(Config) -> ?line {ok, OldDir} = file:get_cwd(), - ?line {Dir1,Name1} = create_script(latest1_sasl,Config), - ?line {_Dir2,Name2} = create_script(current_all_sasl,Config), + ?line {Dir1,Name1} = create_script(latest1,Config), + ?line {_Dir2,Name2} = create_script(current_all,Config), ?line DataDir = filename:absname(?copydir), ?line LibDir = [fname([DataDir, d_normal, lib])], @@ -1565,8 +1627,8 @@ normal_hybrid(Config) -> %% application. hybrid_no_old_sasl(Config) -> ?line {ok, OldDir} = file:get_cwd(), - ?line {Dir1,Name1} = create_script(latest1,Config), - ?line {_Dir2,Name2} = create_script(current_all_sasl,Config), + ?line {Dir1,Name1} = create_script(latest1_no_sasl,Config), + ?line {_Dir2,Name2} = create_script(current_all,Config), ?line DataDir = filename:absname(?copydir), ?line LibDir = [fname([DataDir, d_normal, lib])], @@ -1596,7 +1658,7 @@ hybrid_no_old_sasl(Config) -> %% application. hybrid_no_new_sasl(Config) -> ?line {ok, OldDir} = file:get_cwd(), - ?line {Dir1,Name1} = create_script(latest1_sasl,Config), + ?line {Dir1,Name1} = create_script(latest1,Config), ?line {_Dir2,Name2} = create_script(current_all_no_sasl,Config), ?line DataDir = filename:absname(?copydir), @@ -1640,7 +1702,8 @@ otp_6226(Config) when is_list(Config) -> fname([LibDir, 'db-1.0', ebin]), fname([LibDir, 'fe-3.1', ebin]), fname([DataDir, lib, kernel, ebin]), - fname([DataDir, lib, stdlib, ebin])], + fname([DataDir, lib, stdlib, ebin]), + fname([DataDir, lib, sasl, ebin])], ?line ok = file:set_cwd(LatestDir), @@ -1939,34 +2002,41 @@ create_script(latest_no_mod_vsn,Config) -> {filename:dirname(Name), filename:basename(Name)}; create_script(latest0,Config) -> ?line PrivDir = ?privdir, - ?line Name = fname(PrivDir, 'latest-1'), + ?line Name = fname(PrivDir, latest0), ?line {ok,Fd} = file:open(Name++".rel",write), - ?line io:format(Fd, - "{release, {\"Test release 2\", \"LATEST0\"}, \n" - " {erts, \"4.4\"}, \n" - " [{kernel, \"1.0\"}, {stdlib, \"1.0\"}, \n" - " {db, \"2.1\"}, {fe, \"3.1\"}]}.\n", - []), + ?line RelfileContent = + {release,{"Test release 2", "LATEST0"}, + {erts,"4.4"}, + [{kernel,"1.0"}, + {stdlib,"1.0"}, + {sasl,"1.0"}, + {db,"2.1"}, + {fe,"3.1"}]}, + ?line io:format(Fd,"~p.~n",[RelfileContent]), ?line ok = file:close(Fd), {filename:dirname(Name), filename:basename(Name)}; -create_script(latest1,Config) -> +create_script(latest0_current_erts,Config) -> ?line PrivDir = ?privdir, - ?line Name = fname(PrivDir, latest), + ?line Name = fname(PrivDir, latest0_current_erts), + ?line ErtsVer = erlang:system_info(version), ?line {ok,Fd} = file:open(Name++".rel",write), - ?line io:format(Fd, - "{release, {\"Test release 2\", \"LATEST1\"}, \n" - " {erts, \"4.4\"}, \n" - " [{kernel, \"1.0\"}, {stdlib, \"1.0\"}, \n" - " {db, \"1.0\"}, {fe, \"3.1\"}]}.\n", - []), + ?line RelfileContent = + {release,{"Test release 2", "LATEST0_CURRENT_ERTS"}, + {erts,ErtsVer}, + [{kernel,"1.0"}, % fake - will never happen for real that + {stdlib,"1.0"}, % erts changes verson but not kernel, stdlib, sasl + {sasl,"1.0"}, + {db,"2.1"}, + {fe,"3.1"}]}, + ?line io:format(Fd,"~p.~n",[RelfileContent]), ?line ok = file:close(Fd), {filename:dirname(Name), filename:basename(Name)}; -create_script(latest1_sasl,Config) -> +create_script(latest1,Config) -> ?line PrivDir = ?privdir, - ?line Name = fname(PrivDir, latest_sasl), + ?line Name = fname(PrivDir, latest1), ?line {ok,Fd} = file:open(Name++".rel",write), ?line RelfileContent = - {release,{"Test release 2", "LATEST1_SASL"}, + {release,{"Test release 2", "LATEST1"}, {erts,"4.4"}, [{kernel,"1.0"}, {stdlib,"1.0"}, @@ -1976,16 +2046,15 @@ create_script(latest1_sasl,Config) -> ?line io:format(Fd,"~p.~n",[RelfileContent]), ?line ok = file:close(Fd), {filename:dirname(Name), filename:basename(Name)}; -create_script(latest1_current_erts,Config) -> +create_script(latest1_no_sasl,Config) -> ?line PrivDir = ?privdir, - ?line Name = fname(PrivDir, 'latest_current_erts'), - ?line ErtsVer = erlang:system_info(version), + ?line Name = fname(PrivDir, latest1_no_sasl), ?line {ok,Fd} = file:open(Name++".rel",write), ?line RelfileContent = - {release,{"Test release 2", "LATEST1_CURRENT_ERTS"}, - {erts,ErtsVer}, - [{kernel,"1.0"}, % fake - will never happen for real that - {stdlib,"1.0"}, % erts changes verson but not kernel and stdlib. + {release,{"Test release 2", "LATEST1_NO_SASL"}, + {erts,"4.4"}, + [{kernel,"1.0"}, + {stdlib,"1.0"}, {db,"1.0"}, {fe,"3.1"}]}, ?line io:format(Fd,"~p.~n",[RelfileContent]), @@ -1993,7 +2062,7 @@ create_script(latest1_current_erts,Config) -> {filename:dirname(Name), filename:basename(Name)}; create_script(latest2,Config) -> ?line PrivDir = ?privdir, - ?line Name = fname(PrivDir, 'latest-2'), + ?line Name = fname(PrivDir, latest2), ?line {ok,Fd} = file:open(Name++".rel",write), ?line io:format(Fd, "{release, {\"Test release 1\", \"LATEST2\"}, \n" @@ -2126,9 +2195,9 @@ create_script(current_all_no_sasl,Config) -> ?line io:format(Fd,"~p.~n",[RelfileContent]), ?line ok = file:close(Fd), {filename:dirname(Name), filename:basename(Name)}; -create_script(current_all_sasl,Config) -> +create_script(current_all,Config) -> ?line PrivDir = ?privdir, - ?line Name = fname(PrivDir, 'current_all_sasl'), + ?line Name = fname(PrivDir, current_all), ?line ErtsVer = erlang:system_info(version), ?line application:load(sasl), ?line Apps = application_controller:loaded_applications(), @@ -2137,7 +2206,7 @@ create_script(current_all_sasl,Config) -> ?line {value,{_,_,SaslVer}} = lists:keysearch(sasl,1,Apps), ?line {ok,Fd} = file:open(Name++".rel",write), ?line RelfileContent = - {release,{"Test release 4", "CURRENT_ALL_SASL"}, + {release,{"Test release 4", "CURRENT_ALL"}, {erts,ErtsVer}, [{kernel,KernelVer}, {stdlib,StdlibVer}, @@ -2145,6 +2214,46 @@ create_script(current_all_sasl,Config) -> {db,"2.1"}]},% fe left out here on purpose - for normal_hybrid test ?line io:format(Fd,"~p.~n",[RelfileContent]), ?line ok = file:close(Fd), + {filename:dirname(Name), filename:basename(Name)}; +create_script(current_all_future_erts,Config) -> + ?line PrivDir = ?privdir, + ?line Name = fname(PrivDir, current_all_future_erts), + ?line application:load(sasl), + ?line Apps = application_controller:loaded_applications(), + ?line {value,{_,_,KernelVer}} = lists:keysearch(kernel,1,Apps), + ?line {value,{_,_,StdlibVer}} = lists:keysearch(stdlib,1,Apps), + ?line {value,{_,_,SaslVer}} = lists:keysearch(sasl,1,Apps), + ?line {ok,Fd} = file:open(Name++".rel",write), + ?line RelfileContent = + {release,{"Test release 4", "CURRENT_ALL_FUTURE_ERTS"}, + {erts,"99.99"}, + [{kernel,KernelVer}, + {stdlib,StdlibVer}, + {sasl,SaslVer}, + {db,"2.1"}, + {fe,"3.1"}]}, + ?line io:format(Fd,"~p.~n",[RelfileContent]), + ?line ok = file:close(Fd), + {filename:dirname(Name), filename:basename(Name)}; +create_script(current_all_future_sasl,Config) -> + ?line PrivDir = ?privdir, + ?line Name = fname(PrivDir, current_all_future_sasl), + ?line ErtsVer = erlang:system_info(version), + ?line application:load(sasl), + ?line Apps = application_controller:loaded_applications(), + ?line {value,{_,_,KernelVer}} = lists:keysearch(kernel,1,Apps), + ?line {value,{_,_,StdlibVer}} = lists:keysearch(stdlib,1,Apps), + ?line {ok,Fd} = file:open(Name++".rel",write), + ?line RelfileContent = + {release,{"Test release 4", "CURRENT_ALL_FUTURE_SASL"}, + {erts,ErtsVer}, + [{kernel,KernelVer}, + {stdlib,StdlibVer}, + {sasl,"9.9"}, + {db,"2.1"}, + {fe,"3.1"}]}, + ?line io:format(Fd,"~p.~n",[RelfileContent]), + ?line ok = file:close(Fd), {filename:dirname(Name), filename:basename(Name)}. diff --git a/lib/sasl/test/systools_SUITE_data/lib/sasl-9.9/ebin/sasl.app b/lib/sasl/test/systools_SUITE_data/lib/sasl-9.9/ebin/sasl.app new file mode 100644 index 0000000000..3bcc1a4619 --- /dev/null +++ b/lib/sasl/test/systools_SUITE_data/lib/sasl-9.9/ebin/sasl.app @@ -0,0 +1,6 @@ +{application, sasl, + [{description, "FAKE FUTURE SASL"}, + {vsn, "9.9"}, + {modules, []}, + {registered, []}, + {applications, []}]}. diff --git a/lib/sasl/test/systools_SUITE_data/lib/sasl-9.9/ebin/sasl.appup b/lib/sasl/test/systools_SUITE_data/lib/sasl-9.9/ebin/sasl.appup new file mode 100644 index 0000000000..cff0c69b6e --- /dev/null +++ b/lib/sasl/test/systools_SUITE_data/lib/sasl-9.9/ebin/sasl.appup @@ -0,0 +1,12 @@ +%% +%% Fake release upgrade script for sasl +%% + +{ + "9.9", + [{<<".+">>,[restart_new_emulator]} + ], + + [{<<".+">>,[restart_new_emulator]} + ] +}. -- cgit v1.2.3 From ae1c361f797a104a35aef967cc694b457217f488 Mon Sep 17 00:00:00 2001 From: Siri Hansen Date: Thu, 3 Nov 2011 15:01:11 +0100 Subject: Add documentation for upgrade from pre R15 to post R15 sasl --- lib/sasl/doc/src/systools.xml | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'lib/sasl') diff --git a/lib/sasl/doc/src/systools.xml b/lib/sasl/doc/src/systools.xml index 8c1c327d74..fa2fcbf534 100644 --- a/lib/sasl/doc/src/systools.xml +++ b/lib/sasl/doc/src/systools.xml @@ -111,6 +111,11 @@ low-level instruction to restart the emulator is appended to the relup scripts. This ensures that a complete reboot of the system is done when the system is upgraded or downgraded.

+

If an upgrade includes a change from an emulator earlier + than OTP R15 to OTP R15 or later, the warning + pre_R15_emulator_upgrade is issued. See Design + Principles for more information about this.

By default, errors and warnings are printed to tty and the function returns ok or error. If the option silent is provided, the function instead returns -- cgit v1.2.3 From abae78750427c8696c89e57869b4bcebef168fe5 Mon Sep 17 00:00:00 2001 From: Siri Hansen Date: Tue, 8 Nov 2011 12:07:23 +0100 Subject: Add syntax check of relup to check_install_release and install_release This commit adds a check that all instructions in the relup are valid. Earlier, the last part (after point_of_no_return) was not checked before the actual installation started, meaning that if the relup was hand written, there was a potential for crashing the upgrade here. --- lib/sasl/src/release_handler_1.erl | 86 +++++++++++++++++++++++++-------- lib/sasl/test/release_handler_SUITE.erl | 19 +++++++- 2 files changed, 85 insertions(+), 20 deletions(-) (limited to 'lib/sasl') diff --git a/lib/sasl/src/release_handler_1.erl b/lib/sasl/src/release_handler_1.erl index 3a64e10185..b4b288646f 100644 --- a/lib/sasl/src/release_handler_1.erl +++ b/lib/sasl/src/release_handler_1.erl @@ -60,21 +60,25 @@ check_script(Script, LibDirs) -> end. do_check_script(Script, LibDirs, PurgeMods) -> - {Before, _After} = split_instructions(Script), + {Before, After} = split_instructions(Script), case catch lists:foldl(fun(Instruction, EvalState1) -> eval(Instruction, EvalState1) end, #eval_state{libdirs = LibDirs}, Before) of EvalState2 when is_record(EvalState2, eval_state) -> - {ok,PurgeMods}; + case catch syntax_check_script(After) of + ok -> + {ok,PurgeMods}; + Other -> + {error,Other} + end; {error, Error} -> {error, Error}; Other -> {error, Other} end. - %% eval_script/1 - For testing only - no apps added, just testing instructions eval_script(Script) -> eval_script(Script, [], [], [], []). @@ -91,22 +95,30 @@ eval_script(Script, Apps, LibDirs, NewLibs, Opts) -> newlibs = NewLibs, opts = Opts}, Before) of - EvalState2 when is_record(EvalState2, eval_state) -> - case catch lists:foldl(fun(Instruction, EvalState3) -> - eval(Instruction, EvalState3) - end, - EvalState2, - After) of - EvalState4 when is_record(EvalState4, eval_state) -> - {ok, EvalState4#eval_state.unpurged}; - restart_emulator -> - restart_emulator; - Error -> - {'EXIT', Error} - end; - {error, Error} -> {error, Error}; - Other -> {error, Other} - end; + EvalState2 when is_record(EvalState2, eval_state) -> + case catch syntax_check_script(After) of + ok -> + case catch lists:foldl( + fun(Instruction, EvalState3) -> + eval(Instruction, + EvalState3) + end, + EvalState2, + After) of + EvalState4 + when is_record(EvalState4, eval_state) -> + {ok, EvalState4#eval_state.unpurged}; + restart_emulator -> + restart_emulator; + Error -> + {'EXIT', Error} + end; + Other -> + {error,Other} + end; + {error, Error} -> {error, Error}; + Other -> {error, Other} + end; {error, Mod} -> {error, {old_processes, Mod}} end. @@ -182,6 +194,42 @@ do_check_old_code(Mod,Procs) -> [Mod]. +%% Check the last part of the script, i.e. the part after point_of_no_return. +%% More or less a syntax check in case the script was handwritten. +syntax_check_script([point_of_no_return | Script]) -> + syntax_check_script(Script); +syntax_check_script([{load, {_,_,_}} | Script]) -> + syntax_check_script(Script); +syntax_check_script([{remove, {_,_,_}} | Script]) -> + syntax_check_script(Script); +syntax_check_script([{purge, _} | Script]) -> + syntax_check_script(Script); +syntax_check_script([{suspend, _} | Script]) -> + syntax_check_script(Script); +syntax_check_script([{resume, _} | Script]) -> + syntax_check_script(Script); +syntax_check_script([{code_change, _} | Script]) -> + syntax_check_script(Script); +syntax_check_script([{code_change, _, _} | Script]) -> + syntax_check_script(Script); +syntax_check_script([{stop, _} | Script]) -> + syntax_check_script(Script); +syntax_check_script([{start, _} | Script]) -> + syntax_check_script(Script); +syntax_check_script([{sync_nodes, _, {_,_,_}} | Script]) -> + syntax_check_script(Script); +syntax_check_script([{sync_nodes, _, _} | Script]) -> + syntax_check_script(Script); +syntax_check_script([{apply, {_,_,_}} | Script]) -> + syntax_check_script(Script); +syntax_check_script([restart_emulator | Script]) -> + syntax_check_script(Script); +syntax_check_script([Illegal | _Script]) -> + throw({illegal_instruction_after_point_of_no_return,Illegal}); +syntax_check_script([]) -> + ok. + + %%----------------------------------------------------------------- %% An unpurged module is a module for which there exist an old %% version of the code. This should only be the case if there are diff --git a/lib/sasl/test/release_handler_SUITE.erl b/lib/sasl/test/release_handler_SUITE.erl index 958f6bbfc9..12f86365a3 100644 --- a/lib/sasl/test/release_handler_SUITE.erl +++ b/lib/sasl/test/release_handler_SUITE.erl @@ -60,7 +60,8 @@ 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, - instructions, eval_appup, supervisor_which_children_timeout]. + instructions, eval_appup, supervisor_which_children_timeout, + install_release_syntax_check]. groups() -> [{release,[], @@ -620,6 +621,22 @@ supervisor_which_children_timeout(Conf) -> supervisor_which_children_timeout(cleanup, Conf) -> stop_node(node_name(supervisor_which_children_timeout)). + +%% Test that check_install_release will fail for illegal relup +%% instructions, even after point of no return. +install_release_syntax_check(Conf) when is_list(Conf) -> + + S1 = [point_of_no_return, illegal_instruction], + {error,{illegal_instruction_after_point_of_no_return,illegal_instruction}} = + release_handler_1:check_script(S1,[]), + + S2 = [point_of_no_return,restart_new_emulator], + {error,{illegal_instruction_after_point_of_no_return,restart_new_emulator}} = + release_handler_1:check_script(S2,[]), + + ok. + + %%----------------------------------------------------------------- %% Ticket: OTP-2740 %% Slogan: vsn not numeric doesn't work so good in release_handling -- cgit v1.2.3 From af6941a5265ed613df26fccba3e234c24094405f Mon Sep 17 00:00:00 2001 From: Siri Hansen Date: Wed, 9 Nov 2011 16:42:14 +0100 Subject: Check for sasl application in systools:make_script and make_relup make_script will give warning but allow it make_relup will fail since it is not possible to upgrade if sasl is not included in both releases. --- lib/sasl/src/systools_make.erl | 30 +- lib/sasl/src/systools_relup.erl | 80 ++-- lib/sasl/test/systools_SUITE.erl | 462 ++++++++------------- .../d_bad_appup/lib/fe-2.1/ebin/fe.app | 7 + .../d_no_appup/lib/fe-500.18.7/ebin/fe.app | 7 + 5 files changed, 250 insertions(+), 336 deletions(-) create mode 100644 lib/sasl/test/systools_SUITE_data/d_bad_appup/lib/fe-2.1/ebin/fe.app create mode 100644 lib/sasl/test/systools_SUITE_data/d_no_appup/lib/fe-500.18.7/ebin/fe.app (limited to 'lib/sasl') diff --git a/lib/sasl/src/systools_make.erl b/lib/sasl/src/systools_make.erl index 33bd51ecbb..ce37f3c2ce 100644 --- a/lib/sasl/src/systools_make.erl +++ b/lib/sasl/src/systools_make.erl @@ -364,13 +364,13 @@ get_release(File, Path, ModTestP, Machine) -> end. get_release1(File, Path, ModTestP, Machine) -> - {ok, Release} = read_release(File, Path), + {ok, Release, Warnings1} = read_release(File, Path), {ok, Appls0} = collect_applications(Release, Path), {ok, Appls1} = check_applications(Appls0), {ok, Appls2} = sort_included_applications(Appls1, Release), % OTP-4121 - {ok, Warnings} = check_modules(Appls2, Path, ModTestP, Machine), + {ok, Warnings2} = check_modules(Appls2, Path, ModTestP, Machine), {ok, Appls} = sort_appls(Appls2), - {ok, Release, Appls, Warnings}. + {ok, Release, Appls, Warnings1 ++ Warnings2}. %%______________________________________________________________________ %% read_release(File, Path) -> {ok, #release} | throw({error, What}) @@ -385,11 +385,12 @@ read_release(File, Path) -> check_rel(Release) -> case catch check_rel1(Release) of - {ok, {Name,Vsn,Evsn,Appl,Incl}} -> + {ok, {Name,Vsn,Evsn,Appl,Incl}, Ws} -> {ok, #release{name=Name, vsn=Vsn, erts_vsn=Evsn, applications=Appl, - incl_apps=Incl}}; + incl_apps=Incl}, + Ws}; {error, Error} -> throw({error,?MODULE,Error}); Error -> @@ -400,8 +401,8 @@ check_rel1({release,{Name,Vsn},{erts,EVsn},Appl}) when is_list(Appl) -> check_name(Name), check_vsn(Vsn), check_evsn(EVsn), - {Appls,Incls} = check_appl(Appl), - {ok, {Name,Vsn,EVsn,Appls,Incls}}; + {{Appls,Incls},Ws} = check_appl(Appl), + {ok, {Name,Vsn,EVsn,Appls,Incls},Ws}; check_rel1(_) -> {error, badly_formatted_release}. @@ -454,8 +455,8 @@ check_appl(Appl) -> end, Appl) of [] -> - mandatory_applications(Appl), - split_app_incl(Appl); + {ok,Ws} = mandatory_applications(Appl), + {split_app_incl(Appl),Ws}; Illegal -> throw({error, {illegal_applications,Illegal}}) end. @@ -466,7 +467,12 @@ mandatory_applications(Appl) -> Mand = mandatory_applications(), case filter(fun(X) -> member(X, AppNames) end, Mand) of Mand -> - ok; + case member(sasl,AppNames) of + true -> + {ok,[]}; + _ -> + {ok, [{warning,missing_sasl}]} + end; _ -> throw({error, {missing_mandatory_app, Mand}}) end. @@ -2312,5 +2318,9 @@ form_warn(Prefix, {exref_undef, Undef}) -> [Prefix,M,F,A]) end, map(F, Undef); +form_warn(Prefix, missing_sasl) -> + io_lib:format("~s: Missing application sasl. " + "Can not upgrade with this release~n", + [Prefix]); form_warn(Prefix, What) -> io_lib:format("~s ~p~n", [Prefix,What]). diff --git a/lib/sasl/src/systools_relup.erl b/lib/sasl/src/systools_relup.erl index 5346538dc8..57e375b03e 100644 --- a/lib/sasl/src/systools_relup.erl +++ b/lib/sasl/src/systools_relup.erl @@ -205,7 +205,13 @@ do_mk_relup(TopRelFile, BaseUpRelDcs, BaseDnRelDcs, Path, Opts) -> %% TopRel = #release %% NameVsnApps = [{{Name, Vsn}, #application}] {ok, TopRel, NameVsnApps, Ws0} -> - %% + case lists:member({warning,missing_sasl},Ws0) of + true -> + throw({error,?MODULE,{missing_sasl,TopRel}}); + false -> + ok + end, + %% TopApps = [#application] TopApps = lists:map(fun({_, App}) -> App end, NameVsnApps), @@ -252,7 +258,21 @@ foreach_baserel_up(TopRel, TopApps, [BaseRelDc|BaseRelDcs], Path, Opts, Ws, Acc) -> BaseRelFile = extract_filename(BaseRelDc), - {ok, BaseRel} = systools_make:read_release(BaseRelFile, Path), + {BaseRel, {BaseNameVsns, BaseApps}, Ws0} = + case systools_make:get_release(BaseRelFile, Path) of + {ok, BR, NameVsnApps, Warns} -> + case lists:member({warning,missing_sasl},Warns) of + true -> + throw({error,?MODULE,{missing_sasl,BR}}); + false -> + %% NameVsnApps = [{{Name,Vsn},#application}] + %% Gives two lists - [{Name,Vsn}] and [#application] + {BR,lists:unzip(NameVsnApps),Warns} + end; + Other1 -> + throw(Other1) + end, + %% %% BaseRel = #release @@ -262,7 +282,7 @@ foreach_baserel_up(TopRel, TopApps, [BaseRelDc|BaseRelDcs], Path, Opts, %% application, one for each added applications, and one for %% each removed applications. %% - {RUs1, Ws1} = collect_appup_scripts(up, TopApps, BaseRel, Ws, []), + {RUs1, Ws1} = collect_appup_scripts(up, TopApps, BaseRel, Ws0++Ws, []), {RUs2, Ws2} = create_add_app_scripts(BaseRel, TopRel, RUs1, Ws1), @@ -270,16 +290,6 @@ foreach_baserel_up(TopRel, TopApps, [BaseRelDc|BaseRelDcs], Path, Opts, {RUs4, Ws4} = check_for_emulator_restart(TopRel, BaseRel, RUs3, Ws3, Opts), - {BaseNameVsns,BaseApps} = - case systools_make:get_release(BaseRelFile, Path) of - {ok, _, NameVsnApps, _Warns} -> - %% NameVsnApps = [{{Name,Vsn},#application}] - %% Gives two lists - [{Name,Vsn}] and [#application] - lists:unzip(NameVsnApps); - Other1 -> - throw(Other1) - end, - case systools_rc:translate_scripts(up, RUs4, TopApps, BaseApps) of {ok, RUs5} -> @@ -303,41 +313,41 @@ foreach_baserel_dn(TopRel, TopApps, [BaseRelDc|BaseRelDcs], Path, Opts, Ws, Acc) -> BaseRelFile = extract_filename(BaseRelDc), - {ok, BaseRel} = systools_make:read_release(BaseRelFile, Path), - - %% BaseRel = #release - - %% RUs = (release upgrade scripts) - %% - {RUs1, Ws1} = collect_appup_scripts(dn, TopApps, BaseRel, Ws, []), - - {BaseApps, Ws2} = + {BaseRel, BaseApps, Ws0} = case systools_make:get_release(BaseRelFile, Path) of %% %% NameVsnApps = [{{Name, Vsn}, #application}] - {ok, _, NameVsnApps, Warns} -> - %% - %% NApps = [#application] - NApps = lists:map(fun({_,App}) -> App end, NameVsnApps), - {NApps, Warns ++ Ws1}; + {ok, BR, NameVsnApps, Warns} -> + case lists:member({warning,missing_sasl},Warns) of + true -> + throw({error,?MODULE,{missing_sasl,BR}}); + false -> + %% NApps = [#application] + NApps = lists:map(fun({_,App}) -> App end, NameVsnApps), + {BR, NApps, Warns} + end; Other -> throw(Other) end, - RUs2 = RUs1, + %% BaseRel = #release - {RUs3, Ws3} = create_add_app_scripts(TopRel, BaseRel, RUs2, Ws2), + %% RUs = (release upgrade scripts) + %% + {RUs1, Ws1} = collect_appup_scripts(dn, TopApps, BaseRel, Ws0++Ws, []), - {RUs4, Ws4} = create_remove_app_scripts(TopRel, BaseRel, RUs3, Ws3), + {RUs2, Ws2} = create_add_app_scripts(TopRel, BaseRel, RUs1, Ws1), - {RUs5, Ws5} = check_for_emulator_restart(TopRel, BaseRel, RUs4, Ws4, Opts), + {RUs3, Ws3} = create_remove_app_scripts(TopRel, BaseRel, RUs2, Ws2), - case systools_rc:translate_scripts(dn, RUs5, BaseApps, TopApps) of + {RUs4, Ws4} = check_for_emulator_restart(TopRel, BaseRel, RUs3, Ws3, Opts), + + case systools_rc:translate_scripts(dn, RUs4, BaseApps, TopApps) of {ok, RUs} -> VDR = {BaseRel#release.vsn, extract_description(BaseRelDc), RUs}, foreach_baserel_dn(TopRel, TopApps, BaseRelDcs, Path, - Opts, Ws5, [VDR| Acc]); + Opts, Ws4, [VDR| Acc]); XXX -> throw(XXX) end; @@ -598,7 +608,9 @@ format_error({no_relup, File, App, Vsn}) -> "in file ~p~n", [App#application.name, App#application.vsn, App#application.name, Vsn, File]); - +format_error({missing_sasl,Release}) -> + io_lib:format("No sasl application in release ~p, ~p. Can not be upgraded.", + [Release#release.name, Release#release.vsn]); format_error(Error) -> io:format("~p~n", [Error]). diff --git a/lib/sasl/test/systools_SUITE.erl b/lib/sasl/test/systools_SUITE.erl index e06a26828c..892c4994e8 100644 --- a/lib/sasl/test/systools_SUITE.erl +++ b/lib/sasl/test/systools_SUITE.erl @@ -41,7 +41,7 @@ -export([all/0,suite/0,groups/0,init_per_group/2,end_per_group/2]). -export([ script_options/1, normal_script/1, no_mod_vsn_script/1, - wildcard_script/1, variable_script/1, + wildcard_script/1, variable_script/1, no_sasl_script/1, abnormal_script/1, src_tests_script/1, crazy_script/1, warn_shadow_script/1, included_script/1, included_override_script/1, @@ -49,8 +49,9 @@ -export([ tar_options/1, normal_tar/1, no_mod_vsn_tar/1, variable_tar/1, src_tests_tar/1, shadow_tar/1, var_tar/1, exref_tar/1, link_tar/1, otp_9507/1]). --export([ normal_relup/1, restart_relup/1, abnormal_relup/1, no_appup_relup/1, - bad_appup_relup/1, app_start_type_relup/1, regexp_relup/1, otp_3065/1]). +-export([ normal_relup/1, restart_relup/1, abnormal_relup/1, no_sasl_relup/1, + no_appup_relup/1, bad_appup_relup/1, app_start_type_relup/1, + regexp_relup/1, otp_3065/1]). -export([otp_6226/1]). -export([normal_hybrid/1,hybrid_no_old_sasl/1,hybrid_no_new_sasl/1]). -export([init_per_suite/1, end_per_suite/1, @@ -74,8 +75,8 @@ groups() -> [{script, [], [script_options, normal_script, no_mod_vsn_script, wildcard_script, variable_script, abnormal_script, - src_tests_script, crazy_script, warn_shadow_script, - included_script, included_override_script, + no_sasl_script, src_tests_script, crazy_script, + warn_shadow_script, included_script, included_override_script, included_fail_script, included_bug_script, exref_script, otp_3065]}, {tar, [], @@ -83,8 +84,8 @@ groups() -> src_tests_tar, shadow_tar, var_tar, exref_tar, link_tar, otp_9507]}, {relup, [], - [normal_relup, restart_relup, abnormal_relup, no_appup_relup, - bad_appup_relup, app_start_type_relup, regexp_relup + [normal_relup, restart_relup, abnormal_relup, no_sasl_relup, + no_appup_relup, bad_appup_relup, app_start_type_relup, regexp_relup ]}, {hybrid, [], [normal_hybrid,hybrid_no_old_sasl,hybrid_no_new_sasl]}, {tickets, [], [otp_6226]}]. @@ -388,6 +389,32 @@ abnormal_script(Config) when is_list(Config) -> ok. +%% make_script +%% +no_sasl_script(suite) -> []; +no_sasl_script(doc) -> + ["Create script without sasl appl. Check warning."]; +no_sasl_script(Config) when is_list(Config) -> + ?line {ok, OldDir} = file:get_cwd(), + + ?line {LatestDir, LatestName} = create_script(latest1_no_sasl,Config), + + ?line DataDir = filename:absname(?copydir), + ?line LibDir = [fname([DataDir, d_normal, lib])], + ?line P = [fname([LibDir, '*', ebin]), + fname([DataDir, lib, kernel, ebin]), + fname([DataDir, lib, stdlib, ebin]), + fname([DataDir, lib, sasl, ebin])], + + ?line ok = file:set_cwd(LatestDir), + + ?line {ok, _ , [{warning,missing_sasl}]} = + systools:make_script(LatestName,[{path, P},silent]), + + ?line ok = file:set_cwd(OldDir), + ok. + + %% make_script %% src_tests_script(suite) -> []; @@ -1108,15 +1135,17 @@ otp_9507(Config) when is_list(Config) -> RelName = fname([LatestDir,LatestName]), ?line P1 = ["./ebin", - fname([DataDir, lib, kernel, ebin]), - fname([DataDir, lib, stdlib, ebin])], + fname([DataDir, lib, kernel, ebin]), + fname([DataDir, lib, stdlib, ebin]), + fname([DataDir, lib, sasl, ebin])], ?line {ok, _, _} = systools:make_script(RelName, [silent, {path, P1}]), ?line ok = systools:make_tar(RelName, [{path, P1}]), ?line Content1 = tar_contents(RelName), ?line P2 = ["ebin", - fname([DataDir, lib, kernel, ebin]), - fname([DataDir, lib, stdlib, ebin])], + fname([DataDir, lib, kernel, ebin]), + fname([DataDir, lib, stdlib, ebin]), + fname([DataDir, lib, sasl, ebin])], %% Tickets solves the following line - it used to fail with %% {function_clause,[{filename,join,[[]]},...} @@ -1183,7 +1212,7 @@ normal_relup(Config) when is_list(Config) -> ?line ok = systools:make_relup(LatestName, [LatestName2], [LatestName1], [{path, P}]), ?line ok = check_relup([{fe, "3.1"}, {db, "2.1"}], [{db, "1.0"}]), - ?line {ok, _, _, [{erts_vsn_changed, _}]} = + ?line {ok, _, _, [pre_R15_emulator_upgrade,{erts_vsn_changed, _}]} = systools:make_relup(LatestName, [LatestName2], [LatestName1], [{path, P}, silent]), ?line ok = check_relup([{fe, "3.1"}, {db, "2.1"}], [{db, "1.0"}]), @@ -1345,13 +1374,14 @@ no_appup_relup(Config) when is_list(Config) -> ?line {_LatestDir1,LatestName1} = create_script(latest_small1,Config), ?line DataDir = filename:absname(?copydir), - ?line P1 = [fname([DataDir, d_no_appup, lib, 'fe-3.1', ebin]), - fname([DataDir, lib, kernel, ebin]), - fname([DataDir, lib, stdlib, ebin])], ?line ok = file:set_cwd(LatestDir), %% Check that appup might be missing + ?line P1 = [fname([DataDir, d_no_appup, lib, 'fe-3.1', ebin]), + fname([DataDir, lib, kernel, ebin]), + fname([DataDir, lib, stdlib, ebin]), + fname([DataDir, lib, sasl, ebin])], ?line ok = systools:make_relup(LatestName, [LatestName], [], [{path, P1}]), ?line {ok,_, _, []} = @@ -1359,22 +1389,29 @@ no_appup_relup(Config) when is_list(Config) -> [silent, {path, P1}]), %% Check that appup might NOT be missing when we need it + ?line P2 = [fname([DataDir, d_no_appup, lib, 'fe-3.1', ebin]), + fname([DataDir, d_no_appup, lib, 'fe-2.1', ebin]), + fname([DataDir, lib, kernel, ebin]), + fname([DataDir, lib, stdlib, ebin]), + fname([DataDir, lib, sasl, ebin])], ?line error = - systools:make_relup(LatestName, [LatestName0], [], [{path, P1}]), + systools:make_relup(LatestName, [LatestName0], [], [{path, P2}]), ?line {error,_,{file_problem, {_,{error,{open,_,_}}}}} = systools:make_relup(LatestName, [], [LatestName0], - [silent, {path, P1}]), + [silent, {path, P2}]), %% Check that appups missing vsn traps - ?line P2 = [fname([DataDir, d_no_appup, lib, 'fe-2.1', ebin]), + ?line P3 = [fname([DataDir, d_no_appup, lib, 'fe-2.1', ebin]), + fname([DataDir, d_no_appup, lib, 'fe-500.18.7', ebin]), fname([DataDir, lib, kernel, ebin]), - fname([DataDir, lib, stdlib, ebin])], + fname([DataDir, lib, stdlib, ebin]), + fname([DataDir, lib, sasl, ebin])], ?line error = - systools:make_relup(LatestName0, [LatestName1], [], [{path, P2}]), + systools:make_relup(LatestName0, [LatestName1], [], [{path, P3}]), ?line {error,_,{no_relup, _, _, _}} = systools:make_relup(LatestName0, [], [LatestName1], - [silent, {path, P2}]), + [silent, {path, P3}]), ?line ok = file:set_cwd(OldDir), ok. @@ -1392,8 +1429,10 @@ bad_appup_relup(Config) when is_list(Config) -> ?line DataDir = filename:absname(?copydir), ?line N2 = [fname([DataDir, d_bad_appup, lib, 'fe-3.1', ebin]), + fname([DataDir, d_bad_appup, lib, 'fe-2.1', ebin]), fname([DataDir, lib, kernel, ebin]), - fname([DataDir, lib, stdlib, ebin])], + fname([DataDir, lib, stdlib, ebin]), + fname([DataDir, lib, sasl, ebin])], ?line ok = file:set_cwd(LatestDir), @@ -1440,6 +1479,37 @@ abnormal_relup(Config) when is_list(Config) -> ok. +%% make_relup +%% +no_sasl_relup(suite) -> []; +no_sasl_relup(doc) -> + ["Check relup can not be created is sasl is not in rel file"]; +no_sasl_relup(Config) when is_list(Config) -> + ?line {ok, OldDir} = file:get_cwd(), + ?line {Dir1,Name1} = create_script(latest1_no_sasl,Config), + ?line {_Dir2,Name2} = create_script(latest1,Config), + + ?line DataDir = filename:absname(?copydir), + ?line LibDir = [fname([DataDir, d_normal, lib])], + ?line P = [fname([LibDir, '*', ebin]), + fname([DataDir, lib, kernel, ebin]), + fname([DataDir, lib, stdlib, ebin]), + fname([DataDir, lib, sasl, ebin])], + + ?line ok = file:set_cwd(Dir1), + + ?line error = systools:make_relup(Name2, [Name1], [Name1], [{path, P}]), + ?line R1 = systools:make_relup(Name2, [Name1], [Name1],[silent, {path, P}]), + ?line {error,systools_relup,{missing_sasl,_}} = R1, + + ?line error = systools:make_relup(Name1, [Name2], [Name2], [{path, P}]), + ?line R2 = systools:make_relup(Name1, [Name2], [Name2],[silent, {path, P}]), + ?line {error,systools_relup,{missing_sasl,_}} = R2, + + ?line ok = file:set_cwd(OldDir), + ok. + + %% Check that application start type is used in relup app_start_type_relup(suite) -> []; @@ -1453,29 +1523,31 @@ app_start_type_relup(Config) when is_list(Config) -> ?line Release2 = filename:join(Dir2,Name2), ?line {ok, Release2Relup, systools_relup, []} = systools:make_relup(Release2, [Release1], [Release1], [{outdir, PrivDir}, silent]), - ?line {"2", [{"1",[], UpInstructions}], [{"1",[], DownInstructions}]} = Release2Relup, + ?line {"LATEST_APP_START_TYPE2", + [{"LATEST_APP_START_TYPE1",[], UpInstructions}], + [{"LATEST_APP_START_TYPE1",[], DownInstructions}]} = Release2Relup, %% ?t:format("Up: ~p",[UpInstructions]), %% ?t:format("Dn: ~p",[DownInstructions]), ?line [{load_object_code, {mnesia, _, _}}, - {load_object_code, {sasl, _, _}}, + {load_object_code, {runtime_tools, _, _}}, {load_object_code, {webtool, _, _}}, {load_object_code, {snmp, _, _}}, {load_object_code, {xmerl, _, _}}, point_of_no_return | UpInstructionsT] = UpInstructions, ?line true = lists:member({apply,{application,start,[mnesia,permanent]}}, UpInstructionsT), - ?line true = lists:member({apply,{application,start,[sasl,transient]}}, UpInstructionsT), + ?line true = lists:member({apply,{application,start,[runtime_tools,transient]}}, UpInstructionsT), ?line true = lists:member({apply,{application,start,[webtool,temporary]}}, UpInstructionsT), ?line true = lists:member({apply,{application,load,[snmp]}}, UpInstructionsT), ?line false = lists:any(fun({apply,{application,_,[xmerl|_]}}) -> true; (_) -> false end, UpInstructionsT), ?line [point_of_no_return | DownInstructionsT] = DownInstructions, ?line true = lists:member({apply,{application,stop,[mnesia]}}, DownInstructionsT), - ?line true = lists:member({apply,{application,stop,[sasl]}}, DownInstructionsT), + ?line true = lists:member({apply,{application,stop,[runtime_tools]}}, DownInstructionsT), ?line true = lists:member({apply,{application,stop,[webtool]}}, DownInstructionsT), ?line true = lists:member({apply,{application,stop,[snmp]}}, DownInstructionsT), ?line true = lists:member({apply,{application,stop,[xmerl]}}, DownInstructionsT), ?line true = lists:member({apply,{application,unload,[mnesia]}}, DownInstructionsT), - ?line true = lists:member({apply,{application,unload,[sasl]}}, DownInstructionsT), + ?line true = lists:member({apply,{application,unload,[runtime_tools]}}, DownInstructionsT), ?line true = lists:member({apply,{application,unload,[webtool]}}, DownInstructionsT), ?line true = lists:member({apply,{application,unload,[snmp]}}, DownInstructionsT), ?line true = lists:member({apply,{application,unload,[xmerl]}}, DownInstructionsT), @@ -1493,7 +1565,8 @@ regexp_relup(Config) -> ?line DataDir = filename:absname(?copydir), ?line P = [fname([DataDir, d_regexp_appup, lib, '*', ebin]), fname([DataDir, lib, kernel, ebin]), - fname([DataDir, lib, stdlib, ebin])], + fname([DataDir, lib, stdlib, ebin]), + fname([DataDir, lib, sasl, ebin])], ?line ok = file:set_cwd(LatestDir), @@ -1551,7 +1624,7 @@ normal_hybrid(Config) -> ?line {ok,Hybrid} = systools_make:make_hybrid_boot("tmp_vsn",Boot1,Boot2, BasePaths, [dummy,args]), - ?line {script,{"Test release 4","tmp_vsn"},Script} = binary_to_term(Hybrid), + ?line {script,{"Test release","tmp_vsn"},Script} = binary_to_term(Hybrid), ct:log("~p.~n",[Script]), %% Check that all paths to base apps are replaced by paths from BaseLib @@ -1639,7 +1712,8 @@ hybrid_no_old_sasl(Config) -> ?line ok = file:set_cwd(Dir1), - ?line {ok, _ , []} = systools:make_script(Name1,[{path, P},silent]), + ?line {ok, _ , [{warning,missing_sasl}]} = + systools:make_script(Name1,[{path, P},silent]), ?line {ok, _ , []} = systools:make_script(Name2,[{path, P},silent]), ?line {ok,Boot1} = file:read_file(Name1 ++ ".boot"), ?line {ok,Boot2} = file:read_file(Name2 ++ ".boot"), @@ -1671,7 +1745,8 @@ hybrid_no_new_sasl(Config) -> ?line ok = file:set_cwd(Dir1), ?line {ok, _ , []} = systools:make_script(Name1,[{path, P},silent]), - ?line {ok, _ , []} = systools:make_script(Name2,[{path, P},silent]), + ?line {ok, _ , [{warning,missing_sasl}]} = + systools:make_script(Name2,[{path, P},silent]), ?line {ok,Boot1} = file:read_file(Name1 ++ ".boot"), ?line {ok,Boot2} = file:read_file(Name2 ++ ".boot"), @@ -1971,291 +2046,94 @@ tar_name(Name) -> Name ++ ".tar.gz". create_script(latest,Config) -> - ?line PrivDir = ?privdir, - ?line Name = fname(PrivDir, latest), - ?line Apps = application_controller:which_applications(), - ?line {value,{_,_,KernelVer}} = lists:keysearch(kernel,1,Apps), - ?line {value,{_,_,StdlibVer}} = lists:keysearch(stdlib,1,Apps), - ?line {ok,Fd} = file:open(Name++".rel",write), - ?line io:format(Fd, - "{release, {\"Test release 3\", \"LATEST\"}, \n" - " {erts, \"4.4\"}, \n" - " [{kernel, \"~s\"}, {stdlib, \"~s\"}, \n" - " {db, \"2.1\"}, {fe, \"3.1\"}]}.\n", - [KernelVer,StdlibVer]), - ?line ok = file:close(Fd), - {filename:dirname(Name), filename:basename(Name)}; + Apps = core_apps(current) ++ [{db,"2.1"},{fe,"3.1"}], + do_create_script(latest,Config,"4.4",Apps); create_script(latest_no_mod_vsn,Config) -> - ?line PrivDir = ?privdir, - ?line Name = fname(PrivDir, latest), - ?line Apps = application_controller:which_applications(), - ?line {value,{_,_,KernelVer}} = lists:keysearch(kernel,1,Apps), - ?line {value,{_,_,StdlibVer}} = lists:keysearch(stdlib,1,Apps), - ?line {ok,Fd} = file:open(Name++".rel",write), - ?line io:format(Fd, - "{release, {\"Test release 3\", \"LATESTNOMOD\"}, \n" - " {erts, \"4.4\"}, \n" - " [{kernel, \"~s\"}, {stdlib, \"~s\"}, \n" - " {db, \"3.1\"}, {fe, \"3.1\"}]}.\n", - [KernelVer,StdlibVer]), - ?line ok = file:close(Fd), - {filename:dirname(Name), filename:basename(Name)}; + Apps = core_apps(current) ++ [{db,"3.1"},{fe,"3.1"}], + do_create_script(latest_no_mod_vsn,Config,"4.4",Apps); create_script(latest0,Config) -> - ?line PrivDir = ?privdir, - ?line Name = fname(PrivDir, latest0), - ?line {ok,Fd} = file:open(Name++".rel",write), - ?line RelfileContent = - {release,{"Test release 2", "LATEST0"}, - {erts,"4.4"}, - [{kernel,"1.0"}, - {stdlib,"1.0"}, - {sasl,"1.0"}, - {db,"2.1"}, - {fe,"3.1"}]}, - ?line io:format(Fd,"~p.~n",[RelfileContent]), - ?line ok = file:close(Fd), - {filename:dirname(Name), filename:basename(Name)}; + Apps = core_apps("1.0") ++ [{db,"2.1"},{fe,"3.1"}], + do_create_script(latest0,Config,"4.4",Apps); create_script(latest0_current_erts,Config) -> - ?line PrivDir = ?privdir, - ?line Name = fname(PrivDir, latest0_current_erts), - ?line ErtsVer = erlang:system_info(version), - ?line {ok,Fd} = file:open(Name++".rel",write), - ?line RelfileContent = - {release,{"Test release 2", "LATEST0_CURRENT_ERTS"}, - {erts,ErtsVer}, - [{kernel,"1.0"}, % fake - will never happen for real that - {stdlib,"1.0"}, % erts changes verson but not kernel, stdlib, sasl - {sasl,"1.0"}, - {db,"2.1"}, - {fe,"3.1"}]}, - ?line io:format(Fd,"~p.~n",[RelfileContent]), - ?line ok = file:close(Fd), - {filename:dirname(Name), filename:basename(Name)}; + Apps = core_apps("1.0") ++ [{db,"2.1"},{fe,"3.1"}], + do_create_script(latest0_current_erts,Config,current,Apps); create_script(latest1,Config) -> - ?line PrivDir = ?privdir, - ?line Name = fname(PrivDir, latest1), - ?line {ok,Fd} = file:open(Name++".rel",write), - ?line RelfileContent = - {release,{"Test release 2", "LATEST1"}, - {erts,"4.4"}, - [{kernel,"1.0"}, - {stdlib,"1.0"}, - {sasl,"1.0"}, - {db,"1.0"}, - {fe,"3.1"}]}, - ?line io:format(Fd,"~p.~n",[RelfileContent]), - ?line ok = file:close(Fd), - {filename:dirname(Name), filename:basename(Name)}; + Apps = core_apps("1.0") ++ [{db,"1.0"},{fe,"3.1"}], + do_create_script(latest1,Config,"4.4",Apps); create_script(latest1_no_sasl,Config) -> - ?line PrivDir = ?privdir, - ?line Name = fname(PrivDir, latest1_no_sasl), - ?line {ok,Fd} = file:open(Name++".rel",write), - ?line RelfileContent = - {release,{"Test release 2", "LATEST1_NO_SASL"}, - {erts,"4.4"}, - [{kernel,"1.0"}, - {stdlib,"1.0"}, - {db,"1.0"}, - {fe,"3.1"}]}, - ?line io:format(Fd,"~p.~n",[RelfileContent]), - ?line ok = file:close(Fd), - {filename:dirname(Name), filename:basename(Name)}; + Apps = [{kernel,"1.0"},{stdlib,"1.0"},{db,"1.0"},{fe,"3.1"}], + do_create_script(latest1_no_sasl,Config,"4.4",Apps); create_script(latest2,Config) -> - ?line PrivDir = ?privdir, - ?line Name = fname(PrivDir, latest2), - ?line {ok,Fd} = file:open(Name++".rel",write), - ?line io:format(Fd, - "{release, {\"Test release 1\", \"LATEST2\"}, \n" - " {erts, \"4.3\"}, \n" - " [{kernel, \"1.0\"}, {stdlib, \"1.0\"}, \n" - " {db, \"1.0\"}, {fe, \"2.1\"}]}.\n", - []), - ?line ok = file:close(Fd), - {filename:dirname(Name), filename:basename(Name)}; + Apps = core_apps("1.0") ++ [{db,"1.0"},{fe,"2.1"}], + do_create_script(latest2,Config,"4.3",Apps); create_script(latest_small,Config) -> - ?line PrivDir = ?privdir, - ?line Name = fname(PrivDir, 'latest-small'), - ?line {ok,Fd} = file:open(Name++".rel",write), - ?line io:format(Fd, - "{release, {\"Test release 2\", \"LATEST_SMALL\"}, \n" - " {erts, \"4.4\"}, \n" - " [{kernel, \"1.0\"}, {stdlib, \"1.0\"}, \n" - " {fe, \"3.1\"}]}.\n", - []), - ?line ok = file:close(Fd), - {filename:dirname(Name), filename:basename(Name)}; + Apps = core_apps("1.0") ++ [{fe,"3.1"}], + do_create_script(latest_small,Config,"4.4",Apps); create_script(latest_small0,Config) -> %Differs in fe vsn - ?line PrivDir = ?privdir, - ?line Name = fname(PrivDir, 'latest-small0'), - ?line {ok,Fd} = file:open(Name++".rel",write), - ?line io:format(Fd, - "{release, {\"Test release 2\", \"LATEST_SMALL0\"}, \n" - " {erts, \"4.4\"}, \n" - " [{kernel, \"1.0\"}, {stdlib, \"1.0\"}, \n" - " {fe, \"2.1\"}]}.\n", - []), - ?line ok = file:close(Fd), - {filename:dirname(Name), filename:basename(Name)}; + Apps = core_apps("1.0") ++ [{fe,"2.1"}], + do_create_script(latest_small0,Config,"4.4",Apps); create_script(latest_small1,Config) -> - ?line PrivDir = ?privdir, - ?line Name = fname(PrivDir, 'latest-small1'), - ?line {ok,Fd} = file:open(Name++".rel",write), - ?line io:format(Fd, - "{release, {\"Test release 2\", \"LATEST_SMALL1\"}, \n" - " {erts, \"4.4\"}, \n" - " [{kernel, \"1.0\"}, {stdlib, \"1.0\"}, \n" - " {fe, \"500.18.7\"}]}.\n", - []), - ?line ok = file:close(Fd), - {filename:dirname(Name), filename:basename(Name)}; + Apps = core_apps("1.0") ++ [{fe,"500.18.7"}], + do_create_script(latest_small1,Config,"4.4",Apps); create_script(latest_small2,Config) -> - ?line PrivDir = ?privdir, - ?line Name = fname(PrivDir, 'latest-small2'), - ?line {ok,Fd} = file:open(Name++".rel",write), - ?line io:format(Fd, - "{release, {\"Test release 2\", \"LATEST_SMALL2\"}, \n" - " {erts, \"4.4\"}, \n" - " [{kernel, \"1.0\"}, {stdlib, \"1.0\"}, \n" - " {fe, \"2.1.1\"}]}.\n", - []), - ?line ok = file:close(Fd), - {filename:dirname(Name), filename:basename(Name)}; + Apps = core_apps("1.0") ++ [{fe,"2.1.1"}], + do_create_script(latest_small2,Config,"4.4",Apps); create_script(latest_nokernel,Config) -> - ?line PrivDir = ?privdir, - ?line Name = fname(PrivDir, 'latest-nokernel'), - ?line {ok,Fd} = file:open(Name++".rel",write), - ?line io:format(Fd, - "{release, {\"Test release 3\", \"LATEST_NOKERNEL\"}, \n" - " {erts, \"4.4\"}, \n" - " [{db, \"2.1\"}, {fe, \"3.1\"}]}.\n", - []), - ?line ok = file:close(Fd), - {filename:dirname(Name), filename:basename(Name)}; + Apps = [{db,"2.1"},{fe,"3.1"}], + do_create_script(latest_nokernel,Config,"4.4",Apps); create_script(latest_app_start_type1,Config) -> - ?line PrivDir = ?privdir, - ?line Name = fname(PrivDir, latest_app_start_type1), - ?line ErtsVer = erlang:system_info(version), - ?line Apps = application_controller:which_applications(), - ?line {value,{_,_,KernelVer}} = lists:keysearch(kernel,1,Apps), - ?line {value,{_,_,StdlibVer}} = lists:keysearch(stdlib,1,Apps), - ?line {ok,Fd} = file:open(Name++".rel",write), - ?line RelfileContent = - {release,{"Test release", "1"}, - {erts,ErtsVer}, - [{kernel,KernelVer}, - {stdlib,StdlibVer}]}, - ?line io:format(Fd,"~p.~n",[RelfileContent]), - ?line ok = file:close(Fd), - {filename:dirname(Name), filename:basename(Name)}; + Apps = core_apps(current), + do_create_script(latest_app_start_type1,Config,current,Apps); create_script(latest_app_start_type2,Config) -> - ?line PrivDir = ?privdir, - ?line Name = fname(PrivDir, latest_app_start_type2), - ?line ErtsVer = erlang:system_info(version), - ?line Apps = application_controller:which_applications(), - ?line {value,{_,_,KernelVer}} = lists:keysearch(kernel,1,Apps), - ?line {value,{_,_,StdlibVer}} = lists:keysearch(stdlib,1,Apps), - ?line OtherApps = [{mnesia,permanent}, - {sasl,transient}, - {webtool,temporary}, - {snmp,load}, - {xmerl,none}], - ?line lists:foreach(fun({App,_}) -> application:load(App) end, - OtherApps), - ?line Loaded = application:loaded_applications(), - ?line OtherAppsRel = - lists:map(fun({App,StartType}) -> - {_,_,Ver} = lists:keyfind(App,1,Loaded), - {App,Ver,StartType} - end, - OtherApps), - ?line {ok,Fd} = file:open(Name++".rel",write), - ?line RelfileContent = - {release,{"Test release", "2"}, - {erts,ErtsVer}, - [{kernel,KernelVer}, - {stdlib,StdlibVer} | OtherAppsRel]}, - ?line io:format(Fd,"~p.~n",[RelfileContent]), - ?line ok = file:close(Fd), - {filename:dirname(Name), filename:basename(Name)}; + OtherApps = [{mnesia,current,permanent}, + {runtime_tools,current,transient}, + {webtool,current,temporary}, + {snmp,current,load}, + {xmerl,current,none}], + Apps = core_apps(current) ++ OtherApps, + do_create_script(latest_app_start_type2,Config,current,Apps); create_script(current_all_no_sasl,Config) -> - ?line PrivDir = ?privdir, - ?line Name = fname(PrivDir, 'current_all_no_sasl'), - ?line ErtsVer = erlang:system_info(version), - ?line Apps = application_controller:which_applications(), - ?line {value,{_,_,KernelVer}} = lists:keysearch(kernel,1,Apps), - ?line {value,{_,_,StdlibVer}} = lists:keysearch(stdlib,1,Apps), - ?line {ok,Fd} = file:open(Name++".rel",write), - ?line RelfileContent = - {release,{"Test release 4", "CURRENT_ALL_NO_SASL"}, - {erts,ErtsVer}, - [{kernel,KernelVer}, - {stdlib,StdlibVer}, - {db,"2.1"}, - {fe,"3.1"}]}, - ?line io:format(Fd,"~p.~n",[RelfileContent]), - ?line ok = file:close(Fd), - {filename:dirname(Name), filename:basename(Name)}; + Apps = [{kernel,current},{stdlib,current},{db,"2.1"},{fe,"3.1"}], + do_create_script(current_all_no_sasl,Config,current,Apps); create_script(current_all,Config) -> - ?line PrivDir = ?privdir, - ?line Name = fname(PrivDir, current_all), - ?line ErtsVer = erlang:system_info(version), - ?line application:load(sasl), - ?line Apps = application_controller:loaded_applications(), - ?line {value,{_,_,KernelVer}} = lists:keysearch(kernel,1,Apps), - ?line {value,{_,_,StdlibVer}} = lists:keysearch(stdlib,1,Apps), - ?line {value,{_,_,SaslVer}} = lists:keysearch(sasl,1,Apps), - ?line {ok,Fd} = file:open(Name++".rel",write), - ?line RelfileContent = - {release,{"Test release 4", "CURRENT_ALL"}, - {erts,ErtsVer}, - [{kernel,KernelVer}, - {stdlib,StdlibVer}, - {sasl,SaslVer}, - {db,"2.1"}]},% fe left out here on purpose - for normal_hybrid test - ?line io:format(Fd,"~p.~n",[RelfileContent]), - ?line ok = file:close(Fd), - {filename:dirname(Name), filename:basename(Name)}; + Apps = core_apps(current) ++ [{db,"2.1"}], + do_create_script(current_all,Config,current,Apps); create_script(current_all_future_erts,Config) -> - ?line PrivDir = ?privdir, - ?line Name = fname(PrivDir, current_all_future_erts), - ?line application:load(sasl), - ?line Apps = application_controller:loaded_applications(), - ?line {value,{_,_,KernelVer}} = lists:keysearch(kernel,1,Apps), - ?line {value,{_,_,StdlibVer}} = lists:keysearch(stdlib,1,Apps), - ?line {value,{_,_,SaslVer}} = lists:keysearch(sasl,1,Apps), - ?line {ok,Fd} = file:open(Name++".rel",write), - ?line RelfileContent = - {release,{"Test release 4", "CURRENT_ALL_FUTURE_ERTS"}, - {erts,"99.99"}, - [{kernel,KernelVer}, - {stdlib,StdlibVer}, - {sasl,SaslVer}, - {db,"2.1"}, - {fe,"3.1"}]}, - ?line io:format(Fd,"~p.~n",[RelfileContent]), - ?line ok = file:close(Fd), - {filename:dirname(Name), filename:basename(Name)}; + Apps = core_apps(current) ++ [{db,"2.1"},{fe,"3.1"}], + do_create_script(current_all_future_erts,Config,"99.99",Apps); create_script(current_all_future_sasl,Config) -> + Apps = [{kernel,current},{stdlib,current},{sasl,"9.9"},{db,"2.1"},{fe,"3.1"}], + do_create_script(current_all_future_sasl,Config,current,Apps). + + +do_create_script(Id,Config,ErtsVsn,AppVsns) -> ?line PrivDir = ?privdir, - ?line Name = fname(PrivDir, current_all_future_sasl), - ?line ErtsVer = erlang:system_info(version), - ?line application:load(sasl), - ?line Apps = application_controller:loaded_applications(), - ?line {value,{_,_,KernelVer}} = lists:keysearch(kernel,1,Apps), - ?line {value,{_,_,StdlibVer}} = lists:keysearch(stdlib,1,Apps), + ?line Name = fname(PrivDir, Id), ?line {ok,Fd} = file:open(Name++".rel",write), ?line RelfileContent = - {release,{"Test release 4", "CURRENT_ALL_FUTURE_SASL"}, - {erts,ErtsVer}, - [{kernel,KernelVer}, - {stdlib,StdlibVer}, - {sasl,"9.9"}, - {db,"2.1"}, - {fe,"3.1"}]}, + {release,{"Test release", string:to_upper(atom_to_list(Id))}, + {erts,erts_vsn(ErtsVsn)}, + app_vsns(AppVsns)}, ?line io:format(Fd,"~p.~n",[RelfileContent]), ?line ok = file:close(Fd), {filename:dirname(Name), filename:basename(Name)}. +core_apps(Vsn) -> + [{App,Vsn} || App <- [kernel,stdlib,sasl]]. + +app_vsns(AppVsns) -> + [{App,app_vsn(App,Vsn)} || {App,Vsn} <- AppVsns] ++ + [{App,app_vsn(App,Vsn),Type} || {App,Vsn,Type} <- AppVsns]. +app_vsn(App,current) -> + application:load(App), + {ok,Vsn} = application:get_key(App,vsn), + Vsn; +app_vsn(_App,Vsn) -> + Vsn. + +erts_vsn(current) -> erlang:system_info(version); +erts_vsn(Vsn) -> Vsn. + create_include_files(inc1, Config) -> ?line PrivDir = ?privdir, diff --git a/lib/sasl/test/systools_SUITE_data/d_bad_appup/lib/fe-2.1/ebin/fe.app b/lib/sasl/test/systools_SUITE_data/d_bad_appup/lib/fe-2.1/ebin/fe.app new file mode 100644 index 0000000000..3cb0b0c2cf --- /dev/null +++ b/lib/sasl/test/systools_SUITE_data/d_bad_appup/lib/fe-2.1/ebin/fe.app @@ -0,0 +1,7 @@ +{application, fe, + [{description, "ERICSSON NR FOR FE"}, + {vsn, "2.1"}, + {modules, [{fe1, "1.0"}, {fe2, "1.0"}, {fe3, "2.0"}]}, + {registered, []}, + {applications, []}, + {mod, {fe1, []}}]}. diff --git a/lib/sasl/test/systools_SUITE_data/d_no_appup/lib/fe-500.18.7/ebin/fe.app b/lib/sasl/test/systools_SUITE_data/d_no_appup/lib/fe-500.18.7/ebin/fe.app new file mode 100644 index 0000000000..3a5c0ddd9b --- /dev/null +++ b/lib/sasl/test/systools_SUITE_data/d_no_appup/lib/fe-500.18.7/ebin/fe.app @@ -0,0 +1,7 @@ +{application, fe, + [{description, "ERICSSON NR FOR FE"}, + {vsn, "500.18.7"}, + {modules, [{fe1, "1.0"}, {fe2, "1.0"}, {fe3, "2.0"}]}, + {registered, []}, + {applications, []}, + {mod, {fe1, []}}]}. -- cgit v1.2.3 From 19fc8435cbc938f102ffcd0bcbabfc0371dcccb9 Mon Sep 17 00:00:00 2001 From: Siri Hansen Date: Thu, 10 Nov 2011 11:43:37 +0100 Subject: Add release vsn info to erts_vsn_changed warning --- lib/sasl/src/systools_relup.erl | 2 +- lib/sasl/test/release_handler_SUITE.erl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'lib/sasl') diff --git a/lib/sasl/src/systools_relup.erl b/lib/sasl/src/systools_relup.erl index 57e375b03e..8376e278af 100644 --- a/lib/sasl/src/systools_relup.erl +++ b/lib/sasl/src/systools_relup.erl @@ -366,7 +366,7 @@ check_for_emulator_restart(#release{erts_vsn = Vsn1, name = N1}, %% erts version is changed. Also allow extra restart at the end of %% the upgrade if restart_emulator option is given. NewRUs = [[restart_new_emulator]|RUs], - NewWs = [{erts_vsn_changed, {N1, N2}} | Ws], + NewWs = [{erts_vsn_changed, {{N1,Vsn1}, {N2,Vsn2}}} | Ws], check_for_restart_emulator_opt(NewRUs, NewWs, Opts); check_for_emulator_restart(_, _, RUs, Ws, Opts) -> check_for_restart_emulator_opt(RUs, Ws, Opts). diff --git a/lib/sasl/test/release_handler_SUITE.erl b/lib/sasl/test/release_handler_SUITE.erl index 12f86365a3..620d5b2761 100644 --- a/lib/sasl/test/release_handler_SUITE.erl +++ b/lib/sasl/test/release_handler_SUITE.erl @@ -618,7 +618,7 @@ supervisor_which_children_timeout(Conf) -> ok. -supervisor_which_children_timeout(cleanup, Conf) -> +supervisor_which_children_timeout(cleanup, _Conf) -> stop_node(node_name(supervisor_which_children_timeout)). -- cgit v1.2.3 From cc7c2a74ee9074357f6ab0701be61e7bb57004ef Mon Sep 17 00:00:00 2001 From: Siri Hansen Date: Mon, 14 Nov 2011 12:06:06 +0100 Subject: Fix bug in erts upgrade on windows The service which represents the temporary release during erts upgrade on windows was never deleted. This has been corrected. The service is now renamed just after the emulator restart. --- lib/sasl/src/release_handler.erl | 74 ++++++++++++++++++++++----------- lib/sasl/test/release_handler_SUITE.erl | 3 +- 2 files changed, 52 insertions(+), 25 deletions(-) (limited to 'lib/sasl') diff --git a/lib/sasl/src/release_handler.erl b/lib/sasl/src/release_handler.erl index 87660db3e3..94a704e61f 100644 --- a/lib/sasl/src/release_handler.erl +++ b/lib/sasl/src/release_handler.erl @@ -1000,8 +1000,10 @@ do_install_release(#state{start_prg = StartPrg, %% In case there has been an emulator upgrade, %% remove the temporary release NReleases = - new_emulator_rm_tmp_release(LatestRelease#release.vsn, - RelDir,Releases,Masters), + new_emulator_rm_tmp_release( + LatestRelease#release.vsn, + LatestRelease#release.erts_vsn, + Vsn,RelDir,Releases,Masters), %% Then execute the relup script mon_nodes(true), @@ -1134,12 +1136,46 @@ replace_config(App,Config,AppConfig) -> lists:keystore(App,1,Config,AppConfig). %% Remove all files related to the temporary release -new_emulator_rm_tmp_release(?tmp_vsn(_)=TmpVsn,RelDir,Releases,Masters) -> +new_emulator_rm_tmp_release(?tmp_vsn(_)=TmpVsn,EVsn,NewVsn, + RelDir,Releases,Masters) -> + case os:type() of + {win32, nt} -> + rename_tmp_service(EVsn,TmpVsn,NewVsn); + _ -> + ok + end, remove_dir(filename:join(RelDir,TmpVsn),Masters), lists:keydelete(TmpVsn,#release.vsn,Releases); -new_emulator_rm_tmp_release(_,_,Releases,_) -> +new_emulator_rm_tmp_release(_,_,_,_,Releases,_) -> Releases. +%% Rename the tempoarary service (for erts ugprade) to the real ToVsn +rename_tmp_service(EVsn,TmpVsn,NewVsn) -> + FromName = hd(string:tokens(atom_to_list(node()),"@")) ++ "_" ++ TmpVsn, + ToName = hd(string:tokens(atom_to_list(node()),"@")) ++ "_" ++ NewVsn, + case erlsrv:get_service(EVsn,ToName) of + {error, _Error} -> + ok; + _Data -> + erlsrv:remove_service(ToName) + end, + rename_service(EVsn,FromName,ToName). + + +%% Rename a service and check that it succeeded +rename_service(EVsn,FromName,ToName) -> + case erlsrv:rename_service(EVsn,FromName,ToName) of + {ok,_} -> + case erlsrv:get_service(EVsn,ToName) of + {error,Error1} -> + throw({error,Error1}); + _Data2 -> + ok + end; + Error2 -> + throw({error,{service_rename_failed, Error2}}) + end. + %%% This code chunk updates the services in one of two ways, %%% Either the emulator is restarted, in which case the old service @@ -1157,26 +1193,16 @@ do_make_services_permanent(PermanentVsn,Vsn, PermanentEVsn, EVsn) -> %% rename. case os:getenv("ERLSRV_SERVICE_NAME") == PermName of true -> - case erlsrv:rename_service(EVsn,PermName,Name) of - {ok,_} -> - case erlsrv:get_service(EVsn,Name) of - {error,Error2} -> - throw({error,Error2}); - _Data2 -> - %% The interfaces for doing this are - %% NOT published and may be subject to - %% change. Do NOT do this anywhere else! - - os:putenv("ERLSRV_SERVICE_NAME", Name), - - %% Restart heart port program, this - %% function is only to be used here. - heart:cycle(), - ok - end; - Error3 -> - throw({error,{service_rename_failed, Error3}}) - end; + rename_service(EVsn,PermName,Name), + %% The interfaces for doing this are + %% NOT published and may be subject to + %% change. Do NOT do this anywhere else! + + os:putenv("ERLSRV_SERVICE_NAME", Name), + + %% Restart heart port program, this + %% function is only to be used here. + heart:cycle(); false -> throw({error,service_name_missmatch}) end; diff --git a/lib/sasl/test/release_handler_SUITE.erl b/lib/sasl/test/release_handler_SUITE.erl index 620d5b2761..180592894e 100644 --- a/lib/sasl/test/release_handler_SUITE.erl +++ b/lib/sasl/test/release_handler_SUITE.erl @@ -382,7 +382,8 @@ upgrade_restart(Conf) when is_list(Conf) -> {wait,TestNodeInit2a} -> %% We catched the node too early - it was supposed to %% restart twice, so let's wait for one more restart. - wait_nodes_up([{TestNode,TestNodeInit2a}],"upgrade_restart_2a",[]) + wait_nodes_up([{TestNode,TestNodeInit2a}],"upgrade_restart_2a",[]), + ok = rpc_inst(TestNode, upgrade_restart_2a, []) end, TestNodeInit2 = rpc:call(TestNode,erlang,whereis,[init]), stop_cover(TestNode), -- cgit v1.2.3