📄 release_handler.erl
字号:
Tar = filename:join(RelDir, ReleaseName ++ ".tar.gz"), do_check_file(Tar, regular), Rel = ReleaseName ++ ".rel", extract_rel_file(filename:join("releases", Rel), Tar, Root), RelFile = filename:join(RelDir, Rel), Release = check_rel(Root, RelFile, false), #release{vsn = Vsn} = Release, case lists:keysearch(Vsn, #release.vsn, Releases) of {value, _} -> throw({error, {existing_release, Vsn}}); _ -> ok end, extract_tar(Root, Tar), NewReleases = [Release#release{status = unpacked} | Releases], write_releases(RelDir, NewReleases, false), Dir = filename:join([RelDir, Vsn]), copy_file(RelFile, Dir, false), {ok, NewReleases, Vsn}.%% Note that this function is not executed by a client%% release_handler.clean_release(RelDir, ReleaseName) -> Tar = filename:join(RelDir, ReleaseName ++ ".tar.gz"), Rel = filename:join(RelDir, ReleaseName ++ ".rel"), file:delete(Tar), file:delete(Rel). check_rel(Root, RelFile, Masters) -> check_rel(Root, RelFile, [], Masters).check_rel(Root, RelFile, LibDirs, Masters) -> case consult(RelFile, Masters) of {ok, [RelData]} -> check_rel_data(RelData, Root, LibDirs); {ok, _} -> throw({error, {bad_rel_file, RelFile}}); {error, Reason} when is_tuple(Reason) -> throw({error, {bad_rel_file, RelFile}}); {error, FileError} -> % FileError is posix atom | no_master throw({error, {FileError, RelFile}}) end.check_rel_data({release, {Name, Vsn}, {erts, EVsn}, Libs}, Root, LibDirs) -> Libs2 = lists:map(fun(LibSpec) -> Lib = element(1, LibSpec), LibVsn = element(2, LibSpec), LibName = lists:concat([Lib, "-", LibVsn]), LibDir = case lists:keysearch(Lib, 1, LibDirs) of {value, {_Lib, _Vsn, Dir}} -> Path = filename:join(Dir,LibName), check_path(Path), Path; _ -> filename:join([Root, "lib", LibName]) end, {Lib, LibVsn, LibDir} end, Libs), #release{name = Name, vsn = Vsn, erts_vsn = EVsn, libs = Libs2, status = unpacking};check_rel_data(RelData, _Root, _LibDirs) -> throw({error, {bad_rel_data, RelData}}).check_path(Path) -> case file:read_file_info(Path) of {ok, Info} when Info#file_info.type==directory -> ok; {ok, _Info} -> throw({error, {not_a_directory, Path}}); {error, _Reason} -> throw({error, {no_such_directory, Path}}) end. do_check_install_release(RelDir, Vsn, Releases, Masters) -> case lists:keysearch(Vsn, #release.vsn, Releases) of {value, #release{status = current}} -> {error, {already_installed, Vsn}}; {value, Release} -> LatestRelease = get_latest_release(Releases), VsnDir = filename:join([RelDir, Vsn]), check_file(filename:join(VsnDir, "start.boot"), regular, Masters), IsRelup = check_opt_file(filename:join(VsnDir, "relup"), regular, Masters), check_opt_file(filename:join(VsnDir, "sys.config"), regular, Masters), %% Check that all required libs are present Libs = Release#release.libs, lists:foreach(fun({_Lib, _LibVsn, LibDir}) -> check_file(LibDir, directory, Masters), Ebin = filename:join(LibDir, "ebin"), check_file(Ebin, directory, Masters) end, Libs), if IsRelup -> case get_rh_script(LatestRelease, Release, RelDir, Masters) of {ok, {CurrentVsn, Descr, Script}} -> case catch check_script(Script, Libs) of ok -> {ok, CurrentVsn, Descr}; Else -> Else end; Error -> Error end; true -> {ok, Vsn, ""} end; _ -> {error, {no_such_release, Vsn}} end. do_install_release(#state{start_prg = StartPrg, rel_dir = RelDir, releases = Releases, masters = Masters, static_emulator = Static}, Vsn, Opts) -> case lists:keysearch(Vsn, #release.vsn, Releases) of {value, #release{status = current}} -> {error, {already_installed, Vsn}}; {value, Release} -> LatestRelease = get_latest_release(Releases), case get_rh_script(LatestRelease, Release, RelDir, Masters) of {ok, {CurrentVsn, Descr, Script}} -> mon_nodes(true), 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 {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}; 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, RelDir, Release, PermanentRelease, Masters), {restart_new_emulator, CurrentVsn, Descr}; Else -> application_controller:config_change(EnvBefore), mon_nodes(false), Else end; Error -> Error end; _ -> {error, {no_such_release, Vsn}} end.%%% 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%%% in which case we try to rename the old service to the new name and try%%% to update heart's view of what service we are really running.do_make_services_permanent(PermanentVsn,Vsn, PermanentEVsn, EVsn) -> PermName = hd(string:tokens(atom_to_list(node()),"@")) ++ "_" ++ PermanentVsn, Name = hd(string:tokens(atom_to_list(node()),"@")) ++ "_" ++ Vsn, case erlsrv:get_service(EVsn,Name) of {error, _Error} -> %% We probably do not need to replace services, just %% 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; false -> throw({error,service_name_missmatch}) end; Data -> UpdData = erlsrv:new_service(Name, Data, []), case erlsrv:store_service(EVsn,UpdData) of ok -> erlsrv:disable_service(PermanentEVsn, PermName), erlsrv:enable_service(EVsn, Name), erlsrv:remove_service(PermName), %%% Read comments about these above... os:putenv("ERLSRV_SERVICE_NAME", Name), heart:cycle(), ok; Error4 -> throw(Error4) end end. do_make_permanent(#state{releases = Releases, rel_dir = RelDir, unpurged = Unpurged, masters = Masters, static_emulator = Static}, Vsn) -> case lists:keysearch(Vsn, #release.vsn, Releases) of {value, #release{erts_vsn = EVsn, status = Status}} when Status /= unpacked, Status /= old, Status /= permanent -> Dir = filename:join([RelDir, Vsn]), Sys = case catch check_file(filename:join(Dir, "sys.config"), regular, Masters) of ok -> filename:join(Dir, "sys"); _ -> false end, Boot = filename:join(Dir, "start.boot"), check_file(Boot, regular, Masters), set_permanent_files(RelDir, EVsn, Vsn, Masters, Static), NewReleases = set_status(Vsn, permanent, Releases), write_releases(RelDir, NewReleases, Masters), case os:type() of {win32, nt} -> {value, PermanentRelease} = lists:keysearch(permanent, #release.status, Releases), PermanentVsn = PermanentRelease#release.vsn, PermanentEVsn = PermanentRelease#release.erts_vsn, case catch do_make_services_permanent(PermanentVsn, Vsn, PermanentEVsn, EVsn) of {error,Reason} -> {error,{service_update_failed, Reason}}; _ -> ok end; _ -> ok end, init:make_permanent(filename:join(Dir, "start"), Sys), {ok, NewReleases, brutal_purge(Unpurged)}; {value, #release{status = permanent}} -> {ok, Releases, Unpurged}; {value, #release{status = Status}} -> {error, {bad_status, Status}}; false -> {error, {no_such_release, Vsn}} end.do_back_service(OldVersion, CurrentVersion,OldEVsn,CurrentEVsn) -> NN = hd(string:tokens(atom_to_list(node()),"@")), OldName = NN ++ "_" ++ OldVersion, CurrentName = NN ++ "_" ++ CurrentVersion, UpdData = case erlsrv:get_service(CurrentEVsn,CurrentName) of {error, Error} -> throw({error,Error}); Data -> erlsrv:new_service(OldName, Data, []) end, case erlsrv:store_service(OldEVsn,UpdData) of ok -> erlsrv:disable_service(CurrentEVsn,CurrentName), erlsrv:enable_service(OldEVsn,OldName); Error2 -> throw(Error2) end, OldErlSrv = filename:nativename(erlsrv:erlsrv(OldEVsn)), CurrentErlSrv = filename:nativename(erlsrv:erlsrv(CurrentEVsn)), case heart:set_cmd(CurrentErlSrv ++ " remove " ++ CurrentName ++ " & " ++ OldErlSrv ++ " start " ++ OldName) of ok -> ok; Error3 -> throw({error, {'heart:set_cmd() error', Error3}}) end.do_reboot_old_release(#state{releases = Releases, rel_dir = RelDir, masters = Masters, static_emulator = Static}, Vsn) -> case lists:keysearch(Vsn, #release.vsn, Releases) of {value, #release{erts_vsn = EVsn, status = old}} -> CurrentRunning = case os:type() of {win32,nt} -> %% Get the current release on NT case lists:keysearch(permanent, #release.status, Releases) of false -> lists:keysearch(current, #release.status, Releases); {value,CR} -> CR end; _ -> false end, set_permanent_files(RelDir, EVsn, Vsn, Masters, Static), NewReleases = set_status(Vsn, permanent, Releases), write_releases(RelDir, NewReleases, Masters), case os:type() of {win32,nt} -> %% Edit up the services and set a reasonable heart %% command do_back_service(Vsn,CurrentRunning#release.vsn,EVsn, CurrentRunning#release.erts_vsn); _ -> ok end, ok; {value, #release{status = Status}} -> {error, {bad_status, Status}}; false -> {error, {no_such_release, Vsn}} end.%%-----------------------------------------------------------------%% Depending of if the release_handler is running in normal, client or%% client with static emulator the new system version is made permanent%% in different ways.%%-----------------------------------------------------------------set_permanent_files(RelDir, EVsn, Vsn, false, _) -> write_start(filename:join([RelDir, "start_erl.data"]), EVsn ++ " " ++ Vsn, false);set_permanent_files(RelDir, EVsn, Vsn, Masters, false) -> write_start(filename:join([RelDir, "start_erl.data"]), EVsn ++ " " ++ Vsn, Masters);set_permanent_files(RelDir, _EVsn, Vsn, Masters, _Static) -> VsnDir = filename:join([RelDir, Vsn]), set_static_files(VsnDir, RelDir, Masters).do_remove_service(Vsn) -> %%% Very unconditionally remove the service. ServiceName = hd(string:tokens(atom_to_list(node()),"@")) ++ "_" ++ Vsn, erlsrv:remove_service(ServiceName).do_remove_release(Root, RelDir, Vsn, Releases) -> % Decide which libs should be removed case lists:keysearch(Vsn, #release.vsn, Releases) of {value, #release{status = permanent}} -> {error, {permanent, Vsn}}; {value, #release{libs = RemoveLibs, vsn = Vsn, erts_vsn = EVsn}} -> case os:type() of {win32, nt} -> do_remove_service(Vsn); _ -> ok end, NewReleases = lists:keydelete(Vsn, #release.vsn, Releases), RemoveThese = lists:foldl(fun(#release{libs = Libs}, Remove) -> diff_dir(Remove, Libs) end, RemoveLibs, NewReleases),
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -