summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbenoitc <bchesneau@gmail.com>2014-02-15 10:24:56 +0100
committerbenoitc <bchesneau@gmail.com>2014-02-15 10:24:56 +0100
commit6e59a7834da941fee2e33941097f24f09ac493a0 (patch)
tree17ecaf32c858803ace139dfae0f8a1dea3577bf4
parent483dc97723009f5b1c67194bf6e0e1e05010829d (diff)
downloadcouchdb-1994-merge-rcouch-multi-repo.tar.gz
remove node_package dependency1994-merge-rcouch-multi-repo
-rw-r--r--NOTICE42
-rw-r--r--rebar.config4
-rwxr-xr-xrel/files/app_epath.sh173
-rwxr-xr-xrel/files/env.sh229
-rwxr-xr-xrel/files/erl45
-rwxr-xr-xrel/files/nodetool197
-rwxr-xr-xrel/files/runner319
-rw-r--r--rel/reltool.config.script10
8 files changed, 999 insertions, 20 deletions
diff --git a/NOTICE b/NOTICE
index 60ec29826..1a6139c0b 100644
--- a/NOTICE
+++ b/NOTICE
@@ -21,7 +21,7 @@ This product also includes the following third-party components:
* jQuery (http://jquery.org/)
Copyright 2012 jQuery Foundation and other contributors
-
+
* jQuery UI (http://jqueryui.com)
Copyright 2011, Paul Bakaus
@@ -75,13 +75,13 @@ This product also includes the following third-party components:
Copyright 2011, Jeremy Ashkenas
* Sphinx (http://sphinx-doc.org/)
-
+
Copyright 2011, the Sphinx team
* Sizzle (http://sizzlejs.com/)
-
+
Copyright 2010, The Dojo Foundation
-
+
* Underscore.js 1.4.2 (http://underscorejs.org)
Copyright 2012, Jeremy Ashkenas
@@ -131,25 +131,25 @@ This product also includes the following third-party components:
Copyright 2006-2013 (c) M. Alsup
* couch_dbupdates
-
+
Copyright 2012, Benoît Chesneau <benoitc@refuge.io>
-
+
* mocha.js (https://github.com/visionmedia/mocha)
-
+
Copyright (c) 2011-2013 TJ Holowaychuk <tj@vision-media.ca>
* chaijs https://github.com/chaijs
-
+
Copyright (c) 2011-2013 Jake Luer jake@alogicalparadox.com
* sinon-chai
Copyright © 2012–2013 Domenic Denicola <domenic@domenicdenicola.com>
-
+
* spin.js
Copyright (c) 2011 Felix Gnass [fgnass at neteye dot de]
-
+
* font-awesome http://fortawesome.github.io/Font-Awesome/
Copyright (c) 2013 Dave Gandy
@@ -188,4 +188,24 @@ This product also includes the following third-party components:
* rebar https://github.com/rebar/rebar
- Copyright (c) 2009 Dave Smith (dizzyd@dizzyd.com)
+ Copyright (c) 2009 Dave Smith (dizzyd@dizzyd.com)
+
+ * rel/files/app_epath.sh https://github.com/basho/node_package
+
+ Copyright 2014 Basho - Apache License 2
+
+ * rel/files/env.sh https://github.com/basho/node_package
+
+ Copyright 2014 Basho - Apache License 2
+
+ * rel/files/erl https://github.com/basho/node_package
+
+ Copyright 2014 Basho - Apache License 2
+
+ * rel/files/nodetool https://github.com/basho/node_package
+
+ Copyright 2014 Basho - Apache License 2
+
+ * rel/files/runner https://github.com/basho/node_package
+
+ Copyright 2014 Basho - Apache License 2
diff --git a/rebar.config b/rebar.config
index a6959a382..a7a255c53 100644
--- a/rebar.config
+++ b/rebar.config
@@ -9,10 +9,6 @@
{require_otp_vsn, "R14B04|R15|R16"}.
{deps, [
- %% packaging
- {node_package, ".*", {git, "git://github.com/basho/node_package",
- {tag, "1.3.8"}}},
-
%% erlang oauth module
{oauth, ".*",
{git, "http://git-wip-us.apache.org/repos/asf/couchdb-oauth.git",
diff --git a/rel/files/app_epath.sh b/rel/files/app_epath.sh
new file mode 100755
index 000000000..a3de910b0
--- /dev/null
+++ b/rel/files/app_epath.sh
@@ -0,0 +1,173 @@
+#!/bin/sh
+
+## ---------------------------------------------------------------------
+##
+## app_epath.sh: Parse Erlang app.config with POSIX tools for automation
+##
+## Copyright (c) 2013 Basho Technologies, Inc. All Rights Reserved.
+##
+## This file is provided to you under the Apache License,
+## Version 2.0 (the "License"); you may not use this file
+## except in compliance with the License. You may obtain
+## a copy of the License at
+##
+## http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing,
+## software distributed under the License is distributed on an
+## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+## KIND, either express or implied. See the License for the
+## specific language governing permissions and limitations
+## under the License.
+##
+## ---------------------------------------------------------------------
+
+## Example usage:
+#
+# #!/bin/sh
+#
+# # Load the functions
+# . path/to/app_epath.sh
+#
+# # Build the path info
+# epaths=`make_app_epaths path/to/app.config`
+#
+# # View all of the settings. Quotes are important.
+# echo "$epaths"
+#
+# # Grep around in the paths for various items.
+# echo "$epaths" | grep 'riak_core ring_creation_size'
+# echo "$epaths" | grep "lager handlers lager_file_backend" | grep info
+#
+# # Use the epath function to get directly at settings
+# epath 'riak_core ring_creation_size' "$epaths"
+# epath 'riak_core platform_bin_dir' "$epaths"
+# epath 'riak_kv storage_backend' "$epaths"
+#
+# # Use epath to view all of the riak_core settings
+# epath riak_core
+#
+## End example
+
+## Here is a command you can put in your path for general cli use.
+#
+# #!/bin/sh
+#
+# # $1 quoted eterm path for search: 'riak_core ring_creation_size'
+# # $2 path/to/app.config
+#
+# . path/to/app_epath.sh
+#
+# epaths=`make_app_epaths "$2"`
+# epath "$1" "$epaths"
+#
+## End epath command
+
+# make_app_epaths takes a path to an app.config file as its argument and
+# and returns (prints) a flattened text structure of configuration settings.
+
+make_app_epaths () {
+ # Remove all lines containing comments
+ # Remove all blank lines
+ # Remove the first [
+ # Remove the last ].
+ # Remove all blank lines again (just in case)
+ appconfig=`cat $1 \
+ | sed '/^[ \t]*%/d' \
+ | sed '/^[ \t]*$/d' \
+ | sed -e '/\[/{s///;:a' -e '$!N;$!ba' -e '}' \
+ | sed '$ s/\]\.//g' \
+ | sed '/^[ \t]*$/d'`
+
+ STACK=
+ INQUOTE=0
+ # The awk puts each char, spaces included, on their own line for parsing.
+ echo "$appconfig" | awk '{gsub(//,"\n");print}' | while read i; do
+ case "x${i}x" in
+ "x\"x")
+ # Flip the INQUOTE state and echo the quote
+ if [ 1 -eq $INQUOTE ]; then
+ INQUOTE=0
+ else
+ INQUOTE=1
+ fi
+ STACK="${STACK}${i}"
+ ;;
+ "xx")
+ if [ 1 -eq $INQUOTE ]; then
+ # If in quotes, keep this space
+ STACK="${STACK} "
+ fi
+ ;;
+ "x,x")
+ if [ 1 -eq $INQUOTE ]; then
+ # If in quotes, keep this comma
+ STACK="${STACK},"
+ else
+ # Commas outside quotes means a new item is next
+ STACK="${STACK} "
+ fi
+ ;;
+ "x{x")
+ if [ 1 -eq $INQUOTE ]; then
+ # If in quotes, keep this bracket
+ STACK="${STACK}{"
+ else
+ # Add brace to the stack; will pop off from here on next }
+ STACK="${STACK} __EBRACE__ "
+ fi
+ ;;
+ "x}x")
+ if [ 1 -eq $INQUOTE ]; then
+ # If in quotes, keep this bracket
+ STACK="${STACK}}"
+ else
+ # We're only interested in printing leaves, not
+ # intermediates like 'riak_core http', which contain lists.
+ # See if the current stack ends with ] (end of list).
+ echo $STACK | grep -E "__EBRACKET__$" >/dev/null 2>&1
+ if [ 1 -eq $? ]; then
+ # If not, print the stack without all of the mess.
+ echo "$STACK" | \
+ sed 's/ *__EBRACE__//g;s/ *__EBRACKET__//g;s/^ *//'
+ fi
+ # Pop off everything from the last brace on.
+ STACK=`echo "$STACK" | sed 's/\(.*\) __EBRACE__.*/\1/g'`
+ fi
+ ;;
+ "x[x")
+ if [ 1 -eq $INQUOTE ]; then
+ # If in quotes, keep this bracket
+ STACK="${STACK}["
+ else
+ # Add a placeholder to aid in determining whether or not to
+ # print. That is, we don't want to print 'riak_core http'.
+ STACK="${STACK} __EBRACKET__ "
+ fi
+ ;;
+ "x]x")
+ if [ 1 -eq $INQUOTE ]; then
+ # If in quotes, keep this bracket
+ STACK="${STACK}]"
+ fi
+ # Don't actually do anything with ], as the starting brackets
+ # are instead removed with }.
+ ;;
+ *)
+ # Anything else is just pushed.
+ STACK="${STACK}${i}"
+ ;;
+ esac
+ done
+}
+
+epath () {
+ # arg1 - a pattern to search for
+ # arg2 - output of make_app_epaths, passed in quoted
+ # output - search of arg2 for arg1, trimming arg1 from the beginning
+ # Note: there may be multiple lines of output.
+ pat=$1
+ shift
+ echo "$*" | grep "$pat " | sed "s/^${pat} *//"
+}
+
diff --git a/rel/files/env.sh b/rel/files/env.sh
new file mode 100755
index 000000000..5a44a9919
--- /dev/null
+++ b/rel/files/env.sh
@@ -0,0 +1,229 @@
+#!/bin/sh
+# -*- tab-width:4;indent-tabs-mode:nil -*-
+# ex: ts=4 sw=4 et
+
+# installed by node_package (github.com/basho/node_package)
+
+# /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
+unset POSIX_SHELL # clear it so if we invoke other scripts, they run as ksh as well
+
+RUNNER_SCRIPT_DIR={{runner_script_dir}}
+RUNNER_SCRIPT=${0##*/}
+
+RUNNER_BASE_DIR={{runner_base_dir}}
+RUNNER_ETC_DIR={{runner_etc_dir}}
+RUNNER_LOG_DIR={{runner_log_dir}}
+RUNNER_LIB_DIR={{runner_lib_dir}}
+RUNNER_PATCH_DIR={{runner_patch_dir}}
+PIPE_DIR={{pipe_dir}}
+RUNNER_USER={{runner_user}}
+APP_VERSION={{app_version}}
+
+# Variables needed to support creation of .pid files
+# PID directory and pid file name of this app
+# ex: /var/run/riak & /var/run/riak/riak.pid
+RUN_DIR="/var/run" # for now hard coded unless we find a platform that differs
+PID_DIR=$RUN_DIR/$RUNNER_SCRIPT
+PID_FILE=$PID_DIR/$RUNNER_SCRIPT.pid
+
+# Threshold where users will be warned of low ulimit file settings
+# default it if it is not set
+ULIMIT_WARN={{runner_ulimit_warn}}
+if [ -z "$ULIMIT_WARN" ]; then
+ ULIMIT_WARN=4096
+fi
+
+# Registered process to wait for to consider start a success
+WAIT_FOR_PROCESS={{runner_wait_process}}
+
+WHOAMI=`whoami`
+
+# Echo to stderr on errors
+echoerr() { echo "$@" 1>&2; }
+
+# Extract the target node name from node.args
+NAME_ARG=`egrep '^\-s?name' $RUNNER_ETC_DIR/vm.args`
+if [ -z "$NAME_ARG" ]; then
+ echoerr "vm.args needs to have either -name or -sname parameter."
+ exit 1
+fi
+
+# Learn how to specify node name for connection from remote nodes
+echo "$NAME_ARG" | grep '^-sname' > /dev/null 2>&1
+if [ "X$?" = "X0" ]; then
+ NAME_PARAM="-sname"
+ NAME_HOST=""
+else
+ NAME_PARAM="-name"
+ echo "$NAME_ARG" | grep '@.*' > /dev/null 2>&1
+ if [ "X$?" = "X0" ]; then
+ NAME_HOST=`echo "${NAME_ARG}" | sed -e 's/.*\(@.*\)$/\1/'`
+ else
+ NAME_HOST=""
+ fi
+fi
+
+# Extract the target cookie
+COOKIE_ARG=`grep '^\-setcookie' $RUNNER_ETC_DIR/vm.args`
+if [ -z "$COOKIE_ARG" ]; then
+ echoerr "vm.args needs to have a -setcookie parameter."
+ exit 1
+fi
+
+# Parse out release and erts info
+START_ERL=`cat $RUNNER_BASE_DIR/releases/start_erl.data`
+ERTS_VSN=${START_ERL% *}
+APP_VSN=${START_ERL#* }
+
+# 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"
+NODETOOL_LITE="$ERTS_PATH/escript $ERTS_PATH/nodetool"
+
+# Ping node without stealing stdin
+ping_node() {
+ $NODETOOL ping < /dev/null
+}
+
+# Attempts to create a pid directory like /var/run/APPNAME and then
+# changes the permissions on that directory so the $RUNNER_USER can
+# read/write/delete .pid files during startup/shutdown
+create_pid_dir() {
+ # Validate RUNNER_USER is set and they have permissions to write to /var/run
+ # Don't continue if we've already sudo'd to RUNNER_USER
+ if ([ "$RUNNER_USER" ] && [ "x$WHOAMI" != "x$RUNNER_USER" ]); then
+ if [ -w $RUN_DIR ]; then
+ mkdir -p $PID_DIR
+ ES=$?
+ if [ "$ES" -ne 0 ]; then
+ return 1
+ else
+ # Change permissions on $PID_DIR
+ chown $RUNNER_USER $PID_DIR
+ ES=$?
+ if [ "$ES" -ne 0 ]; then
+ return 1
+ else
+ return 0
+ fi
+ fi
+ else
+ # If we don't have permissions, fail
+ return 1
+ fi
+ fi
+
+ # If RUNNER_USER is not set this is probably a test setup (devrel) and does
+ # not need a .pid file, so do not return error
+ return 0
+}
+
+# Attempt to create a pid file for the process
+# This function assumes the process is already up and running and can
+# respond to a getpid call. It also assumes that two processes
+# with the same name will not be run on the machine
+# Do not print any error messages as failure to create a pid file because
+# pid files are strictly optional
+# This function should really only be called in a "start" function
+# you have been warned
+create_pid_file() {
+ # Validate a pid directory even exists
+ if [ -w $PID_DIR ]; then
+ # Grab the proper pid from getpid
+ get_pid
+ ES=$?
+ if [ "$ES" -ne 0 ]; then
+ return $ES
+ else
+ # Remove pid file if it already exists since we do not
+ # plan for multiple identical runners on a single machine
+ rm -f $PID_FILE
+ echo $PID > $PID_FILE
+ return 0
+ fi
+ else
+ return 1
+ fi
+}
+
+# Function to su into correct user
+check_user() {
+ # Validate that the user running the script is the owner of the
+ # RUN_DIR.
+ if ([ "$RUNNER_USER" ] && [ "x$WHOAMI" != "x$RUNNER_USER" ]); then
+ type sudo > /dev/null 2>&1
+ if [ "$?" -ne 0 ]; then
+ echoerr "sudo doesn't appear to be installed and your EUID isn't $RUNNER_USER" 1>&2
+ exit 1
+ fi
+ exec sudo -H -u $RUNNER_USER -i $RUNNER_SCRIPT_DIR/$RUNNER_SCRIPT $@
+ fi
+}
+
+# Function to validate the node is down
+node_down_check() {
+ MUTE=`ping_node 2> /dev/null`
+ if [ "$?" -eq 0 ]; then
+ echoerr "Node is already running!"
+ exit 1
+ fi
+}
+
+# Function to validate the node is up
+node_up_check() {
+ MUTE=`ping_node 2> /dev/null`
+ if [ "$?" -ne 0 ]; then
+ echoerr "Node is not running!"
+ exit 1
+ fi
+}
+
+# Function to check if the config file is valid
+check_config() {
+ MUTE=`$NODETOOL_LITE chkconfig $RUNNER_ETC_DIR/app.config`
+ if [ "$?" -ne 0 ]; then
+ echoerr "Error reading $RUNNER_ETC_DIR/app.config"
+ exit 1
+ fi
+ echo "config is OK"
+}
+
+# Function to check if ulimit is properly set
+check_ulimit() {
+
+ # don't fail if this is unset
+ if [ ! -z "$ULIMIT_WARN" ]; then
+ ULIMIT_F=`ulimit -n`
+ if [ "$ULIMIT_F" -lt $ULIMIT_WARN ]; then
+ echo "!!!!"
+ echo "!!!! WARNING: ulimit -n is ${ULIMIT_F}; ${ULIMIT_WARN} is the recommended minimum."
+ echo "!!!!"
+ fi
+ fi
+}
+
+# Set the PID global variable, return 1 on error
+get_pid() {
+ PID=`$NODETOOL getpid < /dev/null`
+ if [ "$?" -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
+}
diff --git a/rel/files/erl b/rel/files/erl
new file mode 100755
index 000000000..ec41a7700
--- /dev/null
+++ b/rel/files/erl
@@ -0,0 +1,45 @@
+#!/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
+unset POSIX_SHELL # clear it so if we invoke other scripts, they run as ksh as well
+
+
+## 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.
+
+## installed by node_package (github.com/basho/node_package)
+
+# Determine the abspath of where this script is executing from.
+ERTS_BIN_DIR=$(cd ${0%/*} && pwd)
+
+# 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/nodetool b/rel/files/nodetool
new file mode 100755
index 000000000..41b88e455
--- /dev/null
+++ b/rel/files/nodetool
@@ -0,0 +1,197 @@
+#!/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
+%%
+%% -------------------------------------------------------------------
+
+%% installed by node_package (github.com/basho/node_package)
+
+main(Args) ->
+ ok = start_epmd(),
+ %% Extract the args
+ {RestArgs, TargetNode} = process_args(Args, [], undefined),
+
+ %% Extract the RPC timeout from process dictionary, if it's defined
+ RpcTimeout = case erlang:get(rpctimeout) of
+ undefined ->
+ 60000;
+ Value ->
+ Value
+ end,
+
+ %% process_args() has side-effects (e.g. when processing "-name"),
+ %% so take care of app-starting business first.
+ [application:start(App) || App <- [crypto, public_key, ssl]],
+
+ %% 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(standard_error, "failed to connect to node ~p .\n", [TargetNode]),
+ halt(1);
+ {_, pang} ->
+ io:format(standard_error, "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, [], RpcTimeout)]);
+ ["restart"] ->
+ io:format("~p\n", [rpc:call(TargetNode, init, restart, [], RpcTimeout)]);
+ ["reboot"] ->
+ io:format("~p\n", [rpc:call(TargetNode, init, reboot, [], RpcTimeout)]);
+ ["rpc", Module, Function | RpcArgs] ->
+ case rpc:call(TargetNode, list_to_atom(Module), list_to_atom(Function),
+ [RpcArgs], RpcTimeout) of
+ ok ->
+ ok;
+ {badrpc, Reason} ->
+ io:format(standard_error, "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(standard_error, "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), RpcTimeout) of
+ {badrpc, Reason} ->
+ io:format(standard_error, "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 {ping|stop|restart|reboot|chkconfig}\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(["-rpctimeout", TimeoutStr | Rest], Acc, TargetNode) ->
+ Timeout = case TimeoutStr of
+ "infinity" -> infinity;
+ _ -> list_to_integer(TimeoutStr)
+ end,
+ erlang:put(rpctimeout, Timeout),
+ process_args(Rest, Acc, TargetNode);
+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/runner b/rel/files/runner
new file mode 100755
index 000000000..ffad13f96
--- /dev/null
+++ b/rel/files/runner
@@ -0,0 +1,319 @@
+#!/bin/sh
+# -*- tab-width:4;indent-tabs-mode:nil -*-
+# ex: ts=4 sw=4 et
+
+# installed by node_package (github.com/basho/node_package)
+
+# Pull environment for this install
+. "{{runner_base_dir}}/lib/env.sh"
+
+
+# Keep track of where script was invoked
+ORIGINAL_DIR=$(pwd)
+
+# Make sure CWD is set to runner run dir
+cd $RUNNER_BASE_DIR
+
+# Identify the script name
+SCRIPT=`basename $0`
+
+usage() {
+ echo "Usage: $SCRIPT {start | stop| restart | reboot | ping | console | attach | "
+ echo " attach-direct | ertspath | chkconfig | escript | version | "
+ echo " getpid | top [-interval N] [-sort reductions|memory|msg_q] [-lines N] }"
+}
+
+# All commands must either call bootstrap or bootstrapd
+# Call bootstrap for non-daemon commands like ping or chkconfig
+# Call bootstrapd for daemon commands like start/stop/console
+bootstrap() {
+ # Make sure the user running this script is the owner and/or su to that user
+ check_user $@
+ ES=$?
+ if [ "$ES" -ne 0 ]; then
+ exit $ES
+ fi
+}
+
+bootstrapd() {
+ # Create PID directory if it does not exist before dropping permissiongs
+ # to the runner user
+ create_pid_dir
+ ES=$?
+ if [ "$ES" -ne 0 ]; then
+ echoerr "Unable to access $PID_DIR, permission denied, run script as root"
+ exit 1
+ fi
+
+ # Now call bootstrap to drop to $RUNNER_USER
+ bootstrap $@
+}
+
+# Check the first argument for instructions
+case "$1" in
+ start)
+ # Bootstrap daemon command (check perms & drop to $RUNNER_USER)
+ bootstrapd $@
+
+ # Make sure there is not already a node running
+ node_down_check
+
+ # Sanity check the app.config file
+ check_config > /dev/null
+ ES=$?
+ if [ "$ES" -ne 0 ]; then
+ exit $ES
+ fi
+
+ # Warn the user if ulimit is too low
+ check_ulimit
+
+ # Make sure log directory exists
+ mkdir -p $RUNNER_LOG_DIR
+
+ HEART_COMMAND="$RUNNER_SCRIPT_DIR/$RUNNER_SCRIPT start"
+ export HEART_COMMAND
+ mkdir -p $PIPE_DIR
+ $ERTS_PATH/run_erl -daemon $PIPE_DIR/ $RUNNER_LOG_DIR \
+ "exec $RUNNER_SCRIPT_DIR/$RUNNER_SCRIPT console" 2>&1
+
+ if [ ! -z "$WAIT_FOR_PROCESS" ]; then
+ # Wait for the node to come up. We can't just ping it because
+ # distributed erlang comes up for a second before the node crashes
+ # (eg. in the case of an unwriteable disk). Once the node comes
+ # up we check for the $WAIT_FOR_PROCESS} process. If that's running
+ # then we assume things are good enough. This will at least let
+ # the user know when the node is crashing right after startup.
+ WAIT=${WAIT_FOR_ERLANG:-15}
+ while [ $WAIT -gt 0 ]; do
+ WAIT=`expr $WAIT - 1`
+ sleep 1
+
+ # squash stderr output to not frighten users if the node does not
+ # come up right away
+ MUTE=`ping_node 2> /dev/null`
+ if [ "$?" -ne 0 ]; then
+ continue
+ fi
+ PROCESS=`$NODETOOL rpcterms erlang whereis "'${WAIT_FOR_PROCESS}'."`
+ if [ "$PROCESS" != "undefined" ]; then
+ # Attempt to create a .pid file for the process
+ create_pid_file
+ exit 0
+ fi
+ done
+ echo "${SCRIPT} failed to start within ${WAIT_FOR_ERLANG:-15} seconds,"
+ echo "see the output of '${SCRIPT} console' for more information."
+ echo "If you want to wait longer, set the environment variable"
+ echo "WAIT_FOR_ERLANG to the number of seconds to wait."
+ exit 1
+ fi
+
+ # Attempt to create .pid file
+ create_pid_file
+ ;;
+
+ stop)
+ # Bootstrap daemon command (check perms & drop to $RUNNER_USER)
+ bootstrapd $@
+
+ get_pid
+ ES=$?
+ if [ "$ES" -ne 0 ] || [ -z $PID ]; then
+ exit $ES
+ fi
+
+ # Tell nodetool to stop
+ $NODETOOL stop
+ ES=$?
+ if [ "$ES" -ne 0 ]; then
+ exit $ES
+ fi
+
+ # Now wait for the app to *really* stop
+ while `kill -s 0 $PID 2>/dev/null`;
+ do
+ sleep 1
+ done
+
+ # remove pid file
+ rm -f $PID_FILE
+ ;;
+
+ restart)
+ # Bootstrap daemon command (check perms & drop to $RUNNER_USER)
+ bootstrapd $@
+
+ ## Restart the VM without exiting the process
+ $NODETOOL restart
+ ES=$?
+ if [ "$ES" -ne 0 ]; then
+ exit $ES
+ fi
+ ;;
+
+ reboot)
+ # Bootstrap daemon command (check perms & drop to $RUNNER_USER)
+ bootstrapd $@
+
+ ## Restart the VM completely (uses heart to restart it)
+ $NODETOOL reboot
+ ES=$?
+ if [ "$ES" -ne 0 ]; then
+ exit $ES
+ fi
+ ;;
+
+ ping)
+ # Bootstrap command (simply drop to $RUNNER_USER)
+ bootstrap $@
+
+ ## See if the VM is alive
+ ping_node
+ ES=$?
+ if [ "$ES" -ne 0 ]; then
+ exit $ES
+ fi
+ ;;
+
+ attach-direct)
+ # Bootstrap daemon command (check perms & drop to $RUNNER_USER)
+ bootstrapd $@
+
+ # Allow attaching to a node without pinging it
+ if [ "$2" = "-f" ]; then
+ echo "Forcing connection..."
+ else
+ # Make sure a node is running
+ node_up_check
+ fi
+
+ echo "Direct Shell: Use \"Ctrl-D\" to quit. \"Ctrl-C\" will terminate the $SCRIPT node."
+ shift
+ exec $ERTS_PATH/to_erl $PIPE_DIR
+ ;;
+
+ attach)
+ # Bootstrap daemon command (check perms & drop to $RUNNER_USER)
+ bootstrapd $@
+
+ # Make sure a node is running
+ node_up_check
+
+ echo "Remote Shell: Use \"Ctrl-C a\" to quit. q() or init:stop() will terminate the $SCRIPT node."
+ shift
+ NODE_NAME=${NAME_ARG#* }
+ exec $ERTS_PATH/erl -name c_$$_$NODE_NAME -hidden -remsh $NODE_NAME $COOKIE_ARG
+ ;;
+
+ console)
+ # Bootstrap daemon command (check perms & drop to $RUNNER_USER)
+ bootstrapd $@
+
+ RES=`ping_node`
+ if [ "$?" -eq 0 ]; then
+ echo "Node is already running - use '$SCRIPT attach' instead"
+ exit 1
+ fi
+
+ # Sanity check the app.config file
+ check_config
+ ES=$?
+ if [ "$ES" -ne 0 ]; then
+ exit $ES
+ fi
+
+ # Warn the user if ulimit -n is less than the defined threshold
+ check_ulimit
+
+ # Make sure log directory exists
+ mkdir -p $RUNNER_LOG_DIR
+
+ # Setup beam-required vars
+ ROOTDIR=$RUNNER_BASE_DIR
+ BINDIR=$RUNNER_BASE_DIR/erts-$ERTS_VSN/bin
+ EMU=beam
+ PROGNAME=`echo $0 | sed 's/.*\///'`
+ CMD="$BINDIR/erlexec -boot $RUNNER_BASE_DIR/releases/$APP_VSN/$RUNNER_SCRIPT \
+ -config $RUNNER_ETC_DIR/app.config \
+ -pa $RUNNER_PATCH_DIR \
+ -args_file $RUNNER_ETC_DIR/vm.args -- ${1+"$@"}"
+ export EMU
+ export ROOTDIR
+ export BINDIR
+ export PROGNAME
+
+ # Dump environment info for logging purposes
+ echo "Exec: $CMD"
+ echo "Root: $ROOTDIR"
+
+ # Log the startup
+ logger -t "$SCRIPT[$$]" "Starting up"
+
+ # Start the VM
+ exec $CMD
+ ;;
+
+ top)
+ # Bootstrap command (simply drop to $RUNNER_USER)
+ bootstrap $@
+
+ # Make sure the local node IS running
+ node_up_check
+
+ shift
+ MYPID=$$
+ NODE_NAME=${NAME_ARG#* }
+ $ERTS_PATH/erl -noshell -noinput \
+ -pa $RUNNER_PATCH_DIR \
+ -hidden $NAME_PARAM np_etop$MYPID$NAME_HOST $COOKIE_ARG \
+ -s etop -s erlang halt -output text \
+ -node $NODE_NAME \
+ $* -tracing off
+ ;;
+
+ ertspath)
+ echo $ERTS_PATH
+ ;;
+
+ chkconfig)
+ # Bootstrap command (simply drop to $RUNNER_USER)
+ bootstrap $@
+
+ check_config
+ ;;
+
+ escript)
+ # Bootstrap command (simply drop to $RUNNER_USER)
+ bootstrap $@
+
+ shift
+ $ERTS_PATH/escript "$@"
+ ES=$?
+ if [ "$ES" -ne 0 ]; then
+ exit $ES
+ fi
+ ;;
+
+ version)
+ echo $APP_VERSION
+ ;;
+
+ getpid)
+ # Bootstrap command (simply drop to $RUNNER_USER)
+ bootstrap $@
+
+ # Get the PID from nodetool
+ get_pid
+ ES=$?
+ if [ "$ES" -ne 0 ] || [ -z $PID ]; then
+ exit $ES
+ fi
+ echo $PID
+ ;;
+ *)
+ usage
+ ;;
+esac
+
+exit 0
diff --git a/rel/reltool.config.script b/rel/reltool.config.script
index 60e3a370d..19b40a537 100644
--- a/rel/reltool.config.script
+++ b/rel/reltool.config.script
@@ -127,11 +127,11 @@ CouchJSName = proplists:get_value(couchjs_name, Cfg, "couchjs"),
{copy, "../etc/couchdb/empty", "data/KEEP"},
%% Copy base files for starting and interacting w/ node
- {copy, "../src/node_package/priv/base/erl", "{{erts_vsn}}/bin/erl"},
- {copy, "../src/node_package/priv/base/nodetool", "{{erts_vsn}}/bin/nodetool"},
- {template, "../src/node_package/priv/base/runner", "bin/couchdb"},
- {template, "../src/node_package/priv/base/env.sh", "lib/env.sh"},
- {template, "../src/node_package/priv/base/app_epath.sh", "lib/app_epath.sh"},
+ {copy, "files/erl", "{{erts_vsn}}/bin/erl"},
+ {copy, "files/nodetool", "{{erts_vsn}}/bin/nodetool"},
+ {template, "files/runner", "bin/couchdb"},
+ {template, "files/env.sh", "lib/env.sh"},
+ {template, "files/app_epath.sh", "lib/app_epath.sh"},
%% config files
{template, "../etc/couchdb/app.config", "etc/app.config"},