Skip to content

Example: generating boot scripts from a running system

uwiger edited this page Jun 4, 2012 · 2 revisions

Example: generating boot scripts from a running system

In the following, we will look at how to interactively build an OTP system, and eventually derive from it a set of boot scripts and config files that we can boot from.

Initial system

In the test directory of setup, we find a config file to start playing with, and two versions of an example application: testapp-1 and testapp-2. Neither version actually does anything, but can be started. The setup.conf file looks like this:

%% -*- erlang -*-
RelDir = filename:join(CWD, "releases").
[
 {outdir, filename:join(RelDir, "1")},
 {root, CWD},
 {env, [{sasl, [{releases_dir, RelDir}]}
       ]},
 {apps,
  [kernel,
   stdlib,
   sasl,
   {testapp, "1", [snmp]}
  ]}
].

The variable CWD is predefined by setup and is bound to the directory name of the current config file. Here, we tell the release_handler that our releases directory will be somewhere other than in the OTP root. We provide one root - CWD - so that setup and systools can find the testapp application.

In our apps list, we name version "1" of testapp, and just for demonstration purposes, make snmp an included application. Note that for this to work, snmp must also be named as an included application in testapp.app (it is).

We can in fact build this system using the make target make test, and run it with make run_test


test: compile compile_test
        ./setup_gen test test/test.conf test/releases/1

run_test:
        erl -boot test/releases/1/start -config test/releases/1/sys

Interactively changing the running system

Once we have this system running, we can do some things to change it.

=PROGRESS REPORT==== 4-Jun-2012::14:02:35 ===
         application: testapp
          started_at: nonode@nohost
Eshell V5.9  (abort with ^G)
1> application:start(crypto).
ok
2> 
=PROGRESS REPORT==== 4-Jun-2012::14:35:05 ===
          supervisor: {local,crypto_sup}
             started: [{pid,<0.50.0>},
                       {name,crypto_server},
                       {mfargs,{crypto_server,start_link,[]}},
                       {restart_type,permanent},
                       {shutdown,2000},
                       {child_type,worker}]

=PROGRESS REPORT==== 4-Jun-2012::14:35:05 ===
         application: crypto
          started_at: nonode@nohost

2> setup:reload_app(testapp).
[testapp vsn "2"] soft upgrade from "1"
{ok,[]}

So now we have added one application (os_mon) and upgraded another (testapp). If this were a target system (and it's still running), we would like to ensure that the new set of applications start after a node restart. Another possibility is that we have been playing around, and are happy with the node as it looks right now, and simply want to save the setup, so we can restore it easily.

Saving the current setup

We do this with the function setup:keep_release(RelVsn).

3> setup:keep_release("2").
ok

This is where we can see why it was good to name the releases directory. Our new setup files will be put in setup/test/releases/2. The function will verify that this directory doesn't already exist. It then does the following:

  • Lists all loaded applications, and notes which are actually running

  • Checks included applications (if any)

  • Lists all the environment variables for all apps, and compares with what's in the corresponding .app files.

  • Generates a setup.conf file and calls setup_gen:run/1 to build .rel, .boot and .script files.

Starting the new release

We can now start the saved release just as any other:

$ erl -boot test/releases/2/start -config test/releases/2/sys
Erlang R15B (erts-5.9) [source] [64-bit] [smp:4:4] [async-threads:0] [hipe] [kernel-poll:false]


=PROGRESS REPORT==== 4-Jun-2012::14:37:08 ===
          supervisor: {local,sasl_safe_sup}
             started: [{pid,<0.39.0>},
                       {name,alarm_handler},
                       {mfargs,{alarm_handler,start_link,[]}},
                       {restart_type,permanent},
                       {shutdown,2000},
                       {child_type,worker}]

=PROGRESS REPORT==== 4-Jun-2012::14:37:08 ===
          supervisor: {local,sasl_safe_sup}
             started: [{pid,<0.40.0>},
                       {name,overload},
                       {mfargs,{overload,start_link,[]}},
                       {restart_type,permanent},
                       {shutdown,2000},
                       {child_type,worker}]

=PROGRESS REPORT==== 4-Jun-2012::14:37:08 ===
          supervisor: {local,sasl_sup}
             started: [{pid,<0.38.0>},
                       {name,sasl_safe_sup},
                       {mfargs,
                           {supervisor,start_link,
                               [{local,sasl_safe_sup},sasl,safe]}},
                       {restart_type,permanent},
                       {shutdown,infinity},
                       {child_type,supervisor}]

=PROGRESS REPORT==== 4-Jun-2012::14:37:08 ===
          supervisor: {local,sasl_sup}
             started: [{pid,<0.41.0>},
                       {name,release_handler},
                       {mfargs,{release_handler,start_link,[]}},
                       {restart_type,permanent},
                       {shutdown,2000},
                       {child_type,worker}]

=PROGRESS REPORT==== 4-Jun-2012::14:37:08 ===
         application: sasl
          started_at: nonode@nohost

=PROGRESS REPORT==== 4-Jun-2012::14:37:08 ===
         application: testapp
          started_at: nonode@nohost
Eshell V5.9  (abort with ^G)
1> application:which_applications().
[{testapp,[],"2"},
 {sasl,"SASL  CXC 138 11","2.2"},
 {crypto,"CRYPTO version 2","2.1"},
 {stdlib,"ERTS  CXC 138 10","1.18"},
 {kernel,"ERTS  CXC 138 10","2.15"}]

We can inspect the generated test/releases/2/setup.conf, and perhaps make changes or additions to it:

[{name,"test"},
 {apps,[{kernel,"2.15"},
        {crypto,"2.1"},
        {testapp,"2",[os_mon,snmp]},
        {sasl,"2.2"},
        {snmp,"4.21.4",load},
        {stdlib,"1.18"}]},
 {root,"/Users/uwiger/FL/git"},
 {root,"/Users/uwiger/FL/git/setup/test"},
 {env,[{sasl,[{releases_dir,"/Users/uwiger/FL/git/setup/test/releases"}]}]}].

Note how setup has figured out which roots to add (so-so - in this case, it didn't have to add the FL/git path), and noted that snmp was an included application, and therefore only needed to be loaded.

A tiny detail is that os_mon is listed as an included application. This is because it was so in the testapp.app file, and the OTP app upgrade script changed the included_applications key (wrongly, in my opinion). Setup should detect that os_mon wasn't loaded, even if OTP doesn't. I will work on that.