#!/bin/bash
#
# OCF resource agent to move an IP address within a VPC in the AWS
# Written by Markus Guertler (SUSE)
# Based on code of Adam Gandelman (GitHub ec2-resource-agents/elasticip)
#

###############################################################################
# For testing purposes delete OCF_ROOT after testing
OCF_ROOT=/usr/lib/ocf/
#
# INIT
: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/resource.d/heartbeat}
if [ -f ${OCF_FUNCTIONS_DIR}/.ocf-shellfuncs ]; then
  . ${OCF_FUNCTIONS_DIR}/.ocf-shellfuncs
fi
 
USAGE="usage: $0 {start|stop|status|meta-data}";
###############################################################################


###############################################################################
#
# Functions
#
###############################################################################


metadata() {
cat <<END
<?xml version="1.0"?>
<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
<resource-agent name="aws-vpc-move-ip">
<version>1.0</version>
<longdesc lang="en">
Resource Agent to move IP addresses within a VPC of the Amazon Webservices EC2
by changing an entry in an specific routing table
</longdesc>
<shortdesc lang="en">Move IP within a APC of the AWS EC2</shortdesc>
<parameters>
<parameter name="java_home" required="0">
<longdesc lang="en">
JAVA home directory; Agent tries to determine the java_home directory
automatically
</longdesc>
<shortdesc lang="en">java home directory</shortdesc>
<content type="string" default="" />
</parameter>
<parameter name="ec2_home" required="0">
<longdesc lang="en">
EC2 home directory
</longdesc>
<shortdesc lang="en">ec2 home directory</shortdesc>
<content type="string" default="" />
</parameter>
<parameter name="address" required="1">
<longdesc lang="en">
VPC IP address
</longdesc>
<shortdesc lang="en">vpc ip</shortdesc>
<content type="string" default="" />
</parameter>
<parameter name="routing_table" required="1">
<longdesc lang="en">
Name of the routing table, where the route for the IP address should be changed
</longdesc>
<shortdesc lang="en">routing table name</shortdesc>
<content type="string" default="" />
</parameter>
<parameter name="interface" required="1">
<longdesc lang="en">
Name of the network interfacen, i.e. eth0
</longdesc>
<shortdesc lang="en">network interface name</shortdesc>
<content type="string" default="eth0" />
</parameter>
<parameter name="credentials" required="0">
<longdesc lang="en">
Location of file containing appropriate credentials.
</longdesc>
<shortdesc lang="en">credentials</shortdesc>
<content type="string" default="/root/.cred.txt" /> 
</parameter> 
</parameters>
<actions>
<action name="start" timeout="180" />
<action name="stop" timeout="180" />
<action name="monitor" depth="0" timeout="30" interval="30" />
<action name="validate-all" timeout="5" />
<action name="meta-data" timeout="5" />
</actions>
</resource-agent>
END
}

debug=1

debugger() {
	[[ $debug != 0 ]] && ocf_log info $1
}

ec2ip_validate() {
	debugger "validate"
	
	# IP address
	[[ -z "$OCF_RESKEY_address" ]] && ocf_log error "IP address parameter not set $OCF_RESKEY_ADDRESS!" && exit $OCF_ERR_CONFIGURED
	
	# Network Interface
	[[ -z "$OCF_RESKEY_interface" ]] && ocf_log error "Network interface parameter not set $OCF_RESKEY_INTERFACE!" && exit $OCF_ERR_CONFIGURED
	
	# Routing Table
	[[ -z "$OCF_RESKEY_routing_table" ]] && ocf_log error "Routing table parameter not set $OCF_RESKEY_ROUTING_TABLE!" && exit $OCF_ERR_CONFIGURED

	# Java Home
	if [ -z "$OCF_RESKEY_java_home" ]; then
	    java=`which java`
	    while [ -L "$java" ]; do
	        java=`/bin/ls -l $java | awk '{print $11}'`
	    done
	    export OCF_RESKEY_java_home=`dirname $java`/..
	fi
	[[ -z "$OCF_RESKEY_java_home" ]] && ocf_log error "Paramter $OCF_RESKEY_JAVA_HOME not set and I wasn't able to determine it automatically!" && exit $OCF_ERR_CONFIGURED
	[[ ! -x "${OCF_RESKEY_java_home}/bin/java" ]] && ocf_log error "Couldn't find java executable in ${OCF_RESKEY_java_home}/bin directory" && exit $OCF_ERR_CONFIGURED
	export JAVA_HOME=$OCF_RESKEY_java_home

	# EC2 Home
	if [ -z "$OCF_RESKEY_ec2_home" ]; then
	    $OCF_RESKEY_ec2_home="$HOME/.ec2"
	fi
	
	export EC2_HOME=$OCF_RESKEY_ec2_home
	export PATH="$PATH:$EC2_HOME/bin"
	
	EC2_COMMANDS="ec2-replace-route ec2-describe-route-tables ec2metadata"

	for i in $EC2_COMMANDS ; do
		debugger "- Locating command $i: "
		[[ ! -x $(which $i) ]] && ocf_log error "Command $i not found/exectuable; Have you set the ec2_home parameter?" && exit $OCF_ERR_INSTALLED
		debugger "found"
	done
	
	EC2_INSTANCE_ID=$(ec2metadata --instance-id)
			
	# IP command
	IP=$(which ip)
	[[ -z "$IP" ]] && ocf_log error "ip command from iproute2 package not found!" && exit $OCF_ERR_CONFIGURED
	
	return $OCF_SUCCESS
}

ec2ip_monitor() {
	ec2ip_validate
	debugger "monitor: check routing table"
	ROUTE_TO_INSTANCE="$(ec2-describe-route-tables rtb-d29969be |grep "$OCF_RESKEY_address" | awk '{ print $2 }')"
	[[ "$EC2_INSTANCE_ID" != "$ROUTE_TO_INSTANCE" ]] && debugger "- not routed to this instance ($EC2_INSTANCE_ID) but to $ROUTE_TO_INSTNANCE" && return $OCF_NOT_RUNNING 
	debugger "monitor: ping ip"
	ping -W 1 -c 1 $OCF_RESKEY_address > /dev/null
	[[ $? -gt 0 ]]  && debugger "- IP $OCF_RESKEY_address not locally reachable via ping on this system" && return $OCF_NOT_RUNNING
	debugger "- routed in VPC and locally reachable"
	return $OCF_SUCCESS	
}


ec2ip_drop() {
	debugger "ec2ip_drop: $IP addr delete "${OCF_RESKEY_address}/32" dev $OCF_RESKEY_interface"
	$IP addr delete "${OCF_RESKEY_address}/32" dev $OCF_RESKEY_interface
	[[ $? -gt 2 ]] && debugger "- failed ip addr delete" && return $OCF_ERR_GENERIC
	debugger "- succeeded ip addr delete"
	return $OCF_SUCCESS
}

ec2ip_get_and_configure() {
	debugger "ec2ip_get_and_configure: $ASSOCIATE_CMD"
	ec2-replace-route $OCF_RESKEY_routing_table -r "${OCF_RESKEY_address}/32" -i $EC2_INSTANCE_ID
	[[ $? != 0 ]] && debugger "- failed ec2-replace-route, rc: $?" && return $OCF_ERR_GENERIC
	$IP addr add "${OCF_RESKEY_address}/32" dev $OCF_RESKEY_interface
	[[ $? != 0 ]] && debugger "- failed ip addr add ..., rc: $?" && return $OCF_ERR_GENERIC
	debugger "-success"
	return $OCF_SUCCESS
}

ec2ip_stop() {
	ocf_log info "EC2: Bringing down IP address $OCF_RESKEY_address"
	ec2ip_validate 
	ec2ip_monitor
	[[ $? == $OCF_NOT_RUNNING ]] && ocf_log info "EC2: Address $OCF_RESKEY_address already down" && return $OCF_SUCCESS
	ec2ip_drop
	[[ $? != $OCF_SUCCESS ]] && return $OCF_ERR_GENERIC
	ec2ip_monitor
	[[ $? == $OCF_NOT_RUNNING ]] && ocf_log info "EC2: Successfully brought down $OCF_RESKEY_address" && return $OCF_SUCCESS
	ocf_log error "EC2: Couldn't bring down IP address $OCF_RESKEY_address on interface $OCF_RESKEY_interface." 
	return $OCF_ERR_GENERIC
}

ec2ip_start() {
	ocf_log info "EC2: Moving IP address $OCF_RESKEY_address to this host by adjusting routing table $OCF_RESKEY_routing_table"
	ec2ip_validate
	ec2ip_monitor
	[[ $? == $OCF_SUCCESS ]] && ocf_log info "EC2: $OCF_RESKEY_address already started" && return $OCF_SUCCESS
	ocf_log info "EC2: Adjusting routing table and locally configuring IP address"
	ec2ip_get_and_configure 
	[[ $? != 0 ]] && ocf_log error "Received $? from 'aws'" && return $OCF_ERR_GENERIC
	ec2ip_monitor
	[[ $? == $OCF_SUCCESS ]] &&  return $?
	ocf_log error "EC2: IP address couldn't be configured on this host (IP: $OCF_RESKEY_address, Interface: $OCF_RESKEY_interface)"
	return $OCF_ERR_GENERIC
}

###############################################################################
#
# MAIN
#
###############################################################################

case $__OCF_ACTION in 
	meta-data) metadata
		   exit $OCF_SUCCESS;;
	monitor)
		ec2ip_monitor;;
	stop)
		ec2ip_stop;;
	validate-all) ec2ip_validate;;
	start)
		ec2ip_start;;
	*)	exit $OCF_ERR_UNIMPLEMENTED;;
esac