#!/usr/bin/python
# The Following agent has been tested on:
# - Eaton eMAA12 ePDU - SNMP v1
# - Modified by Hotwired007
import sys, re, pexpect
sys.path.append("/usr/share/fence")
from fencing import *
from fencing_snmp import *
#BEGIN_VERSION_GENERATION
RELEASE_VERSION="3.1.8.6-723b"
BUILD_DATE="(built Mon Jul 9 07:55:22 CEST 2012)"
REDHAT_COPYRIGHT="Copyright (C) Red Hat, Inc. 2004-2010 All rights reserved."
#END_VERSION_GENERATION
### CONSTANTS ###
# oid defining fence device
OID_SYS_OBJECT_ID='.1.3.6.1.2.1.1.2.0'
### GLOBAL VARIABLES ###
# Device - see EatonManagedePDU, EatonSwitchedePDU
device=None
# Port ID
port_id=None
# Switch ID
switch_id=None
# Did we issue a set before get (to adjust OID with Switched ePDU)
after_set=False
# Classes describing Device params
# eMAA12 ePDU
class EatoneMAA12ePDU:
status_oid= '.1.3.6.1.4.1.534.6.6.7.6.6.1.2.0.%d'
control_oid=None
control_oid_on='.1.3.6.1.4.1.534.6.6.7.6.6.1.3.0.%d'
control_oid_off='.1.3.6.1.4.1.534.6.6.7.6.6.1.4.0.%d'
outlet_table_oid='.1.3.6.1.4.1.534.6.6.7.6.6'
ident_str="Eaton eMAA12 ePDU"
state_off=0
state_on=1
state_cycling=2 # FIXME: not usable with fence-agents
turn_off=1
turn_on=1
turn_cycle=2 # FIXME: not usable with fence-agents
has_switches=False
### FUNCTIONS ###
def eaton_set_device(conn,options):
global device
agents_dir={'.1.3.6.1.4.1.534.6.6.7':EatoneMAA12ePDU,}
# First resolve type of Eaton
eaton_type=conn.walk(OID_SYS_OBJECT_ID)
if (not ((len(eaton_type)==1) and (agents_dir.has_key(eaton_type[0][1])))):
eaton_type=[[None,None]]
device=agents_dir[eaton_type[0][1]]
conn.log_command("Trying %s"%(device.ident_str))
def eaton_resolv_port_id(conn,options):
global port_id,switch_id,device
if (device==None):
eaton_set_device(conn,options)
# Restore the increment, that was removed in main for ePDU Managed
if (device.ident_str != "Eaton Managed ePDU"):
options["-n"] = str(int(options["-n"]) + 1)
# Now we resolv port_id/switch_id
if ((options["-n"].isdigit()) and ((not device.has_switches) or (options["-s"].isdigit()))):
port_id=int(options["-n"])
if (device.has_switches):
switch_id=int(options["-s"])
else:
table=conn.walk(device.outlet_table_oid,30)
for x in table:
if (x[1].strip('"')==options["-n"]):
t=x[0].split('.')
if (device.has_switches):
port_id=int(t[len(t)-1])
switch_id=int(t[len(t)-3])
else:
if (device.ident_str == "Eaton Switched ePDU"):
port_id=int(t[len(t)-3])
else:
port_id=int(t[len(t)-1])
if (port_id==None):
# Restore index offset, to provide a valid error output on Managed ePDU
if (device.ident_str != "Eaton Switched ePDU"):
options["-n"] = str(int(options["-n"]) + 1)
fail_usage("Can't find port with name %s!"%(options["-n"]))
def get_power_status(conn,options):
global port_id,switch_id,device,after_set
if (port_id==None):
eaton_resolv_port_id(conn,options)
# Ajust OID for Switched ePDU when the get is after a set
if ((after_set == True) and (device.ident_str == "Eaton Switched ePDU")):
port_id-=1
after_set=False
oid=((device.has_switches) and device.status_oid%(switch_id,port_id) or device.status_oid%(port_id))
try:
(oid,status)=conn.get(oid)
if (status==str(device.state_on)):
return "on"
elif (status==str(device.state_off)):
return "off"
else:
return None
except:
return None
def set_power_status(conn, options):
global port_id,switch_id,device,after_set
after_set = True
if (port_id==None):
eaton_resolv_port_id(conn,options)
#eMAA12 has seperarte off and on oid, so we have to define the control_oid using an if statement
if (options["-o"]=="on"):
device.control_oid = '.1.3.6.1.4.1.534.6.6.7.6.6.1.4.0.%d'
else:
device.control_oid = '.1.3.6.1.4.1.534.6.6.7.6.6.1.3.0.%d'
oid=((device.has_switches) and device.control_oid%(switch_id,port_id) or device.control_oid%(port_id))
conn.set(oid,(options["-o"]=="on" and device.turn_on or device.turn_off))
def get_outlets_status(conn, options):
global device
outletCount = 0
result={}
if (device==None):
eaton_set_device(conn,options)
res_ports=conn.walk(device.outlet_table_oid,30)
for x in res_ports:
outletCount+=1
status=x[1]
t=x[0].split('.')
# Plug indexing start from zero, so we substract '1' from the
# user's given plug number
if (device.ident_str == "Eaton Managed ePDU"):
port_num=str(int(((device.has_switches) and "%s:%s"%(t[len(t)-3],t[len(t)-1]) or "%s"%(t[len(t)-1]))) + 1)
# Plug indexing start from zero, so we add '1'
# for the user's exposed plug number
port_name=str(int(x[1].strip('"')) + 1)
port_status=""
result[port_num]=(port_name,port_status)
else:
# Switched ePDU do not propose an outletCount OID!
# Invalid status (ie value == '0'), retrieved via the walk,
# means the outlet is absent
port_num=str(outletCount)
port_name=str(outletCount)
port_status=""
if (status != '0'):
result[port_num]=(port_name,port_status)
return result
# Define new options
def eaton_snmp_define_defaults():
all_opt["snmp_version"]["default"]="1"
all_opt["community"]["default"]="private"
# Main agent method
def main():
device_opt = [ "help", "version", "agent", "quiet", "verbose", "debug",
"action", "ipaddr", "login", "passwd", "passwd_script",
"test", "port", "separator", "no_login", "no_password",
"snmp_version", "community", "snmp_auth_prot", "snmp_sec_level",
"snmp_priv_prot", "snmp_priv_passwd", "snmp_priv_passwd_script",
"udpport","inet4_only","inet6_only",
"power_timeout", "shell_timeout", "login_timeout", "power_wait" ]
atexit.register(atexit_handler)
snmp_define_defaults ()
eaton_snmp_define_defaults()
options=check_input(device_opt,process_input(device_opt))
## Support for -n [switch]:[plug] notation that was used before
if ((options.has_key("-n")) and (-1 != options["-n"].find(":"))):
(switch, plug) = options["-n"].split(":", 1)
if ((switch.isdigit()) and (plug.isdigit())):
options["-s"] = switch
options["-n"] = plug
if (not (options.has_key("-s"))):
options["-s"]="1"
# Plug indexing start from zero on ePDU Managed, so we substract '1' from
# the user's given plug number.
# For Switched ePDU, we will add this back again later.
if ((options.has_key("-n")) and (options["-n"].isdigit())):
options["-n"] = str(int(options["-n"]) - 1)
docs = { }
docs["shortdesc"] = "Fence agent for Eaton over SNMP"
docs["longdesc"] = "fence_eaton_snmp is an I/O Fencing agent \
which can be used with the Eaton network power switch. It logs \
into a device via SNMP and reboots a specified outlet. It supports \
SNMP v1 and v3 with all combinations of authenticity/privacy settings."
docs["vendorurl"] = "http://powerquality.eaton.com"
show_docs(options, docs)
# Operate the fencing device
result = fence_action(FencingSnmp(options), options, set_power_status, get_power_status, get_outlets_status)
sys.exit(result)
if __name__ == "__main__":
main()