I have updated the synaccess stonith script, to support multiple synaccess devices and multiple power outlets with the same name. This allows redundant power circuits to drive redundant power supplies in the cluster nodes. Because the devices can now be chained together this should also simplify configuring large clusters.

This version also works around a couple of issues that have been discovered with the synaccess devices. More details can be found in the appropriate sections (search for sleep) of the script.

Syntactically this version should be a drop in replacement for the previous version. The only difference is the ability to specify more than one synaccess device in the ip list delimited by spaces or commas. This now matches the behavior of some of the other stonith plug-ins.


The diff was quite large, so I again both attached and pasted the whole script 
below.


#!/bin/bash
#
# External STONITH module for synaccess.
#
# Copyright (c) 2008 Gresham Enterprise Storage
# Jeremy Linton <[EMAIL PROTECTED]>
#
# 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.
#
#
#
# The original version only controlled a single synaccess device
# this version adds the ability to combine multiple devices to control larger
# clusters, or alternatively to have multiple synaccess devices on different 
power
# circuits for redundant power supplies.

#
# This script requires a few things:
# net-snmp
# SYNACCESS-MIB.txt
# the hostnames that are controlled are placed in the "power outlet" "name" 
field.
# The Synaccess device must have SNMP turned on
# The script must have the IP/Hostname of the synaccess device passed in via 
"synaccessip"
#
# finally, if you are using multiple synaccess devices on different power 
circuits plugged
# into redundant power ports, you can specify multiple IPs for the synaccessip 
variable.
# Outlets with the same name on diffrent synaccess devices will be turned 
on/off/reset in parallel.


# in order to use this script you must have installed the MIB that came with 
the synaccess device
# in /usr/share/snmp/mibs/SYNACCESS-MIB.txt or similar. From then on the 
net-snmp utilities
# are aware of the proper names.
# if you are having problems detecting the proper power status make sure the 
mib power status reads:
#outletStatus OBJECT-TYPE
#SYNTAX INTEGER {
#off(0),
#on(1),
#off(2),
#on(257),
#off(256)
#}
# Check the synaccess specific mib with
# snmpwalk -c public -m SYNACCESS-MIB -v 1 x.x.x.x synAcc


# default to 5 seconds of sleep time after all the outlets have been turned off
# before we turn them back on
reset_delay=${reset_delay:-"5"}
# drop "public" in if the community isn't set
community=${community:-"public"}
# rewrite the ip list to accept , or space as a delimiter
synaccessip=`echo $synaccessip | tr ',' ' '`


# commands used to get/set snmp object id (oid) values
SNMP_GETCOMMAND="/usr/bin/snmpget -c $community -m SYNACCESS-MIB -v 1"
SNMP_SETCOMMAND="/usr/bin/snmpset -c $community -m SYNACCESS-MIB -v 1"

# pass the IP and then the name
get_snmp_value()
{
    device_ip=$1
    oid=$2
    echo `$SNMP_GETCOMMAND $device_ip $oid 2>&1|cut -d: -f4`
}

# the port name given in the web interface must match the switched port number
# this discovers all the hostnames set as the outlet name
discover_hostlist()
{
    synaccessdeviceip=$1

    portcount=`get_snmp_value $synaccessdeviceip 
SYNACCESS-MIB::powerOutletNum.0`
    for ((i=1; $i <= ${portcount:-"0"};i++)); do
        portname=`get_snmp_value $synaccessdeviceip 
SYNACCESS-MIB::outletName.$i`
        if [[ "$portname" && "$portname" != "Undefined" ]]; then
            # only save unique host names
            if [[ !("$hostlist" =~ "$portname ") ]]; then
                hostlist="$hostlist$portname "
            fi
        fi
    done
}

# this looks up the port number based on the passed hostname, using the power 
outlet name
get_port_for_host()
{
    synaccessdeviceip=$1
    hostlookup=$2

    portcount=`get_snmp_value $synaccessdeviceip 
SYNACCESS-MIB::powerOutletNum.0`
    if [[ -z "$portcount" ]]; then
        # device isn't responding
        return 0
    else
        ret_code=2 #default to not finding any matching hosts on this device
        for ((i=1; $i <= $portcount ;i++)); do
            portname=`get_snmp_value $synaccessdeviceip 
SYNACCESS-MIB::outletName.$i`
            if [[ "$portname" == "$hostlookup" ]]; then
                echo "$i "
                ret_code=1
            fi
            # the error handling leaves a possible race, if the device dies 
while we are
            # scanning the ports, we just assume the outlet isn't found, if 
this happens
            # and there is more than one synaccess device its possible we only 
set the state
            # for one power rail.
        done
        # if ret_code=2 everything was responding but we didn't find the
        # named port assume it doesn't exist. It could be a configuration error,
        # but we can't tell.
        return $ret_code
    fi
}

# this sends a ON/OFF/RESET action to the given hostname
do_port_action()
{
    synaccessdeviceip=$1
    controlledhost=$2
    newportstate=$3

    portnum=`get_port_for_host $synaccessdeviceip $controlledhost`
    portret=$?
    if [[ "$portret" == "1" ]]; then
        for curport in $portnum ; do
            out=`$SNMP_SETCOMMAND $synaccessdeviceip 
"SYNACCESS-MIB::outletAction.$curport" = $newportstate`
            # this sleep is here, because commands fired in rapid succession 
don't always take affect, the
            # snmp values get updated, but the device fails to internally 
trigger on the change
            sleep 1
            #TODO check to see if port was successfuly set
        done
    fi
    return $portret
}

# this takes the list of synaccess devices, and calls do_port_action for each 
one
# this makes sure that if there are multiple synaccess devices with a 
particular host plugged
# in all the outlets are set, this allows multiple circuit configurations
set_all_ports()
{
    host_to_update=$1
    new_port_state=$2

    failed_to_set_all=0
    set_atleast_one=0

    for deviceip in $synaccessip ; do
        do_port_action $deviceip $host_to_update $new_port_state
        port_set_ok=$?
        case $port_set_ok in
            0)
                # if any of the syanaccess devices fail, then assume
                # that the whole operation failed, this is because we can never
                # know if that device may still be providing power on a 
redunant circuit to the
                # machine
                failed_to_set_all=1
            ;;
            1)
                set_atleast_one=1
            ;;
            2)
               # this device doesn't have a port configured with the given 
hostname, ignore it
            ;;
        esac
    done
    if [[ "$set_atleast_one" == "0" ]]; then
        # none of the synaccess devices had a port with the given name
        # fail the operation
        failed_to_set_all=1
    fi
    return $failed_to_set_all
}


# Handle script commands
case $1 in
gethosts)
        for deviceip in $synaccessip ; do
            discover_hostlist $deviceip
        done
        for h in $hostlist ; do
                echo $h
        done
        exit 0
        ;;
on)
        set_all_ports $2 1
        exit $?
        ;;
off)
        set_all_ports $2 2
        exit $?
        ;;
reset)
        # The synaccess devices have a nice "reboot" function which
        # turns the power off and after a configured length turns
        # it back on. The only problem is that its really a power toggle 
function.
        # If the power is off, then it turns it on, and then back off
        # So, before we use that function, we make sure that the power is 
turned on
        # (which in general it should be)
        # BTW: the setting for the port delay is in the telnet menu, and not in 
the
        # web interface.
        #set_all_ports $2 1
        #set_all_ports $2 3
        #
        # For now the reboot seems to have to many side effects to be truly 
useful
        # instead lets just manually set it off/on
        #
        set_all_ports $2 2 # turn it off
        # wait a few seconds for the power supplies to drain (some have pretty 
long holdup times)
        sleep $reset_delay
        set_all_ports $2 1 # turn it on
        exit $?
        ;;

status)
        # if any of the given devices fail to responed then assume failure
        for deviceip in $synaccessip ; do
            portcount=`get_snmp_value $deviceip SYNACCESS-MIB::powerOutletNum.0`
            if [[ -z $portcount ]]; then
                exit 1
            fi
        done
        exit 0
        ;;
getconfignames)
        echo "synaccessip community"
        exit 0
        ;;
getinfo-devid)
        echo "synaccess"
        exit 0
        ;;
getinfo-devname)
        for deviceip in $synaccessip ; do
            synModel=`get_snmp_value $deviceip SYNACCESS-MIB::systemModel.0`
            synName=`get_snmp_value $deviceip SYNACCESS-MIB::systemName.0`
            echo "Synaccess netBooter $synModel $synName"
        done
        exit 0
        ;;
getinfo-devdescr)
        echo "synaccess netbooter STONITH device"
        exit 0
        ;;
getinfo-devurl)
        echo "http://www.synaccess-net.com";
        exit 0
        ;;
getinfo-xml)
# Parameters (hostname, synaccess IP, synaccess port)
        cat << SAXML
<parameters>
 <parameter name="synaccessip" unique="1" required="1">
  <content type="string" />
  <shortdesc lang="en">SynaccessIp</shortdesc>
  <longdesc lang="en">The IPs of the synaccess devices controlling the 
hosts</longdesc>
 </parameter>
 <parameter name="community" unique="1" required="0">
  <content type="string" />
  <shortdesc lang="en">Community</shortdesc>
  <longdesc lang="en">The SNMP Community string</longdesc>
 </parameter>
</parameters>
SAXML
        exit 0
        ;;
*)
        exit 1
        ;;
esac
#!/bin/bash
#
# External STONITH module for synaccess.
#
# Copyright (c) 2008 Gresham Enterprise Storage 
# Jeremy Linton <[EMAIL PROTECTED]> 
#
# 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.
#
#
#
# The original version only controlled a single synaccess device
# this version adds the ability to combine multiple devices to control larger
# clusters, or alternatively to have multiple synaccess devices on different 
power 
# circuits for redundant power supplies. 

#
# This script requires a few things:
# net-snmp
# SYNACCESS-MIB.txt 
# the hostnames that are controlled are placed in the "power outlet" "name" 
field.
# The Synaccess device must have SNMP turned on
# The script must have the IP/Hostname of the synaccess device passed in via 
"synaccessip"
#
# finally, if you are using multiple synaccess devices on different power 
circuits plugged
# into redundant power ports, you can specify multiple IPs for the synaccessip 
variable.
# Outlets with the same name on diffrent synaccess devices will be turned 
on/off/reset in parallel.


# in order to use this script you must have installed the MIB that came with 
the synaccess device
# in /usr/share/snmp/mibs/SYNACCESS-MIB.txt or similar. From then on the 
net-snmp utilities
# are aware of the proper names.
# if you are having problems detecting the proper power status make sure the 
mib power status reads:
#outletStatus OBJECT-TYPE 
#SYNTAX INTEGER { 
#off(0), 
#on(1), 
#off(2),
#on(257),
#off(256)
#} 
# Check the synaccess specific mib with
# snmpwalk -c public -m SYNACCESS-MIB -v 1 x.x.x.x synAcc


# default to 5 seconds of sleep time after all the outlets have been turned off
# before we turn them back on
reset_delay=${reset_delay:-"5"}
# drop "public" in if the community isn't set
community=${community:-"public"}
# rewrite the ip list to accept , or space as a delimiter
synaccessip=`echo $synaccessip | tr ',' ' '`


# commands used to get/set snmp object id (oid) values
SNMP_GETCOMMAND="/usr/bin/snmpget -c $community -m SYNACCESS-MIB -v 1"
SNMP_SETCOMMAND="/usr/bin/snmpset -c $community -m SYNACCESS-MIB -v 1"

# pass the IP and then the name
get_snmp_value()
{
    device_ip=$1
    oid=$2
    echo `$SNMP_GETCOMMAND $device_ip $oid 2>&1|cut -d: -f4`
}

# the port name given in the web interface must match the switched port number
# this discovers all the hostnames set as the outlet name
discover_hostlist()
{
    synaccessdeviceip=$1

    portcount=`get_snmp_value $synaccessdeviceip 
SYNACCESS-MIB::powerOutletNum.0`
    for ((i=1; $i <= ${portcount:-"0"};i++)); do
        portname=`get_snmp_value $synaccessdeviceip 
SYNACCESS-MIB::outletName.$i`
        if [[ "$portname" && "$portname" != "Undefined" ]]; then
            # only save unique host names
            if [[ !("$hostlist" =~ "$portname ") ]]; then
                hostlist="$hostlist$portname "
            fi
        fi
    done
}

# this looks up the port number based on the passed hostname, using the power 
outlet name
get_port_for_host()
{
    synaccessdeviceip=$1
    hostlookup=$2

    portcount=`get_snmp_value $synaccessdeviceip 
SYNACCESS-MIB::powerOutletNum.0`
    if [[ -z "$portcount" ]]; then
        # device isn't responding
        return 0
    else
        ret_code=2 #default to not finding any matching hosts on this device
        for ((i=1; $i <= $portcount ;i++)); do
            portname=`get_snmp_value $synaccessdeviceip 
SYNACCESS-MIB::outletName.$i`
            if [[ "$portname" == "$hostlookup" ]]; then
                echo "$i "
                ret_code=1
            fi
            # the error handling leaves a possible race, if the device dies 
while we are 
            # scanning the ports, we just assume the outlet isn't found, if 
this happens
            # and there is more than one synaccess device its possible we only 
set the state
            # for one power rail.
        done
        # if ret_code=2 everything was responding but we didn't find the 
        # named port assume it doesn't exist. It could be a configuration error,
        # but we can't tell.
        return $ret_code
    fi
}

# this sends a ON/OFF/RESET action to the given hostname
do_port_action()
{
    synaccessdeviceip=$1
    controlledhost=$2
    newportstate=$3

    portnum=`get_port_for_host $synaccessdeviceip $controlledhost`
    portret=$?
    if [[ "$portret" == "1" ]]; then
        for curport in $portnum ; do
            out=`$SNMP_SETCOMMAND $synaccessdeviceip 
"SYNACCESS-MIB::outletAction.$curport" = $newportstate`
            # this sleep is here, because commands fired in rapid succession 
don't always take affect, the 
            # snmp values get updated, but the device fails to internally 
trigger on the change
            sleep 1 
            #TODO check to see if port was successfuly set
        done
    fi
    return $portret
}

# this takes the list of synaccess devices, and calls do_port_action for each 
one
# this makes sure that if there are multiple synaccess devices with a 
particular host plugged
# in all the outlets are set, this allows multiple circuit configurations
set_all_ports()
{
    host_to_update=$1
    new_port_state=$2
    
    failed_to_set_all=0
    set_atleast_one=0

    for deviceip in $synaccessip ; do
        do_port_action $deviceip $host_to_update $new_port_state 
        port_set_ok=$?
        case $port_set_ok in
            0)
                # if any of the syanaccess devices fail, then assume
                # that the whole operation failed, this is because we can never
                # know if that device may still be providing power on a 
redunant circuit to the 
                # machine
                failed_to_set_all=1
            ;;
            1)
                set_atleast_one=1                
            ;;
            2)
               # this device doesn't have a port configured with the given 
hostname, ignore it
            ;;
        esac
    done
    if [[ "$set_atleast_one" == "0" ]]; then
        # none of the synaccess devices had a port with the given name
        # fail the operation
        failed_to_set_all=1
    fi
    return $failed_to_set_all
}

 
# Handle script commands
case $1 in
gethosts)
        for deviceip in $synaccessip ; do
            discover_hostlist $deviceip
        done
        for h in $hostlist ; do
                echo $h
        done
        exit 0
        ;;
on)
        set_all_ports $2 1
        exit $?
        ;;
off)
        set_all_ports $2 2
        exit $?
        ;;
reset)
        # The synaccess devices have a nice "reboot" function which
        # turns the power off and after a configured length turns
        # it back on. The only problem is that its really a power toggle 
function.
        # If the power is off, then it turns it on, and then back off
        # So, before we use that function, we make sure that the power is 
turned on
        # (which in general it should be)
        # BTW: the setting for the port delay is in the telnet menu, and not in 
the
        # web interface. 
        #set_all_ports $2 1
        #set_all_ports $2 3
        #
        # For now the reboot seems to have to many side effects to be truly 
useful
        # instead lets just manually set it off/on
        # 
        set_all_ports $2 2 # turn it off
        # wait a few seconds for the power supplies to drain (some have pretty 
long holdup times)
        sleep $reset_delay
        set_all_ports $2 1 # turn it on
        exit $?
        ;;

status)
        # if any of the given devices fail to responed then assume failure
        for deviceip in $synaccessip ; do
            portcount=`get_snmp_value $deviceip SYNACCESS-MIB::powerOutletNum.0`
            if [[ -z $portcount ]]; then
                exit 1
            fi
        done
        exit 0
        ;;
getconfignames)
        echo "synaccessip community"
        exit 0
        ;;
getinfo-devid)
        echo "synaccess"
        exit 0
        ;;
getinfo-devname)
        for deviceip in $synaccessip ; do
            synModel=`get_snmp_value $deviceip SYNACCESS-MIB::systemModel.0`
            synName=`get_snmp_value $deviceip SYNACCESS-MIB::systemName.0`
            echo "Synaccess netBooter $synModel $synName"
        done
        exit 0
        ;;
getinfo-devdescr)
        echo "synaccess netbooter STONITH device"
        exit 0
        ;;
getinfo-devurl)
        echo "http://www.synaccess-net.com";
        exit 0
        ;;
getinfo-xml)
# Parameters (hostname, synaccess IP, synaccess port)
        cat << SAXML
<parameters>
 <parameter name="synaccessip" unique="1" required="1">
  <content type="string" />
  <shortdesc lang="en">SynaccessIp</shortdesc>
  <longdesc lang="en">The IPs of the synaccess devices controlling the 
hosts</longdesc>
 </parameter>
 <parameter name="community" unique="1" required="0">
  <content type="string" />
  <shortdesc lang="en">Community</shortdesc>
  <longdesc lang="en">The SNMP Community string</longdesc>
 </parameter>
</parameters>
SAXML
        exit 0
        ;;
*)
        exit 1
        ;;
esac
_______________________________________________________
Linux-HA-Dev: [email protected]
http://lists.linux-ha.org/mailman/listinfo/linux-ha-dev
Home Page: http://linux-ha.org/

Reply via email to