├── rebar.config ├── src ├── lyapp.app.src ├── lyapp_app.erl ├── lyapp_sup.erl └── lyapp_server.erl ├── test └── lyapp_test.erl └── rel ├── files ├── sys.config ├── vm.args ├── erl ├── start_erl.cmd ├── install_upgrade.escript ├── lyapp.cmd ├── nodetool └── lyapp └── reltool.config /rebar.config: -------------------------------------------------------------------------------- 1 | {sub_dirs, ["rel"]}. -------------------------------------------------------------------------------- /src/lyapp.app.src: -------------------------------------------------------------------------------- 1 | {application, lyapp, 2 | [ 3 | {description, ""}, 4 | {vsn, "1"}, 5 | {registered, []}, 6 | {applications, [ 7 | kernel, 8 | stdlib 9 | ]}, 10 | {mod, { lyapp_app, []}}, 11 | {env, []} 12 | ]}. 13 | -------------------------------------------------------------------------------- /test/lyapp_test.erl: -------------------------------------------------------------------------------- 1 | -module(lyapp_test). 2 | -ifdef(TEST). 3 | -include_lib("eunit/include/eunit.hrl"). 4 | -endif. 5 | 6 | -ifdef(TEST). 7 | 8 | my_test() -> 9 | ?assert(1 + 1 =:= 2). 10 | 11 | simple_test() -> 12 | ok = application:start(lyapp), 13 | ?assertNot(undefined == whereis(lyapp_sup)). 14 | 15 | -endif. 16 | 17 | -------------------------------------------------------------------------------- /rel/files/sys.config: -------------------------------------------------------------------------------- 1 | [ 2 | %% SASL config 3 | {sasl, [ 4 | {sasl_error_logger, {file, "log/sasl-error.log"}}, 5 | {errlog_type, error}, 6 | {error_logger_mf_dir, "log/sasl"}, % Log directory 7 | {error_logger_mf_maxbytes, 10485760}, % 10 MB max file size 8 | {error_logger_mf_maxfiles, 5} % 5 files max 9 | ]} 10 | ]. 11 | 12 | -------------------------------------------------------------------------------- /src/lyapp_app.erl: -------------------------------------------------------------------------------- 1 | -module(lyapp_app). 2 | 3 | -behaviour(application). 4 | 5 | %% Application callbacks 6 | -export([start/2, stop/1]). 7 | 8 | %% =================================================================== 9 | %% Application callbacks 10 | %% =================================================================== 11 | 12 | start(_StartType, _StartArgs) -> 13 | lyapp_sup:start_link(). 14 | 15 | stop(_State) -> 16 | ok. 17 | -------------------------------------------------------------------------------- /rel/files/vm.args: -------------------------------------------------------------------------------- 1 | ## Name of the node 2 | -name lyapp@127.0.0.1 3 | 4 | ## Cookie for distributed erlang 5 | -setcookie lyapp 6 | 7 | ## Heartbeat management; auto-restarts VM if it dies or becomes unresponsive 8 | ## (Disabled by default..use with caution!) 9 | ##-heart 10 | 11 | ## Enable kernel poll and a few async threads 12 | ##+K true 13 | ##+A 5 14 | 15 | ## Increase number of concurrent ports/sockets 16 | ##-env ERL_MAX_PORTS 4096 17 | 18 | ## Tweak GC to run more often 19 | ##-env ERL_FULLSWEEP_AFTER 10 20 | -------------------------------------------------------------------------------- /src/lyapp_sup.erl: -------------------------------------------------------------------------------- 1 | 2 | -module(lyapp_sup). 3 | 4 | -behaviour(supervisor). 5 | 6 | %% API 7 | -export([start_link/0]). 8 | 9 | %% Supervisor callbacks 10 | -export([init/1]). 11 | 12 | %% Helper macro for declaring children of supervisor 13 | -define(CHILD(I, Type), {I, {I, start_link, []}, permanent, 5000, Type, [I]}). 14 | 15 | %% =================================================================== 16 | %% API functions 17 | %% =================================================================== 18 | 19 | start_link() -> 20 | supervisor:start_link({local, ?MODULE}, ?MODULE, []). 21 | 22 | %% =================================================================== 23 | %% Supervisor callbacks 24 | %% =================================================================== 25 | 26 | init([]) -> 27 | {ok, { {one_for_one, 5, 10}, []} }. 28 | 29 | -------------------------------------------------------------------------------- /rel/files/erl: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | ## This script replaces the default "erl" in erts-VSN/bin. This is necessary 4 | ## as escript depends on erl and in turn, erl depends on having access to a 5 | ## bootscript (start.boot). Note that this script is ONLY invoked as a side-effect 6 | ## of running escript -- the embedded node bypasses erl and uses erlexec directly 7 | ## (as it should). 8 | ## 9 | ## Note that this script makes the assumption that there is a start_clean.boot 10 | ## file available in $ROOTDIR/release/VSN. 11 | 12 | # Determine the abspath of where this script is executing from. 13 | ERTS_BIN_DIR=$(cd ${0%/*} && pwd) 14 | 15 | # Now determine the root directory -- this script runs from erts-VSN/bin, 16 | # so we simply need to strip off two dirs from the end of the ERTS_BIN_DIR 17 | # path. 18 | ROOTDIR=${ERTS_BIN_DIR%/*/*} 19 | 20 | # Parse out release and erts info 21 | START_ERL=`cat $ROOTDIR/releases/start_erl.data` 22 | ERTS_VSN=${START_ERL% *} 23 | APP_VSN=${START_ERL#* } 24 | 25 | BINDIR=$ROOTDIR/erts-$ERTS_VSN/bin 26 | EMU=beam 27 | PROGNAME=`echo $0 | sed 's/.*\\///'` 28 | CMD="$BINDIR/erlexec" 29 | export EMU 30 | export ROOTDIR 31 | export BINDIR 32 | export PROGNAME 33 | 34 | exec $CMD -boot $ROOTDIR/releases/$APP_VSN/start_clean ${1+"$@"} 35 | -------------------------------------------------------------------------------- /rel/files/start_erl.cmd: -------------------------------------------------------------------------------- 1 | @setlocal 2 | 3 | @rem Parse arguments. erlsrv.exe prepends erl arguments prior to first ++. 4 | @rem Other args are position dependent. 5 | @set args="%*" 6 | @for /F "delims=++ tokens=1,2,3" %%I in (%args%) do @( 7 | @set erl_args=%%I 8 | @call :set_trim node_name %%J 9 | @call :set_trim node_root %%K 10 | ) 11 | 12 | @set releases_dir=%node_root%\releases 13 | 14 | @rem parse ERTS version and release version from start_erl.dat 15 | @for /F "tokens=1,2" %%I in (%releases_dir%\start_erl.data) do @( 16 | @call :set_trim erts_version %%I 17 | @call :set_trim release_version %%J 18 | ) 19 | 20 | @set erl_exe=%node_root%\erts-%erts_version%\bin\erl.exe 21 | @set boot_file=%releases_dir%\%release_version%\%node_name% 22 | 23 | @if exist %releases_dir%\%release_version%\sys.config ( 24 | @set app_config=%releases_dir%\%release_version%\sys.config 25 | ) else ( 26 | @set app_config=%node_root%\etc\app.config 27 | ) 28 | 29 | @if exist %releases_dir%\%release_version%\vm.args ( 30 | @set vm_args=%releases_dir%\%release_version%\vm.args 31 | ) else ( 32 | @set vm_args=%node_root%\etc\vm.args 33 | ) 34 | 35 | @%erl_exe% %erl_args% -boot %boot_file% -config %app_config% -args_file %vm_args% 36 | 37 | :set_trim 38 | @set %1=%2 39 | @goto :EOF 40 | -------------------------------------------------------------------------------- /rel/reltool.config: -------------------------------------------------------------------------------- 1 | {sys, [ 2 | {lib_dirs, ["../../"]}, 3 | {erts, [{mod_cond, derived}, {app_file, strip}]}, 4 | {app_file, strip}, 5 | {rel, "lyapp", "1", 6 | [ 7 | kernel, 8 | stdlib, 9 | sasl, 10 | lyapp 11 | ]}, 12 | {rel, "start_clean", "", 13 | [ 14 | kernel, 15 | stdlib 16 | ]}, 17 | {boot_rel, "lyapp"}, 18 | {profile, embedded}, 19 | {incl_cond, exclude}, 20 | {excl_archive_filters, [".*"]}, %% Do not archive built libs 21 | {excl_sys_filters, ["^bin/.*", "^erts.*/bin/(dialyzer|typer)", 22 | "^erts.*/(doc|info|include|lib|man|src)"]}, 23 | {excl_app_filters, ["\.gitignore"]}, 24 | {app, sasl, [{incl_cond, include}]}, 25 | {app, stdlib, [{incl_cond, include}]}, 26 | {app, kernel, [{incl_cond, include}]}, 27 | {app, lyapp, [{incl_cond, include}]} 28 | ]}. 29 | 30 | {target_dir, "lyapp"}. 31 | 32 | {overlay, [ 33 | {mkdir, "log/sasl"}, 34 | {copy, "files/erl", "\{\{erts_vsn\}\}/bin/erl"}, 35 | {copy, "files/nodetool", "\{\{erts_vsn\}\}/bin/nodetool"}, 36 | {copy, "files/lyapp", "bin/lyapp"}, 37 | {copy, "files/lyapp.cmd", "bin/lyapp.cmd"}, 38 | {copy, "files/start_erl.cmd", "bin/start_erl.cmd"}, 39 | {copy, "files/install_upgrade.escript", "bin/install_upgrade.escript"}, 40 | {copy, "files/sys.config", "releases/\{\{rel_vsn\}\}/sys.config"}, 41 | {copy, "files/vm.args", "releases/\{\{rel_vsn\}\}/vm.args"} 42 | ]}. 43 | -------------------------------------------------------------------------------- /src/lyapp_server.erl: -------------------------------------------------------------------------------- 1 | -module(lyapp_server). 2 | -behaviour(gen_server). 3 | -define(SERVER, ?MODULE). 4 | 5 | %% ------------------------------------------------------------------ 6 | %% API Function Exports 7 | %% ------------------------------------------------------------------ 8 | 9 | -export([start_link/0]). 10 | 11 | %% ------------------------------------------------------------------ 12 | %% gen_server Function Exports 13 | %% ------------------------------------------------------------------ 14 | 15 | -export([init/1, handle_call/3, handle_cast/2, handle_info/2, 16 | terminate/2, code_change/3]). 17 | 18 | %% ------------------------------------------------------------------ 19 | %% API Function Definitions 20 | %% ------------------------------------------------------------------ 21 | 22 | start_link() -> 23 | gen_server:start_link({local, ?SERVER}, ?MODULE, [], []). 24 | 25 | %% ------------------------------------------------------------------ 26 | %% gen_server Function Definitions 27 | %% ------------------------------------------------------------------ 28 | 29 | init(Args) -> 30 | {ok, Args}. 31 | 32 | handle_call(_Request, _From, State) -> 33 | {reply, ok, State}. 34 | 35 | handle_cast(_Msg, State) -> 36 | {noreply, State}. 37 | 38 | handle_info(_Info, State) -> 39 | {noreply, State}. 40 | 41 | terminate(_Reason, _State) -> 42 | ok. 43 | 44 | code_change(_OldVsn, State, _Extra) -> 45 | {ok, State}. 46 | 47 | %% ------------------------------------------------------------------ 48 | %% Internal Function Definitions 49 | %% ------------------------------------------------------------------ 50 | 51 | -------------------------------------------------------------------------------- /rel/files/install_upgrade.escript: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env escript 2 | %%! -noshell -noinput 3 | %% -*- mode: erlang;erlang-indent-level: 4;indent-tabs-mode: nil -*- 4 | %% ex: ft=erlang ts=4 sw=4 et 5 | 6 | -define(TIMEOUT, 60000). 7 | -define(INFO(Fmt,Args), io:format(Fmt,Args)). 8 | 9 | main([NodeName, Cookie, ReleasePackage]) -> 10 | TargetNode = start_distribution(NodeName, Cookie), 11 | {ok, Vsn} = rpc:call(TargetNode, release_handler, unpack_release, 12 | [ReleasePackage], ?TIMEOUT), 13 | ?INFO("Unpacked Release ~p~n", [Vsn]), 14 | {ok, OtherVsn, Desc} = rpc:call(TargetNode, release_handler, 15 | check_install_release, [Vsn], ?TIMEOUT), 16 | {ok, OtherVsn, Desc} = rpc:call(TargetNode, release_handler, 17 | install_release, [Vsn], ?TIMEOUT), 18 | ?INFO("Installed Release ~p~n", [Vsn]), 19 | ok = rpc:call(TargetNode, release_handler, make_permanent, [Vsn], ?TIMEOUT), 20 | ?INFO("Made Release ~p Permanent~n", [Vsn]); 21 | main(_) -> 22 | init:stop(1). 23 | 24 | start_distribution(NodeName, Cookie) -> 25 | MyNode = make_script_node(NodeName), 26 | {ok, _Pid} = net_kernel:start([MyNode, shortnames]), 27 | erlang:set_cookie(node(), list_to_atom(Cookie)), 28 | TargetNode = make_target_node(NodeName), 29 | case {net_kernel:hidden_connect_node(TargetNode), 30 | net_adm:ping(TargetNode)} of 31 | {true, pong} -> 32 | ok; 33 | {_, pang} -> 34 | io:format("Node ~p not responding to pings.\n", [TargetNode]), 35 | init:stop(1) 36 | end, 37 | TargetNode. 38 | 39 | make_target_node(Node) -> 40 | [_, Host] = string:tokens(atom_to_list(node()), "@"), 41 | list_to_atom(lists:concat([Node, "@", Host])). 42 | 43 | make_script_node(Node) -> 44 | list_to_atom(lists:concat([Node, "_upgrader_", os:getpid()])). 45 | -------------------------------------------------------------------------------- /rel/files/lyapp.cmd: -------------------------------------------------------------------------------- 1 | @setlocal 2 | 3 | @set node_name=lyapp 4 | 5 | @rem Get the absolute path to the parent directory, 6 | @rem which is assumed to be the node root. 7 | @for /F "delims=" %%I in ("%~dp0..") do @set node_root=%%~fI 8 | 9 | @set releases_dir=%node_root%\releases 10 | 11 | @rem Parse ERTS version and release version from start_erl.data 12 | @for /F "tokens=1,2" %%I in (%releases_dir%\start_erl.data) do @( 13 | @call :set_trim erts_version %%I 14 | @call :set_trim release_version %%J 15 | ) 16 | 17 | @rem extract erlang cookie from vm.args 18 | @set vm_args=%releases_dir%\%release_version%\vm.args 19 | @for /f "usebackq tokens=1-2" %%I in (`findstr /b \-setcookie %vm_args%`) do @set erlang_cookie=%%J 20 | 21 | @set erts_bin=%node_root%\erts-%erts_version%\bin 22 | 23 | @set service_name=%node_name%_%release_version% 24 | 25 | @if "%1"=="usage" @goto usage 26 | @if "%1"=="install" @goto install 27 | @if "%1"=="uninstall" @goto uninstall 28 | @if "%1"=="start" @goto start 29 | @if "%1"=="stop" @goto stop 30 | @if "%1"=="restart" @call :stop && @goto start 31 | @if "%1"=="console" @goto console 32 | @if "%1"=="query" @goto query 33 | @if "%1"=="attach" @goto attach 34 | @if "%1"=="upgrade" @goto upgrade 35 | @echo Unknown command: "%1" 36 | 37 | :usage 38 | @echo Usage: %~n0 [install^|uninstall^|start^|stop^|restart^|console^|query^|attach^|upgrade] 39 | @goto :EOF 40 | 41 | :install 42 | @%erts_bin%\erlsrv.exe add %service_name% -c "Erlang node %node_name% in %node_root%" -sname %node_name% -w %node_root% -m %node_root%\bin\start_erl.cmd -args " ++ %node_name% ++ %node_root%" -stopaction "init:stop()." 43 | @goto :EOF 44 | 45 | :uninstall 46 | @%erts_bin%\erlsrv.exe remove %service_name% 47 | @%erts_bin%\epmd.exe -kill 48 | @goto :EOF 49 | 50 | :start 51 | @%erts_bin%\erlsrv.exe start %service_name% 52 | @goto :EOF 53 | 54 | :stop 55 | @%erts_bin%\erlsrv.exe stop %service_name% 56 | @goto :EOF 57 | 58 | :console 59 | @start %erts_bin%\werl.exe -boot %releases_dir%\%release_version%\%node_name% -config %releases_dir%\%release_version%\sys.config -args_file %vm_args% -sname %node_name% 60 | @goto :EOF 61 | 62 | :query 63 | @%erts_bin%\erlsrv.exe list %service_name% 64 | @exit /b %ERRORLEVEL% 65 | @goto :EOF 66 | 67 | :attach 68 | @for /f "usebackq" %%I in (`hostname`) do @set hostname=%%I 69 | start %erts_bin%\werl.exe -boot %releases_dir%\%release_version%\start_clean -remsh %node_name%@%hostname% -sname console -setcookie %erlang_cookie% 70 | @goto :EOF 71 | 72 | :upgrade 73 | @if "%2"=="" ( 74 | @echo Missing upgrade package argument 75 | @echo Usage: %~n0 upgrade {package base name} 76 | @echo NOTE {package base name} MUST NOT include the .tar.gz suffix 77 | @goto :EOF 78 | ) 79 | @%erts_bin%\escript.exe %node_root%\bin\install_upgrade.escript %node_name% %erlang_cookie% %2 80 | @goto :EOF 81 | 82 | :set_trim 83 | @set %1=%2 84 | @goto :EOF 85 | -------------------------------------------------------------------------------- /rel/files/nodetool: -------------------------------------------------------------------------------- 1 | %% -*- mode: erlang;erlang-indent-level: 4;indent-tabs-mode: nil -*- 2 | %% ex: ft=erlang ts=4 sw=4 et 3 | %% ------------------------------------------------------------------- 4 | %% 5 | %% nodetool: Helper Script for interacting with live nodes 6 | %% 7 | %% ------------------------------------------------------------------- 8 | 9 | main(Args) -> 10 | ok = start_epmd(), 11 | %% Extract the args 12 | {RestArgs, TargetNode} = process_args(Args, [], undefined), 13 | 14 | %% See if the node is currently running -- if it's not, we'll bail 15 | case {net_kernel:hidden_connect_node(TargetNode), net_adm:ping(TargetNode)} of 16 | {true, pong} -> 17 | ok; 18 | {_, pang} -> 19 | io:format("Node ~p not responding to pings.\n", [TargetNode]), 20 | halt(1) 21 | end, 22 | 23 | case RestArgs of 24 | ["ping"] -> 25 | %% If we got this far, the node already responsed to a ping, so just dump 26 | %% a "pong" 27 | io:format("pong\n"); 28 | ["stop"] -> 29 | io:format("~p\n", [rpc:call(TargetNode, init, stop, [], 60000)]); 30 | ["restart"] -> 31 | io:format("~p\n", [rpc:call(TargetNode, init, restart, [], 60000)]); 32 | ["reboot"] -> 33 | io:format("~p\n", [rpc:call(TargetNode, init, reboot, [], 60000)]); 34 | ["rpc", Module, Function | RpcArgs] -> 35 | case rpc:call(TargetNode, list_to_atom(Module), list_to_atom(Function), 36 | [RpcArgs], 60000) of 37 | ok -> 38 | ok; 39 | {badrpc, Reason} -> 40 | io:format("RPC to ~p failed: ~p\n", [TargetNode, Reason]), 41 | halt(1); 42 | _ -> 43 | halt(1) 44 | end; 45 | ["rpcterms", Module, Function, ArgsAsString] -> 46 | case rpc:call(TargetNode, list_to_atom(Module), list_to_atom(Function), 47 | consult(ArgsAsString), 60000) of 48 | {badrpc, Reason} -> 49 | io:format("RPC to ~p failed: ~p\n", [TargetNode, Reason]), 50 | halt(1); 51 | Other -> 52 | io:format("~p\n", [Other]) 53 | end; 54 | Other -> 55 | io:format("Other: ~p\n", [Other]), 56 | io:format("Usage: nodetool {ping|stop|restart|reboot}\n") 57 | end, 58 | net_kernel:stop(). 59 | 60 | process_args([], Acc, TargetNode) -> 61 | {lists:reverse(Acc), TargetNode}; 62 | process_args(["-setcookie", Cookie | Rest], Acc, TargetNode) -> 63 | erlang:set_cookie(node(), list_to_atom(Cookie)), 64 | process_args(Rest, Acc, TargetNode); 65 | process_args(["-name", TargetName | Rest], Acc, _) -> 66 | ThisNode = append_node_suffix(TargetName, "_maint_"), 67 | {ok, _} = net_kernel:start([ThisNode, longnames]), 68 | process_args(Rest, Acc, nodename(TargetName)); 69 | process_args(["-sname", TargetName | Rest], Acc, _) -> 70 | ThisNode = append_node_suffix(TargetName, "_maint_"), 71 | {ok, _} = net_kernel:start([ThisNode, shortnames]), 72 | process_args(Rest, Acc, nodename(TargetName)); 73 | process_args([Arg | Rest], Acc, Opts) -> 74 | process_args(Rest, [Arg | Acc], Opts). 75 | 76 | 77 | start_epmd() -> 78 | [] = os:cmd(epmd_path() ++ " -daemon"), 79 | ok. 80 | 81 | epmd_path() -> 82 | ErtsBinDir = filename:dirname(escript:script_name()), 83 | Name = "epmd", 84 | case os:find_executable(Name, ErtsBinDir) of 85 | false -> 86 | case os:find_executable(Name) of 87 | false -> 88 | io:format("Could not find epmd.~n"), 89 | halt(1); 90 | GlobalEpmd -> 91 | GlobalEpmd 92 | end; 93 | Epmd -> 94 | Epmd 95 | end. 96 | 97 | 98 | nodename(Name) -> 99 | case string:tokens(Name, "@") of 100 | [_Node, _Host] -> 101 | list_to_atom(Name); 102 | [Node] -> 103 | [_, Host] = string:tokens(atom_to_list(node()), "@"), 104 | list_to_atom(lists:concat([Node, "@", Host])) 105 | end. 106 | 107 | append_node_suffix(Name, Suffix) -> 108 | case string:tokens(Name, "@") of 109 | [Node, Host] -> 110 | list_to_atom(lists:concat([Node, Suffix, os:getpid(), "@", Host])); 111 | [Node] -> 112 | list_to_atom(lists:concat([Node, Suffix, os:getpid()])) 113 | end. 114 | 115 | 116 | %% 117 | %% Given a string or binary, parse it into a list of terms, ala file:consult/0 118 | %% 119 | consult(Str) when is_list(Str) -> 120 | consult([], Str, []); 121 | consult(Bin) when is_binary(Bin)-> 122 | consult([], binary_to_list(Bin), []). 123 | 124 | consult(Cont, Str, Acc) -> 125 | case erl_scan:tokens(Cont, Str, 0) of 126 | {done, Result, Remaining} -> 127 | case Result of 128 | {ok, Tokens, _} -> 129 | {ok, Term} = erl_parse:parse_term(Tokens), 130 | consult([], Remaining, [Term | Acc]); 131 | {eof, _Other} -> 132 | lists:reverse(Acc); 133 | {error, Info, _} -> 134 | {error, Info} 135 | end; 136 | {more, Cont1} -> 137 | consult(Cont1, eof, Acc) 138 | end. 139 | -------------------------------------------------------------------------------- /rel/files/lyapp: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # -*- tab-width:4;indent-tabs-mode:nil -*- 3 | # ex: ts=4 sw=4 et 4 | 5 | RUNNER_SCRIPT_DIR=$(cd ${0%/*} && pwd) 6 | 7 | RUNNER_BASE_DIR=${RUNNER_SCRIPT_DIR%/*} 8 | RUNNER_ETC_DIR=$RUNNER_BASE_DIR/etc 9 | RUNNER_LOG_DIR=$RUNNER_BASE_DIR/log 10 | # Note the trailing slash on $PIPE_DIR/ 11 | PIPE_DIR=/tmp/$RUNNER_BASE_DIR/ 12 | RUNNER_USER= 13 | 14 | # Make sure this script is running as the appropriate user 15 | if [ ! -z "$RUNNER_USER" ] && [ `whoami` != "$RUNNER_USER" ]; then 16 | exec sudo -u $RUNNER_USER -i $0 $@ 17 | fi 18 | 19 | # Make sure CWD is set to runner base dir 20 | cd $RUNNER_BASE_DIR 21 | 22 | # Make sure log directory exists 23 | mkdir -p $RUNNER_LOG_DIR 24 | # Identify the script name 25 | SCRIPT=`basename $0` 26 | 27 | # Parse out release and erts info 28 | START_ERL=`cat $RUNNER_BASE_DIR/releases/start_erl.data` 29 | ERTS_VSN=${START_ERL% *} 30 | APP_VSN=${START_ERL#* } 31 | 32 | # Use releases/VSN/vm.args if it exists otherwise use etc/vm.args 33 | if [ -e "$RUNNER_BASE_DIR/releases/$APP_VSN/vm.args" ]; then 34 | VMARGS_PATH="$RUNNER_BASE_DIR/releases/$APP_VSN/vm.args" 35 | else 36 | VMARGS_PATH="$RUNNER_ETC_DIR/vm.args" 37 | fi 38 | 39 | # Use releases/VSN/sys.config if it exists otherwise use etc/app.config 40 | if [ -e "$RUNNER_BASE_DIR/releases/$APP_VSN/sys.config" ]; then 41 | CONFIG_PATH="$RUNNER_BASE_DIR/releases/$APP_VSN/sys.config" 42 | else 43 | CONFIG_PATH="$RUNNER_ETC_DIR/app.config" 44 | fi 45 | 46 | # Extract the target node name from node.args 47 | NAME_ARG=`egrep '^-s?name' $VMARGS_PATH` 48 | if [ -z "$NAME_ARG" ]; then 49 | echo "vm.args needs to have either -name or -sname parameter." 50 | exit 1 51 | fi 52 | 53 | # Extract the name type and name from the NAME_ARG for REMSH 54 | REMSH_TYPE=`echo $NAME_ARG | awk '{print $1}'` 55 | REMSH_NAME=`echo $NAME_ARG | awk '{print $2}'` 56 | 57 | # Note the `date +%s`, used to allow multiple remsh to the same node transparently 58 | REMSH_NAME_ARG="$REMSH_TYPE remsh`date +%s`@`echo $REMSH_NAME | awk -F@ '{print $2}'`" 59 | REMSH_REMSH_ARG="-remsh $REMSH_NAME" 60 | 61 | # Extract the target cookie 62 | COOKIE_ARG=`grep '^-setcookie' $VMARGS_PATH` 63 | if [ -z "$COOKIE_ARG" ]; then 64 | echo "vm.args needs to have a -setcookie parameter." 65 | exit 1 66 | fi 67 | 68 | # Add ERTS bin dir to our path 69 | ERTS_PATH=$RUNNER_BASE_DIR/erts-$ERTS_VSN/bin 70 | 71 | # Setup command to control the node 72 | NODETOOL="$ERTS_PATH/escript $ERTS_PATH/nodetool $NAME_ARG $COOKIE_ARG" 73 | 74 | # Setup remote shell command to control node 75 | REMSH="$ERTS_PATH/erl $REMSH_NAME_ARG $REMSH_REMSH_ARG $COOKIE_ARG" 76 | 77 | # Check the first argument for instructions 78 | case "$1" in 79 | start) 80 | # Make sure there is not already a node running 81 | RES=`$NODETOOL ping` 82 | if [ "$RES" = "pong" ]; then 83 | echo "Node is already running!" 84 | exit 1 85 | fi 86 | shift # remove $1 87 | RUN_PARAM=$(printf "\'%s\' " "$@") 88 | HEART_COMMAND="$RUNNER_BASE_DIR/bin/$SCRIPT start $RUN_PARAM" 89 | export HEART_COMMAND 90 | mkdir -p $PIPE_DIR 91 | $ERTS_PATH/run_erl -daemon $PIPE_DIR $RUNNER_LOG_DIR "exec $RUNNER_BASE_DIR/bin/$SCRIPT console $RUN_PARAM" 2>&1 92 | ;; 93 | 94 | stop) 95 | # Wait for the node to completely stop... 96 | case `uname -s` in 97 | Linux|Darwin|FreeBSD|DragonFly|NetBSD|OpenBSD) 98 | # PID COMMAND 99 | PID=`ps ax -o pid= -o command=|\ 100 | grep "$RUNNER_BASE_DIR/.*/[b]eam"|awk '{print $1}'` 101 | ;; 102 | SunOS) 103 | # PID COMMAND 104 | PID=`ps -ef -o pid= -o args=|\ 105 | grep "$RUNNER_BASE_DIR/.*/[b]eam"|awk '{print $1}'` 106 | ;; 107 | CYGWIN*) 108 | # UID PID PPID TTY STIME COMMAND 109 | PID=`ps -efW|grep "$RUNNER_BASE_DIR/.*/[b]eam"|awk '{print $2}'` 110 | ;; 111 | esac 112 | $NODETOOL stop 113 | ES=$? 114 | if [ "$ES" -ne 0 ]; then 115 | exit $ES 116 | fi 117 | while `kill -0 $PID 2>/dev/null`; 118 | do 119 | sleep 1 120 | done 121 | ;; 122 | 123 | restart) 124 | ## Restart the VM without exiting the process 125 | $NODETOOL restart 126 | ES=$? 127 | if [ "$ES" -ne 0 ]; then 128 | exit $ES 129 | fi 130 | ;; 131 | 132 | reboot) 133 | ## Restart the VM completely (uses heart to restart it) 134 | $NODETOOL reboot 135 | ES=$? 136 | if [ "$ES" -ne 0 ]; then 137 | exit $ES 138 | fi 139 | ;; 140 | 141 | ping) 142 | ## See if the VM is alive 143 | $NODETOOL ping 144 | ES=$? 145 | if [ "$ES" -ne 0 ]; then 146 | exit $ES 147 | fi 148 | ;; 149 | 150 | attach) 151 | # Make sure a node IS running 152 | RES=`$NODETOOL ping` 153 | ES=$? 154 | if [ "$ES" -ne 0 ]; then 155 | echo "Node is not running!" 156 | exit $ES 157 | fi 158 | 159 | shift 160 | exec $ERTS_PATH/to_erl $PIPE_DIR 161 | ;; 162 | 163 | remote_console) 164 | # Make sure a node IS running 165 | RES=`$NODETOOL ping` 166 | ES=$? 167 | if [ "$ES" -ne 0 ]; then 168 | echo "Node is not running!" 169 | exit $ES 170 | fi 171 | 172 | shift 173 | exec $REMSH 174 | ;; 175 | 176 | upgrade) 177 | if [ -z "$2" ]; then 178 | echo "Missing upgrade package argument" 179 | echo "Usage: $SCRIPT upgrade {package base name}" 180 | echo "NOTE {package base name} MUST NOT include the .tar.gz suffix" 181 | exit 1 182 | fi 183 | 184 | # Make sure a node IS running 185 | RES=`$NODETOOL ping` 186 | ES=$? 187 | if [ "$ES" -ne 0 ]; then 188 | echo "Node is not running!" 189 | exit $ES 190 | fi 191 | 192 | node_name=`echo $NAME_ARG | awk '{print $2}'` 193 | erlang_cookie=`echo $COOKIE_ARG | awk '{print $2}'` 194 | 195 | $ERTS_PATH/escript $RUNNER_BASE_DIR/bin/install_upgrade.escript $node_name $erlang_cookie $2 196 | ;; 197 | 198 | console|console_clean) 199 | # .boot file typically just $SCRIPT (ie, the app name) 200 | # however, for debugging, sometimes start_clean.boot is useful: 201 | case "$1" in 202 | console) BOOTFILE=$SCRIPT ;; 203 | console_clean) BOOTFILE=start_clean ;; 204 | esac 205 | # Setup beam-required vars 206 | ROOTDIR=$RUNNER_BASE_DIR 207 | BINDIR=$ROOTDIR/erts-$ERTS_VSN/bin 208 | EMU=beam 209 | PROGNAME=`echo $0 | sed 's/.*\\///'` 210 | CMD="$BINDIR/erlexec -boot $RUNNER_BASE_DIR/releases/$APP_VSN/$BOOTFILE -mode embedded -config $CONFIG_PATH -args_file $VMARGS_PATH" 211 | export EMU 212 | export ROOTDIR 213 | export BINDIR 214 | export PROGNAME 215 | 216 | # Dump environment info for logging purposes 217 | echo "Exec: $CMD" -- ${1+"$@"} 218 | echo "Root: $ROOTDIR" 219 | 220 | # Log the startup 221 | logger -t "$SCRIPT[$$]" "Starting up" 222 | 223 | # Start the VM 224 | exec $CMD -- ${1+"$@"} 225 | ;; 226 | 227 | foreground) 228 | # start up the release in the foreground for use by runit 229 | # or other supervision services 230 | 231 | BOOTFILE=$SCRIPT 232 | FOREGROUNDOPTIONS="-noinput +Bd" 233 | 234 | # Setup beam-required vars 235 | ROOTDIR=$RUNNER_BASE_DIR 236 | BINDIR=$ROOTDIR/erts-$ERTS_VSN/bin 237 | EMU=beam 238 | PROGNAME=`echo $0 | sed 's/.*\///'` 239 | CMD="$BINDIR/erlexec $FOREGROUNDOPTIONS -boot $RUNNER_BASE_DIR/releases/$APP_VSN/$BOOTFILE -config $CONFIG_PATH -args_file $VMARGS_PATH" 240 | export EMU 241 | export ROOTDIR 242 | export BINDIR 243 | export PROGNAME 244 | 245 | # Dump environment info for logging purposes 246 | echo "Exec: $CMD" -- ${1+"$@"} 247 | echo "Root: $ROOTDIR" 248 | 249 | # Start the VM 250 | exec $CMD -- ${1+"$@"} 251 | ;; 252 | *) 253 | echo "Usage: $SCRIPT {start|foreground|stop|restart|reboot|ping|console|console_clean|attach|remote_console|upgrade}" 254 | exit 1 255 | ;; 256 | esac 257 | 258 | exit 0 259 | --------------------------------------------------------------------------------