#!/bin/sh
#
#
#	SysInfo OCF Resource Agent
#	It records (in the CIB) various attributes of a node
#
# Copyright (c) 2004 SUSE LINUX AG, Lars Marowsky-Bre
#                    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="SysInfo">
<version>1.0</version>

<longdesc lang="en">
This is a SysInfo Resource Agent.
It records (in the CIB) various attributes of a node
Sample Linux output:
   arch:   i686
   os:     Linux-2.4.26-gentoo-r14
   free_swap:      1999
   cpu_info:       Intel(R) Celeron(R) CPU 2.40GHz
   cpu_speed:      4771.02
   cpu_cores:      1
   cpu_load:       0.00
   ram_total:      513
   ram_free:       117
   root_free:      2.4

Sample Darwin output:
   arch:   i386
   os:     Darwin-8.6.2
   cpu_info:       Intel Core Duo
   cpu_speed:      2.16
   cpu_cores:      2
   cpu_load:       0.18
   ram_total:      2016
   ram_free:       787
   root_free:      13

Units:
   free_swap: Mb
   ram_*:     Mb
   cpu_speed (Linux): bogomips
   cpu_speed (Darwin): Ghz
   *_free:    GB (or user-defined: disk_unit)

</longdesc>
<shortdesc lang="en">SysInfo resource agent</shortdesc>

<parameters>

<parameter name="pidfile" unique="0">
<longdesc lang="en">PID file</longdesc>
<shortdesc lang="en">PID file</shortdesc>
<content type="string" default="$OCF_RESKEY_pidfile" />
</parameter>

<parameter name="delay" unique="0">
<longdesc lang="en">Interval to allow values to stabilize</longdesc>
<shortdesc lang="en">Dampening Delay</shortdesc>
<content type="string" default="0s" />
</parameter>

<parameter name="disks" unique="1">
<longdesc lang="en">
Filesystems or Paths to be queried for free disk space as a SPACE separated list - e.g "/dev/sda1 /tmp".
Results will be written to an attribute with leading slashes removed, and other slashes replaced with underscore, and the word 'free' appended - e.g /dev/sda1 -> dev_sda1_free
Note: The root filesystem '/' is always queried to an attribute named 'root_free'
</longdesc>
<shortdesc lang="en">List of Filesytems/Paths to query for free disk space</shortdesc>
<content type="string" />
</parameter>

<parameter name="disk_unit" unique="1">
<longdesc lang="en">
Unit to report disk free space in.
Can be one of: B, K, M, G, T, P (case-insensitive)
</longdesc>
<shortdesc lang="en">Unit to report disk free space in</shortdesc>
<content type="string" default="G"/>
</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
}

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

UpdateStat() {
    name=$1; shift
    value="$*"
    printf "%s:\t%s\n" "$name" "$value"
    ${HA_SBIN_DIR}/attrd_updater ${OCF_RESKEY_delay} -S status -n $name -v "$value"
}

SysInfoStats() {

    UpdateStat arch "`uname -m`"
    UpdateStat os "`uname -s`-`uname -r`"

    case `uname -s` in
	"Darwin")
	    mem=`top -l 1 | grep Mem: | awk '{print $10}'`
	    mem_used=`top -l 1 | grep Mem: | awk '{print $8}'`
	    mem=`SysInfo_mem_units $mem`
	    mem_used=`SysInfo_mem_units $mem_used`
	    mem_total=`expr $mem_used + $mem`
	    cpu_type=`system_profiler SPHardwareDataType | awk -F': ' '/^CPU Type/ {print $2; exit}'`
	    cpu_speed=`system_profiler SPHardwareDataType | awk -F': ' '/^CPU Speed/ {print $2; exit}'`
	    cpu_cores=`system_profiler SPHardwareDataType | awk -F': ' '/^Number Of/ {print $2; exit}'`
	;;
	"Linux")
	    if [ -f /proc/cpuinfo ]; then
		cpu_type=`awk -F': ' '/model name/ {print $2; exit}' /proc/cpuinfo`
		cpu_speed=`awk -F': ' '/bogomips/ {print $2; exit}' /proc/cpuinfo`
		cpu_cores=`grep "^processor" /proc/cpuinfo | wc -l`
	    fi

	    if [ -f /proc/meminfo ]; then
	        # meminfo results are in kB
		mem=`grep "SwapFree" /proc/meminfo | awk '{print $2"k"}'`
		if [ ! -z $mem ]; then
		    UpdateStat free_swap `SysInfo_mem_units $mem`
		fi
		mem=`grep "Inactive" /proc/meminfo | awk '{print $2"k"}'`
		mem_total=`grep "MemTotal" /proc/meminfo | awk '{print $2"k"}'`
	    else
		mem=`top -n 1 | grep Mem: | awk '{print $7}'`
	    fi
	    ;;
	*)
    esac

    if [ x != x"$cpu_type" ]; then
	UpdateStat cpu_info "$cpu_type"
    fi

    if [ x != x"$cpu_speed" ]; then
	UpdateStat cpu_speed "$cpu_speed"
    fi

    if [ x != x"$cpu_cores" ]; then
	UpdateStat cpu_cores "$cpu_cores"
    fi

    loads=`uptime`
    load15=`echo ${loads} | awk '{print $10}'`
    UpdateStat cpu_load $load15

    if [ ! -z "$mem" ]; then
        # Massage the memory values
 	UpdateStat ram_total `SysInfo_mem_units $mem_total`
	UpdateStat ram_free `SysInfo_mem_units $mem`
    fi

    # Portability notes:
    #   o tail: explicit "-n" not available in Solaris; instead simplify
    #	  'tail -n <c>' to the equivalent 'tail -<c>'.
    for disk in "/" ${OCF_RESKEY_disks}; do
	unset disk_free disk_label
	disk_free=`df -h ${disk} | tail -1 | awk '{print $4}'`
	if [ x != x"$disk_free" ]; then
	    disk_label=`echo $disk | sed -e 's#^/$#root#;s#^/*##;s#/#_#g'`
	    UpdateStat ${disk_label}_free `SysInfo_hdd_units $disk_free`
	fi
    done
}

SysInfo_megabytes() {
    # Size in megabytes
    echo $1 | awk '{ n = $0;
		     sub(/[0-9]+(.[0-9]+)?/, "");
		     split(n, a, $0);
                     n=a[1];
                     if ($0 == "G" || $0 == "") { n *= 1024 };
                     if (/^kB?/) { n /= 1024 };
                     printf "%d\n", n }' # Intentionaly round to an integer
}

SysInfo_mem_units() {
    mem=$1

    if [ -z $1 ]; then 
	return
    fi

    mem=$(SysInfo_megabytes "$1")
    # Round to the next multiple of 50
    r=$(($mem % 50))
    if [ $r != 0 ]; then
	mem=$(($mem + 50 - $r))
    fi

    echo $mem    
}

SysInfo_hdd_units() {
    # Defauts to size in gigabytes

    case $OCF_RESKEY_disk_unit in 
	[Pp]) echo $(($(SysInfo_megabytes "$1") / 1024 / 1024 / 1024));;
	[Tt]) echo $(($(SysInfo_megabytes "$1") / 1024 / 1024));;
	[Gg]) echo $(($(SysInfo_megabytes "$1") / 1024));;
	[Mm]) echo SysInfo_megabytes "$1";;
	[Kk]) echo $(($(SysInfo_megabytes "$1") * 1024));;
	[Bb]) echo $(($(SysInfo_megabytes "$1") * 1024 * 1024));;
	*) 
	    ocf_log err "Invalid value for disk_unit: $OCF_RESKEY_disk_unit"
	    echo $(($(SysInfo_megabytes "$1") / 1024));;
    esac
}

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

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

SysInfo_start() {
    echo $OCF_RESKEY_clone > $OCF_RESKEY_pidfile
    SysInfoStats
    exit $OCF_SUCCESS
}

SysInfo_stop() {
    rm $OCF_RESKEY_pidfile
    exit $OCF_SUCCESS
}

SysInfo_monitor() {
    if [ -f $OCF_RESKEY_pidfile ]; then
	clone=`cat $OCF_RESKEY_pidfile`
    fi

    if [ x$clone = x ]; then
	rm $OCF_RESKEY_pidfile
	exit $OCF_NOT_RUNNING

    elif [ $clone = $OCF_RESKEY_clone ]; then
	SysInfoStats
	exit $OCF_SUCCESS

    elif [ x$OCF_RESKEY_CRM_meta_globally_unique = xtrue  
	    -o x$OCF_RESKEY_CRM_meta_globally_unique = xTrue
	    -o x$OCF_RESKEY_CRM_meta_globally_unique = xyes
	    -o x$OCF_RESKEY_CRM_meta_globally_unique = xYes
	]; then
	SysInfoStats
	exit $OCF_SUCCESS
    fi
    exit $OCF_NOT_RUNNING
}

SysInfo_validate() {
    return $OCF_SUCCESS
}

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

: ${OCF_RESKEY_pidfile:="$HA_VARRUN/SysInfo-${OCF_RESOURCE_INSTANCE}"}
: ${OCF_RESKEY_disk_unit:="G"}
: ${OCF_RESKEY_clone:="0"}
if [ x != x${OCF_RESKEY_delay} ]; then
    OCF_RESKEY_delay="-d ${OCF_RESKEY_delay}"
fi

case $__OCF_ACTION in
meta-data)	meta_data
		exit $OCF_SUCCESS
		;;
start)		SysInfo_start
		;;
stop)		SysInfo_stop
		;;
monitor)	SysInfo_monitor
		;;
validate-all)	SysInfo_validate
		;;
usage|help)	SysInfo_usage
		exit $OCF_SUCCESS
		;;
*)		SysInfo_usage
		exit $OCF_ERR_UNIMPLEMENTED
		;;
esac

exit $?
