diff options
Diffstat (limited to 'system')
-rw-r--r-- | system/doc/design_principles/release_handling.xml | 44 | ||||
-rw-r--r-- | system/doc/design_principles/release_structure.xml | 20 | ||||
-rw-r--r-- | system/doc/system_principles/create_target.xmlsrc | 295 |
3 files changed, 73 insertions, 286 deletions
diff --git a/system/doc/design_principles/release_handling.xml b/system/doc/design_principles/release_handling.xml index 8ed36f3c56..4378b6599c 100644 --- a/system/doc/design_principles/release_handling.xml +++ b/system/doc/design_principles/release_handling.xml @@ -178,13 +178,13 @@ <marker id="instr"></marker> <title>Release Handling Instructions</title> <p>OTP supports a set of <em>release handling instructions</em> - that is used when creating <c>.appup</c> files. The release + that are used when creating <c>.appup</c> files. The release handler understands a subset of these, the <em>low-level</em> instructions. To make it easier for the user, there are also a number of <em>high-level</em> instructions, which are translated to low-level instructions by <c>systools:make_relup</c>.</p> <p>Here, some of the most frequently used instructions are - described. The complete list of instructions is found in + described. The complete list of instructions can be found in <c>appup(4)</c>.</p> <p>First, some definitions:</p> <taglist> @@ -239,9 +239,10 @@ <p><c>update</c> with argument <c>supervisor</c> is used when changing the start specification of a supervisor. See <seealso marker="appup_cookbook#sup">Appup Cookbook</seealso>.</p> - <p>The release handler finds the processes <em>using</em> a module - to update by traversing the supervision tree of each running - application and checking all the child specifications:</p> + <p>When a module is to be updated, the release handler finds + which processes that are <em>using</em> the module by + traversing the supervision tree of each running application + and checking all the child specifications:</p> <code type="none"> {Id, StartFunc, Restart, Shutdown, Type, Modules}</code> <p>A process is using a module if the name is listed in @@ -265,8 +266,8 @@ <p>The instruction loads the module and is absolutely necessary when running Erlang in embedded mode. It is not strictly required when running Erlang in interactive (default) mode, - since the code server automatically searches for and loads - unloaded modules.</p> + since the code server then automatically searches for and + loads unloaded modules.</p> <p>The opposite of <c>add_module</c> is <c>delete_module</c> which unloads a module:</p> <code type="none"> @@ -294,7 +295,7 @@ the modules are unloaded using a number of <c>delete_module</c> instructions and then the application specification is unloaded from the application controller.</p> - <p>Instruction for removing an application:</p> + <p>Instruction for restarting an application:</p> <code type="none"> {restart_application, Application}</code> <p>Restarting an application means that the application is stopped @@ -331,17 +332,17 @@ of the emulator and the core applications. Then it shuts down the current emulator by calling <c>init:reboot()</c>, see <c>init(3)</c>. All processes are terminated gracefully and - the system can then be rebooted by the heart program, using - the temporary boot file. After the reboot, the rest of the - relup instructions are executed. This is done as a part of the - boot script.</p> + the system is rebooted by the heart program, using the + temporary boot file. After the reboot, the rest of the relup + instructions are executed. This is done as a part of the + temporary boot script.</p> <p>An info report is written when the upgrade is completed. To programatically find out if the upgrade is complete, - call <c>release_handler:which_releases/0</c> and check if the - expected release has status <c>current</c>.</p> - <p>The new version must be made permanent when the new emulator - is up and running. Otherwise, the old version will be used in - case of a new system reboot.</p> + call <c>release_handler:which_releases(current)</c> and check + if it returns the expected (i.e. the new) release.</p> + <p>The new release version must be made permanent when the new + emulator is up and running. Otherwise, the old version will be + used in case of a new system reboot.</p> <p>On UNIX, the release handler tells the heart program which command to use to reboot the system. Note that the environment variable <c>HEART_COMMAND</c>, normally used by the heart @@ -362,8 +363,8 @@ a relup script, and it shall always be placed at the end. If the relup is generated by <c>systools:make_relup/3,4</c> this is automatically ensured.</p> - <p>When the release handler encounters the instruction, it shuts down - the emulator by calling <c>init:reboot()</c>, see + <p>When the release handler encounters the instruction, it shuts + down the emulator by calling <c>init:reboot()</c>, see <c>init(3)</c>. All processes are terminated gracefully and the system can then be rebooted by the heart program using the new release version. No more upgrade instruction will be @@ -581,8 +582,8 @@ release_handler:remove_release(Vsn) => ok</code> [].</code> <p>2) Start the system as a simple target system. Note that in reality, it should be started as an embedded system. However, - using <c>erl</c> with the correct boot script and <c>.config</c> - file is enough for illustration purposes:</p> + using <c>erl</c> with the correct boot script and config file is + enough for illustration purposes:</p> <pre> % <input>cd $ROOT</input> % <input>bin/erl -boot $ROOT/releases/A/start -config $ROOT/releases/A/sys</input> @@ -617,6 +618,7 @@ lib/ch_app-2/ebin/ch3.beam releases/B/start.boot releases/B/relup releases/B/sys.config +releases/B/ch_rel-2.rel releases/ch_rel-2.rel</code> <p>4) Copy the release package <c>ch_rel-2.tar.gz</c> to the <c>$ROOT/releases</c> directory.</p> diff --git a/system/doc/design_principles/release_structure.xml b/system/doc/design_principles/release_structure.xml index 2e1daa611a..8aea0e1a10 100644 --- a/system/doc/design_principles/release_structure.xml +++ b/system/doc/design_principles/release_structure.xml @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>2003</year><year>2009</year> + <year>2003</year><year>2011</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -61,12 +61,14 @@ {ApplicationN, AppVsnN}]}.</code> <p>The file must be named <c>Rel.rel</c>, where <c>Rel</c> is a unique name.</p> - <p><c>Name</c>, <c>Vsn</c> and <c>Evsn</c> are strings.</p> + <p><c>Name</c>, <c>Vsn</c> and <c>EVsn</c> are strings.</p> <p>Each <c>Application</c> (atom) and <c>AppVsn</c> (string) is the name and version of an application included in the release. - Note the the minimal release based on Erlang/OTP consists of + Note that the minimal release based on Erlang/OTP consists of the <c>kernel</c> and <c>stdlib</c> applications, so these applications must be included in the list.</p> + <p>If the release is to be upgraded, it must also include + the <c>sasl</c> application.</p> <marker id="ch_rel"></marker> <p>Example: We want to make a release of <c>ch_app</c> from the <seealso marker="applications#ch_app">Applications</seealso> @@ -173,6 +175,7 @@ lib/ch_app-1/ebin/ch_app.beam lib/ch_app-1/ebin/ch_sup.beam lib/ch_app-1/ebin/ch3.beam releases/A/start.boot +releases/A/ch_rel-1.rel releases/ch_rel-1.rel</pre> <p>Note that a new boot script was generated, without the <c>local</c> option set, before the release package was made. @@ -180,6 +183,17 @@ releases/ch_rel-1.rel</pre> under <c>lib</c>. Also, we do not know where the release package will be installed, so we do not want any hardcoded absolute paths in the boot script here.</p> + <p>The release resource file <c>mysystem.rel</c> is duplicated in + the tar file. Originally, this file was only stored in + the <c>releases</c> directory in order to make it possible for + the <c>release_handler</c> to extract this file + separately. After unpacking the tar file, <c>release_handler</c> + would automatically copy the file + to <c>releases/FIRST</c>. However, sometimes the tar file is + unpacked without involving the <c>release_handler</c> (e.g. when + unpacking the first target system) and therefore the file is now + instead duplicated in the tar file so no manual copying is + necessary.</p> <p>If a <c>relup</c> file and/or a system configuration file called <c>sys.config</c> is found, these files are included in the release package as well. See diff --git a/system/doc/system_principles/create_target.xmlsrc b/system/doc/system_principles/create_target.xmlsrc index 1564423e00..bc2a76db47 100644 --- a/system/doc/system_principles/create_target.xmlsrc +++ b/system/doc/system_principles/create_target.xmlsrc @@ -44,9 +44,9 @@ may be irrelevant for the purpose in question. Thus, there is a need to be able to create a new system based on a given Erlang/OTP system, where dispensable applications are removed, - and a set of new applications that are included in the new - system. Documentation and source code is irrelevant and is - therefore not included in the new system.</p> + and a set of new applications are included. Documentation and + source code is irrelevant and is therefore not included in the + new system.</p> <p>This chapter is about creating such a system, which we call a <em>target system</em>.</p> <p>In the following sections we consider creating target systems with @@ -63,10 +63,11 @@ </list> <p>We only consider the case when Erlang/OTP is running on a UNIX system.</p> - <p>There is an example Erlang module <c>target_system.erl</c> that - contains functions for creating and installing a target system. - That module is used in the examples below. The source code of - the module is listed at the end of this chapter.</p> + <p>In the <c>sasl</c> application there is an example Erlang + module <c>target_system.erl</c> that contains functions for + creating and installing a target system. This module is used in + the examples below, and the source code of the module is listed + at the end of this chapter.</p> </section> <section> @@ -117,28 +118,41 @@ os> <input>erl -pa /home/user/target_system/myapps/pea-1.0/ebin</input></pre> <code type="none"> erts-5.1/bin/ releases/FIRST/start.boot +releases/FIRST/mysystem.rel releases/mysystem.rel lib/kernel-2.7/ lib/stdlib-1.10/ lib/sasl-1.9.3/ lib/pea-1.0/ </code> <p>The file <c>releases/FIRST/start.boot</c> is a copy of our - <c>mysystem.boot</c>, and a copy of the original - <c>mysystem.rel</c> has been put in the <c>releases</c> - directory.</p> + <c>mysystem.boot</c></p> + <p>The release resource file <c>mysystem.rel</c> is duplicated + in the tar file. Originally, this file was only stored in + the <c>releases</c> directory in order to make it possible + for the <c>release_handler</c> to extract this file + separately. After unpacking the tar + file, <c>release_handler</c> would automatically copy the + file to <c>releases/FIRST</c>. However, sometimes the tar + file is unpacked without involving + the <c>release_handler</c> (e.g. when unpacking the first + target system) and therefore the file is now instead + duplicated in the tar file so no manual copying is + necessary.</p> </item> <item>Creates the temporary directory <c>tmp</c> and extracts the tar file <c>mysystem.tar.gz</c> into that directory. </item> <item>Deletes the <c>erl</c> and <c>start</c> files from - <c>tmp/erts-5.1/bin</c>. XXX Why.</item> + <c>tmp/erts-5.1/bin</c>. These files will be created again from + source when installing the release.</item> <item>Creates the directory <c>tmp/bin</c>.</item> - <item>Copies the previously creates file <c>plain.boot</c> to + <item>Copies the previously created file <c>plain.boot</c> to <c>tmp/bin/start.boot</c>.</item> <item>Copies the files <c>epmd</c>, <c>run_erl</c>, and <c>to_erl</c> from the directory <c>tmp/erts-5.1/bin</c> to the directory <c>tmp/bin</c>.</item> - <item>Creates the file <c>tmp/releases/start_erl.data</c> with the - contents "5.1 FIRST". + <item>Creates the file <c>tmp/releases/start_erl.data</c> with + the contents "5.1 FIRST". This file is to be passed as data + file to the <c>start_erl</c> script. </item> <item>Recreates the file <c>mysystem.tar.gz</c> from the directories in the directory <c>tmp</c>, and removes <c>tmp</c>.</item> @@ -210,7 +224,7 @@ os> <input>/usr/local/erl-target/bin/erl -boot /usr/local/erl-target/releases/FI file of the release version found (<c>"releases/FIRST/start.boot"</c>).</p> <p><c>start_erl</c> also assumes that there is <c>sys.config</c> in - release version directory (<c>"releases/FIRST/sys.config</c>). That + release version directory (<c>"releases/FIRST/sys.config"</c>). That is the topic of the next section (see below).</p> <p>The <c>start_erl</c> shell script should normally not be altered by the user.</p> @@ -222,7 +236,7 @@ os> <input>/usr/local/erl-target/bin/erl -boot /usr/local/erl-target/releases/FI <c>sys.config</c> in the release version directory (<c>"releases/FIRST/sys.config"</c>). If there is no such a file, the system start will fail. Hence such a file has to - added as well.</p> + be added as well.</p> <p></p> <p>If you have system configuration data that are neither file location dependent nor site dependent, it may be convenient to @@ -245,252 +259,9 @@ os> <input>/usr/local/erl-target/bin/erl -boot /usr/local/erl-target/releases/FI <section> <title>Listing of target_system.erl</title> - <code type="none"><![CDATA[ --module(target_system). --include_lib("kernel/include/file.hrl"). --export([create/1, install/2]). --define(BUFSIZE, 8192). + <p>This module can also be found in the <c>examples</c> directory + of the <c>sasl</c> application.</p> + <codeinclude file="../../../lib/sasl/examples/src/target_system.erl" tag="%module" type="erl"></codeinclude> -%% Note: RelFileName below is the *stem* without trailing .rel, -%% .script etc. -%% - -%% create(RelFileName) -%% -create(RelFileName) -> - RelFile = RelFileName ++ ".rel", - io:fwrite("Reading file: \"~s\" ...~n", [RelFile]), - {ok, [RelSpec]} = file:consult(RelFile), - io:fwrite("Creating file: \"~s\" from \"~s\" ...~n", - ["plain.rel", RelFile]), - {release, - {RelName, RelVsn}, - {erts, ErtsVsn}, - AppVsns} = RelSpec, - PlainRelSpec = {release, - {RelName, RelVsn}, - {erts, ErtsVsn}, - lists:filter(fun({kernel, _}) -> - true; - ({stdlib, _}) -> - true; - (_) -> - false - end, AppVsns) - }, - {ok, Fd} = file:open("plain.rel", [write]), - io:fwrite(Fd, "~p.~n", [PlainRelSpec]), - file:close(Fd), - - io:fwrite("Making \"plain.script\" and \"plain.boot\" files ...~n"), - make_script("plain"), - - io:fwrite("Making \"~s.script\" and \"~s.boot\" files ...~n", - [RelFileName, RelFileName]), - make_script(RelFileName), - - TarFileName = io_lib:fwrite("~s.tar.gz", [RelFileName]), - io:fwrite("Creating tar file \"~s\" ...~n", [TarFileName]), - make_tar(RelFileName), - - io:fwrite("Creating directory \"tmp\" ...~n"), - file:make_dir("tmp"), - - io:fwrite("Extracting \"~s\" into directory \"tmp\" ...~n", [TarFileName]), - extract_tar(TarFileName, "tmp"), - - TmpBinDir = filename:join(["tmp", "bin"]), - ErtsBinDir = filename:join(["tmp", "erts-" ++ ErtsVsn, "bin"]), - io:fwrite("Deleting \"erl\" and \"start\" in directory \"~s\" ...~n", - [ErtsBinDir]), - file:delete(filename:join([ErtsBinDir, "erl"])), - file:delete(filename:join([ErtsBinDir, "start"])), - - io:fwrite("Creating temporary directory \"~s\" ...~n", [TmpBinDir]), - file:make_dir(TmpBinDir), - - io:fwrite("Copying file \"plain.boot\" to \"~s\" ...~n", - [filename:join([TmpBinDir, "start.boot"])]), - copy_file("plain.boot", filename:join([TmpBinDir, "start.boot"])), - - io:fwrite("Copying files \"epmd\", \"run_erl\" and \"to_erl\" from \n" - "\"~s\" to \"~s\" ...~n", - [ErtsBinDir, TmpBinDir]), - copy_file(filename:join([ErtsBinDir, "epmd"]), - filename:join([TmpBinDir, "epmd"]), [preserve]), - copy_file(filename:join([ErtsBinDir, "run_erl"]), - filename:join([TmpBinDir, "run_erl"]), [preserve]), - copy_file(filename:join([ErtsBinDir, "to_erl"]), - filename:join([TmpBinDir, "to_erl"]), [preserve]), - - StartErlDataFile = filename:join(["tmp", "releases", "start_erl.data"]), - io:fwrite("Creating \"~s\" ...~n", [StartErlDataFile]), - StartErlData = io_lib:fwrite("~s ~s~n", [ErtsVsn, RelVsn]), - write_file(StartErlDataFile, StartErlData), - - io:fwrite("Recreating tar file \"~s\" from contents in directory " - "\"tmp\" ...~n", [TarFileName]), - {ok, Tar} = erl_tar:open(TarFileName, [write, compressed]), - {ok, Cwd} = file:get_cwd(), - file:set_cwd("tmp"), - erl_tar:add(Tar, "bin", []), - erl_tar:add(Tar, "erts-" ++ ErtsVsn, []), - erl_tar:add(Tar, "releases", []), - erl_tar:add(Tar, "lib", []), - erl_tar:close(Tar), - file:set_cwd(Cwd), - io:fwrite("Removing directory \"tmp\" ...~n"), - remove_dir_tree("tmp"), - ok. - - -install(RelFileName, RootDir) -> - TarFile = RelFileName ++ ".tar.gz", - io:fwrite("Extracting ~s ...~n", [TarFile]), - extract_tar(TarFile, RootDir), - StartErlDataFile = filename:join([RootDir, "releases", "start_erl.data"]), - {ok, StartErlData} = read_txt_file(StartErlDataFile), - [ErlVsn, RelVsn| _] = string:tokens(StartErlData, " \n"), - ErtsBinDir = filename:join([RootDir, "erts-" ++ ErlVsn, "bin"]), - BinDir = filename:join([RootDir, "bin"]), - io:fwrite("Substituting in erl.src, start.src and start_erl.src to\n" - "form erl, start and start_erl ...\n"), - subst_src_scripts(["erl", "start", "start_erl"], ErtsBinDir, BinDir, - [{"FINAL_ROOTDIR", RootDir}, {"EMU", "beam"}], - [preserve]), - io:fwrite("Creating the RELEASES file ...\n"), - create_RELEASES(RootDir, - filename:join([RootDir, "releases", RelFileName])). - -%% LOCALS - -%% make_script(RelFileName) -%% -make_script(RelFileName) -> - Opts = [no_module_tests], - systools:make_script(RelFileName, Opts). - -%% make_tar(RelFileName) -%% -make_tar(RelFileName) -> - RootDir = code:root_dir(), - systools:make_tar(RelFileName, [{erts, RootDir}]). - -%% extract_tar(TarFile, DestDir) -%% -extract_tar(TarFile, DestDir) -> - erl_tar:extract(TarFile, [{cwd, DestDir}, compressed]). - -create_RELEASES(DestDir, RelFileName) -> - release_handler:create_RELEASES(DestDir, RelFileName ++ ".rel"). - -subst_src_scripts(Scripts, SrcDir, DestDir, Vars, Opts) -> - lists:foreach(fun(Script) -> - subst_src_script(Script, SrcDir, DestDir, - Vars, Opts) - end, Scripts). - -subst_src_script(Script, SrcDir, DestDir, Vars, Opts) -> - subst_file(filename:join([SrcDir, Script ++ ".src"]), - filename:join([DestDir, Script]), - Vars, Opts). - -subst_file(Src, Dest, Vars, Opts) -> - {ok, Conts} = read_txt_file(Src), - NConts = subst(Conts, Vars), - write_file(Dest, NConts), - case lists:member(preserve, Opts) of - true -> - {ok, FileInfo} = file:read_file_info(Src), - file:write_file_info(Dest, FileInfo); - false -> - ok - end. - -%% subst(Str, Vars) -%% Vars = [{Var, Val}] -%% Var = Val = string() -%% Substitute all occurrences of %Var% for Val in Str, using the list -%% of variables in Vars. -%% -subst(Str, Vars) -> - subst(Str, Vars, []). - -subst([$%, C| Rest], Vars, Result) when $A =< C, C =< $Z -> - subst_var([C| Rest], Vars, Result, []); -subst([$%, C| Rest], Vars, Result) when $a =< C, C =< $z -> - subst_var([C| Rest], Vars, Result, []); -subst([$%, C| Rest], Vars, Result) when C == $_ -> - subst_var([C| Rest], Vars, Result, []); -subst([C| Rest], Vars, Result) -> - subst(Rest, Vars, [C| Result]); -subst([], _Vars, Result) -> - lists:reverse(Result). - -subst_var([$%| Rest], Vars, Result, VarAcc) -> - Key = lists:reverse(VarAcc), - case lists:keysearch(Key, 1, Vars) of - {value, {Key, Value}} -> - subst(Rest, Vars, lists:reverse(Value, Result)); - false -> - subst(Rest, Vars, [$%| VarAcc ++ [$%| Result]]) - end; -subst_var([C| Rest], Vars, Result, VarAcc) -> - subst_var(Rest, Vars, Result, [C| VarAcc]); -subst_var([], Vars, Result, VarAcc) -> - subst([], Vars, [VarAcc ++ [$%| Result]]). - -copy_file(Src, Dest) -> - copy_file(Src, Dest, []). - -copy_file(Src, Dest, Opts) -> - {ok, InFd} = file:open(Src, [raw, binary, read]), - {ok, OutFd} = file:open(Dest, [raw, binary, write]), - do_copy_file(InFd, OutFd), - file:close(InFd), - file:close(OutFd), - case lists:member(preserve, Opts) of - true -> - {ok, FileInfo} = file:read_file_info(Src), - file:write_file_info(Dest, FileInfo); - false -> - ok - end. - -do_copy_file(InFd, OutFd) -> - case file:read(InFd, ?BUFSIZE) of - {ok, Bin} -> - file:write(OutFd, Bin), - do_copy_file(InFd, OutFd); - eof -> - ok - end. - -write_file(FName, Conts) -> - {ok, Fd} = file:open(FName, [write]), - file:write(Fd, Conts), - file:close(Fd). - -read_txt_file(File) -> - {ok, Bin} = file:read_file(File), - {ok, binary_to_list(Bin)}. - -remove_dir_tree(Dir) -> - remove_all_files(".", [Dir]). - -remove_all_files(Dir, Files) -> - lists:foreach(fun(File) -> - FilePath = filename:join([Dir, File]), - {ok, FileInfo} = file:read_file_info(FilePath), - case FileInfo#file_info.type of - directory -> - {ok, DirFiles} = file:list_dir(FilePath), - remove_all_files(FilePath, DirFiles), - file:del_dir(FilePath); - _ -> - file:delete(FilePath) - end - end, Files). - ]]></code> </section> </chapter> |