#!/bin/sh
#
#
#	NodeUtilization OCF Resource Agent
#
# Copyright (c) 2011 SUSE LINUX, John Shi
#                    All Rights Reserved.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of version 2 of the GNU General Public License as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it would be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
#
# Further, this software is distributed without any warranty that it is
# free of the rightful claim of any third person regarding infringement
# or the like.  Any license provided herein, whether implied or
# otherwise, applies only to this software file.  Patent licenses, if
# any, provided herein do not apply to combinations of this program with
# other software, or any other product whatsoever.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write the Free Software Foundation,
# Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
#
#######################################################################
# Initialization:

. ${OCF_ROOT}/resource.d/heartbeat/.ocf-shellfuncs

: ${OCF_RESKEY_utilization_cpu_reservation="1"}
: ${OCF_RESKEY_utilization_host_memory_reservation="512"}
: ${OCF_RESKEY_utilization_hv_memory_reservation="512"}

#######################################################################

meta_data() {
	cat <<END
<?xml version="1.0"?>
<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
<resource-agent name="NodeUtilization">
<version>1.0</version>

<longdesc lang="en">
This is an NodeUtilization Resource Agent.
This agent detects system parameters and put them into HA by crm_attribute,
and it runs on every node as clone resource.
</longdesc>
<shortdesc lang="en">NodeUtilization resource agent</shortdesc>

<parameters>
<parameter name="dynamic" unique="0" required="0">
<longdesc lang="en">
If set, some of the HA parameters will be reset if there are
difference between HA parameters and system parameters when HA monitor.
Otherwise, the HA parameters will be set once when the resource instance starts.
</longdesc>
<shortdesc lang="en">Set HA parameters when start or monitor</shortdesc>
<content type="boolean" default="true" />
</parameter>

<parameter name="utilization_cpu" unique="0" required="0">
<longdesc lang="en">Enable setting cpu utilization.</longdesc>
<shortdesc lang="en">Enable setting cpu utilization.</shortdesc>
<content type="boolean" default="true" />
</parameter>

<parameter name="utilization_cpu_reservation" unique="0" required="0">
<longdesc lang="en">CPU reserved for non-HA related usage.</longdesc>
<shortdesc lang="en">CPU reserved for non-HA related usage.</shortdesc>
<content type="integer" default="1" />
</parameter>

<parameter name="utilization_host_memory" unique="0" required="0">
<longdesc lang="en">Enable setting memory utilization of host.</longdesc>
<shortdesc lang="en">Enable setting memory utilization of host.</shortdesc>
<content type="boolean" default="true" />

<parameter name="utilization_host_memory_reservation" unique="0" required="0">
<longdesc lang="en">Memory reserved for other services inside host, in MB.</longdesc>
<shortdesc lang="en">Memory reserved for other services inside host, in MB.</shortdesc>
<content type="integer" default="512" />

<parameter name="utilization_hv_memory" unique="0" required="0">
<longdesc lang="en">Enable setting the memory utilization of hypervisor.</longdesc>
<shortdesc lang="en">Enable setting the memory utilization of hypervisor.</shortdesc>
<content type="boolean" default="true" />

<parameter name="utilization_hv_memory_reservation" unique="0" required="0">
<longdesc lang="en">Memory reserved for the hypervisor, in MB.</longdesc>
<shortdesc lang="en">Memory reserved for the hypervisor, in MB.</shortdesc>
<content type="integer" default="512" />

</parameter>

</parameters>

<actions>
<action name="start"   timeout="90" />
<action name="stop"    timeout="100" />
<action name="monitor" timeout="20s" interval="60s"/>
<action name="meta-data"  timeout="5" />
<action name="validate-all"  timeout="30" />
</actions>
</resource-agent>
END
}

set_utilization() {
    host_name="$(hostname)"

    if [ "$OCF_RESKEY_utilization_cpu" = "true" -o "$OCF_RESKEY_utilization_cpu" = "1" ]; then
        sys_cpu=$(grep -c processor /proc/cpuinfo)
		let sys_cpu=$sys_cpu-$OCF_RESKEY_utilization_cpu_reservation
        uti_cpu=$(crm_attribute -Q -t nodes -U "$host_name" -z -n cpu 2>/dev/null)

        if [ "$sys_cpu" != "$uti_cpu" ]; then
            if ! crm_attribute -t nodes -U "$host_name" -z -n cpu -v $sys_cpu; then
                ocf_log err "Failed to set cpu of utilization by crm_attribute."
                return 1
            fi
        fi
    fi

    if [ "$OCF_RESKEY_utilization_host_memory" = "true" -o "$OCF_RESKEY_utilization_host_memory" = "1" ]; then
        sys_mem=$(awk '/MemTotal/{printf("%d\n",$2/1024);exit(0)}' /proc/meminfo)
		let sys_mem=$sys_mem-$OCF_RESKEY_utilization_host_memory_reservation
        uti_mem=$(crm_attribute -Q -t nodes -U "$host_name" -z -n host_memory 2>/dev/null)

        if [ "$sys_mem" != "$uti_mem" ]; then
            if ! crm_attribute -t nodes -U "$host_name" -z -n host_memory -v $sys_mem; then
                ocf_log err "Failed to set memory of utilization by crm_attribute."
                return 1
            fi
        fi
    fi

	if [ -x /usr/sbin/xm ]; then
		if [ "$OCF_RESKEY_utilization_hv_memory" = "true" -o "$OCF_RESKEY_utilization_hv_memory" = "1" ]; then
			hv_mem=$(xm info | awk '/max_free_memory/{printf("%d\n",$3);exit(0)}')
			let hv_mem=$hv_mem-$utilization_hv_memory_reservation
			uti_mem=$(crm_attribute -Q -t nodes -U "$host_name" -z -n hv_memory 2>/dev/null)

			if [ "$sys_mem" != "$uti_mem" ]; then
				if ! crm_attribute -t nodes -U "$host_name" -z -n hv_memory -v $sys_mem; then
					ocf_log err "Failed to set memory of utilization by crm_attribute."
					return 1
				fi
			fi
		fi
	fi
}

NodeUtilization_usage() {
	cat <<END
usage: $0 {start|stop|monitor|validate-all|meta-data}

Expects to have a fully populated OCF RA-compliant environment set.
END
}

NodeUtilization_start() {
    if ! touch "$OCF_RESKEY_pidfile"; then
        ocf_log err "Failed to touch pidfile: ${OCF_RESKEY_pidfile}."
        exit $OCF_ERR_GENERIC
    fi
    if [ "$OCF_RESKEY_dynamic" = "false" -o "$OCF_RESKEY_dynamic" = "0" ]; then
        if ! set_utilization; then
            exit $OCF_ERR_GENERIC
        fi
    fi
    exit $OCF_SUCCESS
}

NodeUtilization_stop() {
    rm -f $OCF_RESKEY_pidfile
    exit $OCF_SUCCESS
}

NodeUtilization_monitor() {
    if [ ! -f $OCF_RESKEY_pidfile ]; then
        exit $OCF_NOT_RUNNING
    fi

    if [ "$OCF_RESKEY_dynamic" = "true" -o "$OCF_RESKEY_dynamic" = "1" ]; then
        if ! set_utilization; then
            exit $OCF_ERR_GENERIC
        fi
    fi
    exit $OCF_SUCCESS
}

NodeUtilization_validate() {
    exit $OCF_SUCCESS
}


if [ $# -ne 1 ]; then
    NodeUtilization_usage
    exit $OCF_ERR_ARGS
fi

: ${OCF_RESKEY_pidfile:="$HA_VARRUN/NodeUtilization-${OCF_RESOURCE_INSTANCE}"}
: ${OCF_RESKEY_dynamic:="true"}
: ${OCF_RESKEY_utilization_cpu:="true"}
: ${OCF_RESKEY_utilization_memory:="true"}

case $__OCF_ACTION in
meta-data)	meta_data
		exit $OCF_SUCCESS
		;;
start)		NodeUtilization_start
		;;
stop)		NodeUtilization_stop
		;;
monitor)	NodeUtilization_monitor
		;;
validate-all)	NodeUtilization_validate
		;;
usage|help)	NodeUtilization_usage
		exit $OCF_SUCCESS
		;;
*)		NodeUtilization_usage
		exit $OCF_ERR_UNIMPLEMENTED
		;;
esac

exit $?
