Skip to content

Commit

Permalink
Add support for new relx directive that provides start/stop script hooks
Browse files Browse the repository at this point in the history
New 'extended_start_script_hooks' directive that allows the
developer to define four different hook scripts to be invoked
at pre/post start/stop phases.
The hook scripts are invoked with the 'source' command, therefore
they have access to all the variables in the start script.
  • Loading branch information
lrascao committed Aug 24, 2016
1 parent 88db273 commit 09838d5
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 9 deletions.
27 changes: 22 additions & 5 deletions priv/templates/extended_bin
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@ REL_DIR="$RELEASE_ROOT_DIR/releases/$REL_VSN"
ERL_OPTS="{{ erl_opts }}"
RUNNER_LOG_DIR="${RUNNER_LOG_DIR:-$RELEASE_ROOT_DIR/log}"

# start/stop pre/post hooks
PRE_START_HOOK="{{ pre_start_hook }}"
POST_START_HOOK="{{ post_start_hook }}"
PRE_STOP_HOOK="{{ pre_stop_hook }}"
POST_STOP_HOOK="{{ post_stop_hook }}"

find_erts_dir() {
__erts_dir="$RELEASE_ROOT_DIR/erts-$ERTS_VSN"
if [ -d "$__erts_dir" ]; then
Expand Down Expand Up @@ -234,11 +240,15 @@ case "$1" in

mkdir -p "$PIPE_DIR"

[ "$PRE_START_HOOK" ] && . "$PRE_START_HOOK"
"$BINDIR/run_erl" -daemon "$PIPE_DIR" "$RUNNER_LOG_DIR" \
"$(relx_start_command)"
"$(relx_start_command)" &
[ "$POST_START_HOOK" ] && . "$POST_START_HOOK"
wait $!
;;

stop)
[ "$PRE_STOP_HOOK" ] && . "$PRE_STOP_HOOK"
# Wait for the node to completely stop...
PID="$(relx_get_pid)"
if ! relx_nodetool "stop"; then
Expand All @@ -248,6 +258,7 @@ case "$1" in
do
sleep 1
done
[ "$POST_STOP_HOOK" ] && . "$POST_STOP_HOOK"
;;

restart)
Expand Down Expand Up @@ -389,8 +400,11 @@ case "$1" in
echo "$RELEASE_ROOT_DIR"
logger -t "$REL_NAME[$$]" "Starting up"

# Start the VM
exec "$@" -- ${1+$ARGS}
# Start the VM, invoke pre/post hooks
[ "$PRE_START_HOOK" ] && . "$PRE_START_HOOK"
exec "$@" -- ${1+$ARGS} &
[ "$POST_START_HOOK" ] && . "$POST_START_HOOK"
wait $!
;;

foreground)
Expand Down Expand Up @@ -421,8 +435,11 @@ case "$1" in
echo "Exec: $@" -- ${1+$ARGS}
echo "Root: $ROOTDIR"

# Start the VM
exec "$@" -- ${1+$ARGS}
# Start the VM, invoke pre/post hooks
[ "$PRE_START_HOOK" ] && . "$PRE_START_HOOK"
exec "$@" -- ${1+$ARGS} &
[ "$POST_START_HOOK" ] && . "$POST_START_HOOK"
wait $!
;;
rpc)
# Make sure a node IS running
Expand Down
15 changes: 12 additions & 3 deletions src/rlx_prv_assembler.erl
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,10 @@ write_bin_file(State, Release, OutputDir, RelDir) ->
false ->
ok
end,
extended_bin_file_contents(OsFamily, RelName, RelVsn, rlx_release:erts(Release), ErlOpts)
Hooks = rlx_state:get(State, extended_start_script_hooks, []),
extended_bin_file_contents(OsFamily, RelName, RelVsn,
rlx_release:erts(Release), ErlOpts,
Hooks)
end,
%% We generate the start script by default, unless the user
%% tells us not too
Expand Down Expand Up @@ -613,13 +616,19 @@ bin_file_contents(OsFamily, RelName, RelVsn, ErtsVsn, ErlOpts) ->
render(Template, [{rel_name, RelName}, {rel_vsn, RelVsn},
{erts_vsn, ErtsVsn}, {erl_opts, ErlOpts}]).

extended_bin_file_contents(OsFamily, RelName, RelVsn, ErtsVsn, ErlOpts) ->
extended_bin_file_contents(OsFamily, RelName, RelVsn, ErtsVsn, ErlOpts, Hooks) ->
Template = case OsFamily of
unix -> extended_bin;
win32 -> extended_bin_windows
end,
PreStartHook = proplists:get_value(pre_start, Hooks, ""),
PostStartHook = proplists:get_value(post_start, Hooks, ""),
PreStopHook = proplists:get_value(pre_stop, Hooks, ""),
PostStopHook = proplists:get_value(post_stop, Hooks, ""),
render(Template, [{rel_name, RelName}, {rel_vsn, RelVsn},
{erts_vsn, ErtsVsn}, {erl_opts, ErlOpts}]).
{erts_vsn, ErtsVsn}, {erl_opts, ErlOpts},
{pre_start_hook, PreStartHook}, {post_start_hook, PostStartHook},
{pre_stop_hook, PreStopHook}, {post_stop_hook, PostStopHook}]).

erl_ini(OutputDir, ErtsVsn) ->
ErtsDirName = string:concat("erts-", ErtsVsn),
Expand Down
54 changes: 53 additions & 1 deletion test/rlx_release_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@
make_dev_mode_release/1,
make_config_script_release/1,
make_release_twice/1,
make_release_twice_dev_mode/1]).
make_release_twice_dev_mode/1,
make_release_start_script_hooks/1]).

-include_lib("common_test/include/ct.hrl").
-include_lib("eunit/include/eunit.hrl").
Expand Down Expand Up @@ -1036,6 +1037,57 @@ make_release_twice_dev_mode(Config) ->
?assert(lists:member({goal_app_2, "0.0.1"}, AppSpecs1)),
?assert(lists:member({lib_dep_1, "0.0.1", load}, AppSpecs1)).

make_release_start_script_hooks(Config) ->
LibDir1 = proplists:get_value(lib1, Config),

rlx_test_utils:create_app(LibDir1, "goal_app", "0.0.1", [stdlib,kernel], []),

ConfigFile = filename:join([LibDir1, "relx.config"]),
rlx_test_utils:write_config(ConfigFile,
[{release, {foo, "0.0.1"},
[goal_app]},
{lib_dirs, [filename:join(LibDir1, "*")]},
{generate_start_script, true},
{extended_start_script, true},
{extended_start_script_hooks, [
{pre_start, "./scripts/pre_start"},
{post_start, "./scripts/post_start"},
{pre_stop, "./scripts/pre_stop"},
{post_stop, "./scripts/post_stop"}
]},
{mkdir, "scripts"},
{overlay, [{copy, "./pre_start", "scripts/pre_start"},
{copy, "./post_start", "scripts/post_start"},
{copy, "./pre_stop", "scripts/pre_stop"},
{copy, "./post_stop", "scripts/post_stop"}]}
]),

%% write the hook scripts, each of them will write an erlang term to a file
%% that will later be consulted
ok = file:write_file(filename:join([LibDir1, "./pre_start"]),
"#!/bin/bash\n# $*\necho \\{pre_start, $REL_NAME, \\'$NAME\\', $COOKIE\\}. >> test"),
ok = file:write_file(filename:join([LibDir1, "./post_start"]),
"#!/bin/bash\n# $*\necho \\{post_start, $REL_NAME, \\'$NAME\\', $COOKIE\\}. >> test"),
ok = file:write_file(filename:join([LibDir1, "./pre_stop"]),
"#!/bin/bash\n# $*\necho \\{pre_stop, $REL_NAME, \\'$NAME\\', $COOKIE\\}. >> test"),
ok = file:write_file(filename:join([LibDir1, "./post_stop"]),
"#!/bin/bash\n# $*\necho \\{post_stop, $REL_NAME, \\'$NAME\\', $COOKIE\\}. >> test"),

OutputDir = filename:join([proplists:get_value(priv_dir, Config),
rlx_test_utils:create_random_name("relx-output")]),
{ok, _State} = relx:do(foo, undefined, [], [LibDir1], 3,
OutputDir, ConfigFile),
%% now start/stop the release to make sure the script hooks are really getting
%% executed
os:cmd(filename:join([OutputDir, "foo", "bin", "foo start"])),
timer:sleep(2000),
os:cmd(filename:join([OutputDir, "foo", "bin", "foo stop"])),
%% now check that the output file contains the expected format
{ok,[{pre_start, foo, _, foo},
{post_start, foo, _, foo},
{pre_stop, foo, _, foo},
{post_stop, foo, _, foo}]} = file:consult(filename:join([OutputDir, "foo", "test"])).

%%%===================================================================
%%% Helper Functions
%%%===================================================================

0 comments on commit 09838d5

Please sign in to comment.