Current section

Files

Jump to
edeliver strategies erlang-node-execute
Raw

strategies/erlang-node-execute

#!/usr/bin/env bash
REQUIRED_CONFIGS+=("APP")
REQUIRED_CONFIGS+=("NODE_ACTION")
REQUIRED_CONFIGS+=("NODE_ENVIRONMENT")
require_node_config
help() {
case "$NODE_ACTION" in
(start|stop|restart|ping|version)
echo -e "
${bldwht}Usage:${txtrst}
edeliver $NODE_ACTION [staging|production] [Options]
${txtbld}Options:${txtrst}
--host=[u@]vwx.yz Run command only on that host,
even if different hosts are configured"
case "$NODE_ACTION" in
(start) echo -e "\n${bldylw}Info:${txtrst} Starts the node(s) on the deploy hosts.\n" ;;
(stop) echo -e "\n${bldylw}Info:${txtrst} Stops the node(s) on the deploy hosts.\n" ;;
(restart) echo -e "\n${bldylw}Info:${txtrst} Restarts the application on the deploy host(s) (not the emulator).\n" ;;
(ping) echo -e "\n${bldylw}Info:${txtrst} Checks whether the node(s) on the deploy host(s)\n are running.\n" ;;
(version) echo -e "\n${bldylw}Info:${txtrst} Displays the running version(s) on the deploy host(s).\n" ;;
esac
;;
(migrate)
echo -e "
${bldwht}Usage:${txtrst}
edeliver migrate [staging|production] [up|down] [--version=<migration-version>]
${txtbld}Options:${txtrst}
--host=[u@]vwx.yz Run migrations only on that host,
even if different hosts are configured
--version=<migration-version> The version to migrate to.
${bldylw}Info:${txtrst}
Migrates the database schema on the deploy host(s) either
${bldwht}up${txtrst} or ${bldwht}down${txtrst}. Make sure the release / upgrade containing
the migrations is installed before.
"
;;
(migrations)
echo -e "
${bldwht}Usage:${txtrst}
edeliver [show] migrations [on] [staging|production]
${txtbld}Options:${txtrst}
--host=[u@]vwx.yz Show migrations only from that host,
even if different hosts are configured
${bldylw}Info:${txtrst} Shows the pending migration on the deploy host(s).
"
;;
(*)
[[ -n "$COMMAND_INFO" ]] && local _command="$COMMAND $COMMAND_INFO" || local _command="$COMMAND"
error "\nNo custom help provided for command '$_command'. Try --help option.\n"
;;
esac
}
run() {
[[ "$NODE_ACTION" = version ]] && status "getting release versions from $NODE_ENVIRONMENT servers" || status "${NODE_ACTION}ing $NODE_ENVIRONMENT servers"
authorize_hosts
if [[ "$NODE_ACTION" = version ]] && [[ "$RELEASE_CMD" = "mix" ]]; then
NODE_ACTION="rpc Elixir.Edeliver run_command '[[release_version, \"$APP\"]].' | tail -n+2 | tr -d \\\""
elif [[ "$NODE_ACTION" = ping ]] && [[ "$RELEASE_CMD" = "mix" ]]; then
NODE_ACTION="ping | tail -n+2"
elif [[ "$NODE_ACTION" = migrations ]] && [[ "$RELEASE_CMD" = "mix" ]]; then
NODE_ACTION="rpc Elixir.Edeliver run_command '[[list_pending_migrations, \"$APP\"]].' | tail -n+2"
elif [[ "$NODE_ACTION" = migrations ]] && [[ "$RELEASE_CMD" != "mix" ]]; then
error "Showing migrations is only supported when using mix as release command."
elif [[ "$NODE_ACTION" = migrate ]] && [[ "$RELEASE_CMD" = "mix" ]]; then
local __up_or_down="up"
for args in $ARGS; do [[ "$arg" = "down" ]] && local __up_or_down="down"; done
[[ -n "$VERSION" ]] && local __to_version=", \"$VERSION\"" || local __to_version=""
NODE_ACTION="rpc Elixir.Edeliver run_command '[[migrate, \"$APP\", ${__up_or_down}${__to_version}]].' | tail -n+2"
elif [[ "$NODE_ACTION" = migrate ]] && [[ "$RELEASE_CMD" != "mix" ]]; then
error "Executing migrations is only supported when using mix as release command."
elif [[ "$RELEASE_CMD" = "mix" ]]; then
NODE_ACTION="$NODE_ACTION | tail -n+2"
fi
__exec_if_defined execute_custom_node_command "$NODE_ACTION" || execute_node_command "$NODE_ACTION"
}
# executes a node command asynchronously on all
# remote nodes and prints the result for each node.
# if there is only one single node and the node command
# is start, the progress of the start command output
# is printed continuously to the screen.
execute_node_command() {
local _node_command=$1
if [[ $(echo $NODES | wc -w) -eq 1 ]]; then
__execute_node_command_synchronously "$_node_command"
else
__execute_node_command_asynchronously "$_node_command"
fi
}
# executes a node command asynchronously on all
# remote nodes and prints the result for each node.
__execute_node_command_asynchronously() {
local _node_command=$1
echo
background_jobs_pids=()
local i=0;
for _node in $NODES;
do
{
local _output=""
local _lines=-1
local _result
while read line; do
_result=$line
_output="${_output}${line}\n"
_lines=$(( $_lines + 1 ))
done
_output=$(echo -e "$_output" | head -n $_lines)
__print_node_command_result "$i" "$_result" "$_node" "$_output"
exit $result
} < <(__execute_node_command $i "$_node" "$_node_command") &
background_jobs_pids+=("$!")
i=$((i+1))
done
local _had_errors=0
for (( i = 0 ; i < ${#background_jobs_pids[@]} ; i++ ))
do
wait ${background_jobs_pids[$i]}
[[ "$?" = 0 ]] || _had_errors=1
done
return $_had_errors
}
# executes a node command synchronously on a single
# remote node and prints the output of the command
# continuously.
__execute_node_command_synchronously() {
local _node_command=$1
local _node=${NODES# *}
__print_node_command_result "single_node" "0" "$_node" ""
echo -n " response: "
local _response=$(__execute_node_command "single_node" "$_node" "$_node_command")
__format_response "$_response"
}
# formats the response when node command is executed
# synchronously. If version is displayed and --verbose option passed
# the last git revisions are displayed in addition if the version
# contains the git revsion.
__format_response() {
local _response="$@"
if [[ "$COMMAND" = "version" ]] && [[ "$_response" =~ "+" ]]; then
local _is_first_line="true" _line _revision="$(grep -oe '[0-9a-fA-F]\{7\}' <<< "$_response")"
if [[ -n "$_revision" ]]; then
echo -e "${txtylw}$_response${txtrst}"
local _branch="$(git branch -a --contains "$_revision" | head -n 1 | cut -b3-)"
[[ -n "$_branch" ]] && echo -e " branch : ${_branch}"
echo " revision: $_revision"
local _commit_date="$(git show -s --format=%ci "$_revision" 2>/dev/null)"
[[ -n "$_commit_date" ]] && echo -e " date : $_commit_date (git commit)"
local _last_commits=${VERSION_INFO_LAST_COMMITS:-5}
(IFS='
'
for _line in $(git log "$_revision" -"$_last_commits" --pretty=oneline 2>/dev/null | cut -d" " -f2-); do
_line="$(xargs <<< "$_line")"
[[ "$_is_first_line" = "true" ]] && echo -n " commits : " || echo -n " "
echo -e "$_line"
_is_first_line="false"
done
[[ "$_is_first_line" = "false" ]] && [[ "$_last_commits" != "1" ]] && echo " ..."
)
return 0
fi
fi
echo "${bldylw}$_response${txtrst}"
}
# executes a node command on a given node.
__execute_node_command() {
local _node_index=$1
local _node_name=$2
local _node_command=$3
local _config; local _config_arg
local _user=${_node_name%@*}
local _host=${_node#*@}
local _path=${_host#*:}
[[ "$_path" =~ .*\|.* ]] && _config=${_path#*|} || _config=""
_path=${_path%|*}
_host=${_host%:*}
[[ -n "$_config" ]] && _config_arg="--config=${_config}" || _config_arg=""
[ "${_node_index}" != "single_node" ] && [ "${_node_command}" = "start" ] && _config_arg="$_config_arg --short"
[[ -n "$ECTO_REPOSITORY" ]] && local _node_env="ECTO_REPOSITORY='$ECTO_REPOSITORY' "
_remote_job="
[ -f ~/.profile ] && source ~/.profile
set -e
cd ${_path}/${APP} $SILENCE
${_node_env}bin/${APP} ${_node_command} ${_config_arg}
"
[ "${_node_index}" = "single_node" ] && local _terminal_option="-t -q" || local _terminal_option=
ssh $_terminal_option -o ConnectTimeout="$SSH_TIMEOUT" "${_user}@${_host}" "$_remote_job"
local _status_code="$?"
[ "${_node_index}" != "single_node" ] && echo -e "\n${_status_code}"
[[ "$_status_code" = "0" ]] && return 0 || return 1
}
# prints the result from the execution of a node command on a remote node.
__print_node_command_result() {
local _node_index=$1
local _status_code=$2
local _node_name=$3
local _node_action_response=$4
local _config; local _config_arg
local _message=""
_message="${bldgrn}$NODE_ENVIRONMENT${txtrst} node: $_node_index\n\n"
[[ "$_node_index" = "single_node" ]] && _message="${bldgrn}$NODE_ENVIRONMENT${txtrst} node:\n\n"
echo
local _user=${_node_name%@*}
local _host=${_node_name#*@}
local _path=${_host#*:}
[[ "$_path" =~ .*\|.* ]] && _config=${_path#*|} || _config=""
_path=${_path%|*}
_host=${_host%:*}
_message="${_message} user : $_user\n"
_message="${_message} host : $_host\n"
_message="${_message} path : $_path\n"
[[ -n "$_config" ]] && _message="${_message} config : $_config\n"
if [[ "$_node_action_response" =~ ": " ]]; then
local _node=${_node_action_response%: *}
_node_action_response=${_node_action_response#*: }
_node=$(echo ${_node} | grep -oe "[^ @]\+@.*")
_message="${_message} node : $_node\n"
fi
if [[ "$_node_index" = "single_node" ]]; then
echo -en "${_message}" && return 0
elif [[ "$_status_code" = "0" ]] && [[ -n "$_node_index" ]]; then
_node_action_response="$(__format_response "$_node_action_response")"
_message="${_message} response: ${_node_action_response}\n"
elif [[ -n "$_node_index" ]]; then
_message="${_message} response: ${bldred}failed${txtrst}\n";
[[ -n "$_node_action_response" ]] && {
local lines=0
while read line; do
[[ "$lines" = "0" ]] && _message="${_message} error : ${line}\n" || _message="${_message} ${line}\n"
lines=$(($lines+1))
done < <(echo -e "$_node_action_response")
}
_message="$_message\n${txtrst}"
fi
echo -e "${_message}"
[[ "$_status_code" = "0" ]] && return 0 || return 1
}