#!/bin/sh set -e SCRIPT_DIR="$(dirname "$0")" RELEASE_ROOT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" REL_NAME="{{ rel_name }}" REL_VSN="{{ rel_vsn }}" ERTS_VSN="{{ erts_vsn }}" REL_DIR="$RELEASE_ROOT_DIR/releases/$REL_VSN" ERL_OPTS="{{ erl_opts }}" RUNNER_LOG_DIR="${RUNNER_LOG_DIR:-$RELEASE_ROOT_DIR/log}" find_erts_dir() { local erts_dir="$RELEASE_ROOT_DIR/erts-$ERTS_VSN" if [ -d "$erts_dir" ]; then ERTS_DIR="$erts_dir"; ROOTDIR="$RELEASE_ROOT_DIR" else local erl="$(which erl)" code="io:format(\"~s\", [code:root_dir()])." local erl_root="$("$erl" -noshell -eval "$code" -s init stop)" ERTS_DIR="$erl_root/erts-$ERTS_VSN" ROOTDIR="$erl_root" fi } # Connect to a remote node relx_rem_sh() { # Generate a unique id used to allow multiple remsh to the same node # transparently id="remsh$(relx_gen_id)-${NAME}" # Get the node's ticktime so that we use the same thing. TICKTIME="$(relx_nodetool rpcterms net_kernel get_net_ticktime)" # Setup remote shell command to control node exec "$BINDIR/erl" "$NAME_TYPE" "$id" -remsh "$NAME" -boot start_clean \ -boot_var ERTS_LIB_DIR "$ERTS_LIB_DIR" \ -setcookie "$COOKIE" -kernel net_ticktime $TICKTIME } # Generate a random id relx_gen_id() { od -X /dev/urandom | head -n1 | cut -d ' ' -f2 } # Control a node relx_nodetool() { command="$1"; shift "$ERTS_DIR/bin/escript" "$ROOTDIR/bin/nodetool" "$NAME_TYPE" "$NAME" \ -setcookie "$COOKIE" "$command" $@ } # Run an escript in the node's environment relx_escript() { shift; scriptpath="$1"; shift export RELEASE_ROOT_DIR "$ERTS_DIR/bin/escript" "$ROOTDIR/$scriptpath" $@ } # Output a start command for the last argument of run_erl relx_start_command() { printf "exec \"%s\" \"%s\"" "$RELEASE_ROOT_DIR/bin/$REL_NAME" \ "$START_OPTION" } # Use $CWD/vm.args if exists, otherwise releases/VSN/vm.args if [ -z "$VMARGS_PATH" ]; then if [ -f "$RELEASE_ROOT_DIR/vm.args" ]; then VMARGS_PATH="$RELEASE_ROOT_DIR/vm.args" USE_DIR="$RELEASE_ROOT_DIR" else USE_DIR="$REL_DIR" VMARGS_PATH="$REL_DIR/vm.args" fi fi if [ $RELX_REPLACE_OS_VARS ]; then awk '{while(match($0,"[$]{[^}]*}")) {var=substr($0,RSTART+2,RLENGTH -3);gsub("[$]{"var"}",ENVIRON[var])}}1' < $VMARGS_PATH > $VMARGS_PATH.2.config VMARGS_PATH=$VMARGS_PATH.2.config fi # Make sure log directory exists mkdir -p "$RUNNER_LOG_DIR" if [ -z "$CONFIG_PATH" ]; then if [ -f "$USE_DIR/sys.config" ]; then CONFIG_PATH="$USE_DIR/sys.config" else CONFIG_PATH="$REL_DIR/sys.config" fi fi if [ $RELX_REPLACE_OS_VARS ]; then awk '{while(match($0,"[$]{[^}]*}")) {var=substr($0,RSTART+2,RLENGTH -3);gsub("[$]{"var"}",ENVIRON[var])}}1' < $CONFIG_PATH > $CONFIG_PATH.2.config CONFIG_PATH=$CONFIG_PATH.2.config 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 NAME_TYPE="$(echo "$NAME_ARG" | awk '{print $1}')" NAME="$(echo "$NAME_ARG" | awk '{print $2}')" # User can specify an sname without @hostname # This will fail when creating remote shell # So here we check for @ and add @hostname if missing case $NAME in *@*) # Nothing to do ;; *) # Add @hostname case $NAME_TYPE in -sname) NAME=$NAME@`hostname -s` ;; -name) NAME=$NAME@`hostname -f` ;; esac ;; esac PIPE_DIR="${PIPE_DIR:-/tmp/erl_pipes/$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 # Extract cookie name from COOKIE_ARG COOKIE="$(echo "$COOKIE_ARG" | awk '{print $2}')" find_erts_dir export ROOTDIR="$RELEASE_ROOT_DIR" export BINDIR="$ERTS_DIR/bin" export EMU="beam" export PROGNAME="erl" export LD_LIBRARY_PATH="$ERTS_DIR/lib:$LD_LIBRARY_PATH" ERTS_LIB_DIR="$ERTS_DIR/../lib" cd "$ROOTDIR" # Check the first argument for instructions case "$1" in start|start_boot) # Make sure there is not already a node running #RES=`$NODETOOL ping` #if [ "$RES" = "pong" ]; then # echo "Node is already running!" # exit 1 #fi # Save this for later. CMD=$1 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="$@" # Set arguments for the heart command set -- "$SCRIPT_DIR/$REL_NAME" "$HEART_OPTION" [ "$RUN_PARAM" ] && set -- "$@" "$RUN_PARAM" # Export the HEART_COMMAND HEART_COMMAND="$RELEASE_ROOT_DIR/bin/$REL_NAME $CMD" export HEART_COMMAND mkdir -p "$PIPE_DIR" "$BINDIR/run_erl" -daemon "$PIPE_DIR" "$RUNNER_LOG_DIR" \ "$(relx_start_command)" ;; stop) # Wait for the node to completely stop... case $(uname -s) in Linux|Darwin|FreeBSD|DragonFly|NetBSD|OpenBSD) # PID COMMAND PID=$(ps ax -o pid= -o command=| grep "$RELEASE_ROOT_DIR/.*/[b]eam"|awk '{print $1}') ;; SunOS) # PID COMMAND PID=$(ps -ef -o pid= -o args=| grep "$RELEASE_ROOT_DIR/.*/[b]eam"|awk '{print $1}') ;; CYGWIN*) # UID PID PPID TTY STIME COMMAND PID=$(ps -efw|grep "$RELEASE_ROOT_DIR/.*/[b]eam"|awk '{print $2}') ;; esac if ! relx_nodetool "stop"; then exit $? fi while $(kill -0 "$PID" 2>/dev/null); do sleep 1 done ;; restart) ## Restart the VM without exiting the process if ! relx_nodetool "restart"; then exit $? fi ;; reboot) ## Restart the VM completely (uses heart to restart it) if ! relx_nodetool "reboot"; then exit $? fi ;; ping) ## See if the VM is alive if ! relx_nodetool "ping"; then exit $? fi ;; escript) ## Run an escript under the node's environment if ! relx_escript $@; then exit $? fi ;; attach) # Make sure a node IS running if ! relx_nodetool "ping" > /dev/null; then ES="$?" echo "Node is not running!" exit $ES fi shift exec "$BINDIR/to_erl" "$PIPE_DIR" ;; remote_console) # Make sure a node IS running if ! relx_nodetool "ping" > /dev/null; then ES="$?" echo "Node is not running!" exit $ES fi shift relx_rem_sh ;; upgrade|downgrade|install) if [ -z "$2" ]; then echo "Missing package argument" echo "Usage: $REL_NAME $1 {package base name}" echo "NOTE {package base name} MUST NOT include the .tar.gz suffix" exit 1 fi # Make sure a node IS running if ! relx_nodetool "ping" > /dev/null; then ES="$?" echo "Node is not running!" exit $ES fi exec "$BINDIR/escript" "$ROOTDIR/bin/install_upgrade.escript" \ "$REL_NAME" "$NAME" "$COOKIE" "$2" ;; console|console_clean|console_boot) # .boot file typically just $REL_NAME (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) if [ -f "$REL_DIR/$REL_NAME.boot" ]; then BOOTFILE="$REL_DIR/$REL_NAME" else BOOTFILE="$REL_DIR/start" fi ;; console_clean) BOOTFILE="$ROOTDIR/bin/start_clean" ;; console_boot) shift BOOTFILE="$1" shift ;; esac # Setup beam-required vars EMU="beam" PROGNAME="${0#*/}" export EMU export PROGNAME # Store passed arguments since they will be erased by `set` ARGS="$@" # Build an array of arguments to pass to exec later on # Build it here because this command will be used for logging. set -- "$BINDIR/erlexec" -boot "$BOOTFILE" \ -boot_var ERTS_LIB_DIR "$ERTS_LIB_DIR" \ -env ERL_LIBS "$REL_DIR/lib" -config "$CONFIG_PATH" \ -args_file "$VMARGS_PATH" # Dump environment info for logging purposes echo "Exec: $@" -- ${1+$ARGS} echo "Root: $ROOTDIR" # Log the startup echo "$RELEASE_ROOT_DIR" logger -t "$REL_NAME[$$]" "Starting up" # Start the VM exec "$@" -- ${1+$ARGS} ;; foreground) # start up the release in the foreground for use by runit # or other supervision services [ -f "$REL_DIR/$REL_NAME.boot" ] && BOOTFILE="$REL_NAME" || BOOTFILE=start FOREGROUNDOPTIONS="-noshell -noinput +Bd" # Setup beam-required vars EMU=beam PROGNAME="${0#*/}" export EMU export PROGNAME # Store passed arguments since they will be erased by `set` ARGS="$@" # Build an array of arguments to pass to exec later on # Build it here because this command will be used for logging. set -- "$BINDIR/erlexec" $FOREGROUNDOPTIONS \ -boot "$REL_DIR/$BOOTFILE" -mode embedded -config "$CONFIG_PATH" \ -boot_var ERTS_LIB_DIR "$ERTS_LIB_DIR" \ -args_file "$VMARGS_PATH" # Dump environment info for logging purposes echo "Exec: $@" -- ${1+$ARGS} echo "Root: $ROOTDIR" # Start the VM exec "$@" -- ${1+$ARGS} ;; *) echo "Usage: $REL_NAME {start|start_boot |foreground|stop|restart|reboot|ping|console|console_clean|console_boot |attach|remote_console|upgrade|escript}" exit 1 ;; esac exit 0