Created
March 19, 2011 07:28
-
-
Save yyfrankyy/877304 to your computer and use it in GitHub Desktop.
Joyent's NodeJS post-receive script.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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 [email protected]." | |
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