diff options
Diffstat (limited to 'lib/sasl')
27 files changed, 952 insertions, 287 deletions
diff --git a/lib/sasl/src/erlsrv.erl b/lib/sasl/src/erlsrv.erl index f9804c41dc..086dc7c651 100644 --- a/lib/sasl/src/erlsrv.erl +++ b/lib/sasl/src/erlsrv.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1998-2009. All Rights Reserved. +%% Copyright Ericsson AB 1998-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 @@ -75,14 +75,21 @@ write_all_data(Port,[H|T]) -> write_all_data(Port,T). read_all_data(Port) -> + lists:reverse(read_all_data(Port,[],[])). +read_all_data(Port,Line,Lines) -> receive + {Port, {data, {noeol,Data}}} -> + read_all_data(Port,Line++Data,Lines); {Port, {data, {eol,Data}}} -> - [ Data | read_all_data(Port)]; - _ -> + read_all_data(Port,[],[Line++Data|Lines]); + {Port,_Other} -> Port ! {self(), close}, receive {Port, closed} -> - [] + case Line of + [] -> Lines; + _ -> [Line|Lines] + end end end. @@ -208,7 +215,7 @@ store_service(EmulatorVersion,Service) -> false -> {error, no_servicename}; {value, {_,Name}} -> - {Action,Service1} = case get_service(Name) of + {Action,Service1} = case get_service(EmulatorVersion,Name) of {error, no_such_service} -> {"add",Service}; _ -> @@ -377,8 +384,14 @@ pick_argument(_,[],Acc) -> {Acc, ""}; pick_argument(normal,[$ |T],Acc) -> {Acc,T}; +pick_argument(normal,[$\\|T],Acc) -> + pick_argument(normal_escaped,T,[$\\|Acc]); pick_argument(normal,[$"|T],Acc) -> pick_argument(quoted,T,[$"|Acc]); +pick_argument(normal_escaped,[$"|T],Acc) -> + pick_argument(bquoted,T,[$"|Acc]); +pick_argument(normal_escaped,[A|T],Acc) -> + pick_argument(normal,T,[A|Acc]); pick_argument(quoted_escaped,[H|T],Acc) -> pick_argument(quoted,T,[H|Acc]); pick_argument(quoted,[$"|T],Acc) -> @@ -387,6 +400,14 @@ pick_argument(quoted,[$\\|T],Acc) -> pick_argument(quoted_escaped,T,[$\\|Acc]); pick_argument(quoted,[H|T],Acc) -> pick_argument(quoted,T,[H|Acc]); +pick_argument(bquoted_escaped,[$"|T],Acc) -> + pick_argument(normal,T,[$"|Acc]); +pick_argument(bquoted_escaped,[H|T],Acc) -> + pick_argument(bquoted,T,[H|Acc]); +pick_argument(bquoted,[$\\|T],Acc) -> + pick_argument(bquoted_escaped,T,[$\\|Acc]); +pick_argument(bquoted,[H|T],Acc) -> + pick_argument(bquoted,T,[H|Acc]); pick_argument(normal,[H|T],Acc) -> pick_argument(normal,T,[H|Acc]). diff --git a/lib/sasl/src/release_handler.erl b/lib/sasl/src/release_handler.erl index b60aa847df..ab54b1d00b 100644 --- a/lib/sasl/src/release_handler.erl +++ b/lib/sasl/src/release_handler.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2010. All Rights Reserved. +%% Copyright Ericsson AB 1996-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 @@ -291,7 +291,8 @@ check_script(Script, LibDirs) -> release_handler_1:check_script(Script, LibDirs). %%----------------------------------------------------------------- -%% eval_script(Script, Apps, LibDirs, Opts) -> {ok, UnPurged} | +%% eval_script(Script, Apps, LibDirs, NewLibs, Opts) -> +%% {ok, UnPurged} | %% restart_new_emulator | %% {error, Error} %% {'EXIT', Reason} @@ -299,9 +300,13 @@ check_script(Script, LibDirs) -> %% net_kernel:monitor_nodes(true) before calling this function. %% No! No other process than the release_handler can ever call this %% function, if sync_nodes is used. -%%----------------------------------------------------------------- -eval_script(Script, Apps, LibDirs, Opts) -> - catch release_handler_1:eval_script(Script, Apps, LibDirs, Opts). +%% +%% LibDirs is a list of all applications, while NewLibs is a list of +%% applications that have changed version between the current and the +%% new release. +%% ----------------------------------------------------------------- +eval_script(Script, Apps, LibDirs, NewLibs, Opts) -> + catch release_handler_1:eval_script(Script, Apps, LibDirs, NewLibs, Opts). %%----------------------------------------------------------------- %% Func: create_RELEASES(Root, RelFile, LibDirs) -> ok | {error, Reason} @@ -405,6 +410,7 @@ eval_appup_script(App, ToVsn, ToDir, Script) -> Res = release_handler_1:eval_script(Script, [], % [AppSpec] [{App, ToVsn, ToDir}], + [{App, ToVsn, ToDir}], []), % [Opt] case Res of {ok, _Unpurged} -> @@ -890,6 +896,7 @@ do_check_install_release(RelDir, Vsn, Releases, Masters) -> end. do_install_release(#state{start_prg = StartPrg, + root = RootDir, rel_dir = RelDir, releases = Releases, masters = Masters, static_emulator = Static}, @@ -905,7 +912,9 @@ do_install_release(#state{start_prg = StartPrg, EnvBefore = application_controller:prep_config_change(), Apps = change_appl_data(RelDir, Release, Masters), LibDirs = Release#release.libs, - case eval_script(Script, Apps, LibDirs, Opts) of + 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), @@ -926,8 +935,8 @@ do_install_release(#state{start_prg = StartPrg, NReleases = set_status(Vsn, current, Releases), NReleases2 = set_status(Vsn,tmp_current,NReleases), write_releases(RelDir, NReleases2, Masters), - prepare_restart_new_emulator(StartPrg, RelDir, - Release, + prepare_restart_new_emulator(StartPrg, RootDir, + RelDir, Release, PermanentRelease, Masters), {restart_new_emulator, CurrentVsn, Descr}; @@ -997,7 +1006,7 @@ do_make_services_permanent(PermanentVsn,Vsn, PermanentEVsn, EVsn) -> throw(Error4) end end. - + do_make_permanent(#state{releases = Releases, rel_dir = RelDir, unpurged = Unpurged, masters = Masters, @@ -1409,8 +1418,8 @@ prepare_restart_nt(#release{erts_vsn = EVsn, vsn = Vsn}, FutureServiceName = hd(string:tokens(atom_to_list(node()),"@")) ++ "_" ++ Vsn, CurrentService = case erlsrv:get_service(PermEVsn,CurrentServiceName) of - {error, Reason} -> - throw({error, Reason}); + {error, _} = Error1 -> + throw(Error1); CS -> CS end, @@ -1425,37 +1434,33 @@ prepare_restart_nt(#release{erts_vsn = EVsn, vsn = Vsn}, CurrentServiceName), case erlsrv:store_service(EVsn, FutureService) of - {error, Rison} -> - throw({error,Rison}); - _ -> + {error, _} = Error2 -> + throw(Error2); + _X -> erlsrv:disable_service(EVsn, FutureServiceName), ErlSrv = filename:nativename(erlsrv:erlsrv(EVsn)), - case heart:set_cmd(ErlSrv ++ " enable " ++ FutureServiceName ++ - " & " ++ ErlSrv ++ " start " ++ - FutureServiceName ++ - " & " ++ ErlSrv ++ " disable " ++ - FutureServiceName) of + StartDisabled = ErlSrv ++ " start_disabled " ++ FutureServiceName, + case heart:set_cmd(StartDisabled) of ok -> ok; - Error -> - throw({error, {'heart:set_cmd() error', Error}}) + Error3 -> + throw({error, {'heart:set_cmd() error', Error3}}) end end. - %%----------------------------------------------------------------- %% Set things up for restarting the new emulator. The actual %% restart is performed by calling init:reboot() higher up. %%----------------------------------------------------------------- -prepare_restart_new_emulator(StartPrg, RelDir, - Release, PRelease, - Masters) -> +prepare_restart_new_emulator(StartPrg, RootDir, RelDir, + Release, PRelease, Masters) -> #release{erts_vsn = EVsn, vsn = Vsn} = Release, Data = EVsn ++ " " ++ Vsn, DataFile = write_new_start_erl(Data, RelDir, Masters), %% Tell heart to use DataFile instead of start_erl.data case os:type() of {win32,nt} -> + write_ini_file(RootDir,EVsn,Masters), prepare_restart_nt(Release,PRelease,DataFile); {unix,_} -> StartP = check_start_prg(StartPrg, Masters), @@ -1832,50 +1837,10 @@ write_start(File, Data, false) -> end; write_start(File, Data, Masters) -> all_masters(Masters), - write_start_m(File, Data, Masters). + safe_write_file_m(File, Data, Masters). %%----------------------------------------------------------------- -%% Write the "start_erl.data" file at all master nodes. -%% 1. Save "start_erl.backup" at all nodes. -%% 2. Write the "start_erl.change" file at all nodes. -%% 3. Move "start_erl.change" to "start_erl.data". -%% 4. Remove "start_erl.backup" at all nodes. -%% -%% If one of the steps above fails, all steps is recovered from -%% (as long as possible), except for 4 which is allowed to fail. -%%----------------------------------------------------------------- -write_start_m(File, Data, Masters) -> - Dir = filename:dirname(File), - Backup = filename:join(Dir, "start_erl.backup"), - Change = filename:join(Dir, "start_erl.change"), - case at_all_masters(Masters, ?MODULE, do_copy_files, - [File, [Backup]]) of - ok -> - case at_all_masters(Masters, ?MODULE, do_write_file, - [Change, Data]) of - ok -> - case at_all_masters(Masters, file, rename, - [Change, File]) of - ok -> - remove_files(all, [Backup, Change], Masters), - ok; - {error, {Master, R}} -> - takewhile(Master, Masters, file, rename, - [Backup, File]), - remove_files(all, [Backup, Change], Masters), - throw({error, {Master, R, move_start_erl}}) - end; - {error, {Master, R}} -> - remove_files(all, [Backup, Change], Masters), - throw({error, {Master, R, write_start_erl}}) - end; - {error, {Master, R}} -> - remove_files(Master, [Backup], Masters), - throw({error, {Master, R, backup_start_erl}}) - end. - -%%----------------------------------------------------------------- %% Copy the "start.boot" and "sys.config" from SrcDir to DestDir at all %% master nodes. %% 1. Save DestDir/"start.backup" and DestDir/"sys.backup" at all nodes. @@ -1917,3 +1882,97 @@ set_static_files(SrcDir, DestDir, Masters) -> remove_files(Master, [BackupBoot, BackupConf], Masters), throw({error, {Master, R, backup_start_config}}) end. + +%%----------------------------------------------------------------- +%% Write erl.ini +%% Writes the erl.ini file used by erl.exe when (re)starting the erlang node. +%% At first installation, this is done by Install.exe, which means that if +%% the format of this file for some reason is changed, then Install.c must +%% also be updated (and probably some other c-files which read erl.ini) +%%----------------------------------------------------------------- +write_ini_file(RootDir,EVsn,Masters) -> + BinDir = filename:join([RootDir,"erts-"++EVsn,"bin"]), + Str0 = io_lib:format("[erlang]~n" + "Bindir=~s~n" + "Progname=erl~n" + "Rootdir=~s~n", + [filename:nativename(BinDir), + filename:nativename(RootDir)]), + Str = re:replace(Str0,"\\\\","\\\\\\\\",[{return,list},global]), + IniFile = filename:join(BinDir,"erl.ini"), + do_write_ini_file(IniFile,Str,Masters). + +do_write_ini_file(File,Data,false) -> + case do_write_file(File, Data) of + ok -> ok; + Error -> throw(Error) + end; +do_write_ini_file(File,Data,Masters) -> + all_masters(Masters), + safe_write_file_m(File, Data, Masters). + + +%%----------------------------------------------------------------- +%% Write the given file at all master nodes. +%% 1. Save <File>.backup at all nodes. +%% 2. Write <File>.change at all nodes. +%% 3. Move <File>.change to <File> +%% 4. Remove <File>.backup at all nodes. +%% +%% If one of the steps above fails, all steps are recovered from +%% (as long as possible), except for 4 which is allowed to fail. +%%----------------------------------------------------------------- +safe_write_file_m(File, Data, Masters) -> + Backup = File ++ ".backup", + Change = File ++ ".change", + case at_all_masters(Masters, ?MODULE, do_copy_files, + [File, [Backup]]) of + ok -> + case at_all_masters(Masters, ?MODULE, do_write_file, + [Change, Data]) of + ok -> + case at_all_masters(Masters, file, rename, + [Change, File]) of + ok -> + remove_files(all, [Backup, Change], Masters), + ok; + {error, {Master, R}} -> + takewhile(Master, Masters, file, rename, + [Backup, File]), + remove_files(all, [Backup, Change], Masters), + throw({error, {Master, R, rename, + filename:basename(Change), + filename:basename(File)}}) + end; + {error, {Master, R}} -> + remove_files(all, [Backup, Change], Masters), + throw({error, {Master, R, write, filename:basename(Change)}}) + end; + {error, {Master, R}} -> + remove_files(Master, [Backup], Masters), + throw({error, {Master, R, backup, + filename:basename(File), + filename:basename(Backup)}}) + end. + +%%----------------------------------------------------------------- +%% Figure out which applications that have changed version between the +%% two releases. The paths for these applications must always be +%% updated, even if the relup script does not load any modules. See +%% OTP-9402. +%% +%% A different situation is when the same application version is used +%% in old and new release, but the path has changed. This is not +%% handled here - instead it must be explicitely indicated by the +%% 'update_paths' option to release_handler:install_release/2 if the +%% code path shall be updated then. +%% ----------------------------------------------------------------- +get_new_libs([{App,Vsn,LibDir}|CurrentLibs], NewLibs) -> + case lists:keyfind(App,1,NewLibs) of + {App,NewVsn,_} = LibInfo when NewVsn =/= Vsn -> + [LibInfo | get_new_libs(CurrentLibs,NewLibs)]; + _ -> + get_new_libs(CurrentLibs,NewLibs) + end; +get_new_libs([],_) -> + []. diff --git a/lib/sasl/src/release_handler_1.erl b/lib/sasl/src/release_handler_1.erl index 8d050fb7b0..ff62f847ac 100644 --- a/lib/sasl/src/release_handler_1.erl +++ b/lib/sasl/src/release_handler_1.erl @@ -19,7 +19,7 @@ -module(release_handler_1). %% External exports --export([eval_script/3, eval_script/4, check_script/2]). +-export([eval_script/1, eval_script/5, check_script/2]). -export([get_current_vsn/1]). %% exported because used in a test case -record(eval_state, {bins = [], stopped = [], suspended = [], apps = [], @@ -33,11 +33,11 @@ %% libdirs = [{Lib, LibVsn, LibDir}] - Maps Lib to Vsn and Directory %% unpurged = [{Mod, soft_purge | brutal_purge}] %% vsns = [{Mod, OldVsn, NewVsn}] - remember the old vsn of a mod -%% before it is removed/a new vsn is loaded; the new vsn +%% before a new vsn is loaded; the new vsn %% is kept in case of a downgrade, where the code_change %% function receives the vsn of the module to downgrade %% *to*. -%% newlibs = [{Lib, Dir}] - list of all new libs; used to change +%% newlibs = [{Lib, LibVsn, LibDir}] - list of all new libs; used to change %% the code path %% opts = [{Tag, Value}] - list of options %%----------------------------------------------------------------- @@ -63,10 +63,11 @@ check_script(Script, LibDirs) -> {error, {old_processes, Mod}} end. -eval_script(Script, Apps, LibDirs) -> - eval_script(Script, Apps, LibDirs, []). +%% eval_script/1 - For testing only - no apps added, just testing instructions +eval_script(Script) -> + eval_script(Script, [], [], [], []). -eval_script(Script, Apps, LibDirs, Opts) -> +eval_script(Script, Apps, LibDirs, NewLibs, Opts) -> case catch check_old_processes(Script) of ok -> {Before, After} = split_instructions(Script), @@ -75,6 +76,7 @@ eval_script(Script, Apps, LibDirs, Opts) -> end, #eval_state{apps = Apps, libdirs = LibDirs, + newlibs = NewLibs, opts = Opts}, Before) of EvalState2 when is_record(EvalState2, eval_state) -> @@ -214,16 +216,15 @@ check_old_code(Mod) -> %%----------------------------------------------------------------- eval({load_object_code, {Lib, LibVsn, Modules}}, EvalState) -> case lists:keysearch(Lib, 1, EvalState#eval_state.libdirs) of - {value, {Lib, LibVsn, LibDir}} -> - Ebin = filename:join(LibDir, "ebin"), + {value, {Lib, LibVsn, LibDir} = LibInfo} -> Ext = code:objfile_extension(), {NewBins, NewVsns} = lists:foldl(fun(Mod, {Bins, Vsns}) -> File = lists:concat([Mod, Ext]), - FName = filename:join(Ebin, File), + FName = filename:join([LibDir, "ebin", File]), case erl_prim_loader:get_file(FName) of {ok, Bin, FName2} -> - NVsns = add_new_vsn(Mod, Bin, Vsns), + NVsns = add_vsns(Mod, Bin, Vsns), {[{Mod, Bin, FName2} | Bins],NVsns}; error -> throw({error, {no_such_file,FName}}) @@ -232,7 +233,7 @@ eval({load_object_code, {Lib, LibVsn, Modules}}, EvalState) -> {EvalState#eval_state.bins, EvalState#eval_state.vsns}, Modules), - NewLibs = [{Lib, Ebin} | EvalState#eval_state.newlibs], + NewLibs = lists:keystore(Lib,1,EvalState#eval_state.newlibs,LibInfo), EvalState#eval_state{bins = NewBins, newlibs = NewLibs, vsns = NewVsns}; @@ -242,15 +243,14 @@ eval({load_object_code, {Lib, LibVsn, Modules}}, EvalState) -> eval(point_of_no_return, EvalState) -> Libs = case get_opt(update_paths, EvalState, false) of false -> - EvalState#eval_state.newlibs; % [{Lib, Path}] + EvalState#eval_state.newlibs; true -> - lists:map(fun({Lib, _LibVsn, LibDir}) -> - Ebin= filename:join(LibDir,"ebin"), - {Lib, Ebin} - end, - EvalState#eval_state.libdirs) + EvalState#eval_state.libdirs end, - lists:foreach(fun({Lib, Path}) -> code:replace_path(Lib, Path) end, + lists:foreach(fun({Lib, _LibVsn, LibDir}) -> + Ebin = filename:join(LibDir,"ebin"), + code:replace_path(Lib, Ebin) + end, Libs), EvalState; eval({load, {Mod, _PrePurgeMethod, PostPurgeMethod}}, EvalState) -> @@ -258,32 +258,21 @@ eval({load, {Mod, _PrePurgeMethod, PostPurgeMethod}}, EvalState) -> {value, {_Mod, Bin, File}} = lists:keysearch(Mod, 1, Bins), % load_binary kills all procs running old code % if soft_purge, we know that there are no such procs now - Vsns = EvalState#eval_state.vsns, - NewVsns = add_old_vsn(Mod, Vsns), code:load_binary(Mod, File, Bin), % Now, the prev current is old. There might be procs % running it. Find them. Unpurged = do_soft_purge(Mod,PostPurgeMethod,EvalState#eval_state.unpurged), EvalState#eval_state{bins = lists:keydelete(Mod, 1, Bins), - unpurged = Unpurged, - vsns = NewVsns}; + unpurged = Unpurged}; eval({remove, {Mod, _PrePurgeMethod, PostPurgeMethod}}, EvalState) -> - % purge kills all procs running old code - % if soft_purge, we know that there are no such procs now - Vsns = EvalState#eval_state.vsns, - NewVsns = add_old_vsn(Mod, Vsns), + %% purge kills all procs running old code + %% if soft_purge, we know that there are no such procs now code:purge(Mod), code:delete(Mod), - % Now, the prev current is old. There might be procs - % running it. Find them. - Unpurged = - case code:soft_purge(Mod) of - true -> EvalState#eval_state.unpurged; - false -> [{Mod, PostPurgeMethod} | EvalState#eval_state.unpurged] - end, -%% Bins = EvalState#eval_state.bins, -%% EvalState#eval_state{bins = lists:keydelete(Mod, 1, Bins), - EvalState#eval_state{unpurged = Unpurged, vsns = NewVsns}; + %% Now, the prev current is old. There might be procs + %% running it. Find them. + Unpurged = do_soft_purge(Mod,PostPurgeMethod,EvalState#eval_state.unpurged), + EvalState#eval_state{unpurged = Unpurged}; eval({purge, Modules}, EvalState) -> % Now, if there are any processes still executing old code, OR % if some new processes started after suspend but before load, @@ -606,26 +595,20 @@ sync_nodes(Id, Nodes) -> end, NNodes). -add_old_vsn(Mod, Vsns) -> +add_vsns(Mod, NewBin, Vsns) -> + OldVsn = get_current_vsn(Mod), + NewVsn = get_vsn(NewBin), case lists:keysearch(Mod, 1, Vsns) of - {value, {Mod, undefined, NewVsn}} -> - OldVsn = get_current_vsn(Mod), - lists:keyreplace(Mod, 1, Vsns, {Mod, OldVsn, NewVsn}); - {value, {Mod, _OldVsn, _NewVsn}} -> - Vsns; + {value, {Mod, OldVsn0, NewVsn0}} -> + lists:keyreplace(Mod, 1, Vsns, {Mod, + replace_undefined(OldVsn0,OldVsn), + replace_undefined(NewVsn0,NewVsn)}); false -> - OldVsn = get_current_vsn(Mod), - [{Mod, OldVsn, undefined} | Vsns] + [{Mod, OldVsn, NewVsn} | Vsns] end. -add_new_vsn(Mod, Bin, Vsns) -> - NewVsn = get_vsn(Bin), - case lists:keysearch(Mod, 1, Vsns) of - {value, {Mod, OldVsn, undefined}} -> - lists:keyreplace(Mod, 1, Vsns, {Mod, OldVsn, NewVsn}); - false -> - [{Mod, undefined, NewVsn} | Vsns] - end. +replace_undefined(undefined,Vsn) -> Vsn; +replace_undefined(Vsn,_) -> Vsn. %%----------------------------------------------------------------- %% Func: get_current_vsn/1 @@ -645,7 +628,9 @@ get_current_vsn(Mod) -> {ok, Bin, _File2} -> get_vsn(Bin); error -> - throw({error, {no_such_file, File}}) + %% This is the case when a new module is added, there will + %% be no current version of it at the time of this call. + undefined end. %%----------------------------------------------------------------- diff --git a/lib/sasl/src/systools_lib.erl b/lib/sasl/src/systools_lib.erl index b652c109fe..f951647b79 100644 --- a/lib/sasl/src/systools_lib.erl +++ b/lib/sasl/src/systools_lib.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2009. All Rights Reserved. +%% Copyright Ericsson AB 1996-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 @@ -176,21 +176,26 @@ add_dirs(RegName, Dirs, Root) -> regexp_match(RegName, D0, Root) -> case file:list_dir(D0) of {ok, Files} when length(Files) > 0 -> - FR = fun(F) -> - case regexp:match(F, RegName) of - {match,1,N} when N == length(F) -> - DirF = join(D0, F, Root), - case dir_p(DirF) of - true -> - {true, DirF}; + case re:compile(RegName) of + {ok, MP} -> + FR = fun(F) -> + case re:run(F, MP) of + {match,[{0,N}]} when N == length(F) -> + DirF = join(D0, F, Root), + case dir_p(DirF) of + true -> + {true, DirF}; + _ -> + false + end; _ -> false - end; - _ -> - false - end - end, - {true,lists:zf(FR, Files)}; + end + end, + {true,lists:zf(FR, Files)}; + _ -> + false + end; _ -> false end. diff --git a/lib/sasl/test/Makefile b/lib/sasl/test/Makefile index 2d92305fcf..65be134462 100644 --- a/lib/sasl/test/Makefile +++ b/lib/sasl/test/Makefile @@ -31,7 +31,8 @@ MODULES= \ systools_SUITE \ systools_rc_SUITE \ overload_SUITE \ - rb_SUITE + rb_SUITE \ + rh_test_lib ERL_FILES= $(MODULES:%=%.erl) diff --git a/lib/sasl/test/installer.erl b/lib/sasl/test/installer.erl index a114c4b5c9..f5ceab0dc4 100644 --- a/lib/sasl/test/installer.erl +++ b/lib/sasl/test/installer.erl @@ -119,6 +119,7 @@ install_3(TestNode,PrivDir) -> ?print(["install_3 unpack_release P2A ok"]), ?check_release("P2A",unpacked,["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"]), @@ -268,23 +269,30 @@ client1_1(TestNode,PrivDir,MasterDir,ClientSname) -> erl_boot_server:start([IP]), ok = net_kernel:monitor_nodes(true), - Node = start_client(TestNode,ClientSname), + Node = start_client(TestNode,client1,ClientSname), trace_disallowed_calls(Node), %% Check env var for SASL on client node SaslEnv = rpc:call(Node, application, get_all_env, [sasl]), + ?print([{client1_1,sasl_env},SaslEnv]), {_,CliDir} = lists:keyfind(client_directory,1,SaslEnv), {_,[Master]} = lists:keyfind(masters,1,SaslEnv), {_,StartCli} = lists:keyfind(start_prg,1,SaslEnv), - Root = code:root_dir(), - true = (CliDir =:= filename:join([Root,"clients","type1",Node])), - true = (StartCli =:= filename:join([CliDir,"bin","start"])), + NodeStr = atom_to_list(Node), + [NodeStr,"type1","clients"|_] = lists:reverse(filename:split(CliDir)), true = (Master =:= node()), + case os:type() of + {unix,_} -> + true = (StartCli =:= filename:join([CliDir,"bin","start"])); + _ -> + ok + end, %% Unpack P1H on master {ok, "P1H"} = unpack_release(PrivDir,"rel1"), %% Unpack and install P1H on client + Root = code:root_dir(), P1HDir = filename:join([Root, "releases", "P1H"]), %% The AppDirs argument (last arg to set_unpacked) below is really @@ -339,6 +347,7 @@ client1_2(TestNode,PrivDir,Node) -> ?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_disallowed_calls(), reboot(TestNode,Node), @@ -584,7 +593,7 @@ trace_disallowed_calls(Node) -> MasterProc = self(), rpc:call(Node,dbg,tracer,[process,{fun(T,_) -> MasterProc ! T end,[]}]), rpc:call(Node,dbg,p,[all,call]), - rpc:call(Node,dbg,tp,[file,[]]). + rpc:call(Node,dbg,tp,[file,[{'_',[],[{message,{caller}}]}]]). check_disallowed_calls() -> receive @@ -594,13 +603,12 @@ check_disallowed_calls() -> ok end. -start_client(TestNode,Client) -> - {Start, Node} = do_start_client(Client,test_host()), - Cmd = lists:concat(["env NODENAME=",Client," ", - filename:join(code:root_dir(), Start)]), - ?print([{start_client,Client},Cmd]), - Res = os:cmd(Cmd), - ?print([{start_client,result},Res]), +start_client(TestNode,Client,Sname) -> + Node = list_to_atom(lists:concat([Sname,"@",test_host()])), + case os:type() of + {unix,_} -> start_client_unix(TestNode,Sname,Node); + {win32,_} -> start_client_win32(TestNode,Client,Sname) + end, receive {nodeup, Node} -> wait_started(TestNode,Node) @@ -609,10 +617,34 @@ start_client(TestNode,Client) -> ?fail({"can not start", Node}) end. -do_start_client(Client, Host) -> - Node = list_to_atom(lists:concat([Client,"@",Host])), +start_client_unix(TestNode,Sname,Node) -> Start = filename:join(["clients", "type1", Node, "bin", "start"]), - {Start, Node}. + Cmd = lists:concat(["env NODENAME=",Sname," ", + filename:join(code:root_dir(), Start)]), + ?print([{start_client,Sname},Cmd]), + Res = os:cmd(Cmd), + ?print([{start_client,result},Res]). + +start_client_win32(TestNode,Client,ClientSname) -> + Name = atom_to_list(ClientSname) ++ "_P1G", + RootDir = code:root_dir(), + ErtsBinDir = filename:join(RootDir,"erts-4.4/bin"), + + {ClientArgs,RelClientDir} = rh_test_lib:get_client_args(Client,ClientSname, + RootDir), + StartErlArgs = rh_test_lib:get_start_erl_args(RootDir,RelClientDir, + ClientArgs), + ServiceArgs = rh_test_lib:get_service_args(RootDir, RelClientDir, + ClientSname, StartErlArgs), + + ?print([{start_client,ClientSname},ServiceArgs]), + Erlsrv = filename:nativename(filename:join(ErtsBinDir,"erlsrv")), + rh_test_lib:erlsrv(Erlsrv,stop,Name), + rh_test_lib:erlsrv(Erlsrv,remove,Name), + ok = rh_test_lib:erlsrv(Erlsrv,add,Name,ServiceArgs), + ok = rh_test_lib:erlsrv(Erlsrv,start,Name), + ?print([{start_client,result},ok]), + ok. reboot(TestNode,Node) -> cover_client(TestNode,Node,stop_cover), @@ -628,7 +660,7 @@ check_reboot(TestNode,Node) -> receive {nodeup, Node} -> wait_started(TestNode,Node) after 30000 -> - ?fail({Node, "not rebooted",net_adm:ping(Node)}) + ?fail({Node, "not rebooted",net_adm:ping(Node)}) end after 30000 -> ?fail({Node, "not closing down",net_adm:ping(Node)}) @@ -678,22 +710,28 @@ client2(TestNode,PrivDir,ClientSname) -> release_handler:remove_release("P1H"), ok = net_kernel:monitor_nodes(true), - Node = start_client(TestNode,ClientSname), + Node = start_client(TestNode,client2,ClientSname), %% Check env var for SASL on client node - ?print([{sasl_env, Node}, rpc:call(Node, application, get_all_env, [sasl])]), SaslEnv = rpc:call(Node, application, get_all_env, [sasl]), + ?print([{client1_1,sasl_env},SaslEnv]), {_,CliDir} = lists:keyfind(client_directory,1,SaslEnv), {_,[Master,Master2]} = lists:keyfind(masters,1,SaslEnv), {_,StartCli} = lists:keyfind(start_prg,1,SaslEnv), - Root = code:root_dir(), - true = (CliDir =:= filename:join([Root,"clients","type1",Node])), - true = (StartCli =:= filename:join([CliDir,"bin","start"])), + NodeStr = atom_to_list(Node), + [NodeStr,"type1","clients"|_] = lists:reverse(filename:split(CliDir)), true = (Master =:= node()), true = (Master2 =:= list_to_atom("master2@"++TestHost)), + case os:type() of + {unix,_} -> + true = (StartCli =:= filename:join([CliDir,"bin","start"])); + _ -> + ok + end, {ok, "P1H"} = unpack_release(PrivDir,"rel1"), + Root = code:root_dir(), {error,{bad_masters,[Master2]}} = rpc:call(Node, release_handler, set_unpacked, [filename:join([Root, "releases", "P1H", "rel1.rel"]),[]]), diff --git a/lib/sasl/test/release_handler_SUITE.erl b/lib/sasl/test/release_handler_SUITE.erl index efa775f344..9c7733b7ec 100644 --- a/lib/sasl/test/release_handler_SUITE.erl +++ b/lib/sasl/test/release_handler_SUITE.erl @@ -51,11 +51,11 @@ unix_cases() -> [target_system] ++ RunErlCases ++ cases(). win32_cases() -> - cases(). + [{group,release} | cases()]. %% Cases that can be run on all platforms cases() -> - [otp_2740, otp_2760, otp_5761, instructions, eval_appup]. + [otp_2740, otp_2760, otp_5761, otp_9402, otp_9417, instructions, eval_appup]. groups() -> [{release,[], @@ -148,6 +148,10 @@ init_per_group(release_gg, Config0) -> end_per_group(release, Config) -> Dog = ?t:timetrap(?default_timeout), stop_print_proc(), + case os:type() of + {win32,_} -> delete_all_services(); + _ -> ok + end, delete_release(Config), ?t:timetrap_cancel(Dog), Config; @@ -169,6 +173,10 @@ end_per_testcase(Case, Config) -> Dog=?config(watchdog, Config), test_server:timetrap_cancel(Dog), + try apply(?MODULE,Case,[cleanup,Config]) + catch error:undef -> ok + end, + %% DEBUG case ?config(tc_status,Config) of ok -> @@ -206,10 +214,6 @@ end_per_testcase(Case, Config) -> %% immediately restarted by heart and the test cases wait until %% the node is actually up and running -- see wait_nodes_up/2) file:delete("sasl_erl_crash.dump"), - - try apply(?MODULE,Case,[cleanup,Config]) - catch error:undef -> ok - end, ok. gg_node_snames(Config) -> @@ -224,7 +228,10 @@ gg_node_snames(Config) -> no_run_erl(Config) when is_list(Config) -> {comment, "No run_erl program"}. - +break(Config) -> + erlang:display(test_break), + ?t:break(priv_dir(Config)), + ok. %% Test upgrade and downgrade of erts upgrade(Conf) when is_list(Conf) -> @@ -323,7 +330,7 @@ client1(Conf) when is_list(Conf) -> %% Copy the P1G release to a directory for use in this testcase ok = copy_installed(Conf,p1g_install,[Master]), - ok = copy_client(Conf,Master,Client,"start_cli1"), + ok = copy_client(Conf,Master,Client,client1), %% start the master node [TestNode] = start_nodes(Conf,[Master],"client1"), @@ -348,7 +355,7 @@ client2(Conf) when is_list(Conf) -> %% Copy the P1G release to a directory for use in this testcase ok = copy_installed(Conf,p1g_install,[Master]), - ok = copy_client(Conf,Master,Client,"start_cli2"), + ok = copy_client(Conf,Master,Client,client2), %% start the master node [TestNode] = start_nodes(Conf,[Master],"client2"), @@ -386,7 +393,7 @@ instructions(Conf) when is_list(Conf) -> {stop, [aa]}, {apply, {?MODULE, no_cc, []}}, {start, [aa]}], - {ok, _} = release_handler_1:eval_script(S1, [], []), + {ok, _} = release_handler_1:eval_script(S1), case whereis(cc) of Pid2 when is_pid(Pid2) -> ok; @@ -396,17 +403,17 @@ instructions(Conf) when is_list(Conf) -> %% Make bb run old version of b. S2 = [point_of_no_return, {remove, {b, soft_purge, soft_purge}}], - {ok, [{b, soft_purge}]} = release_handler_1:eval_script(S2, [], []), + {ok, [{b, soft_purge}]} = release_handler_1:eval_script(S2), check_bstate("first", [FirstBB]), false = code:is_loaded(b), - {error,{old_processes,b}} = release_handler_1:eval_script(S2,[],[]), + {error,{old_processes,b}} = release_handler_1:eval_script(S2), check_bstate("first", [FirstBB]), %% Let supervisor restart bb with new code S3 = [point_of_no_return, {purge, [b]}], - {ok, []} = release_handler_1:eval_script(S3, [], []), + {ok, []} = release_handler_1:eval_script(S3), ok = wait_for(bb), check_bstate("second", []), SecondBB = whereis(bb), @@ -439,7 +446,7 @@ instructions(Conf) when is_list(Conf) -> %% Let supervisor restart bb yet another time S4 = [point_of_no_return, {remove, {b, brutal_purge, soft_purge}}], - {ok, HopefullyEmpty} = release_handler_1:eval_script(S4, [], []), + {ok, HopefullyEmpty} = release_handler_1:eval_script(S4), ok = wait_for(bb), FourthBB = whereis(bb), @@ -559,8 +566,7 @@ otp_2760(Conf) -> %% Execute the relup script and check that app1 is unloaded {ok, [{"after", [{_Rel1Vsn, _Descr, Script}], _}]} = file:consult(filename:join(Rel2Dir, "relup")), - {ok, []} = rpc:call(Node, release_handler_1, eval_script, - [Script, [], []]), + {ok, []} = rpc:call(Node, release_handler_1, eval_script, [Script]), false = rpc:call(Node, code, is_loaded, [app1]), true = stop_node(Node), @@ -651,6 +657,126 @@ otp_5761(Conf) when is_list(Conf) -> true = stop_node(Node), ok. + +%% When a new version of an application is added, but no module is +%% changed - the path was not updated - i.e. code:priv_dir would point +%% to the old location. +otp_9402(Conf) when is_list(Conf) -> + %% Set some paths + PrivDir = priv_dir(Conf), + Dir = filename:join(PrivDir,"otp_9402"), + LibDir = filename:join(?config(data_dir, Conf), "lib"), + + %% Create the releases + Rel1 = create_and_install_fake_first_release(Dir, + [{a,"1.1",LibDir}]), + Rel2 = create_fake_upgrade_release(Dir, + "2", + [{a,"1.2",LibDir}], + {Rel1,Rel1,[LibDir]}), + Rel1Dir = filename:dirname(Rel1), + Rel2Dir = filename:dirname(Rel2), + + %% Start a slave node + {ok, Node} = t_start_node(otp_9402, Rel1, filename:join(Rel1Dir,"sys.config")), + + %% Check path + Dir1 = filename:join([LibDir, "a-1.1"]), + Dir1 = rpc:call(Node, code, lib_dir, [a]), + ABeam = rpc:call(Node, code, which, [a]), + + %% Install second release, with no changed modules + {ok, RelVsn2} = + rpc:call(Node, release_handler, set_unpacked, + [Rel2++".rel", [{a,"1.2",LibDir}]]), + ok = rpc:call(Node, release_handler, install_file, + [RelVsn2, filename:join(Rel2Dir, "relup")]), + ok = rpc:call(Node, release_handler, install_file, + [RelVsn2, filename:join(Rel2Dir, "start.boot")]), + ok = rpc:call(Node, release_handler, install_file, + [RelVsn2, filename:join(Rel2Dir, "sys.config")]), + + {ok, RelVsn1, []} = + rpc:call(Node, release_handler, install_release, [RelVsn2]), + + %% Check path + Dir2 = filename:join([LibDir, "a-1.2"]), + Dir2 = rpc:call(Node, code, lib_dir, [a]), + APrivDir2 = rpc:call(Node, code, priv_dir, [a]), + true = filelib:is_regular(filename:join(APrivDir2,"file")), + + %% Just to make sure no modules have been re-loaded + ABeam = rpc:call(Node, code, which, [a]), + + %% Install RelVsn1 again + {ok, _OtherVsn, []} = + rpc:call(Node, release_handler, install_release, [RelVsn1]), + + %% Check path + Dir1 = rpc:call(Node, code, lib_dir, [a]), + APrivDir1 = rpc:call(Node, code, priv_dir, [a]), + false = filelib:is_regular(filename:join(APrivDir1,"file")), + + %% Just to make sure no modules have been re-loaded + ABeam = rpc:call(Node, code, which, [a]), + + ok. + + +%% When a module is deleted in an appup instruction, the upgrade +%% failed if the module was not loaded. +otp_9417(Conf) when is_list(Conf) -> + %% Set some paths + PrivDir = priv_dir(Conf), + Dir = filename:join(PrivDir,"otp_9417"), + LibDir = filename:join(?config(data_dir, Conf), "lib"), + + %% Create the releases + Rel1 = create_and_install_fake_first_release(Dir, + [{b,"1.0",LibDir}]), + Rel2 = create_fake_upgrade_release(Dir, + "2", + [{b,"2.0",LibDir}], + {Rel1,Rel1,[LibDir]}), + Rel1Dir = filename:dirname(Rel1), + Rel2Dir = filename:dirname(Rel2), + + %% Start a slave node + {ok, Node} = t_start_node(otp_9417, Rel1, filename:join(Rel1Dir,"sys.config")), + + %% Check paths + Dir1 = filename:join([LibDir, "b-1.0"]), + Dir1 = rpc:call(Node, code, lib_dir, [b]), + BLibBeam = filename:join([Dir1,"ebin","b_lib.beam"]), + BLibBeam = rpc:call(Node,code,which,[b_lib]), + false = rpc:call(Node,code,is_loaded,[b_lib]), + false = rpc:call(Node,code,is_loaded,[b_server]), + + %% Install second release, which removes b_lib module + {ok, RelVsn2} = + rpc:call(Node, release_handler, set_unpacked, + [Rel2++".rel", [{b,"2.0",LibDir}]]), + ok = rpc:call(Node, release_handler, install_file, + [RelVsn2, filename:join(Rel2Dir, "relup")]), + ok = rpc:call(Node, release_handler, install_file, + [RelVsn2, filename:join(Rel2Dir, "start.boot")]), + ok = rpc:call(Node, release_handler, install_file, + [RelVsn2, filename:join(Rel2Dir, "sys.config")]), + + {ok, _RelVsn1, []} = + rpc:call(Node, release_handler, install_release, [RelVsn2]), + + %% Check that the module does no longer exist + false = rpc:call(Node, code, is_loaded, [b_lib]), + non_existing = rpc:call(Node, code, which, [b_lib]), + + %% And check some paths + Dir2 = filename:join([LibDir, "b-2.0"]), + Dir2 = rpc:call(Node, code, lib_dir, [b]), + BServerBeam = filename:join([Dir2,"ebin","b_server.beam"]), + {file,BServerBeam} = rpc:call(Node,code,is_loaded,[b_server]), + ok. + %% Test upgrade and downgrade of applications eval_appup(Conf) when is_list(Conf) -> @@ -983,19 +1109,16 @@ stop_node(Node) -> ?t:stop_node(Node). -copy_client(Conf,Master,Sname,StartScript) -> +copy_client(Conf,Master,Sname,Client) -> io:format("copy_client(Conf)"), DataDir = ?config(data_dir, Conf), MasterDir = filename:join(priv_dir(Conf),Master), - {ok,Host} = inet:gethostname(), - {ok,IpTuple} = inet:getaddr(Host,inet), - IpAddr = inet_parse:ntoa(IpTuple), - - CliNode = node_name(Sname), + {ClientArgs,RelCliDir} = rh_test_lib:get_client_args(Client,Sname,MasterDir, + node_name(Master)), - Cli = filename:join([MasterDir, "clients", "type1", CliNode]), + Cli = filename:join([MasterDir, RelCliDir]), ok = filelib:ensure_dir(filename:join([Cli,"bin","."])), ok = filelib:ensure_dir(filename:join([Cli,"releases","."])), ok = filelib:ensure_dir(filename:join([Cli,"log","."])), @@ -1003,12 +1126,16 @@ copy_client(Conf,Master,Sname,StartScript) -> P1GOrig = filename:join([MasterDir, "releases", "P1G"]), ok = copy_tree(Conf,P1GOrig,filename:join(Cli,"releases")), - ok = subst_file(filename:join([DataDir, "clients", StartScript]), - filename:join([Cli,"bin","start"]), - [{"ROOT",MasterDir}, - {"MASTER",atom_to_list(Master)}, - {"IPADDR",IpAddr}], - [{chmod,8#0755}]), + case os:type() of + {unix,_} -> + ok = subst_file(filename:join([DataDir, "start_client"]), + filename:join([Cli,"bin","start"]), + [{"ROOT",MasterDir}, + {"CLIENTARGS",ClientArgs}], + [{chmod,8#0755}]); + _ -> + ok + end, StartErlData = filename:join([MasterDir, "releases", "start_erl.data"]), CliRelDir = filename:join([Cli, "releases"]), @@ -1030,21 +1157,32 @@ delete_release(Conf) -> {ok, Dirs} = file:list_dir(PrivDir), ?t:format("======== deleting ~p~n",[Dirs]), - ok = delete_release_os(Dirs), - ?t:format("======== remaining ~p~n",[file:list_dir(PrivDir)]), + ok = delete_release_os(Dirs--["save"]), + {ok,Remaining} = file:list_dir(PrivDir), + ?t:format("======== remaining ~p~n",[Remaining]), + + case Remaining of + [] -> + ok; + _ -> + delete_release_os(Remaining), + Remaining2 = file:list_dir(PrivDir), + ?t:format("======== remaining after second try ~p~n",[Remaining2]) + end, + ok = file:set_cwd(OrigWd), ok. delete_release_os(Dirs) -> case os:type() of - {unix, _} -> - delete_release_unix(Dirs); - {win32, _} -> - delete_release_win32(Dirs); - Os -> - test_server:fail({error, {not_yet_implemented_os, Os}}) - end. + {unix, _} -> + delete_release_unix(Dirs); + {win32, _} -> + delete_release_win32(Dirs); + Os -> + test_server:fail({error, {not_yet_implemented_os, Os}}) + end. delete_release_unix([]) -> @@ -1075,7 +1213,14 @@ delete_release_win32([]) -> delete_release_win32(["save"|Dirs]) -> delete_release_win32(Dirs); delete_release_win32([Dir|Dirs]) -> - Rm = string:concat("rmdir /s ", Dir), + Rm = + case filelib:is_dir(Dir) of + true -> + string:concat("rmdir /s /q ", Dir); + false -> + string:concat("del /q ", Dir) + end, + ?t:format("============== COMMAND ~p~n",[Rm]), [] = os:cmd(Rm), delete_release_win32(Dirs). @@ -1200,7 +1345,12 @@ subst_var([], Vars, Result, VarAcc) -> priv_dir(Conf) -> - filename:absname(?config(priv_dir, Conf)). % Get rid of trailing slash +%% 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 + Dir = filename:absname(filename:join(?config(data_dir, Conf),priv_dir)), + filelib:ensure_dir(filename:join(Dir,"*")), + Dir. latest_version(Dir) -> List = filelib:wildcard(Dir ++ "*"), @@ -1256,12 +1406,28 @@ do_create_p1g(Conf,TargetDir) -> ErtsLatest = latest_version(filename:join(code:root_dir(),"erts")), ok = copy_tree(Conf, ErtsLatest, ErtsDir, TargetDir), ErtsBinDir = filename:join([TargetDir,ErtsDir,bin]), - copy_file(filename:join([ErtsBinDir, "epmd"]), BinDir, [preserve]), - copy_file(filename:join([ErtsBinDir, "run_erl"]), BinDir, [preserve]), - copy_file(filename:join([ErtsBinDir, "to_erl"]), BinDir, [preserve]), + + case os:type() of + {unix, _} -> + copy_file(filename:join([ErtsBinDir, "epmd"]), BinDir, [preserve]), + copy_file(filename:join([ErtsBinDir, "run_erl"]), BinDir, [preserve]), + copy_file(filename:join([ErtsBinDir, "to_erl"]), BinDir, [preserve]), + + %% Create the start_erl shell script + ok = subst_file(filename:join([ErtsBinDir,"start_erl.src"]), + filename:join([BinDir,"start_erl"]), + [{"EMU","beam"}], + [{chmod,8#0755}]); + {win32,_} -> + %% Add a batch file to use as HEART_COMMAND + ok = copy_file(filename:join(DataDir, "heart_restart.bat"), + ErtsBinDir,[preserve]) + end, copy_file(filename:join(DataDir, "../installer.beam"), filename:join([DataDir,lib,"installer-1.0",ebin])), + copy_file(filename:join(DataDir, "../rh_test_lib.beam"), + filename:join([DataDir,lib,"installer-1.0",ebin])), %% Create .rel, .script and .boot files RelName = "rel0", @@ -1272,7 +1438,7 @@ do_create_p1g(Conf,TargetDir) -> ok = filelib:ensure_dir(RelFile), LibPath = filename:join([DataDir,lib,"*",ebin]), - TarFile = create_basic_release(RelFile, RelVsn, {ErtsVsn,false}, + TarFile = create_basic_release(Conf, RelFile, RelVsn, {ErtsVsn,false}, LibPath, [], [], [], []), %% Extract tar file in target directory (i.e. same directory as erts etc.) @@ -1286,20 +1452,6 @@ do_create_p1g(Conf,TargetDir) -> %% Create RELEASES ok = release_handler:create_RELEASES(TargetDir,ReleasesDir,RelFile,[]), - %% Create start_erl - ok = subst_file(filename:join([ErtsBinDir,"start_erl.src"]), - filename:join([BinDir,"start_erl"]), - [{"EMU","beam"}], - [{chmod,8#0755}]), - - %% Create start script - %% Using a customized start script from DataDir where some options - %% (heart and nodename) are added compared to the start.src in the - %% erlang distribution. - ok = subst_file(filename:join(DataDir, "start"), - filename:join([BinDir, "start"]), - [{"ROOT",TargetDir}], - [preserve]), ok. %% Create version P1H - which is P1G + a-1.0 @@ -1336,12 +1488,12 @@ create_upgrade_release(Conf,RelName,RelVsn,Erts,Apps,Config,{UpFromName,Descr}) UpFrom = [{filename:join([PrivDir,UpFromName,UpFromName]),Descr}], - create_basic_release(RelFile, RelVsn, Erts, LibPath, + create_basic_release(Conf, RelFile, RelVsn, Erts, LibPath, Apps, Config, UpFrom, []), ok. %% Create .rel, .script, .boot, sys.config and tar -create_basic_release(RelFile,RelVsn,{ErtsVsn,ErtsDir},LibPath,ExtraApps,Config,UpFrom,DownTo) -> +create_basic_release(Conf, RelFile,RelVsn,{ErtsVsn,ErtsDir},LibPath,ExtraApps,Config,UpFrom,DownTo) -> RelDir = filename:dirname(RelFile), RelFileName = filename:rootname(RelFile), @@ -1370,7 +1522,14 @@ create_basic_release(RelFile,RelVsn,{ErtsVsn,ErtsDir},LibPath,ExtraApps,Config,U _ -> [{erts,ErtsDir}] end]), - RelFileName ++ ".tar.gz". + TarFileName = RelFileName ++ ".tar.gz", + + case os:type() of + {win32,_} when ErtsDir=/=false -> modify_tar_win32(Conf, TarFileName); + _ -> ok + end, + + TarFileName. %% Create a .rel file create_installer_rel_file(RelFile,RelVsn,ErtsVsn,ExtraApps) -> @@ -1470,21 +1629,70 @@ permanent_p1h(Node) -> copy_installed(Conf,FromNode,ToNodes) -> PrivDir = priv_dir(Conf), DataDir = ?config(data_dir,Conf), + + %% Instead of using copy_tree on the complete node directory, I'm + %% splitting this in separate tar files per subdirectory so the + %% log directory can be completely skipped. The reason for this is + %% that the tar file might become faulty if the node is alive and + %% writing to the log while the tar is created. + FromDir = filename:join(PrivDir,FromNode), + {ok,FromDirNames} = file:list_dir(FromDir), + TempTarFiles = + [begin + TempTarFile = filename:join(PrivDir,"temp_" ++ FDN ++ ".tar"), + {ok,Tar} = erl_tar:open(TempTarFile,[write]), + ok = erl_tar:add(Tar,filename:join(FromDir,FDN),FDN,[]), + ok = erl_tar:close(Tar), + TempTarFile + end || FDN <- FromDirNames, FDN=/="log"], lists:foreach( fun(Node) -> - ok = copy_tree(Conf,filename:join(PrivDir,FromNode),Node,PrivDir), NodeDir = filename:join(PrivDir,Node), - ok = subst_file(filename:join(DataDir, "start"), - filename:join([NodeDir, "bin", "start"]), - [{"ROOT",NodeDir}]), - LogDir = filename:join(NodeDir,log), - {ok,Logs} = file:list_dir(LogDir), - lists:foreach(fun(Log) -> - file:delete(filename:join(LogDir,Log)) - end, - Logs) + ok = filelib:ensure_dir(filename:join([NodeDir,"log","*"])), + lists:foreach( + fun(TempTarFile) -> + ok = erl_tar:extract(TempTarFile,[{cwd,NodeDir}]) + end, TempTarFiles), + case os:type() of + {unix,_} -> + %% Create start script + %% Using a customized start script from DataDir + %% where some options (heart and nodename) are + %% added compared to the start.src in the erlang + %% distribution. + ok = subst_file(filename:join(DataDir, "start"), + filename:join([NodeDir, "bin", "start"]), + [{"ROOT",NodeDir}], + [preserve]); + {win32,_} -> + %% Write erl.ini + ErtsDirs = + filelib:wildcard(filename:join(NodeDir,"erts-*")), + lists:foreach( + fun(ErtsDir) -> + ok = subst_file( + filename:join(DataDir, "erl.ini.src"), + filename:join([ErtsDir, "bin", "erl.ini"]), + [{"ROOTDIR",NodeDir}, + {"BINDIR",filename:join(ErtsDir,"bin")}]) + end, + ErtsDirs), + + %% The service on windows runs as local + %% administrator (not otptest user), so we need + %% to chmod the release in order to allow the + %% executing node to install releases, write + %% logs etc. + chmod_release_win32(NodeDir) + end end, - ToNodes). + ToNodes), + + lists:foreach(fun(TempTarFile) -> file:delete(TempTarFile) end, TempTarFiles), + ok. + +chmod_release_win32(Dir) -> + os:cmd("echo y|cacls " ++ Dir ++ " /T /E /G Administrators:F"). start_nodes(Conf,Snames,Tag) -> PrivDir = priv_dir(Conf), @@ -1493,19 +1701,42 @@ start_nodes(Conf,Snames,Tag) -> fun(Sname) -> NodeDir = filename:join(PrivDir,Sname), Node = node_name(Sname), - - Script = filename:join([NodeDir,"bin","start"]), - Cmd = "env NODENAME="++atom_to_list(Sname) ++ " " ++ Script, - %% {ok,StartFile} = file:read_file(Cmd), - %% io:format("~s:\n~s~n~n",[Start,binary_to_list(StartFile)]), - Res = os:cmd(Cmd), - io:format("Start ~p: ~p~n=>\t~p~n", [Sname,Cmd,Res]), + + case os:type() of + {unix,_} -> + start_node_unix(Sname,NodeDir); + {win32,_} -> + start_node_win32(Sname,NodeDir) + end, Node end, Snames), wait_nodes_up(Nodes,Tag), Nodes. +start_node_unix(Sname,NodeDir) -> + Script = filename:join([NodeDir,"bin","start"]), + Cmd = "env NODENAME="++atom_to_list(Sname) ++ " " ++ Script, + %% {ok,StartFile} = file:read_file(Cmd), + %% io:format("~s:\n~s~n~n",[Start,binary_to_list(StartFile)]), + Res = os:cmd(Cmd), + io:format("Start ~p: ~p~n=>\t~p~n", [Sname,Cmd,Res]). + +start_node_win32(Sname,NodeDir) -> + Name = atom_to_list(Sname) ++ "_P1G", + ErtsBinDir = filename:join(NodeDir,"erts-4.4/bin"), + + StartErlArgs = rh_test_lib:get_start_erl_args(NodeDir), + ServiceArgs = rh_test_lib:get_service_args(NodeDir, Sname, StartErlArgs), + + Erlsrv = filename:nativename(filename:join(ErtsBinDir,"erlsrv")), + rh_test_lib:erlsrv(Erlsrv,stop,Name), + rh_test_lib:erlsrv(Erlsrv,remove,Name), + ok = rh_test_lib:erlsrv(Erlsrv,add,Name,ServiceArgs), + ok = rh_test_lib:erlsrv(Erlsrv,start,Name), + ok. + +%% Create a unique node name for each test case tc_sname(Config) -> tc_sname(Config,""). tc_sname(Config,Fix) when is_atom(Fix) -> @@ -1649,3 +1880,32 @@ create_fake_release(Dir,RelName,RelVsn,AppDirs) -> rpc_inst(Node,Func,Args) -> rpc:call(Node,installer,Func,[node()|Args]). + +delete_all_services() -> + ErlSrv = erlsrv:erlsrv(erlang:system_info(version)), + [_|Serviceinfo] = string:tokens(os:cmd(ErlSrv ++ " list"),"\n"), + Services = + [lists:takewhile(fun($\t) -> false; (_) -> true end,S) + || S <- Serviceinfo], + ?t:format("Services to remove: ~p~n",[Services]), + lists:foreach(fun(S) -> + rh_test_lib:erlsrv(ErlSrv,stop,S), + rh_test_lib:erlsrv(ErlSrv,remove,S) + end, + Services). + +modify_tar_win32(Conf, TarFileName) -> + DataDir = ?config(data_dir,Conf), + PrivDir = priv_dir(Conf), + TmpDir = filename:join(PrivDir,"tmp_modify_tar_win32"), + ok = erl_tar:extract(TarFileName,[{cwd,TmpDir},compressed]), + + ErtsBinDir = filelib:wildcard(filename:join([TmpDir,"erts-*","bin"])), + ok = copy_file(filename:join(DataDir, "heart_restart.bat"), + ErtsBinDir,[preserve]), + + {ok,Fs} = file:list_dir(TmpDir), + {ok,T} = erl_tar:open(TarFileName,[write,compressed]), + [ok = erl_tar:add(T,filename:join(TmpDir,F),F,[]) || F <- Fs], + ok = erl_tar:close(T), + ok. diff --git a/lib/sasl/test/release_handler_SUITE_data/Makefile.src b/lib/sasl/test/release_handler_SUITE_data/Makefile.src index 85e25fdc2f..a12e526d2e 100644 --- a/lib/sasl/test/release_handler_SUITE_data/Makefile.src +++ b/lib/sasl/test/release_handler_SUITE_data/Makefile.src @@ -1,14 +1,19 @@ EFLAGS=+debug_info P2B= \ - P2B/a-2.0/ebin/a.beam \ - P2B/a-2.0/ebin/a_sup.beam + P2B/a-2.0/ebin/a.@EMULATOR@ \ + P2B/a-2.0/ebin/a_sup.@EMULATOR@ LIB= \ - lib/a-1.1/ebin/a.beam \ - lib/a-1.1/ebin/a_sup.beam \ - lib/a-1.0/ebin/a.beam \ - lib/a-1.0/ebin/a_sup.beam \ + lib/a-1.2/ebin/a.@EMULATOR@ \ + lib/a-1.2/ebin/a_sup.@EMULATOR@ \ + lib/a-1.1/ebin/a.@EMULATOR@ \ + lib/a-1.1/ebin/a_sup.@EMULATOR@ \ + lib/a-1.0/ebin/a.@EMULATOR@ \ + lib/a-1.0/ebin/a_sup.@EMULATOR@ \ + lib/b-1.0/ebin/b_server.@EMULATOR@ \ + lib/b-1.0/ebin/b_lib.@EMULATOR@ \ + lib/b-2.0/ebin/b_server.@EMULATOR@ APP= \ app1_app2/lib1/app1-1.0/ebin/app1_sup.@EMULATOR@ \ @@ -57,6 +62,21 @@ lib/a-1.1/ebin/a_sup.@EMULATOR@: lib/a-1.1/src/a_sup.erl erlc $(EFLAGS) -olib/a-1.1/ebin lib/a-1.1/src/a_sup.erl +lib/a-1.2/ebin/a.@EMULATOR@: lib/a-1.2/src/a.erl + erlc $(EFLAGS) -olib/a-1.2/ebin lib/a-1.2/src/a.erl +lib/a-1.2/ebin/a_sup.@EMULATOR@: lib/a-1.2/src/a_sup.erl + erlc $(EFLAGS) -olib/a-1.2/ebin lib/a-1.2/src/a_sup.erl + +lib/b-1.0/ebin/b_server.@EMULATOR@: lib/b-1.0/src/b_server.erl + erlc $(EFLAGS) -olib/b-1.0/ebin lib/b-1.0/src/b_server.erl +lib/b-1.0/ebin/b_lib.@EMULATOR@: lib/b-1.0/src/b_lib.erl + erlc $(EFLAGS) -olib/b-1.0/ebin lib/b-1.0/src/b_lib.erl + +lib/b-2.0/ebin/b_server.@EMULATOR@: lib/b-2.0/src/b_server.erl + erlc $(EFLAGS) -olib/b-2.0/ebin lib/b-2.0/src/b_server.erl + + + app1_app2/lib1/app1-1.0/ebin/app1_sup.@EMULATOR@: app1_app2/lib1/app1-1.0/src/app1_sup.erl erlc $(EFLAGS) -oapp1_app2/lib1/app1-1.0/ebin app1_app2/lib1/app1-1.0/src/app1_sup.erl app1_app2/lib1/app1-1.0/ebin/app1_server.@EMULATOR@: app1_app2/lib1/app1-1.0/src/app1_server.erl diff --git a/lib/sasl/test/release_handler_SUITE_data/clients/start_cli1 b/lib/sasl/test/release_handler_SUITE_data/clients/start_cli1 deleted file mode 100755 index ee3d8c97cf..0000000000 --- a/lib/sasl/test/release_handler_SUITE_data/clients/start_cli1 +++ /dev/null @@ -1,38 +0,0 @@ -#!/bin/sh -# -# This program invokes the erlang emulator by calling run_erl. -# It should only be used at an embedded target system. -# It should be modified to give the correct flags to erl (via start_erl), -# e.g -mode embedded -sname XXX -# -# Usage: start [Data] -# - -if [ "x${NODENAME}" = "x" ] -then - echo "ERROR: Variable \$NODENAME is not set!!" - exit 1 -fi - -TESTHOST=`hostname | sed 's/[.].*//'` -IPADDR=%IPADDR% - -ROOTDIR=%ROOT% -CLIENTDIR=$ROOTDIR/clients/type1/$NODENAME@$TESTHOST - -RELDIR=$CLIENTDIR/releases - -# Note that this scripts is modified an copied to $CLIENTDIR/bin/start -# in release_handler_SUITE:copy_client - therefore HEART_COMMAND is as follows: -HEART_COMMAND=$CLIENTDIR/bin/start -HW_WD_DISABLE=true -export HW_WD_DISABLE HEART_COMMAND - -START_ERL_DATA=${1:-$RELDIR/start_erl.data} - -if [ ! -d /tmp/$NODENAME@$TESTHOST ] -then - mkdir /tmp/$NODENAME@$TESTHOST -fi - -$ROOTDIR/bin/run_erl /tmp/$NODENAME@$TESTHOST/ $CLIENTDIR/log "exec $ROOTDIR/bin/start_erl $ROOTDIR $RELDIR $START_ERL_DATA -heart -sname $NODENAME -sasl start_prg \\\"$CLIENTDIR/bin/start\\\" masters \[\\'%MASTER%@$TESTHOST\\'\] client_directory \\\"$CLIENTDIR\\\" -loader inet -id $NODENAME -hosts $IPADDR" > $CLIENTDIR/log/run_erl.out 2>&1 & diff --git a/lib/sasl/test/release_handler_SUITE_data/erl.ini.src b/lib/sasl/test/release_handler_SUITE_data/erl.ini.src new file mode 100644 index 0000000000..b8791e75a5 --- /dev/null +++ b/lib/sasl/test/release_handler_SUITE_data/erl.ini.src @@ -0,0 +1,4 @@ +[erlang] +Bindir=%BINDIR% +Progname=erl +Rootdir=%ROOTDIR% diff --git a/lib/sasl/test/release_handler_SUITE_data/heart_restart.bat b/lib/sasl/test/release_handler_SUITE_data/heart_restart.bat new file mode 100755 index 0000000000..ede1ad4ff3 --- /dev/null +++ b/lib/sasl/test/release_handler_SUITE_data/heart_restart.bat @@ -0,0 +1,3 @@ +@echo off +%ERLSRV_EXECUTABLE% stop %ERLSRV_SERVICE_NAME% +%ERLSRV_EXECUTABLE% start %ERLSRV_SERVICE_NAME%
\ No newline at end of file diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/README b/lib/sasl/test/release_handler_SUITE_data/lib/README new file mode 100644 index 0000000000..667d21d4cf --- /dev/null +++ b/lib/sasl/test/release_handler_SUITE_data/lib/README @@ -0,0 +1,16 @@ +a-1.0: +start version + +a-1.1: +can be upgraded to from a-1.0. Module a has changed + +a-1.2: +can be upgraded to from a-1.1. +No module have changed, but priv dir is added including one 'file' + +b-1.0: +start version, includes b_lib and b_server + +b-2.0: +can be upgraded to from b-1.0. +Removes b_lib and updates b_server diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/a-1.0/src/a.app b/lib/sasl/test/release_handler_SUITE_data/lib/a-1.2/ebin/a.app index e938137f67..b38722f06d 100644 --- a/lib/sasl/test/release_handler_SUITE_data/lib/a-1.0/src/a.app +++ b/lib/sasl/test/release_handler_SUITE_data/lib/a-1.2/ebin/a.app @@ -1,7 +1,7 @@ {application, a, [{description, "A CXC 138 11"}, - {vsn, "1.0"}, - {modules, [{a, 1}, {a_sup,1}]}, + {vsn, "1.2"}, + {modules, [{a, 2}, {a_sup,1}]}, {registered, [a_sup]}, {applications, [kernel, stdlib]}, {env, [{key1, val1}]}, diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/a-1.2/ebin/a.appup b/lib/sasl/test/release_handler_SUITE_data/lib/a-1.2/ebin/a.appup new file mode 100644 index 0000000000..3df0546316 --- /dev/null +++ b/lib/sasl/test/release_handler_SUITE_data/lib/a-1.2/ebin/a.appup @@ -0,0 +1,3 @@ +{"1.2", + [{"1.1",[]}], + [{"1.1",[]}]}. diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/a-1.2/priv/file b/lib/sasl/test/release_handler_SUITE_data/lib/a-1.2/priv/file new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/lib/sasl/test/release_handler_SUITE_data/lib/a-1.2/priv/file diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/a-1.2/src/a.erl b/lib/sasl/test/release_handler_SUITE_data/lib/a-1.2/src/a.erl new file mode 100644 index 0000000000..c082ad5339 --- /dev/null +++ b/lib/sasl/test/release_handler_SUITE_data/lib/a-1.2/src/a.erl @@ -0,0 +1,54 @@ +%% ``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 via the world wide web 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. +%% +%% The Initial Developer of the Original Code is Ericsson Utvecklings AB. +%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings +%% AB. All Rights Reserved.'' +%% +%% $Id$ +%% +-module(a). + + +-behaviour(gen_server). + +%% External exports +-export([start_link/0, a/0, b/0]). +%% Internal exports +-export([init/1, handle_call/3, handle_info/2, terminate/2, code_change/3]). + +start_link() -> gen_server:start_link({local, aa}, a, [], []). + +a() -> gen_server:call(aa, a). +b() -> gen_server:call(aa, b). + +%%----------------------------------------------------------------- +%% Callback functions from gen_server +%%----------------------------------------------------------------- +init([]) -> + process_flag(trap_exit, true), + {ok, {state, bval}}. + +handle_call(a, _From, State) -> + X = application:get_all_env(a), + {reply, X, State}; + +handle_call(b, _From, State) -> + {reply, {ok, element(2, State)}, State}. + +handle_info(_, State) -> + {noreply, State}. + +terminate(_Reason, _State) -> + ok. + +code_change(1, Extra, State) -> + {ok, {state, bval}}. diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/a-1.2/src/a_sup.erl b/lib/sasl/test/release_handler_SUITE_data/lib/a-1.2/src/a_sup.erl new file mode 100644 index 0000000000..a141c1767b --- /dev/null +++ b/lib/sasl/test/release_handler_SUITE_data/lib/a-1.2/src/a_sup.erl @@ -0,0 +1,37 @@ +%% ``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 via the world wide web 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. +%% +%% The Initial Developer of the Original Code is Ericsson Utvecklings AB. +%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings +%% AB. All Rights Reserved.'' +%% +%% $Id$ +%% +-module(a_sup). + + +-behaviour(supervisor). + +%% External exports +-export([start/2]). + +%% Internal exports +-export([init/1]). + +start(_, _) -> + supervisor:start_link({local, a_sup}, a_sup, []). + +init([]) -> + SupFlags = {one_for_one, 4, 3600}, + Config = {a, + {a, start_link, []}, + permanent, 2000, worker, [a]}, + {ok, {SupFlags, [Config]}}. diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/b-1.0/ebin/b.app b/lib/sasl/test/release_handler_SUITE_data/lib/b-1.0/ebin/b.app new file mode 100644 index 0000000000..00347b2754 --- /dev/null +++ b/lib/sasl/test/release_handler_SUITE_data/lib/b-1.0/ebin/b.app @@ -0,0 +1,7 @@ +%% -*- erlang -*- +{application, b, + [{description, "B CXC 138 12"}, + {vsn, "1.0"}, + {modules, [{b_server, 1},{b_lib, 1}]}, + {registered, [b_server]}, + {applications, [kernel, stdlib]}]}. diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/b-1.0/src/b_lib.erl b/lib/sasl/test/release_handler_SUITE_data/lib/b-1.0/src/b_lib.erl new file mode 100644 index 0000000000..7e8a308a5e --- /dev/null +++ b/lib/sasl/test/release_handler_SUITE_data/lib/b-1.0/src/b_lib.erl @@ -0,0 +1,3 @@ +-module(b_lib). +-compile(export_all). +foo() -> ok. diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/b-1.0/src/b_server.erl b/lib/sasl/test/release_handler_SUITE_data/lib/b-1.0/src/b_server.erl new file mode 100644 index 0000000000..e1a80a076f --- /dev/null +++ b/lib/sasl/test/release_handler_SUITE_data/lib/b-1.0/src/b_server.erl @@ -0,0 +1,37 @@ +-module(b_server). + +-behaviour(gen_server). + +%% API +-export([start_link/0]). + +%% gen_server callbacks +-export([init/1, handle_call/3, handle_cast/2, handle_info/2, + terminate/2, code_change/3]). + +-define(SERVER, ?MODULE). + +-record(state, {}). + +start_link() -> + gen_server:start_link({local, ?SERVER}, ?MODULE, [], []). + +init([]) -> + {ok, #state{}}. + +handle_call(_Request, _From, State) -> + Reply = ok, + {reply, Reply, State}. + +handle_cast(_Msg, State) -> + {noreply, State}. + +handle_info(_Info, State) -> + {noreply, State}. + +terminate(_Reason, _State) -> + ok. + +code_change(OldVsn, State, Extra) -> + file:write_file("/tmp/b_server",io_lib:format("~p~n",[{"1.0",OldVsn,Extra}])), + {ok, State}. diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/b-2.0/ebin/b.app b/lib/sasl/test/release_handler_SUITE_data/lib/b-2.0/ebin/b.app new file mode 100644 index 0000000000..73c8e42b32 --- /dev/null +++ b/lib/sasl/test/release_handler_SUITE_data/lib/b-2.0/ebin/b.app @@ -0,0 +1,7 @@ +%% -*- erlang -*- +{application, b, + [{description, "B CXC 138 12"}, + {vsn, "2.0"}, + {modules, [{b_server, 1}]}, + {registered, [b_server]}, + {applications, [kernel, stdlib]}]}. diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/b-2.0/ebin/b.appup b/lib/sasl/test/release_handler_SUITE_data/lib/b-2.0/ebin/b.appup new file mode 100644 index 0000000000..d261a37732 --- /dev/null +++ b/lib/sasl/test/release_handler_SUITE_data/lib/b-2.0/ebin/b.appup @@ -0,0 +1,3 @@ +{"2.0", + [{"1.0",[{delete_module,b_lib}, {update,b_server,{advanced,[]}}]}], + [{"1.0",[{add_module,b_lib},{update,b_server,{advanced,[]}}]}]}. diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/b-2.0/src/b_lib.erl b/lib/sasl/test/release_handler_SUITE_data/lib/b-2.0/src/b_lib.erl new file mode 100644 index 0000000000..7e8a308a5e --- /dev/null +++ b/lib/sasl/test/release_handler_SUITE_data/lib/b-2.0/src/b_lib.erl @@ -0,0 +1,3 @@ +-module(b_lib). +-compile(export_all). +foo() -> ok. diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/b-2.0/src/b_server.erl b/lib/sasl/test/release_handler_SUITE_data/lib/b-2.0/src/b_server.erl new file mode 100644 index 0000000000..f8bfbdaff7 --- /dev/null +++ b/lib/sasl/test/release_handler_SUITE_data/lib/b-2.0/src/b_server.erl @@ -0,0 +1,37 @@ +-module(b_server). + +-behaviour(gen_server). + +%% API +-export([start_link/0]). + +%% gen_server callbacks +-export([init/1, handle_call/3, handle_cast/2, handle_info/2, + terminate/2, code_change/3]). + +-define(SERVER, ?MODULE). + +-record(state, {}). + +start_link() -> + gen_server:start_link({local, ?SERVER}, ?MODULE, [], []). + +init([]) -> + {ok, #state{}}. + +handle_call(_Request, _From, State) -> + Reply = ok, + {reply, Reply, State}. + +handle_cast(_Msg, State) -> + {noreply, State}. + +handle_info(_Info, State) -> + {noreply, State}. + +terminate(_Reason, _State) -> + ok. + +code_change(OldVsn, State, Extra) -> + file:write_file("/tmp/b_server",io_lib:format("~p~n",[{"2.0",OldVsn,Extra}])), + {ok, State}. diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/installer-1.0/ebin/installer.app b/lib/sasl/test/release_handler_SUITE_data/lib/installer-1.0/ebin/installer.app index 6f77317f6a..e1391c0605 100644 --- a/lib/sasl/test/release_handler_SUITE_data/lib/installer-1.0/ebin/installer.app +++ b/lib/sasl/test/release_handler_SUITE_data/lib/installer-1.0/ebin/installer.app @@ -1,6 +1,6 @@ {application, installer, [{description, "Installer application"}, {vsn, "1.0"}, - {modules, [{installer, 1}]}, + {modules, [installer,rh_test_lib]}, {registered, []}, {applications, [kernel, stdlib, sasl]}]}. diff --git a/lib/sasl/test/release_handler_SUITE_data/clients/start_cli2 b/lib/sasl/test/release_handler_SUITE_data/start_client index 88912cf884..5ea94d6f7c 100755 --- a/lib/sasl/test/release_handler_SUITE_data/clients/start_cli2 +++ b/lib/sasl/test/release_handler_SUITE_data/start_client @@ -34,4 +34,4 @@ then mkdir /tmp/$NODENAME@$TESTHOST fi -$ROOTDIR/bin/run_erl /tmp/$NODENAME@$TESTHOST/ $CLIENTDIR/log "exec $ROOTDIR/bin/start_erl $ROOTDIR $RELDIR $START_ERL_DATA -heart -sname $NODENAME -sasl start_prg \\\"$CLIENTDIR/bin/start\\\" masters \[\\'%MASTER%@$TESTHOST\\',\\'master2@$TESTHOST\\'\] client_directory \\\"$CLIENTDIR\\\"" > /dev/null 2>&1 & +$ROOTDIR/bin/run_erl /tmp/$NODENAME@$TESTHOST/ $CLIENTDIR/log "exec $ROOTDIR/bin/start_erl $ROOTDIR $RELDIR $START_ERL_DATA -heart -sname $NODENAME %CLIENTARGS%" > $CLIENTDIR/log/run_erl.out 2>&1 & diff --git a/lib/sasl/test/rh_test_lib.erl b/lib/sasl/test/rh_test_lib.erl new file mode 100644 index 0000000000..99a7f919a7 --- /dev/null +++ b/lib/sasl/test/rh_test_lib.erl @@ -0,0 +1,100 @@ +-module(rh_test_lib). + +-export([erlsrv/3, + erlsrv/4]). +-export([get_service_args/3, + get_service_args/4, + get_start_erl_args/1, + get_start_erl_args/3, + get_client_args/3, + get_client_args/4]). + + +erlsrv(Erlsrv,Action,Name) -> + erlsrv(Erlsrv,Action,Name,""). +erlsrv(Erlsrv,Action,Name,Rest) -> + Cmd = Erlsrv ++ " " ++ atom_to_list(Action) ++ " " ++ Name ++ " " ++ Rest, + io:format("erlsrv cmd: ~p~n",[Cmd]), + Port = open_port({spawn, Cmd}, [stream, {line, 100}, eof, in]), + Res = recv_prog_output(Port), + case Res of + [] -> + failed; + _Y -> + io:format("erlsrv res: ~p~n",[_Y]), + ok + end. + +recv_prog_output(Port) -> + receive + {Port, {data, {eol,Data}}} -> + %%io:format("Got data: ~s~n", [Data]), + [ Data, "\n" | recv_prog_output(Port)]; + {Port, {data, {noeol,Data}}} -> + %%io:format("Got data: ~s~n", [Data]), + [ Data | recv_prog_output(Port)]; + {Port, _Other} -> + %%io:format("Got ~p from port~n", [_Other]), + Port ! {self(), close}, + receive + {Port,closed} -> + [] + end + end. + +get_service_args(RootDir, Sname, StartErlArgs) -> + get_service_args(RootDir, "", Sname, StartErlArgs). +get_service_args(RootDir, RelClientDir, Sname, StartErlArgs) -> + LogDir = filename:nativename(filename:join([RootDir,RelClientDir,"log"])), + %% start_erl.exe will be found since it is in the same directory as erlsrv.exe + %% And heart_restart.bat will be found since the erts bin dir is + %% always in the path for the erlang virtual machine. + " -machine start_erl.exe -workdir " ++ LogDir ++ + " -debugtype new -sname " ++ atom_to_list(Sname) ++ + " -env HEART_COMMAND=heart_restart.bat -args \"" ++ StartErlArgs ++ "\"". + +get_start_erl_args(RootDir) -> + get_start_erl_args(RootDir,"",""). +get_start_erl_args(RootDir,RelClientDir,ExtraArgs) -> + Cookie = atom_to_list(erlang:get_cookie()), + RelDir = filename:join([RootDir,RelClientDir,"releases"]), + ExtraArgs ++ " -setcookie " ++ Cookie ++ + " -heart ++ -rootdir " ++ filename:nativename(RootDir) ++ + " -reldir " ++ filename:nativename(RelDir). + +%% Must be called on the master node +get_client_args(Client,Sname,RootDir) -> + get_client_args(Client,Sname,RootDir,node()). +get_client_args(Client,Sname,RootDir,Master) -> + {ok,Host} = inet:gethostname(), + Node = atom_to_list(Sname) ++ "@" ++ Host, + RelClientDir = filename:join(["clients","type1",Node]), + ClientDir = filename:join([RootDir,RelClientDir]), + StartPrg = filename:join([ClientDir,"bin","start"]), + {" -sasl start_prg \\\\\\\"" ++ StartPrg ++ "\\\\\\\" masters \[" ++ + single_quote() ++ atom_to_list(Master) ++ single_quote() ++ + get_client_extra_master(Client,Host) ++ + "\] client_directory \\\\\\\"" ++ ClientDir ++ "\\\\\\\"" ++ + get_client_loader_args(Client,Sname,Host), + RelClientDir}. + +get_client_loader_args(client1,Sname,Host) -> + {ok,IpTuple} = inet:getaddr(Host,inet), + IpAddr = inet_parse:ntoa(IpTuple), + " -loader inet -id " ++ + atom_to_list(Sname) ++ " -hosts " ++ IpAddr; +get_client_loader_args(_,_,_) -> + "". + +get_client_extra_master(client2,Host) -> + "," ++ single_quote() ++ "master2@" ++ Host ++ single_quote(); +get_client_extra_master(_,_) -> + "". + +single_quote() -> + case os:type() of + {win32,_} -> + "\'"; + _ -> + "\\'" + end. |