#!/bin/bash
#
# $Id: euca_conf,v 1.7 2008-12-24 18:28:07 nurmi Exp $

FILE="$EUCALYPTUS/etc/eucalyptus/eucalyptus.conf"
EUCALYPTUS=""
START_CC=""
START_NC=""
CC_PORT=""
NC_PORT=""
CLOUD=""
CLOUD_PORT=""
CLOUD_SSL_PORT=""
NAME=""
INSTANCE=""
EUCA_USER=""
HYPERVISOR=""
DHCPD=""
DHCP_USER=""
NEWNODE=""
NODEMODE=""
CLUSNAME=""
NEWCLUS=""
CLUSMODE=""

usage () {
	echo "$0 [options] [<file>]"
	echo
	echo "   -help                       this message"
	echo "   -d <dir>                    point EUCALYPTUS to <dir>"
	echo "   -addnode <hostname>         add new node to EUCALYPTUS"
	echo "   -delnode <hostname>         remove node from EUCALYPTUS"
	echo "   -addcluster <clusname> <hostname> add new cluster to EUCALYPTUS"
#	echo "   -delcluster <clusname> <hostname> remove cluster from EUCALYPTUS"
	echo "   -cc {Y|N}                   enable/disable CC"
	echo "   -nc {Y|N}                   enable/disable NC"
	echo "   -cloud {Y|N}                enable/disable Cloud Controller"
	echo "   -nodes \"host host ...\"    list of NCs"
	echo "   -ccp <port>                 set CC port"
	echo "   -ncp <port>                 set NC port"
	echo "   -instances <path>           set the INSTANCE path"
	echo "   -cloudp <port1> <port2>     set the 2 cloud ports"
	echo "   -hypervisor <kvm|xen>       set hypervisor to use"
	echo "   -user <euca_user>           set the user to use"
	echo "   -dhcpd <dhcpd>              set the dhcpd binary to <name>"
	echo "   -dhcp_user <user>           set the username to run dhcpd as"
	echo "   -name <var>                 returns the value or <name>"
	echo "where <file> is the configuration file ($FILE by default)"
	echo
}

# 3 paramenter: the file, the variable name, the new value
change_var_value () {
	cp $1 /tmp/euca-tmp.$$
	sed "s<\(${2}\).*<\1=\"${3}\"<" /tmp/euca-tmp.$$ > $1
	rm -f /tmp/euca-tmp.$$
}
# comment lines matching $2 ($1 is the file)
comment () {
	cp $1 /tmp/euca-tmp.$$
	sed "s<[[:blank:]]*\(${2}.*\)<#\1<" /tmp/euca-tmp.$$ > $1
	rm -f /tmp/euca-tmp.$$
}
# comment lines matching $2 ($1 is the file)
uncomment () {
	cp $1 /tmp/euca-tmp.$$
	sed "s<[#[:blank:]]*\(${2}.*\)<\1<" /tmp/euca-tmp.$$ > $1
	rm -f /tmp/euca-tmp.$$
}

if [ $# -eq 0 ]; then
	usage
	exit 1
fi

# let's parse the command line
while [ $# -gt 0 ]; do
	if [ "$1" = "-h" -o "$1" = "-help" -o "$1" = "?" -o "$1" = "--help" ]; then
		usage
		exit 1
	fi

	if [ $# -eq 1 ]; then
		# we dont have options with no argument, so it has to be
		# the file
		FILE="$1"
		break
	fi

	# all other parameters requires at least 1 argument
	if [ $# -lt 2 ]; then
		usage
		exit 1
	fi

	# now let's parse the command line
	if [ "$1" = "-d" ]; then
		if [ ! -d "${2}" ]; then
			echo "Is $2 where Eucalyptus is installed?"
			exit 1
		fi
		EUCALYPTUS="${2}"
		#FILE="$EUCALYPTUS/$FILE"
		shift; shift
		continue
	fi
	if [ "$1" = "-name" ]; then
		if [ -n "$NAME" ]; then
			echo "Only one -name can be specified!"
			exit 1
		fi
		NAME="$2"
		shift; shift
		continue
	fi		
	if [ "$1" = "-cloud" ]; then
		START_CLOUD="$2"
		shift; shift
		continue
	fi		
	if [ "$1" = "-cc" ]; then
		START_CC="$2"
		shift; shift
		continue
	fi		
	if [ "$1" = "-dhcpd" ]; then
		DHCPD="$2"
		shift; shift
		continue
	fi		
	if [ "$1" = "-dhcp_user" ]; then
		DHCPC_USER="$2"
		shift; shift
		continue
	fi		
	if [ "$1" = "-nc" ]; then
		START_NC="$2"
		shift; shift
		continue
	fi		
	if [ "$1" = "-nodes" ]; then
		NODES="${2}"
		shift; shift
		continue
	fi		
	if [ "$1" = "-ccp" ]; then
		CC_PORT="$2"
		shift; shift
		continue
	fi		
	if [ "$1" = "-ncp" ]; then
		NC_PORT="$2"
		shift; shift
		continue
	fi
	if [ "$1" = "-instances" ]; then
		INSTANCE="$2"
		shift; shift
		continue
	fi
	if [ "$1" = "-user" ]; then
		EUCA_USER="$2"
		shift; shift
		continue
	fi
	if [ "$1" = "-hypervisor" ]; then
		if [ "$2" != "xen" -a "$2" != "kvm" ]; then
			echo "Only kvm or xen are supported at the moment"
			exit 1
		fi
		HYPERVISOR="$2"
		shift; shift
		continue
	fi
	if [ "$1" = "-cloudp" ]; then
		if [ $# -lt 3 ]; then
			echo "We need 2 ports for cloud controller"
			exit 1
		fi
		CLOUD_PORT="$2"
		CLOUD_SSL_PORT="$3"
		shift; shift; shift
		continue
	fi
	if [ "$1" = "-addnode" ]; then 
	    if [ $# -lt 2 ]; then
		echo "Requires the hostname of the node to add"
		exit 1
	    fi
	    NEWNODE="$2"
	    NODEMODE="ADD"
	    shift; shift
	    continue
	fi
	if [ "$1" = "-delnode" ]; then 
	    if [ $# -lt 2 ]; then
		echo "Requires the hostname of the node to delete"
		exit 1
	    fi
	    NEWNODE="$2"
	    NODEMODE="REM"
	    shift; shift
	    continue
	fi
	if [ "$1" = "-addcluster" ]; then
	    if [ $# -lt 3 ]; then
		echo "Requires the cluster nice name, hostname and admin access key"
		exit 1
	    fi
	    CLUSNAME="$2"
	    NEWCLUS="$3"
	    CLUSMODE="ADD"
	    shift; shift; shift; shift
	    continue
	fi
	usage 
	exit 1
done

# some basic check
if [ -z "${FILE}" -o ! -f "${FILE}" ]; then
	echo "Is <$FILE> a valid eucalyptus configuration file?"
	exit 1
fi

# let's change the value
if [ -n "$EUCALYPTUS" ]; then
	change_var_value $FILE EUCALYPTUS "${EUCALYPTUS}"
fi
if [ -n "$START_CLOUD" ]; then
	change_var_value $FILE START_CLOUD "${START_CLOUD}"
fi
if [ -n "$START_CC" ]; then
	change_var_value $FILE START_CC "${START_CC}"
fi
if [ -n "$START_NC" ]; then
	change_var_value $FILE START_NC "${START_NC}"
fi
if [ -n "$CC_PORT" ]; then
	change_var_value $FILE CC_PORT "${CC_PORT}"
fi
if [ -n "$NC_PORT" ]; then
	change_var_value $FILE NC_PORT "${NC_PORT}"
fi
if [ -n "$CLOUD_PORT" ]; then
	change_var_value $FILE CLOUD_PORT "${CLOUD_PORT}"
fi
if [ -n "$CLOUD_SSL_PORT" ]; then
	change_var_value $FILE CLOUD_SSL_PORT "${CLOUD_SSL_PORT}"
fi
if [ -n "$INSTANCE" ]; then
	change_var_value $FILE INSTANCE_PATH "${INSTANCE}"
fi
if [ -n "$DHCPD" ]; then
	change_var_value $FILE VNET_DHCPDAEMON "${DHCPD}"
fi
if [ -n "$DHCPC_USER" ]; then
	change_var_value $FILE VNET_DHCPUSER "${DHCPC_USER}"
	uncomment $FILE VNET_DHCPUSER
fi
if [ -n "$NODES" ]; then
	change_var_value $FILE NODES "${NODES}"
fi
if [ -n "$HYPERVISOR" ]; then
	change_var_value $FILE HYPERVISOR "${HYPERVISOR}"
	uncomment $FILE HYPERVISOR
fi
if [ -n "$EUCA_USER" ]; then
	change_var_value $FILE EUCA_USER "${EUCA_USER}"
fi
if [ -n "$NAME" ]; then
	VALUE=`cat $FILE |grep $NAME|cut -f 2 -d =|tr  '"' ' '`
	echo $VALUE
fi
if [ -n "$NEWCLUS" ]; then

    if [ -f "$FILE" ]; then
	. $FILE
    else
	echo "ERROR: cannot find file '$EUCALYPTUS/etc/eucalyptus.conf'. Is your EUCALYPTUS enviroment variable set?"
	exit 1
    fi
    
    if [ -d "$EUCALYPTUS/var/lib/eucalyptus/db/" ]; then
	DBDIR="$EUCALYPTUS/var/lib/eucalyptus/db/"
    elif [ -d "$EUCALYPTUS/var/eucalyptus/db/" ]; then
	DBDIR="$EUCALYPTUS/var/eucalyptus/db/"
    else
	echo "ERROR: cannot locate eucalyptus database, try logging in through the admin web interface"
	exit 1
    fi
    FIELD=`grep -i "CREATE .*TABLE USERS" ${DBDIR}/* | sed 's/,/\n/g' | awk '/[Uu][Ss][Ee][Rr]_[Ss][Ee][Cc][Rr][Ee][Tt][Kk][Ee][Yy]/ {print NR}'`
    if [ "$FIELD" = "" ]; then
	echo "ERROR: cannot locate entry in eucalyptus database, try logging in through the admin web interface"
	exit 1
    fi
    KEY=$(eval echo $(awk -v field=${FIELD} -F, '/INSERT INTO USERS.*admin/ {print $field}' ${DBDIR}/* | head -n 1))
    
    ARGS="AWSAccessKeyId=ISMvKXpXpadDiUoOSoAfww&Action=DescribeAvailabilityZones"
    ARGS="${ARGS}&SignatureMethod=HmacSHA256&SignatureVersion=2&Timestamp=$(date '+%Y-%m-%dT%H%%3A%M%%3A%S.000Z')&Version=2008-12-01"
    SIGNATURE=$(echo -en "GET\n127.0.0.1\n/services/Eucalyptus\n${ARGS}" | openssl dgst -sha256 -hmac ${KEY} -binary | openssl base64)
    ISUP=`wget -O - "http://127.0.0.1:8773/services/Eucalyptus?${ARGS}&Signature=${SIGNATURE}" 2>/dev/null | grep UP`
    if [ -n "$ISUP" ]; then
	echo "ERROR: there is already a cluster registered with the system."
	exit 1
    fi

    ARGS="AWSAccessKeyId=ISMvKXpXpadDiUoOSoAfww&Action=AddCluster&Host=${NEWCLUS}&Name=${CLUSNAME}&Port=${CC_PORT}"
    ARGS="${ARGS}&SignatureMethod=HmacSHA256&SignatureVersion=2&Timestamp=$(date '+%Y-%m-%dT%H%%3A%M%%3A%S.000Z')&Version=2008-12-01"
    SIGNATURE=$(echo -en "GET\n127.0.0.1\n/services/Eucalyptus\n${ARGS}" | openssl dgst -sha256 -hmac ${KEY} -binary | openssl base64)
    
    ISREG=`wget -O - "http://127.0.0.1:8773/services/Eucalyptus?${ARGS}&Signature=${SIGNATURE}" 2>/dev/null`
    if [ ! -n "$ISREG" ]; then
	echo "ERROR: failed to register new cluster, please log in to the admin interface and check cluster status."
	exit 1
    fi
    echo "New cluster '${NEWCLUS}' on host '${NEWCLUS}' successfully added."
fi

if [ -n "$NEWNODE" ]; then

    if [ -f "$FILE" ]; then
	. $FILE
    else
	echo "ERROR: cannot find file '$EUCALYPTUS/etc/eucalyptus.conf'. Is your EUCALYPTUS enviroment variable set?"
	exit 1
    fi
    TMPFILE="$FILE.$$"
    
    
    if [ "$NODEMODE" = "ADD" ]; then
	EUCA_HOME=`su - -c 'echo $HOME' $EUCA_USER`
	echo $EUCA_HOME
	SSHKEY=`cat ${EUCA_HOME}/.ssh/id_rsa.pub`
	
	if [ "$SSHKEY" = "" ]; then
	    echo "ERROR: cannot read ssh key ~${EUCA_USER}/.ssh/id_rsa.pub, syncronization will probably not work"
	else
	    echo "First, please run the following commands on '$NEWNODE':"
	    echo ""
	    echo "sudo apt-get install eucalyptus-nc"
	    echo "sudo tee ~${EUCA_USER}/.ssh/authorized_keys > /dev/null <<EOT"
	    echo "$SSHKEY"
	    echo "EOT"
	    echo ""
	    echo "hit return to continue"
	    read
	fi
    fi
    
    if [ -d "$EUCALYPTUS/var/lib/eucalyptus/keys/" ]; then
	KEYDIR="$EUCALYPTUS/var/lib/eucalyptus/keys/"
    elif [ -d "$EUCALYPTUS/var/eucalyptus/keys/" ]; then
	KEYDIR="$EUCALYPTUS/var/eucalyptus/keys/"
    else
	echo "ERROR: cannot locate eucalyptus database, try logging in through the admin web interface"
	exit 1
    fi
    
    if [ "$NODEMODE" = "ADD" ]; then
	sudo -u eucalyptus scp ${KEYDIR}/* ${EUCA_USER}@${NEWNODE}:${KEYDIR}
	if [ "$?" != "0" ]; then
	    echo "ERROR: could not syncronize keys, check authorized_keys on ${NEWNODE}, then run this command again."
	    exit 1
	fi
    fi
    
    export NODES=`echo $NODES | sed "s/ *$NEWNODE *//g"`

# sed in new value
    if [ "$NODEMODE" = "ADD" ]; then
	cat $FILE | sed "/NODES=/s/NODES=.*/NODES=\"$NODES $NEWNODE\"/" > $TMPFILE
    elif [ "$NODEMODE" = "REM" ]; then
	cat $FILE | sed "/NODES=/s/ *$NEWNODE *//g" > $TMPFILE
    else
	echo "ERROR: unknown mode '$NODEMODE', don't know what to do"
	exit 1
    fi    
    
    if [ ! -s "$TMPFILE" ]; then
	echo "ERROR: failed to add node to $FILE"
	exit 1
    fi
    
# create backup
    cp $FILE $FILE.bak && cp $TMPFILE $FILE
    if [ "$?" != "0" ]; then
	echo "ERROR: could not install new conf file"
	exit 1
    fi
    
    rm $TMPFILE
    if [ "$NODEMODE" = "ADD" ]; then
	echo "SUCCESS: added node '$NEWNODE' to '$FILE'"
    elif [ "$NODEMODE" = "REM" ]; then
	echo "SUCCESS: removed node '$NEWNODE' from '$FILE'"
    fi
fi
