REPLICASETNAME="CMapsShard4" MONGOS="ec2-54-228-106-184.eu-west-1.compute.amazonaws.com" HOSTNAME=`/usr/bin/curl -s http://169.254.169.254/latest/meta-data/public-hostname` PORT=27017 # This could be used to check if we are already member of a replicaset: # echo "db.serverStatus().repl" | mongo # Now we just assume we are not, and proceed to either intiate a new replicaset, # or discover and join an existing one for LOOPCOUNT in 1 2 3 4 do # Find out if REPLICASETNAME is already registered with the mongos servers FOUND=`echo "db.shards.find()" | mongo $MONGOS/config | grep $REPLICASETNAME | wc -l` if [ $FOUND -gt 0 ]; then echo "Shard $REPLICASETNAME found. I will now proceed to add myself to it." # Find the first member of the replica set, then connect to it and add myself RSHOST=`echo "db.shards.find( { \"_id\" : \"$REPLICASETNAME\" }, { \"host\" : true, \"_id\" : false } )" | mongo $MONGOS/config | grep $REPLICASETNAME | awk -F":" '{ print $2}' | awk -F"/" '{print $2}'` RSPORT=`echo "db.shards.find( { \"_id\" : \"$REPLICASETNAME\" }, { \"host\" : true, \"_id\" : false } )" | mongo $MONGOS/config | grep $REPLICASETNAME | awk -F":" '{ print $3}' | awk -F"," '{print $1}' | awk -F'"' '{print $1}'` echo "Found existing member of the shard: $RSHOST:$RSPORT. I will now connect to it." echo "rs.add('$HOSTNAME')" | mongo "$RSHOST:$RSPORT" exit 0 fi # If the shard didn't exist yet, we are in for a ride. MongoDB sure doesn't make automated AWS deployment easy... # Due to the way replicasets are initialized, we need to use our own locking mechanism # to avoid race conditions with other nodes that might be doing this at the same time. # (Basically, only one node can do the rs.initialize() and there's no easy way to undo # it if 2 would do it at the same time.) echo "Shard $REPLICASETNAME does not exist yet. I will now try to get the lock to initialize replica set." # This will throw "norepl" error. This is ok, it's because we are writing to the config nodes echo "db.deployment.locks.insert( { _id : \"$REPLICASETNAME\", locked: true, owner: \"$HOSTNAME:$PORT\" } )" | mongo $MONGOS/config # Now check if we got the lock or not # Note that if someone else already inserted the same lock, then our above insert failed HAVE_LOCK=`echo "db.deployment.locks.find( { _id : \"$REPLICASETNAME\", locked : true, owner : \"$HOSTNAME:$PORT\" } ).count()" | mongo --quiet $MONGOS/config` if [ $HAVE_LOCK -gt 0 ]; then echo "Got the lock. Now initializing replica set..." # We need to use this to use the public $HOSTNAME from above. By default rs.initiate() uses `hostname` cat < /tmp/replicaSetConfigInit.js config = {_id: "$REPLICASETNAME", members : [ {_id : 0, host:"$HOSTNAME:$PORT"}, ]}; rs.initiate(config); EOF mongo /tmp/replicaSetConfigInit.js echo "The ReplicaSet is still configuring itself. Sleep 60 sec before proceeding" sleep 60 # Add myself as the first member of this shard mongo --eval "sh.addShard('$REPLICASETNAME/$HOSTNAME')" $MONGOS # Release the lock (just cleanup, nobody should ever need it again echo "db.deployment.locks.remove( { _id : \"$REPLICASETNAME\" } )" | mongo $MONGOS/config exit 0 fi # Someone else has the lock and is hopefully doing rs.initialize(). # All we can do is wait and start from the beginning. echo "Someone else is holding the lock to do rs.initialize(). I will sleep 120 seconds and then retry to join the shard." sleep 120 done