Hi, 22.02.2011 18:46, Dejan Muhamedagic wrote: > If there's no connectivity then you can use ping, if there's some > then what matters is what kind of connection you have. "status" > is more like on/off. Here you try to find out a specific network > metric. >
ok. 's/ifstatus/ifspeed/g' done >>> - since this is a stateless agent, you should use the existing >>> functions for that purpose: >>> >>> http://www.linux-ha.org/doc/dev-guides/_pseudo_resources_literal_ha_pseudo_resource_literal.html >> >> Will look at that, thank you for pointer. ping RA seems to be missing >> this too BTW. Not critical anyway I think. > > It is there for exactly this purpose and it makes no sense > duplicating code. Don't forget that code needs to be reviewed, > tested, and maintained. done > >>> - almost all function names start with "ifstatus" which sometimes >>> makes it difficult to follow the code (e.g. ifstatus_iface_get_speed) >> >> Just copy-pasted skeleton from ping RA and did 's/ping/ifstatus/g'. And >> then named all other functions accordingly. This is completely to taste >> I think. And RA is meant to be used, not re-coded every now and then ;). > > If you were in my shoes, you'd appreciate code eligibility a bit > more. No, hopefully it's not to be reimplemented, but a) it needs > to be reviewed by somebody and b) it needs to be maintained just > like anything else in the repository. 's/ifspeed_//g' done Please find attached. Tested. Works. Best, Vladislav
#!/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 underlying interfaces. # # Copyright (c) 2011 Vladislav Bogdanov <bub...@hoster-ok.com> # 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: weight of each 10Mbps in interface speed (1Gbps = 100 * 10Mbps) in CIB score points # # Initialization: : ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/resource.d/heartbeat} . ${OCF_FUNCTIONS_DIR}/.ocf-shellfuncs # Defaults OCF_RESKEY_name_default="ifspeed" OCF_RESKEY_bridge_ports_default="detect" OCF_RESKEY_weight_base_default=10 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) speed of active network interfaces from a list. </longdesc> <shortdesc lang="en">Network interface status</shortdesc> <parameters> <parameter name="name" unique="1"> <longdesc lang="en"> The name of the attributes 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"> Weight of each 10Mbps in interface speed (1Gbps = 100 * 10Mbps). With default value 1Gbps interface will be counted as 1000. </longdesc> <shortdesc lang="en">Weight of 10Mbps interface</shortdesc> <content type="integer" default="${OCF_RESKEY_weight_base_default}"/> </parameter> <parameter name="dampen" unique="0"> <longdesc lang="en"> The time to wait (dampening) further changes 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"> Enables to use default attrd_updater verbose logging on every call. </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|monitor|migrate_to|migrate_from|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 } 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 check interval if ocf_is_decimal "${OCF_RESKEY_CRM_meta_interval}" && [ ${OCF_RESKEY_CRM_meta_interval} -gt 0 ]; then : else ocf_log err "Invalid check interval ${OCF_RESKEY_interval}. It should be positive integer!" exit $OCF_ERR_CONFIGURED fi # Check the intarfaces list if [ "x" = "x${OCF_RESKEY_iface}" ]; then ocf_log err "Empty iface parameter. Please specify some network interface to check" exit $OCF_ERR_CONFIGURED fi return $OCF_SUCCESS } iface_get_speed() { local iface=$1 local operstate local carrier local speed if [ ! -e "/sys/class/net/${iface}" ] ; then echo 0 elif iface_is_bridge ${iface} ; then bridge_get_speed ${iface} 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 operstate < "/sys/class/net/${iface}/operstate" read carrier < "/sys/class/net/${iface}/carrier" if [ "${operstate}" != "up" ] || [ "${carrier}" != "1" ] ; then speed="0" else read speed < "/sys/class/net/${iface}/speed" fi echo ${speed} 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 grep "^${iface} " "/proc/net/vlan/config" | sed -r 's/.*\| +(.*)/\1/' } 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 echo "${root_ports# }" } # 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=bridge_is_stp_enabled ${bridge} local warn=0 if [ -z "${ports}" ] || [ "${ports}" = "detect" ] ; then ports=$( bridge_get_root_ports ${bridge} ) 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 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 echo ${aggregate_speed} } bond_get_slaves() { local iface=$1 local slaves read slaves < "/sys/class/net/${iface}/bonding/slaves" echo ${slaves} } bond_get_active_iface() { local iface=$1 local active read active < "/sys/class/net/${iface}/bonding/active_slave" echo ${active} } 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 if ! iface_is_bond ${iface} ; then echo 0 return fi local slaves=$( bond_get_slaves ${iface} ) if bond_is_balancing ${iface} ; then for slave in ${slaves} ; do : $(( aggregate_speed += $( iface_get_speed ${slave} ) )) done # Bonding is unable to get speed*n : $(( aggregate_speed = aggregate_speed*8/10 )) else : $(( aggregate_speed = $( iface_get_speed $( bond_get_active_iface ${iface} ) ) )) fi echo ${aggregate_speed} } update() { local speed=$( iface_get_speed ${OCF_RESKEY_iface} ) : $(( score = speed * ${OCF_RESKEY_weight_base} / 10 )) 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} } if [ `uname` != "Linux" ] ; then ocf_log err "This RA works only on linux." exit $OCF_ERR_INSTALLED fi if ! ocf_is_true ${OCF_RESKEY_CRM_meta_globally_unique} ; then : ${ha_pseudo_resource_name:="ifspeed-${OCF_RESKEY_name}"} else : ${ha_pseudo_resource_name:="ifspeed-${OCF_RESOURCE_INSTANCE}"} fi attrd_options='-q' if ocf_is_true ${OCF_RESKEY_debug} ; then attrd_options='' fi case $__OCF_ACTION in meta-data) meta_data exit $OCF_SUCCESS ;; start) start ;; stop) stop ;; monitor) monitor ;; reload) start ;; validate-all) validate ;; usage|help) usage exit $OCF_SUCCESS ;; *) usage exit $OCF_ERR_UNIMPLEMENTED ;; esac exit $?
_______________________________________________ Pacemaker mailing list: Pacemaker@oss.clusterlabs.org 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