13.04.2011 12:06, Andrew Beekhof wrote:
> On Sat, Mar 19, 2011 at 6:10 PM, Vladislav Bogdanov
> <[email protected]> wrote:
>> Hi,
>>
>> just bumping this to be not forgotten.
> 
> Actually I'd missed that this was a Pacemaker specific one and
> therefore something I needed to look at :-)
> 
>> RA runs fine for almost a month, several simulated network outages were
>> passed with full success, so it could be included in some package. I
>> think pacemaker, because this RA uses pacemaker-specific calls.
>>
>> Andrew?
> 
> Looks pretty reasonable.
> Can you resend with hg headers (ie. "hg export") so that you can have
> the appropriate credit?
> It should be added to extra/resources

Please find attached.
It also has one issue with newer pacemaker fixed
(OCF_RESKEY_CRM_meta_interval is not longer supplied for some reason).


Vladislav
# HG changeset patch
# User Vladislav Bogdanov <[email protected]>
# Date 1302687018 -10800
# Node ID db47bd038103b1f476c90dd787b7f65cdabac9fe
# Parent  5bdfc629f35af0305bb87676297d81251f0511ea
Add ifspeed resource agent

diff -r 5bdfc629f35a -r db47bd038103 extra/resources/ifspeed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/extra/resources/ifspeed	Wed Apr 13 12:30:18 2011 +0300
@@ -0,0 +1,457 @@
+#!/bin/bash
+#
+# OCF resource agent which monitors state of network interface and records it
+# as a value in CIB based on summ of speeds of its active (up, link detected,
+# not blocked) underlying interfaces.
+#
+# Copyright (c) 2011 Vladislav Bogdanov <[email protected]>
+# Partially based on 'ping' RA by Andrew Beekhof
+#
+# OCF instance parameters:
+#    OCF_RESKEY_name:         name of attribute to set in CIB
+#    OCF_RESKEY_iface:        network interface to monitor
+#    OCF_RESKEY_bridge_ports: if not null and OCF_RESKEY_iface is a bridge, list of
+#                             bridge ports to consider.
+#                             Default is all ports which have designated_bridge=root_id 
+#    OCF_RESKEY_weight_base:  Relative weight of 1Gbps. This can be used to tune
+#                             value of resulting CIB attribute.
+#
+# Initialization:
+
+: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat}
+. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs
+
+# Defaults
+OCF_RESKEY_name_default="ifspeed"
+OCF_RESKEY_bridge_ports_default="detect"
+OCF_RESKEY_weight_base_default=1000
+OCF_RESKEY_dampen_default=5
+
+: ${OCF_RESKEY_name=${OCF_RESKEY_name_default}}
+: ${OCF_RESKEY_bridge_ports=${OCF_RESKEY_bridge_ports_default}}
+: ${OCF_RESKEY_weight_base=${OCF_RESKEY_weight_base_default}}
+: ${OCF_RESKEY_dampen=${OCF_RESKEY_dampen_default}}
+
+meta_data() {
+        cat <<END
+<?xml version="1.0"?>
+<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
+<resource-agent name="ifspeed">
+<version>1.0</version>
+
+<longdesc lang="en">
+Every time the monitor action is run, this resource agent records (in the CIB)
+(relative) speed of network interface it monitors.
+
+This RA can monitor physical interfaces, bonds, bridges, vlans and (hopefully)
+any combination of them.
+
+Examples:
+*) Bridge on top of one 10Gbps interface (eth2) and 802.3ad bonding (bond0) built
+   on two 1Gbps interfaces (eth0 and eth1).
+*) Active-backup bonding built on top of one physical interface and one vlan on
+   another interface.
+
+For STP-enabled bridges this RA tries to some-how guess network topology and by
+default looks only on ports which are connected to upstream switch. This can be
+overriden by 'bridge_ports' parameter. Active interfaces in this case are those
+in "forwarding" state.
+
+For balancing bonds this RA summs speeds of underlying "up" slave interfaces
+(and applies coefficient 0.8 to result).
+
+For non-balancing bonds ('active-backup' and probably 'brodcast') only speed of
+now active slave is used. 
+</longdesc>
+<shortdesc lang="en">Network interface speed monitor</shortdesc>
+
+<parameters>
+
+<parameter name="name" unique="1">
+<longdesc lang="en">
+The name of the attribute to set.  This is the name to be used in the constraints.
+</longdesc>
+<shortdesc lang="en">Attribute name</shortdesc>
+<content type="string" default="${OCF_RESKEY_name_default}"/>
+</parameter>
+
+<parameter name="iface" unique="0" required="1">
+<longdesc lang="en">
+Network interface to monitor.
+</longdesc>
+<shortdesc lang="en">Network interface</shortdesc>
+<content type="string" default=""/>
+</parameter>
+
+<parameter name="bridge_ports" unique="0">
+<longdesc lang="en">
+If not null and OCF_RESKEY_iface is a bridge, list of bridge ports to consider.
+Default is all ports which have designated_bridge=root_id.
+</longdesc>
+<shortdesc lang="en">Bridge ports</shortdesc>
+<content type="string" default="${OCF_RESKEY_bridge_ports_default}"/>
+</parameter>
+
+<parameter name="weight_base" unique="0">
+<longdesc lang="en">
+Relative weight of 1Gbps in interface speed.
+Can be used to tune how big attribute value will be.
+</longdesc>
+<shortdesc lang="en">Weight of 1Gbps</shortdesc>
+<content type="integer" default="${OCF_RESKEY_weight_base_default}"/>
+</parameter>
+
+<parameter name="dampen" unique="0">
+<longdesc lang="en">
+The time to wait (dampening) for further changes to occur.
+</longdesc>
+<shortdesc lang="en">Dampening interval</shortdesc>
+<content type="integer" default="${OCF_RESKEY_dampen_default}"/>
+</parameter>
+
+<parameter name="debug" unique="0">
+<longdesc lang="en">
+Log what have been done more verbosely.
+</longdesc>
+<shortdesc lang="en">Verbose logging</shortdesc>
+<content type="string" default="false"/>
+</parameter>
+
+</parameters>
+
+<actions>
+<action name="start"   timeout="30" />
+<action name="stop"    timeout="30" />
+<action name="reload"  timeout="30" />
+<action name="monitor" depth="0"  timeout="30" interval="10"/>
+<action name="meta-data"  timeout="5" />
+<action name="validate-all"  timeout="30" />
+</actions>
+</resource-agent>
+END
+}
+
+usage() {
+    cat <<END
+usage: $0 {start|stop|reload|monitor|validate-all|meta-data}
+
+Expects to have a fully populated OCF RA-compliant environment set.
+END
+}
+
+start() {
+    monitor
+    if [ $? -eq $OCF_SUCCESS ]; then
+        return $OCF_SUCCESS
+    fi
+    ha_pseudo_resource ${ha_pseudo_resource_name} start
+    update
+    return $?
+}
+
+stop() {
+    ha_pseudo_resource ${ha_pseudo_resource_name} stop
+    attrd_updater -D -n ${OCF_RESKEY_name} -d ${OCF_RESKEY_dampen} ${attrd_options}
+    return $OCF_SUCCESS
+}
+
+monitor() {
+    local ret
+    ha_pseudo_resource ${ha_pseudo_resource_name} monitor
+    ret=$?
+    if [ ${ret} -eq $OCF_SUCCESS ] ; then
+        update
+    fi
+    return ${ret}
+}
+
+validate() {
+    # Check the interface parameter
+    if [ -z "${OCF_RESKEY_iface}" ]; then 
+        ocf_log err "Empty iface parameter.  Please specify network interface to check"
+        exit $OCF_ERR_CONFIGURED
+    fi
+
+    return $OCF_SUCCESS
+}
+
+iface_get_speed() {
+    local iface=$1
+    local operstate
+    local carrier
+    local bridge_iface_speed
+    local bond_iface_speed
+    local vlan_iface_speed
+    local speed
+
+    if [ ! -e "/sys/class/net/${iface}" ] ; then
+        echo "0"
+    elif iface_is_bridge ${iface} ; then # bridges do not have operstate
+        read carrier < "/sys/class/net/${iface}/carrier"
+
+        if [ "${carrier}" != "1" ] ; then
+            echo "0"
+        else
+            bridge_get_speed ${iface}
+        fi
+    else
+        read operstate < "/sys/class/net/${iface}/operstate"
+        read carrier < "/sys/class/net/${iface}/carrier"
+
+        if [ "${operstate}" != "up" ] || [ "${carrier}" != "1" ] ; then
+            echo "0"
+        elif iface_is_bond ${iface} ; then
+            bond_get_speed ${iface}
+        elif iface_is_vlan ${iface} ; then
+            iface_get_speed $( vlan_get_phy ${iface} )
+        else
+            read speed < "/sys/class/net/${iface}/speed"
+            echo ${speed}
+        fi
+    fi
+}
+
+iface_is_vlan() {
+    local iface=$1
+    [ -e "/proc/net/vlan/${iface}" ] && return 0 || return 1
+}
+
+iface_is_bridge() {
+    local iface=$1
+    [ -e "/sys/class/net/${iface}/bridge" ] && return 0 || return 1
+}
+
+iface_is_bond() {
+    local iface=$1
+    [ -e "/sys/class/net/${iface}/bonding" ] && return 0 || return 1
+}
+
+vlan_get_phy() {
+    local iface=$1
+    sed -ne "s/^${iface} .*| *//p" < /proc/net/vlan/config
+}
+
+bridge_is_stp_enabled() {
+    local iface=$1
+    local stp
+    read stp < "/sys/class/net/${iface}/bridge/stp_state"
+    [ "${stp}" = "1" ] && return 0 || return 1
+}
+
+bridge_get_root_ports() {
+    local bridge=$1
+    local root_id
+    local root_ports=""
+    local bridge_id
+
+    read root_id < "/sys/class/net/${bridge}/bridge/root_id"
+
+    for port in /sys/class/net/${bridge}/brif/* ; do
+        read bridge_id < "${port}/designated_bridge"
+        if [ "${bridge_id}" = "${root_id}" ] ; then
+            root_ports="${root_ports} ${port##*/}"
+        fi
+    done
+
+    root_ports=${root_ports# }
+
+    if [ -n "$2" ] ; then # Record value in specified var. This expects we were called not in a sub-shell. 
+        eval $2=\${root_ports}
+    else # Expect sub-shell
+        echo ${root_ports}
+    fi
+}
+
+# From /inlude/linux/if_bridge.h:
+#define BR_STATE_DISABLED 0
+#define BR_STATE_LISTENING 1
+#define BR_STATE_LEARNING 2
+#define BR_STATE_FORWARDING 3
+#define BR_STATE_BLOCKING 4
+
+bridge_get_active_ports() {
+    local bridge=$1
+    shift 1
+    local ports="$*"
+    local active_ports=""
+    local port_state
+    local stp_state
+    local warn=0
+
+    bridge_is_stp_enabled ${bridge}
+    stp_state=$?
+
+    if [ -z "${ports}" ] || [ "${ports}" = "detect" ] ; then
+        bridge_get_root_ports ${bridge} ports
+    fi
+
+    for port in $ports ; do
+        if [ ! -e "/sys/class/net/${bridge}/brif/${port}" ] ; then
+            ocf_log warning "Port ${port} doesn't belong to bridge ${bridge}"
+            continue
+        fi
+        read port_state < "/sys/class/net/${bridge}/brif/${port}/state"
+        if [ "${port_state}" = "3" ] ; then
+            if [ -n "${active_ports}" ] && ${stp_state} ; then
+                warn=1
+            fi
+            active_ports="${active_ports} ${port}"
+        fi
+    done
+    if [ ${warn} -eq 1 ] ; then
+        ocf_log warning "More then one upstream port in bridge '${bridge}' is in forwarding state while STP is enabled: ${active_ports}" 
+    fi
+    echo "${active_ports# }"
+}
+
+bridge_get_speed() {
+    local iface=$1
+    local bridge_port_speed
+    local aggregate_speed=0
+
+    if ! iface_is_bridge ${iface} ; then
+        echo 0
+        return
+    fi
+
+    local ports=$( bridge_get_active_ports ${iface} ${OCF_RESKEY_bridge_ports} )
+    for port in ${ports} ; do
+        : $(( aggregate_speed += $( iface_get_speed ${port} ) ))
+    done
+    if [ -n "$2" ] ; then # Record value in specified var. This expects we were called not in a sub-shell. 
+        eval $2=\${aggregate_speed}
+    else # Expect sub-shell
+        echo ${aggregate_speed}
+    fi
+}
+
+bond_get_slaves() {
+    local iface=$1
+    local slaves
+    read slaves < "/sys/class/net/${iface}/bonding/slaves"
+    if [ -n "$2" ] ; then # Record value in specified var. This expects we were called not in a sub-shell. 
+        eval $2=\${slaves}
+    else # Expect sub-shell
+        echo ${slaves}
+    fi
+}
+
+bond_get_active_iface() {
+    local iface=$1
+    local active
+    read active < "/sys/class/net/${iface}/bonding/active_slave"
+    if [ -n "$2" ] ; then # Record value in specified var. This expects we were called not in a sub-shell. 
+        eval $2=\${active}
+    else # Expect sub-shell
+        echo ${active}
+    fi
+}
+
+bond_is_balancing() {
+    local iface=$1
+    read mode mode_index < "/sys/class/net/${iface}/bonding/mode"
+    case ${mode} in
+        "balance-rr"|"balance-xor"|"802.3ad"|"balance-tlb"|"balance-alb")
+            return 0
+            ;;
+        *)
+            return 1
+            ;;
+    esac
+}
+
+bond_get_speed() {
+    local iface=$1
+    local aggregate_speed=0
+    local bond_slave_speed
+    local active_iface
+    local bond_slaves
+
+    if ! iface_is_bond ${iface} ; then
+        echo 0
+        return
+    fi
+
+    bond_get_slaves ${iface} bond_slaves
+
+    if bond_is_balancing ${iface} ; then
+        for slave in ${bond_slaves} ; do
+            : $(( aggregate_speed += $( iface_get_speed ${slave} ) ))
+        done
+        # Bonding is unable to get speed*n
+        : $(( aggregate_speed = aggregate_speed * 8 / 10 ))
+    else
+        bond_get_active_iface ${iface} active_iface
+        aggregate_speed=$( iface_get_speed $active_iface )
+    fi
+    if [ -n "$2" ] ; then # Record value in specified var. This expects we were called not in a sub-shell. 
+        eval $2=\${aggregate_speed}
+    else # Expect sub-shell
+        echo ${aggregate_speed}
+    fi
+}
+
+update() {
+    local speed=$( iface_get_speed ${OCF_RESKEY_iface} )
+
+    : $(( score = speed * ${OCF_RESKEY_weight_base} / 1000 ))
+    attrd_updater -n ${OCF_RESKEY_name} -v ${score} -d ${OCF_RESKEY_dampen} ${attrd_options}
+    rc=$?
+    case ${rc} in
+        0)
+            ocf_is_true ${OCF_RESKEY_debug} && ocf_log debug "Updated ${OCF_RESKEY_name} = ${score}"
+            ;;
+        *)
+            ocf_log warn "Could not update ${OCF_RESKEY_name} = ${score}: rc=${rc}"
+            ;;
+    esac
+    return ${rc}
+}
+
+case $__OCF_ACTION in
+    meta-data)
+        meta_data
+        exit $OCF_SUCCESS
+        ;;
+    usage|help)
+        usage
+        exit $OCF_SUCCESS
+        ;;
+esac
+
+if [ `uname` != "Linux" ] ; then
+    ocf_log err "This RA works only on linux."
+    exit $OCF_ERR_INSTALLED
+fi
+
+: ${ha_pseudo_resource_name:="ifspeed-${OCF_RESOURCE_INSTANCE}"}
+
+attrd_options='-q'
+if ocf_is_true ${OCF_RESKEY_debug} ; then
+    attrd_options=''
+fi
+
+validate || exit $?
+
+case $__OCF_ACTION in
+    start)
+        start
+        ;;
+    stop)
+        stop
+        ;;
+    monitor)
+        monitor
+        ;;
+    reload)
+        start
+        ;;
+    validate-all)
+        ;;
+    *)
+        usage
+        exit $OCF_ERR_UNIMPLEMENTED
+        ;;
+esac
+
+exit $?
_______________________________________________
Pacemaker mailing list: [email protected]
http://oss.clusterlabs.org/mailman/listinfo/pacemaker

Project Home: http://www.clusterlabs.org
Getting started: http://www.clusterlabs.org/doc/Cluster_from_Scratch.pdf
Bugs: http://developerbugs.linux-foundation.org/enter_bug.cgi?product=Pacemaker

Reply via email to