Skip to content

Instantly share code, notes, and snippets.

@yyfrankyy
Created March 19, 2011 07:28
Show Gist options
  • Save yyfrankyy/877304 to your computer and use it in GitHub Desktop.
Save yyfrankyy/877304 to your computer and use it in GitHub Desktop.
Joyent's NodeJS post-receive script.
#!/bin/bash -
# The "post-receive" script is run after receive-pack has accepted a pack
# and the repository has been updated. It is passed arguments in through
# stdin in the form
# <oldrev> <newrev> <refname>
# For example:
# aa453216d1b3e49e7f6f98441fa56946ddcd6a20 68f7abf4e6f922807889f52bc043ecd31b79f814 refs/heads/master
#set -x
# This script is specific to the node-service. It checkouts out an updated
# version of the software and updates the SMF config to run it.
read oldrev newrev refname
function rollbackToDefault() {
local log=$1
echo
echo "Rolling back to default server."
start_state=$(svcs -H -o state node-service)
if [ "$start_state" != "disabled" ]; then
svcadm disable -s node-service
fi
svccfg import /opt/nodejs/default_server/default-server.xml
# Long sleep to attempt to break out of "Restarting too quickly, changing
# state to maintenance." from svc.startd.
if [ "$start_state" == "maintenance" ]; then
sleep 10
fi
# Give it a little bit to crash, necessary because our service "start" method
# returns immediately.
svcadm enable -s node-service
sleep 1
if [ "$(svcs -H -o state node-service)" != "online" ]; then
echo "Rollback failed. Please report this to support@joyent.com."
echo "* * *"
tail -10 $log
echo "* * *"
else
echo "Rollback succeeded."
fi
}
svcadm disable -s node-service
if [ "`svcs -H -o state node-service`" != "disabled" ]; then
echo "Failed to disable current node-service."
exit 1
fi
# Get the short version of the sha1 tag.
rev=`echo $newrev | cut -c-6`
date=`date +%Y%m%d%H%M%S`
log="/var/svc/log/site-node-service:default.log"
service_dir="/home/node/node-service"
releases_dir="$service_dir/releases"
current_dir="$service_dir/current"
profile="$service_dir/profile"
dir="$releases_dir/$date"
if [ -d $releases_dir ]; then
last_release=`ls $releases_dir | grep -v xml | tail -1`
fi
mkdir -p $releases_dir
# make sure the service profile is existing
if ! [ -f "$profile" ]; then
ln -s /opt/nodejs/service-profile $profile
fi
unset GIT_DIR
unset GIT_WORK_TREE
#
# Poor man's git-archive. Why? git-submodules suck.
#
git clone /home/node/repo $dir >& /dev/null
cd $dir
git submodule update --init --recursive >& /dev/null
if ! [ -f $dir/server.js ]; then
( echo
echo "Please add a server.js file to the root of your repo before pushing."
echo "Cannot start node service without it."
echo
) >&2
exit 1
fi
# Figure out which version of Node this revision wants to be running.
nodeversion=`/opt/nodejs/get-node-version $dir`
# Build and install the updated SMF manifest for the node service.
manifest="$releases_dir/$date.xml"
gsed -e "s/@@NODEVERSION@@/$nodeversion/g" \
-e "s/@@REV@@/$rev/g" \
-e "s#@@DIR@@#$dir#g" \
-e "s/@@VERSION@@/$date/g" \
/opt/nodejs/node-service-manifest.xml.in > $manifest
svccfg import $manifest
svccfg -s node-service:default refresh
# The current dir isn't referenced in the node-service-manifest
# it's just for convenience.
rm -f $current_dir
# Give it a little bit to crash, necessary because our service "start" method
# returns immediately.
echo "Starting node $nodeversion..."
svcadm enable -s node-service
sleep 1
if [ "$(svcs -H -o state node-service)" == "online" ]; then
echo "Successful"
ln -s $dir $current_dir
else
echo
echo "Failed to start new server."
echo
echo "* * * tail of '$log' * * *"
tail -50 $log
echo "* * *"
cd $releases_dir
rm $manifest
rm -rf $dir
# Rollback
if [ ! -z $last_release ]; then
echo
echo "Rolling back to $last_release ... (please wait)"
original_state=$(svcs -H -o state node-service)
svcadm disable -s node-service
# Setup the last service config (my understanding is that this effectively
# clears any maintenance state as well).
dir="$releases_dir/$last_release"
manifest="$dir.xml"
svccfg import $manifest
# Long sleep to attempt to break out of "Restarting too quickly, changing
# state to maintenance." from svc.startd.
if [ "$original_state" == "maintenance" ]; then
sleep 10
fi
# Give it a little bit to crash, similar awful race as above.
svcadm enable -s node-service
sleep 1
if [ "$(svcs -H -o state node-service)" != "online" ]; then
echo "Rollback failed (old server did not start properly)."
echo "* * *"
tail -10 $log
echo "* * *"
else
echo "Rollback succeeded."
ln -s $dir $current_dir
fi
else
rollbackToDefault $log
fi
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment