#!/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_FUNCTIONS=${OCF_ROOT}/resource.d/heartbeat/.ocf-shellfuncs}
. ${OCF_FUNCTIONS}
: ${__OCF_ACTION=$1}

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

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 CIB 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>

<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>

<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>

<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_is_true "$OCF_RESKEY_utilization_cpu"; then
        sys_cpu=$(( $(grep -c processor /proc/cpuinfo) - $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_is_true "$OCF_RESKEY_utilization_host_memory"; then
        sys_mem=$(( $(awk '/MemTotal/{printf("%d\n",$2/1024);exit(0)}' /proc/meminfo) - $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 host_memory of utilization by crm_attribute."
                return 1
            fi
        fi
    fi

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

            if [ "$hv_mem" != "$uti_mem" ]; then
                if ! crm_attribute -t nodes -U "$host_name" -z -n hv_memory -v $hv_mem; then
                    ocf_log err "Failed to set hv_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_is_true "$OCF_RESKEY_dynamic"; 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_is_true "$OCF_RESKEY_dynamic"; then
        if ! set_utilization; then
            exit $OCF_ERR_GENERIC
        fi
    fi
    exit $OCF_SUCCESS
}

NodeUtilization_validate() {
    exit $OCF_SUCCESS
}


: ${OCF_RESKEY_pidfile:="$HA_VARRUN/NodeUtilization-${OCF_RESOURCE_INSTANCE}"}
: ${OCF_RESKEY_dynamic:="true"}
: ${OCF_RESKEY_utilization_cpu:="true"}
: ${OCF_RESKEY_utilization_cpu_reservation="1"}
: ${OCF_RESKEY_utilization_hv_memory:="true"}
: ${OCF_RESKEY_utilization_hv_memory_reservation="512"}
: ${OCF_RESKEY_utilization_host_memory:="true"}
: ${OCF_RESKEY_utilization_host_memory_reservation="512"}

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

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 $?
