#!/bin/sh


# WARNING!!!!
# Making changes here may require you to also change the wwinitrd itself (ie.
# the VNFS_GET_METHOD clients, or even mkfs binaries).

# What method do you wish to use to download the VNFS image? Default for most
# clusters is preferred, but if you have extreamly large numbers of nodes,
# with large VNFS images (ie. full distro images), you can use other
# mechanisms. Default is VNFSD, but others that could be considered is
# TORRENT, and/or RSYNC.
# 
# note: For using TORRENT and RSYNC, you will have to make changes to the
# wwinitrd (initial ram disk).

VNFS_GET_METHOD=VNFSD


# Enable network segment relaying? (EXPERIMENTAL)
# This paramater is used for larger clusters where the nodes are broken into
# discrete node groups based on subnets. This will enable the top most node
# in the node group to be the "team leader", and it will be delegated the
# responsiability of handing the VNFS to the other slave nodes on that network
# segment. For this to work, you MUST set this to the number of the first node
# in the node sequence and the last (eg. first:last).
#
# note: to enable this, you *MUST* make the binaries in extras/misc for dolly
# and peeradr, put them into /var/warewulf/wwinitrd/bin/, and then wwmkinitrd!!!
#
# anohter note: The first and last represent not the node designations, but
# their place in the network... eg. 0 is reserved, 1 is the first usable IP on
# that network, 2 is the second, etc...

#ENABLE_DOLLY_NET=64:71


# Were do you want to create the new root file system? Options are TMPFS and
# DISKFS. If you select DISKFS, be sure to customize the below create_diskfs()
# function!

STORAGE_DEV=TMPFS


# If/when using STORAGE_DEV == DISKFS, it will call this function. Because
# there are so many wacky ways of partitioning it is pointless for me to
# script a portable solution. I did however provide a basic template that
# should work for most infrastructures.

create_diskfs() {
   # Must install sfdisk mkfs.??? into /var/warewulf/wwinitrd/sbin/ if you 
   # wish to use this function!

   # What disk to use?
   DISK=/dev/hda
   # What file system to use for the root partition?
   FILESYSTEM=ext2

   # This will partition the drive with a ~2GB swap, and then the rest as a
   # standard Linux partition
   echo -ne ",254,82\n,,83\n" | /sbin/sfdisk $DISK

   # Format the partitions
   mkswap              ${DISK}1
   mkfs.$FILESYSTEM    ${DISK}2

   # Do the mount
   mount -t $FILESYSTEM ${DISK}2 /newroot
}



exit_error() {
   # This is a utility function, it doesn't actually do work...
   # Make sure you call me after any critical commands to be sure that the
   # node reboots if there is an error!
   echo "*** ERROR ***"
   echo
   echo "I will reboot in 30 seconds..."
   sleep 30
   reboot
}

create_tmpfs() {
   # This is the default file system for Warewulf. It works well because tmpfs
   # will get pushed into swap space (if configured on local disk) in the
   # event that a local program needs access to all RAM. It is also fast, and
   # generally works well.
   echo "   creating the newroot tmpfs file system"
   mkdir /newroot
   mount -t tmpfs none /newroot
   if [ $? -ne "0" ]; then
      exit_error
   fi
   echo "   making this (RAM) file system the real root dev"
}

vnfs_vnfsd() {
   # This is the default vnfs mechanism. It scales very well for large
   # clusters, that don't utilize large disk images (the way it should be
   # under normal circumstances).
   echo "   obtaining the VNFS::$VNFS image"
   cd /newroot
   wget -O - http://$MASTER:9874/$VNFS/vnfs.tar.gz | tar xzf -
   if [ $? -ne "0" ]; then
      exit_error
   fi
}

vnfs_vnfsd_get() {
   # This is the default vnfs mechanism. It scales very well for large
   # clusters, that don't utilize large disk images (the way it should be
   # under normal circumstances).
   echo "   obtaining the VNFS::$VNFS image"
	mkdir -p /newroot/tmp
   cd /newroot/tmp
   wget http://$MASTER:9874/$VNFS/vnfs.tar.gz
   if [ $? -ne "0" ]; then
      exit_error
   fi
}

vnfs_torrent() {
   # note: The 1.03 version of libbt/btget seemed to have some bugs that 
   #       I(GMK) worked out. Get my hacked version if you want to get the i
   #       vnfs via the torrent.
   echo "   obtaining the TORRENT:$VNFS image, and then seeding for 10 extra seconds"
   mkdir -p /newroot/tmp
   cd /newroot/tmp/
   # Run btget locally if it exsists, otherwise try to pull it from vnfsd on
   # the master.
   if [ -f "/bin/btget" -o -f "/sbin/btget" ]; then
      btget -q 10 -f /newroot/tmp/vnfs.tar.gz -u http://$MASTER:9874/$VNFS/vnfs.tar.gz.torrent
   else
      wget http://$MASTER:9874/$VNFS/btget
      chmod +x btget 2>/dev/null
      ./btget -q 10 -f /newroot/tmp/vnfs.tar.gz -u http://$MASTER:9874/$VNFS/vnfs.tar.gz.torrent
      if [ $? -ne "0" ]; then
         exit_error
      fi
   fi
   if [ $? -ne "0" ]; then
      exit_error
   fi
   echo "   exploding the VNFS image..."
   cd /newroot
   tar xvf tmp/vnfs.tar.gz
   if [ $? -ne "0" ]; then
      exit_error
   fi
	rm tmp/vnfs.tar.gz
}

vnfs_rsync() {
   # Typically used to keep local disk images in sync with the master vnfs. If
   # using this method, you may want to not format the disk on every boot. See
   # the create_diskfs() function defined above. Just a thought....
   echo "   obtaining the RSYNC::$VNFS image"
   cd /newroot
   # You must install rsync either statically compiled, or include all of the
   # libs into /var/warewulf/wwinitrd/(bin|lib)/ if you wish to use rsync.
   rsync -aHP --delete $MASTER::$VNFS/ .
   if [ $? -ne "0" ]; then
      exit_error
   fi
}

dolly_net() {
	# Lets start off setting some vars
	LEAD_DOLLY_NODE=`echo $ENABLE_DOLLY_NET | cut -d ':' -f 1`
	FIRST_DOLLY_NODE=`expr $LEAD_DOLLY_NODE + 1`
	LAST_DOLLY_NODE=`echo $ENABLE_DOLLY_NET | cut -d ':' -f 2`
	SLAVE_COUNT=`expr $LAST_DOLLY_NODE - $LEAD_DOLLY_NODE`
	TEAM_LEAD=`peeraddr $IPADDR $NETMASK $LEAD_DOLLY_NODE`
	FIRST=`peeraddr $IPADDR $NETMASK $FIRST_DOLLY_NODE`
	LAST=`peeraddr $IPADDR $NETMASK $LAST_DOLLY_NODE`
	COUNT=$FIRST_DOLLY_NODE

	# Build the config file
	mkdir -p /tmp                             2> /dev/null
	echo "infile /newroot/tmp/vnfs.tar.gz"    >  /tmp/dolly.conf
	echo "outfile /newroot/tmp/vnfs.tar.gz"   >> /tmp/dolly.conf
	echo "server $TEAM_LEAD"                  >> /tmp/dolly.conf
	echo "firstclient $FIRST"                 >> /tmp/dolly.conf
	echo "lastclient $LAST"                   >> /tmp/dolly.conf
	echo "clients $SLAVE_COUNT"               >> /tmp/dolly.conf
	while [ $COUNT -le $LAST_DOLLY_NODE ]; do
		CUR=`peeraddr $IPADDR $NETMASK $COUNT`
		echo "$CUR"                            >> /tmp/dolly.conf
		COUNT=`expr $COUNT + 1`
	done
	echo "endconfig"                          >> /tmp/dolly.conf

	# MYNODENAME is needed because dolly typically only uses just hostnames to
	# meet the parents.
	export MYNODENAME=$IPADDR
	COUNT=1
	if [ "x$IPADDR" = "x$TEAM_LEAD" ]; then
		# I am the team lead! :)
		vnfs_vnfsd_get
		# we ware going to try and do the right thing 5 times, otherwise we will
		# giveup
		while [ $COUNT -le 5 -a "x$RETVAL" != "x0" ]; do
			dolly -s -v -f /tmp/dolly.conf
			RETVAL=$?
			COUNT=`expr $COUNT + 1`
		done
	else
		# I am a friend of a friend...
		mkdir -p /newroot/tmp/
		touch /newroot/tmp/vnfs.tar.gz
		# we ware going to try and do the right thing 5 times, otherwise we will
		# giveup, *AND* then failover to hitting the warewulf VNFSD master
		while [ $COUNT -le 5 -a "x$RETVAL" != "x0" ]; do
			dolly -v -f /tmp/dolly.conf
			RETVAL=$?
			COUNT=`expr $COUNT + 1`
		done
		# This is the failover part... 
		if [ $RETVAL -ne 0 ]; then
			vnfs_vnfsd_get
		fi
	fi
	cd /newroot
	tar xzf tmp/vnfs.tar.gz
	rm tmp/vnfs.tar.gz
}


##############################################################################
# TIME FOR WORK


# Mount the /newroot file system
STORAGE=`echo $STORAGE_DEV | cut -d ':' -f 1`
DEV=`echo $STORAGE_DEV | cut -d ':' -f 2`

if [ "x$STORAGE" = "xTMPFS" ]; then
   create_tmpfs
   FILESYSTEM=tmpfs
elif [ "x$STORAGE" = "xDISKFS" ]; then
   create_diskfs
else
   echo "I don't know how to create the storage device \"$STORAGE_DEV\"..."
   sleep 5
fi

# Obtain the VNFS
if [ "x$ENABLE_DOLLY_NET" != "x" ]; then
   dolly_net
elif [ "x$VNFS_GET_METHOD" = "xVNFSD" ]; then
   vnfs_vnfsd
elif [ "x$VNFS_GET_METHOD" = "xTORRENT" ]; then
   vnfs_torrent
elif [ "x$VNFS_GET_METHOD" = "xRSYNC" ]; then
   vnfs_rsync
fi


# If udev is in the VNFS, we should probably start the thing!
if [ -x "/newroot/sbin/start_udev" ]; then
   mount -t proc none /newroot/proc
   chroot /newroot /sbin/start_udev
   umount /newroot/proc
fi


echo "   some final configurations"
# Logging will need this!
mknod /newroot/dev/console c 5 1 2>/dev/null

# replace the root file system macro in the fstab with the root file system
sed -i "s@%{root entry}@VNFS($VNFS)       /       $FILESYSTEM   defaults        1 1@" /newroot/etc/fstab

echo "   all done..."
