diff options
-rw-r--r-- | priv/templates/builtin_hook_status | 3 | ||||
-rwxr-xr-x | priv/templates/extended_bin | 28 | ||||
-rw-r--r-- | src/rlx_prv_assembler.erl | 18 | ||||
-rw-r--r-- | test/rlx_extended_bin_SUITE.erl | 79 |
4 files changed, 114 insertions, 14 deletions
diff --git a/priv/templates/builtin_hook_status b/priv/templates/builtin_hook_status new file mode 100644 index 0000000..e5dd792 --- /dev/null +++ b/priv/templates/builtin_hook_status @@ -0,0 +1,3 @@ +#!/bin/bash + +echo $(relx_nodetool eval "application:which_applications().") diff --git a/priv/templates/extended_bin b/priv/templates/extended_bin index f05fb31..ed68748 100755 --- a/priv/templates/extended_bin +++ b/priv/templates/extended_bin @@ -40,12 +40,13 @@ ERL_OPTS="{{ erl_opts }}" RUNNER_LOG_DIR="${RUNNER_LOG_DIR:-$RELEASE_ROOT_DIR/log}" # start/stop/install/upgrade pre/post hooks -PRE_START_HOOKS="{{ pre_start_hooks }}" -POST_START_HOOKS="{{ post_start_hooks }}" -PRE_STOP_HOOKS="{{ pre_stop_hooks }}" -POST_STOP_HOOKS="{{ post_stop_hooks }}" -PRE_INSTALL_UPGRADE_HOOKS="{{ pre_install_upgrade_hooks }}" -POST_INSTALL_UPGRADE_HOOKS="{{ post_install_upgrade_hooks }}" +PRE_START_HOOKS="{{{ pre_start_hooks }}}" +POST_START_HOOKS="{{{ post_start_hooks }}}" +PRE_STOP_HOOKS="{{{ pre_stop_hooks }}}" +POST_STOP_HOOKS="{{{ post_stop_hooks }}}" +PRE_INSTALL_UPGRADE_HOOKS="{{{ pre_install_upgrade_hooks }}}" +POST_INSTALL_UPGRADE_HOOKS="{{{ post_install_upgrade_hooks }}}" +STATUS_HOOK="{{{ status_hook }}}" relx_usage() { command="$1" @@ -101,8 +102,12 @@ relx_usage() { echo " --no-permanent Install release package VERSION but" echo " don't make it permanent" ;; + status) + echo "Usage: $REL_NAME status" + echo "Obtains node status information." + ;; *) - echo "Usage: $REL_NAME {start|start_boot <file>|foreground|stop|restart|reboot|pid|ping|console|console_clean|console_boot <file>|attach|remote_console|upgrade|downgrade|install|uninstall|versions|escript|rpc|rpcterms|eval}" + echo "Usage: $REL_NAME {start|start_boot <file>|foreground|stop|restart|reboot|pid|ping|console|console_clean|console_boot <file>|attach|remote_console|upgrade|downgrade|install|uninstall|versions|escript|rpc|rpcterms|eval|status}" ;; esac } @@ -584,6 +589,15 @@ case "$1" in shift relx_nodetool "eval" $@ ;; + status) + # Make sure a node IS running + if ! relx_nodetool "ping" > /dev/null; then + echo "Node is not running!" + exit 1 + fi + + [ "$SCRIPT_DIR/$STATUS_HOOK" ] && . "$SCRIPT_DIR/$STATUS_HOOK" $@ + ;; help) if [ -z "$2" ]; then relx_usage diff --git a/src/rlx_prv_assembler.erl b/src/rlx_prv_assembler.erl index f40a0c2..278756d 100644 --- a/src/rlx_prv_assembler.erl +++ b/src/rlx_prv_assembler.erl @@ -398,7 +398,8 @@ write_bin_file(State, Release, OutputDir, RelDir) -> include_nodetool(BinDir), Hooks = expand_hooks(BinDir, rlx_state:get(State, - extended_start_script_hooks, []), + extended_start_script_hooks, + [{status, [builtin_status]}]), State), extended_bin_file_contents(OsFamily, RelName, RelVsn, rlx_release:erts(Release), ErlOpts, @@ -475,6 +476,8 @@ validate_hook(post_start, wait_for_vm_start) -> true; validate_hook(post_start, {wait_for_process, _}) -> true; %% custom hooks are allowed in all phases validate_hook(_Phase, {custom, _}) -> true; +%% as well as status hooks +validate_hook(status, _) -> true; %% deny all others validate_hook(_, _) -> false. @@ -482,7 +485,8 @@ hook_filename({custom, CustomScript}) -> CustomScript; hook_filename(pid) -> "hooks/builtin/pid"; hook_filename({pid, _}) -> "hooks/builtin/pid"; hook_filename(wait_for_vm_start) -> "hooks/builtin/wait_for_vm_start"; -hook_filename({wait_for_process, _}) -> "hooks/builtin/wait_for_process". +hook_filename({wait_for_process, _}) -> "hooks/builtin/wait_for_process"; +hook_filename(builtin_status) -> "hooks/builtin/status". hook_invocation({custom, CustomScript}) -> CustomScript; %% the pid builtin hook with no arguments writes to pid file @@ -496,13 +500,15 @@ hook_invocation({wait_for_process, Name}) -> %% wait_for_process takes an atom as argument %% which is the process name to wait for string:join(["hooks/builtin/wait_for_process", - atom_to_list(Name)], "|"). + atom_to_list(Name)], "|"); +hook_invocation(builtin_status) -> "hooks/builtin/status". hook_template({custom, _}) -> custom; hook_template(pid) -> builtin_hook_pid; hook_template({pid, _}) -> builtin_hook_pid; hook_template(wait_for_vm_start) -> builtin_hook_wait_for_vm_start; -hook_template({wait_for_process, _}) -> builtin_hook_wait_for_process. +hook_template({wait_for_process, _}) -> builtin_hook_wait_for_process; +hook_template(builtin_status) -> builtin_hook_status. %% custom hooks are not rendered, they should %% be copied by the release overlays @@ -795,6 +801,7 @@ extended_bin_file_contents(OsFamily, RelName, RelVsn, ErtsVsn, ErlOpts, Hooks) - Hooks, []), " "), PostInstallUpgradeHooks = string:join(proplists:get_value(post_install_upgrade, Hooks, []), " "), + StatusHook = string:join(proplists:get_value(status, Hooks, []), " "), render(Template, [{rel_name, RelName}, {rel_vsn, RelVsn}, {erts_vsn, ErtsVsn}, {erl_opts, ErlOpts}, {pre_start_hooks, PreStartHooks}, @@ -802,7 +809,8 @@ extended_bin_file_contents(OsFamily, RelName, RelVsn, ErtsVsn, ErlOpts, Hooks) - {pre_stop_hooks, PreStopHooks}, {post_stop_hooks, PostStopHooks}, {pre_install_upgrade_hooks, PreInstallUpgradeHooks}, - {post_install_upgrade_hooks, PostInstallUpgradeHooks}]). + {post_install_upgrade_hooks, PostInstallUpgradeHooks}, + {status_hook, StatusHook}]). erl_ini(OutputDir, ErtsVsn) -> ErtsDirName = string:concat("erts-", ErtsVsn), diff --git a/test/rlx_extended_bin_SUITE.erl b/test/rlx_extended_bin_SUITE.erl index c3f534a..c049209 100644 --- a/test/rlx_extended_bin_SUITE.erl +++ b/test/rlx_extended_bin_SUITE.erl @@ -41,7 +41,8 @@ builtin_wait_for_vm_start_script_hook/1, builtin_pid_start_script_hook/1, builtin_wait_for_process_start_script_hook/1, - mixed_custom_and_builtin_start_script_hooks/1]). + mixed_custom_and_builtin_start_script_hooks/1, + builtin_status_script/1, custom_status_script/1]). -include_lib("common_test/include/ct.hrl"). -include_lib("eunit/include/eunit.hrl"). @@ -70,7 +71,8 @@ all() -> remote_console, replace_os_vars, replace_os_vars_multi_node, replace_os_vars_included_config, replace_os_vars_custom_location, replace_os_vars_dev_mode, replace_os_vars_twice, custom_start_script_hooks, builtin_wait_for_vm_start_script_hook, builtin_pid_start_script_hook, - builtin_wait_for_process_start_script_hook, mixed_custom_and_builtin_start_script_hooks]. + builtin_wait_for_process_start_script_hook, mixed_custom_and_builtin_start_script_hooks, + builtin_status_script, custom_status_script]. ping(Config) -> LibDir1 = proplists:get_value(lib1, Config), @@ -1318,6 +1320,79 @@ mixed_custom_and_builtin_start_script_hooks(Config) -> {pre_stop, foo, _, foo}, {post_stop, foo, _, foo}]} = file:consult(filename:join([OutputDir, "foo", "test"])). +builtin_status_script(Config) -> + LibDir1 = proplists:get_value(lib1, Config), + + rlx_test_utils:create_full_app(LibDir1, "goal_app", "0.0.1", + [stdlib,kernel], []), + + OutputDir = filename:join([proplists:get_value(priv_dir, Config), + rlx_test_utils:create_random_name("relx-output")]), + + 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} + ]), + + {ok, _State} = relx:do(foo, undefined, [], [LibDir1], 3, + OutputDir, ConfigFile), + os:cmd(filename:join([OutputDir, "foo", "bin", "foo start"])), + timer:sleep(2000), + {ok, "pong"} = sh(filename:join([OutputDir, "foo", "bin", "foo ping"])), + %% write the status to a file + {ok, StatusStr} = sh(filename:join([OutputDir, "foo", "bin", "foo status"])), + ec_file:write(filename:join([OutputDir, "status.txt"]), + StatusStr ++ ".\n"), + os:cmd(filename:join([OutputDir, "foo", "bin", "foo stop"])), + {ok, [Status]} = file:consult(filename:join([OutputDir, "status.txt"])), + Apps = lists:map(fun({App, _, _}) -> App end, Status), + {ok, [goal_app, kernel, stdlib] = lists:sort(Apps)}. + +custom_status_script(Config) -> + LibDir1 = proplists:get_value(lib1, Config), + + rlx_test_utils:create_full_app(LibDir1, "goal_app", "0.0.1", + [stdlib,kernel], []), + + OutputDir = filename:join([proplists:get_value(priv_dir, Config), + rlx_test_utils:create_random_name("relx-output")]), + + 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, [ + {status, [ + {custom, "hooks/status"} + ]} + ]}, + {overlay, [ + {copy, "./status", "bin/hooks/status"}]} + ]), + + %% write the hook status script + ok = file:write_file(filename:join([LibDir1, "./status"]), + "#!/bin/bash\n# $*\necho \\{status, $REL_NAME, \\'$NAME\\', $COOKIE\\}."), + + {ok, _State} = relx:do(foo, undefined, [], [LibDir1], 3, + OutputDir, ConfigFile), + os:cmd(filename:join([OutputDir, "foo", "bin", "foo start"])), + timer:sleep(2000), + {ok, "pong"} = sh(filename:join([OutputDir, "foo", "bin", "foo ping"])), + %% write the status to a file + {ok, StatusStr} = sh(filename:join([OutputDir, "foo", "bin", "foo status"])), + ec_file:write(filename:join([OutputDir, "status.txt"]), StatusStr), + os:cmd(filename:join([OutputDir, "foo", "bin", "foo stop"])), + {ok, [Status]} = file:consult(filename:join([OutputDir, "status.txt"])), + {ok, {status, foo, _, foo} = Status}. + %%%=================================================================== %%% Helper Functions %%%=================================================================== |