diff options
-rw-r--r-- | hvac_demo/backend.config | 2 | ||||
-rw-r--r-- | hvac_demo/tizen_vehicle.config | 2 | ||||
-rwxr-xr-x | rebar | bin | 152225 -> 166839 bytes | |||
-rw-r--r-- | rebar.config | 2 | ||||
-rwxr-xr-x | rel/files/erl | 44 | ||||
-rw-r--r-- | rel/files/install_upgrade.escript | 44 | ||||
-rwxr-xr-x | rel/files/nodetool | 182 | ||||
-rwxr-xr-x | rel/files/rvi | 347 | ||||
-rw-r--r-- | rel/files/rvi.cmd | 103 | ||||
-rw-r--r-- | rel/files/start_erl.cmd | 40 | ||||
-rw-r--r-- | rel/files/vm.args | 19 | ||||
-rw-r--r-- | rel/reltool.config | 44 | ||||
-rwxr-xr-x | setup_rvi_node.sh | 91 |
13 files changed, 909 insertions, 11 deletions
diff --git a/hvac_demo/backend.config b/hvac_demo/backend.config index d2cecb6..8989f01 100644 --- a/hvac_demo/backend.config +++ b/hvac_demo/backend.config @@ -44,7 +44,7 @@ [ {lager, [ { handlers, - [{lager_console_backend, notice}] + [{lager_console_backend, debug}] } ] }, diff --git a/hvac_demo/tizen_vehicle.config b/hvac_demo/tizen_vehicle.config index 2f05163..b9e84f2 100644 --- a/hvac_demo/tizen_vehicle.config +++ b/hvac_demo/tizen_vehicle.config @@ -64,7 +64,7 @@ [ { handlers, %% Change this to debug, info, notice, warning, or error in %% order to lower the console chatter. - [ {lager_console_backend, notice} ] + [ {lager_console_backend, debug} ] } ] }, Binary files differdiff --git a/rebar.config b/rebar.config index 02d2bae..f4b875b 100644 --- a/rebar.config +++ b/rebar.config @@ -4,6 +4,8 @@ %% Top level app that controls other apps. %% {erl_opts, [debug_info]}. +{lib_dirs, ["deps"]}. +{sub_dirs, ["rel"]}. {deps, [ {setup, ".*", {git, "https://github.com/uwiger/setup.git", "HEAD"}}, diff --git a/rel/files/erl b/rel/files/erl new file mode 100755 index 0000000..f4c63af --- /dev/null +++ b/rel/files/erl @@ -0,0 +1,44 @@ +#!/bin/sh + +# /bin/sh on Solaris is not a POSIX compatible shell, but /usr/bin/ksh is. +if [ `uname -s` = 'SunOS' -a "${POSIX_SHELL}" != "true" ]; then + POSIX_SHELL="true" + export POSIX_SHELL + exec /usr/bin/ksh $0 "$@" +fi + +# clear it so if we invoke other scripts, they run as ksh as well +unset POSIX_SHELL + +## This script replaces the default "erl" in erts-VSN/bin. This is +## necessary as escript depends on erl and in turn, erl depends on +## having access to a bootscript (start.boot). Note that this script +## is ONLY invoked as a side-effect of running escript -- the embedded +## node bypasses erl and uses erlexec directly (as it should). +## +## Note that this script makes the assumption that there is a +## start_clean.boot file available in $ROOTDIR/release/VSN. + +# Determine the abspath of where this script is executing from. +ERTS_BIN_DIR=$(cd ${0%/*} && pwd -P) + +# Now determine the root directory -- this script runs from erts-VSN/bin, +# so we simply need to strip off two dirs from the end of the ERTS_BIN_DIR +# path. +ROOTDIR=${ERTS_BIN_DIR%/*/*} + +# Parse out release and erts info +START_ERL=`cat $ROOTDIR/releases/start_erl.data` +ERTS_VSN=${START_ERL% *} +APP_VSN=${START_ERL#* } + +BINDIR=$ROOTDIR/erts-$ERTS_VSN/bin +EMU=beam +PROGNAME=`echo $0 | sed 's/.*\\///'` +CMD="$BINDIR/erlexec" +export EMU +export ROOTDIR +export BINDIR +export PROGNAME + +exec $CMD -boot $ROOTDIR/releases/$APP_VSN/start_clean ${1+"$@"} diff --git a/rel/files/install_upgrade.escript b/rel/files/install_upgrade.escript new file mode 100644 index 0000000..56cea19 --- /dev/null +++ b/rel/files/install_upgrade.escript @@ -0,0 +1,44 @@ +#!/usr/bin/env escript +%%! -noshell -noinput +%% -*- mode: erlang;erlang-indent-level: 4;indent-tabs-mode: nil -*- +%% ex: ft=erlang ts=4 sw=4 et + +-define(TIMEOUT, 60000). +-define(INFO(Fmt,Args), io:format(Fmt,Args)). + +main([NodeName, Cookie, ReleasePackage]) -> + TargetNode = start_distribution(NodeName, Cookie), + {ok, Vsn} = rpc:call(TargetNode, release_handler, unpack_release, + [ReleasePackage], ?TIMEOUT), + ?INFO("Unpacked Release ~p~n", [Vsn]), + {ok, OtherVsn, Desc} = rpc:call(TargetNode, release_handler, + check_install_release, [Vsn], ?TIMEOUT), + {ok, OtherVsn, Desc} = rpc:call(TargetNode, release_handler, + install_release, [Vsn], ?TIMEOUT), + ?INFO("Installed Release ~p~n", [Vsn]), + ok = rpc:call(TargetNode, release_handler, make_permanent, [Vsn], ?TIMEOUT), + ?INFO("Made Release ~p Permanent~n", [Vsn]); +main(_) -> + init:stop(1). + +start_distribution(NodeName, Cookie) -> + MyNode = make_script_node(NodeName), + {ok, _Pid} = net_kernel:start([MyNode, shortnames]), + erlang:set_cookie(node(), list_to_atom(Cookie)), + TargetNode = make_target_node(NodeName), + case {net_kernel:hidden_connect_node(TargetNode), + net_adm:ping(TargetNode)} of + {true, pong} -> + ok; + {_, pang} -> + io:format("Node ~p not responding to pings.\n", [TargetNode]), + init:stop(1) + end, + TargetNode. + +make_target_node(Node) -> + [_, Host] = string:tokens(atom_to_list(node()), "@"), + list_to_atom(lists:concat([Node, "@", Host])). + +make_script_node(Node) -> + list_to_atom(lists:concat([Node, "_upgrader_", os:getpid()])). diff --git a/rel/files/nodetool b/rel/files/nodetool new file mode 100755 index 0000000..ce06c6a --- /dev/null +++ b/rel/files/nodetool @@ -0,0 +1,182 @@ +#!/usr/bin/env escript +%% -*- mode: erlang;erlang-indent-level: 4;indent-tabs-mode: nil -*- +%% ex: ft=erlang ts=4 sw=4 et +%% ------------------------------------------------------------------- +%% +%% nodetool: Helper Script for interacting with live nodes +%% +%% ------------------------------------------------------------------- +main(Args) -> + ok = start_epmd(), + %% Extract the args + {RestArgs, TargetNode} = process_args(Args, [], undefined), + + %% any commands that don't need a running node + case RestArgs of + ["chkconfig", File] -> + case file:consult(File) of + {ok, _} -> + io:format("ok\n"), + halt(0); + {error, {Line, Mod, Term}} -> + io:format(standard_error, ["Error on line ", + file:format_error({Line, Mod, Term}), "\n"], []), + halt(1); + {error, R} -> + io:format(standard_error, ["Error reading config file: ", + file:format_error(R), "\n"], []), + halt(1) + end; + _ -> + ok + end, + + %% See if the node is currently running -- if it's not, we'll bail + case {net_kernel:hidden_connect_node(TargetNode), + net_adm:ping(TargetNode)} of + {true, pong} -> + ok; + {false,pong} -> + io:format("Failed to connect to node ~p .\n", [TargetNode]), + halt(1); + {_, pang} -> + io:format("Node ~p not responding to pings.\n", [TargetNode]), + halt(1) + end, + + case RestArgs of + ["getpid"] -> + io:format("~p\n", + [list_to_integer(rpc:call(TargetNode, os, getpid, []))]); + ["ping"] -> + %% If we got this far, the node already responsed to a + %% ping, so just dump a "pong" + io:format("pong\n"); + ["stop"] -> + io:format("~p\n", [rpc:call(TargetNode, init, stop, [], 60000)]); + ["restart"] -> + io:format("~p\n", [rpc:call(TargetNode, init, restart, [], 60000)]); + ["reboot"] -> + io:format("~p\n", [rpc:call(TargetNode, init, reboot, [], 60000)]); + ["rpc", Module, Function | RpcArgs] -> + case rpc:call(TargetNode, + list_to_atom(Module), + list_to_atom(Function), + [RpcArgs], 60000) of + ok -> + ok; + {badrpc, Reason} -> + io:format("RPC to ~p failed: ~p\n", [TargetNode, Reason]), + halt(1); + _ -> + halt(1) + end; + ["rpc_infinity", Module, Function | RpcArgs] -> + case rpc:call(TargetNode, + list_to_atom(Module), + list_to_atom(Function), + [RpcArgs], infinity) of + ok -> + ok; + {badrpc, Reason} -> + io:format("RPC to ~p failed: ~p\n", [TargetNode, Reason]), + halt(1); + _ -> + halt(1) + end; + ["rpcterms", Module, Function, ArgsAsString] -> + case rpc:call(TargetNode, + list_to_atom(Module), + list_to_atom(Function), + consult(ArgsAsString), 60000) of + {badrpc, Reason} -> + io:format("RPC to ~p failed: ~p\n", [TargetNode, Reason]), + halt(1); + Other -> + io:format("~p\n", [Other]) + end; + Other -> + io:format("Other: ~p\n", [Other]), + io:format("Usage: nodetool {chkconfig|getpid|ping|stop|restart|reboot|rpc|rpc_infinity|rpcterms}\n") + end, + net_kernel:stop(). + +process_args([], Acc, TargetNode) -> + {lists:reverse(Acc), TargetNode}; +process_args(["-setcookie", Cookie | Rest], Acc, TargetNode) -> + erlang:set_cookie(node(), list_to_atom(Cookie)), + process_args(Rest, Acc, TargetNode); +process_args(["-name", TargetName | Rest], Acc, _) -> + ThisNode = append_node_suffix(TargetName, "_maint_"), + {ok, _} = net_kernel:start([ThisNode, longnames]), + process_args(Rest, Acc, nodename(TargetName)); +process_args(["-sname", TargetName | Rest], Acc, _) -> + ThisNode = append_node_suffix(TargetName, "_maint_"), + {ok, _} = net_kernel:start([ThisNode, shortnames]), + process_args(Rest, Acc, nodename(TargetName)); +process_args([Arg | Rest], Acc, Opts) -> + process_args(Rest, [Arg | Acc], Opts). + + +start_epmd() -> + [] = os:cmd(epmd_path() ++ " -daemon"), + ok. + +epmd_path() -> + ErtsBinDir = filename:dirname(escript:script_name()), + Name = "epmd", + case os:find_executable(Name, ErtsBinDir) of + false -> + case os:find_executable(Name) of + false -> + io:format("Could not find epmd.~n"), + halt(1); + GlobalEpmd -> + GlobalEpmd + end; + Epmd -> + Epmd + end. + + +nodename(Name) -> + case string:tokens(Name, "@") of + [_Node, _Host] -> + list_to_atom(Name); + [Node] -> + [_, Host] = string:tokens(atom_to_list(node()), "@"), + list_to_atom(lists:concat([Node, "@", Host])) + end. + +append_node_suffix(Name, Suffix) -> + case string:tokens(Name, "@") of + [Node, Host] -> + list_to_atom(lists:concat([Node, Suffix, os:getpid(), "@", Host])); + [Node] -> + list_to_atom(lists:concat([Node, Suffix, os:getpid()])) + end. + + +%% +%% Given a string or binary, parse it into a list of terms, ala file:consult/0 +%% +consult(Str) when is_list(Str) -> + consult([], Str, []); +consult(Bin) when is_binary(Bin)-> + consult([], binary_to_list(Bin), []). + +consult(Cont, Str, Acc) -> + case erl_scan:tokens(Cont, Str, 0) of + {done, Result, Remaining} -> + case Result of + {ok, Tokens, _} -> + {ok, Term} = erl_parse:parse_term(Tokens), + consult([], Remaining, [Term | Acc]); + {eof, _Other} -> + lists:reverse(Acc); + {error, Info, _} -> + {error, Info} + end; + {more, Cont1} -> + consult(Cont1, eof, Acc) + end. diff --git a/rel/files/rvi b/rel/files/rvi new file mode 100755 index 0000000..c2ef258 --- /dev/null +++ b/rel/files/rvi @@ -0,0 +1,347 @@ +#!/bin/sh +# -*- tab-width:4;indent-tabs-mode:nil -*- +# ex: ts=4 sw=4 et + +# /bin/sh on Solaris is not a POSIX compatible shell, but /usr/bin/ksh is. +if [ `uname -s` = 'SunOS' -a "${POSIX_SHELL}" != "true" ]; then + POSIX_SHELL="true" + export POSIX_SHELL + # To support 'whoami' add /usr/ucb to path + PATH=/usr/ucb:$PATH + export PATH + exec /usr/bin/ksh $0 "$@" +fi + +# clear it so if we invoke other scripts, they run as ksh +unset POSIX_SHELL + +RUNNER_SCRIPT_DIR=$(cd ${0%/*} && pwd -P) + +CALLER_DIR=$PWD + +RUNNER_BASE_DIR=${RUNNER_SCRIPT_DIR%/*} +RUNNER_ETC_DIR=$RUNNER_BASE_DIR/etc +# Note the trailing slash on $PIPE_DIR/ +PIPE_DIR=/tmp/$RUNNER_BASE_DIR/ +RUNNER_USER= +WHOAMI=$(whoami) + +# Make sure this script is running as the appropriate user +if ([ "$RUNNER_USER" ] && [ "x$WHOAMI" != "x$RUNNER_USER" ]); then + type sudo > /dev/null 2>&1 + if [ $? -ne 0 ]; then + echo "sudo doesn't appear to be installed and your EUID isn't $RUNNER_USER" 1>&2 + exit 1 + fi + echo "Attempting to restart script through sudo -H -u $RUNNER_USER" >&2 + exec sudo -H -u $RUNNER_USER -i $RUNNER_SCRIPT_DIR/$RUNNER_SCRIPT $@ +fi + +# Identify the script name +SCRIPT=`basename $0` + +# Parse out release and erts info +START_ERL=`cat $RUNNER_BASE_DIR/releases/start_erl.data` +ERTS_VSN=${START_ERL% *} +APP_VSN=${START_ERL#* } + +# Use $CWD/vm.args if exists, otherwise releases/APP_VSN/vm.args, or +# else etc/vm.args +if [ -e "$CALLER_DIR/vm.args" ]; then + VMARGS_PATH=$CALLER_DIR/vm.args + USE_DIR=$CALLER_DIR +else + USE_DIR=$RUNNER_BASE_DIR + if [ -e "$RUNNER_BASE_DIR/releases/$APP_VSN/vm.args" ]; then + VMARGS_PATH="$RUNNER_BASE_DIR/releases/$APP_VSN/vm.args" + else + VMARGS_PATH="$RUNNER_ETC_DIR/vm.args" + fi +fi + +RUNNER_LOG_DIR=$USE_DIR/log +# Make sure log directory exists +mkdir -p $RUNNER_LOG_DIR + +# Use releases/VSN/sys.config if it exists otherwise use etc/app.config +if [ -e "$USE_DIR/sys.config" ]; then + CONFIG_PATH="$USE_DIR/sys.config" +else + if [ -e "$RUNNER_BASE_DIR/releases/$APP_VSN/sys.config" ]; then + CONFIG_PATH="$RUNNER_BASE_DIR/releases/$APP_VSN/sys.config" + else + CONFIG_PATH="$RUNNER_ETC_DIR/app.config" + fi +fi + +# Extract the target node name from node.args +NAME_ARG=`egrep '^\-s?name' $VMARGS_PATH` +if [ -z "$NAME_ARG" ]; then + echo "vm.args needs to have either -name or -sname parameter." + exit 1 +fi + +# Extract the name type and name from the NAME_ARG for REMSH +REMSH_TYPE=`echo $NAME_ARG | awk '{print $1}'` +REMSH_NAME=`echo $NAME_ARG | awk '{print $2}'` + +# Note the `date +%s`, used to allow multiple remsh to the same node +# transparently +REMSH_NAME_ARG="$REMSH_TYPE remsh`date +%s`@`echo $REMSH_NAME | awk -F@ '{print $2}'`" +REMSH_REMSH_ARG="-remsh $REMSH_NAME" + +# Extract the target cookie +COOKIE_ARG=`grep '^\-setcookie' $VMARGS_PATH` +if [ -z "$COOKIE_ARG" ]; then + echo "vm.args needs to have a -setcookie parameter." + exit 1 +fi + +# Make sure CWD is set to the right dir +cd $USE_DIR + +# Make sure log directory exists +mkdir -p $USE_DIR/log + +# Add ERTS bin dir to our path +ERTS_PATH=$RUNNER_BASE_DIR/erts-$ERTS_VSN/bin + +# Setup command to control the node +NODETOOL="$ERTS_PATH/escript $ERTS_PATH/nodetool $NAME_ARG $COOKIE_ARG" + +# Setup remote shell command to control node +REMSH="$ERTS_PATH/erl $REMSH_NAME_ARG $REMSH_REMSH_ARG $COOKIE_ARG" + +# Common functions + +# Ping node without allowing nodetool to take stdin +ping_node() { + $NODETOOL ping < /dev/null +} + +# Set the PID global variable, return 1 on error +get_pid() { + PID=`$NODETOOL getpid < /dev/null` + ES=$? + if [ "$ES" -ne 0 ]; then + echo "Node is not running!" + return 1 + fi + + # don't allow empty or init pid's + if [ -z $PID ] || [ "$PID" -le 1 ]; then + return 1 + fi + + return 0 +} + +# Check the first argument for instructions +case "$1" in + start|start_boot) + # Make sure there is not already a node running + RES=`ping_node` + if [ "$RES" = "pong" ]; then + echo "Node is already running!" + exit 1 + fi + case "$1" in + start) + shift + START_OPTION="console" + HEART_OPTION="start" + ;; + start_boot) + shift + START_OPTION="console_boot" + HEART_OPTION="start_boot" + ;; + esac + RUN_PARAM=$(printf "\'%s\' " "$@") + HEART_COMMAND="$RUNNER_BASE_DIR/bin/$SCRIPT $HEART_OPTION $RUN_PARAM" + export HEART_COMMAND + mkdir -p $PIPE_DIR + $ERTS_PATH/run_erl -daemon $PIPE_DIR $RUNNER_LOG_DIR "exec $RUNNER_BASE_DIR/bin/$SCRIPT $START_OPTION $RUN_PARAM" 2>&1 + ;; + + stop) + # Wait for the node to completely stop... + case `uname -s` in + Darwin) + # Make sure we explicitly set this because iTerm.app doesn't for + # some reason. + COMMAND_MODE=unix2003 + esac + + # Get the PID from nodetool + get_pid + GPR=$? + if [ "$GPR" -ne 0 ] || [ -z $PID ]; then + exit $GPR + fi + + # Tell nodetool to initiate a stop + $NODETOOL stop + ES=$? + if [ "$ES" -ne 0 ]; then + exit $ES + fi + + # Wait for the node to completely stop... + while `kill -s 0 $PID 2>/dev/null` + do + sleep 1 + done + ;; + + restart) + ## Restart the VM without exiting the process + $NODETOOL restart + ES=$? + if [ "$ES" -ne 0 ]; then + exit $ES + fi + ;; + + reboot) + ## Restart the VM completely (uses heart to restart it) + $NODETOOL reboot + ES=$? + if [ "$ES" -ne 0 ]; then + exit $ES + fi + ;; + + ping) + ## See if the VM is alive + ping_node + ES=$? + if [ "$ES" -ne 0 ]; then + exit $ES + fi + ;; + + attach) + # Make sure a node is running + ping_node + ES=$? + if [ "$ES" -ne 0 ]; then + echo "Node is not running!" + exit $ES + fi + + shift + exec $ERTS_PATH/to_erl $PIPE_DIR + ;; + + remote_console) + # Make sure a node is running + ping_node + ES=$? + if [ "$ES" -ne 0 ]; then + echo "Node is not running!" + exit $ES + fi + + shift + exec $REMSH + ;; + + upgrade) + if [ -z "$2" ]; then + echo "Missing upgrade package argument" + echo "Usage: $SCRIPT upgrade {package base name}" + echo "NOTE {package base name} MUST NOT include the .tar.gz suffix" + exit 1 + fi + + # Make sure a node IS running + ping_node + ES=$? + if [ "$ES" -ne 0 ]; then + echo "Node is not running!" + exit $ES + fi + + node_name=`echo $NAME_ARG | awk '{print $2}'` + erlang_cookie=`echo $COOKIE_ARG | awk '{print $2}'` + + $ERTS_PATH/escript $RUNNER_BASE_DIR/bin/install_upgrade.escript $node_name $erlang_cookie $2 + ;; + + console|console_clean|console_boot) + # .boot file typically just $SCRIPT (ie, the app name) + # however, for debugging, sometimes start_clean.boot is useful. + # For e.g. 'setup', one may even want to name another boot script. + case "$1" in + console) BOOTFILE=$SCRIPT ;; + console_clean) BOOTFILE=start_clean ;; + console_boot) + shift + BOOTFILE="$1" + shift + ;; + esac + # Setup beam-required vars + ROOTDIR=$RUNNER_BASE_DIR + BINDIR=$ROOTDIR/erts-$ERTS_VSN/bin + EMU=beam + PROGNAME=`echo $0 | sed 's/.*\\///'` + CMD="$BINDIR/erlexec -boot $RUNNER_BASE_DIR/releases/$APP_VSN/$BOOTFILE -mode embedded -config $CONFIG_PATH -args_file $VMARGS_PATH" + export EMU + export ROOTDIR + export BINDIR + export PROGNAME + + # Dump environment info for logging purposes + echo "Exec: $CMD" -- ${1+"$@"} + echo "Root: $ROOTDIR" + + # Log the startup + logger -t "$SCRIPT[$$]" "Starting up" + + # Start the VM + exec $CMD -- ${1+"$@"} + ;; + + foreground) + # start up the release in the foreground for use by runit + # or other supervision services + + BOOTFILE=$SCRIPT + FOREGROUNDOPTIONS="-noinput +Bd" + + # Setup beam-required vars + ROOTDIR=$RUNNER_BASE_DIR + BINDIR=$ROOTDIR/erts-$ERTS_VSN/bin + EMU=beam + PROGNAME=`echo $0 | sed 's/.*\///'` + CMD="$BINDIR/erlexec $FOREGROUNDOPTIONS -boot $RUNNER_BASE_DIR/releases/$APP_VSN/$BOOTFILE -config $CONFIG_PATH -args_file $VMARGS_PATH" + export EMU + export ROOTDIR + export BINDIR + export PROGNAME + + # Dump environment info for logging purposes + echo "Exec: $CMD" -- ${1+"$@"} + echo "Root: $ROOTDIR" + + # Start the VM + exec $CMD -- ${1+"$@"} + ;; + getpid) + # Get the PID from nodetool + get_pid + ES=$? + if [ "$ES" -ne 0 ] || [ -z $PID ]; then + exit $ES + fi + echo $PID + ;; + *) + echo "Usage: $SCRIPT {start|start_boot <file>|foreground|stop|restart|reboot|ping|console|getpid|console_clean|console_boot <file>|attach|remote_console|upgrade}" + exit 1 + ;; +esac + +exit 0 diff --git a/rel/files/rvi.cmd b/rel/files/rvi.cmd new file mode 100644 index 0000000..4df8a3c --- /dev/null +++ b/rel/files/rvi.cmd @@ -0,0 +1,103 @@ +@setlocal + +@set node_name=rvi + +@rem Get the absolute path to the parent directory, +@rem which is assumed to be the node root. +@for /F "delims=" %%I in ("%~dp0..") do @set node_root=%%~fI + +@set releases_dir=%node_root%\releases + +@rem Parse ERTS version and release version from start_erl.data +@for /F "usebackq tokens=1,2" %%I in ("%releases_dir%\start_erl.data") do @( + @call :set_trim erts_version %%I + @call :set_trim release_version %%J +) + +@set vm_args=%releases_dir%\%release_version%\vm.args +@set sys_config=%releases_dir%\%release_version%\sys.config +@set node_boot_script=%releases_dir%\%release_version%\%node_name% +@set clean_boot_script=%releases_dir%\%release_version%\start_clean + +@rem extract erlang cookie from vm.args +@for /f "usebackq tokens=1-2" %%I in (`findstr /b \-setcookie "%vm_args%"`) do @set erlang_cookie=%%J + +@set erts_bin=%node_root%\erts-%erts_version%\bin + +@set service_name=%node_name%_%release_version% + +@set erlsrv="%erts_bin%\erlsrv.exe" +@set epmd="%erts_bin%\epmd.exe" +@set escript="%erts_bin%\escript.exe" +@set werl="%erts_bin%\werl.exe" +@set nodetool="%erts_bin%\nodetool" + +@if "%1"=="usage" @goto usage +@if "%1"=="install" @goto install +@if "%1"=="uninstall" @goto uninstall +@if "%1"=="start" @goto start +@if "%1"=="stop" @goto stop +@if "%1"=="restart" @call :stop && @goto start +@if "%1"=="console" @goto console +@if "%1"=="ping" @goto ping +@if "%1"=="query" @goto query +@if "%1"=="attach" @goto attach +@if "%1"=="upgrade" @goto upgrade +@echo Unknown command: "%1" + +:usage +@echo Usage: %~n0 [install^|uninstall^|start^|stop^|restart^|console^|ping^|query^|attach^|upgrade] +@goto :EOF + +:install +@set description=Erlang node %node_name% in %node_root% +@set start_erl=%node_root%\bin\start_erl.cmd +@set args= ++ %node_name% ++ %node_root% +@%erlsrv% add %service_name% -c "%description%" -sname %node_name% -w "%node_root%" -m "%start_erl%" -args "%args%" -stopaction "init:stop()." +@goto :EOF + +:uninstall +@%erlsrv% remove %service_name% +@%epmd% -kill +@goto :EOF + +:start +@%erlsrv% start %service_name% +@goto :EOF + +:stop +@%erlsrv% stop %service_name% +@goto :EOF + +:console +@start "%node_name% console" %werl% -boot "%node_boot_script%" -config "%sys_config%" -args_file "%vm_args%" -sname %node_name% +@goto :EOF + +:ping +@%escript% %nodetool% ping -sname "%node_name%" -setcookie "%erlang_cookie%" +@exit %ERRORLEVEL% +@goto :EOF + +:query +@%erlsrv% list %service_name% +@exit %ERRORLEVEL% +@goto :EOF + +:attach +@for /f "usebackq" %%I in (`hostname`) do @set hostname=%%I +start "%node_name% attach" %werl% -boot "%clean_boot_script%" -remsh %node_name%@%hostname% -sname console -setcookie %erlang_cookie% +@goto :EOF + +:upgrade +@if "%2"=="" ( + @echo Missing upgrade package argument + @echo Usage: %~n0 upgrade {package base name} + @echo NOTE {package base name} MUST NOT include the .tar.gz suffix + @goto :EOF +) +@%escript% %node_root%\bin\install_upgrade.escript %node_name% %erlang_cookie% %2 +@goto :EOF + +:set_trim +@set %1=%2 +@goto :EOF diff --git a/rel/files/start_erl.cmd b/rel/files/start_erl.cmd new file mode 100644 index 0000000..c0f2072 --- /dev/null +++ b/rel/files/start_erl.cmd @@ -0,0 +1,40 @@ +@setlocal + +@rem Parse arguments. erlsrv.exe prepends erl arguments prior to first ++. +@rem Other args are position dependent. +@set args="%*" +@for /F "delims=++ tokens=1,2,3" %%I in (%args%) do @( + @set erl_args=%%I + @call :set_trim node_name %%J + @rem Trim spaces from the left of %%K (node_root), which may have spaces inside + @for /f "tokens=* delims= " %%a in ("%%K") do @set node_root=%%a +) + +@set releases_dir=%node_root%\releases + +@rem parse ERTS version and release version from start_erl.dat +@for /F "usebackq tokens=1,2" %%I in ("%releases_dir%\start_erl.data") do @( + @call :set_trim erts_version %%I + @call :set_trim release_version %%J +) + +@set erl_exe="%node_root%\erts-%erts_version%\bin\erl.exe" +@set boot_file="%releases_dir%\%release_version%\%node_name%" + +@if exist "%releases_dir%\%release_version%\sys.config" ( + @set app_config="%releases_dir%\%release_version%\sys.config" +) else ( + @set app_config="%node_root%\etc\app.config" +) + +@if exist "%releases_dir%\%release_version%\vm.args" ( + @set vm_args="%releases_dir%\%release_version%\vm.args" +) else ( + @set vm_args="%node_root%\etc\vm.args" +) + +@%erl_exe% %erl_args% -boot %boot_file% -config %app_config% -args_file %vm_args% + +:set_trim +@set %1=%2 +@goto :EOF diff --git a/rel/files/vm.args b/rel/files/vm.args new file mode 100644 index 0000000..08e1ff1 --- /dev/null +++ b/rel/files/vm.args @@ -0,0 +1,19 @@ +## Name of the node +-name rvi@127.0.0.1 + +## Cookie for distributed erlang +-setcookie rvi + +## Heartbeat management; auto-restarts VM if it dies or becomes unresponsive +## (Disabled by default..use with caution!) +##-heart + +## Enable kernel poll and a few async threads +##+K true +##+A 5 + +## Increase number of concurrent ports/sockets +##-env ERL_MAX_PORTS 4096 + +## Tweak GC to run more often +##-env ERL_FULLSWEEP_AFTER 10 diff --git a/rel/reltool.config b/rel/reltool.config new file mode 100644 index 0000000..8405060 --- /dev/null +++ b/rel/reltool.config @@ -0,0 +1,44 @@ +%% -*- mode: erlang -*- +%% ex: ft=erlang +{sys, [ + {lib_dirs, ["../deps/"]}, + {erts, [{mod_cond, derived}, {app_file, strip}]}, + {app_file, strip}, + {rel, "rvi", "1", + [ + kernel, + stdlib, + sasl, + rvi + ]}, + {rel, "start_clean", "", + [ + kernel, + stdlib + ]}, + {boot_rel, "rvi"}, + {profile, embedded}, + {incl_cond, derived}, + {excl_archive_filters, [".*"]}, %% Do not archive built libs + {excl_sys_filters, ["^bin/(?!start_clean.boot)", + "^erts.*/bin/(dialyzer|typer)", + "^erts.*/(doc|info|include|lib|man|src)"]}, + {excl_app_filters, ["\.gitignore"]}, + {app, rvi, [{mod_cond, app}, {incl_cond, include}, {lib_dir, ".."}]} + ]}. + +{target_dir, "rvi"}. + +{overlay, [ + {mkdir, "log/sasl"}, + {copy, "files/erl", "\{\{erts_vsn\}\}/bin/erl"}, + {copy, "files/nodetool", "\{\{erts_vsn\}\}/bin/nodetool"}, + {copy, "rvi/bin/start_clean.boot", + "\{\{erts_vsn\}\}/bin/start_clean.boot"}, + {copy, "files/rvi", "bin/rvi"}, + {copy, "files/rvi.cmd", "bin/rvi.cmd"}, + {copy, "files/start_erl.cmd", "bin/start_erl.cmd"}, + {copy, "files/install_upgrade.escript", "bin/install_upgrade.escript"}, + {copy, "files/sys.config", "releases/\{\{rel_vsn\}\}/sys.config"}, + {copy, "files/vm.args", "releases/\{\{rel_vsn\}\}/vm.args"} + ]}. diff --git a/setup_rvi_node.sh b/setup_rvi_node.sh index 9daeb10..b63c65b 100755 --- a/setup_rvi_node.sh +++ b/setup_rvi_node.sh @@ -25,23 +25,96 @@ # SETUP_GEN=./deps/setup/setup_gen # Ulf's kitchen sink setup utility -if [ "$#" != "2" ] -then - echo "Usage: $0 <release_name> <config_file>" - echo "Will create a subdirectory named <release_name> which contains" - echo "all configuration and boot files necessary to bring up an rvi node." +usage() { + echo "Usage: $0 [-d] -n node_name -c config_file" + echo " -n node_name Specify the name of the rvi node to setup" + echo + echo " -c config_file Specifies the setup config file to use when setting " + echo " up the node" + echo + echo " -d Create a development release. See below." + echo + echo "The generated node will be created in a subdirectory with the same" + echo "name as the node name." + echo + echo "The created node can be started with: ./rvi_node -n node_name" + echo + echo "If the node was created with the -d flag, you need to start" + echo "the node with ./rvi_node -d -n node_name" echo - echo "Launch the node with ./rvi_node.sh <release_name>" + echo "Configuration file examples can be found in hvac_demo/vehicle.config" + echo + echo "The -d flag creates a development release that uses the erlang " + echo "binaries found in ebin/ and deps/*/ebin. This means that new builds," + echo "created by make, can be run directly through " + echo "./rvi_node -n node_name without having to run ./setup_rvi_node.sh ." echo - echo "See rvi_sample.config for configuration file example." + echo "If the -d flag is omitted, the release will be self-contained in the " + echo "newly created subdirectory rel/[node_name]." + echo "This directory, containing a standard erlang reltool release, " + echo "including the erlang runtime system, can be copied as a stand-alone" + echo "system to a destination node." echo + echo "Configuration file examples can be found in hvac_demo/vehicle.config" exit 1 +} + + +build_type=rel +while getopts "dn:c:" o; do + case "${o}" in + n) + NODE_NAME=${OPTARG} + ;; + c) + CONFIG_NAME=${OPTARG} + ;; + d) + build_type=dev + ;; + *) + usage + ;; + esac +done + +if [ -z "${NODE_NAME}" ] ; then + echo "Missing -n flag" + usage +fi +if [ -z "${CONFIG_NAME}" ] ; then + echo "Missing -c flag" + usage fi + export ERL_LIBS=$PWD/deps:$ERL_LIBS:$PWD +echo "Setting up node $NODE_NAME." +$SETUP_GEN $NODE_NAME $CONFIG_NAME $NODE_NAME -$SETUP_GEN $1 $2 $1 +if [ "${build_type}" = "dev" ] +then + echo "RVI Node $NODE_NAME has been setup. Launch with ./rvi_node.sh -n $NODE_NAME" + exit +else + echo "Building stand-alone release for $NODE_NAME" + # Copy the newly created config file. + cp $NODE_NAME/sys.config rel/files/sys.config + rebar generate + # Rename the release after the node name + mv rel/rvi rel/$NODE_NAME + echo "Stand alone release for $NODE_NAME created under ./rel/$NODE_NAME." + echo + echo "Start: ./rel/$NODE_NAME/bin/rvi start" + echo "Attach console: ./rel/$NODE_NAME/bin/rvi attach" + echo "Stop: ./rel/$NODE_NAME/bin/rvi stop" + echo "Start console mode: ./rel/$NODE_NAME/bin/rvi console" + echo + echo "Start dev mode: ./rvi_node.sh -n $NODE_NAME" + echo + echo "./rel/$NODE_NAME can be copied and installed on its destination host." + +fi -echo "RVI Node $1 has been setup. Launch with ./rvi_node.sh -n $1" exit 0 |