summaryrefslogtreecommitdiffstats
path: root/agents/apc_snmp/fence_apc_snmp.py
diff options
context:
space:
mode:
Diffstat (limited to 'agents/apc_snmp/fence_apc_snmp.py')
-rw-r--r--agents/apc_snmp/fence_apc_snmp.py232
1 files changed, 232 insertions, 0 deletions
diff --git a/agents/apc_snmp/fence_apc_snmp.py b/agents/apc_snmp/fence_apc_snmp.py
new file mode 100644
index 0000000..cd60166
--- /dev/null
+++ b/agents/apc_snmp/fence_apc_snmp.py
@@ -0,0 +1,232 @@
+#!@PYTHON@ -tt
+
+# The Following agent has been tested on:
+# - APC Switched Rack PDU - SNMP v1
+# (MB:v3.7.0 PF:v2.7.0 PN:apc_hw02_aos_270.bin AF1:v2.7.3
+# AN1:apc_hw02_aos_270.bin AF1:v2.7.3 AN1:apc_hw02_rpdu_273.bin MN:AP7930 HR:B2)
+# - APC Web/SNMP Management Card - SNMP v1 and v3 (noAuthNoPrivacy,authNoPrivacy, authPrivacy)
+# (MB:v3.8.6 PF:v3.5.8 PN:apc_hw02_aos_358.bin AF1:v3.5.7
+# AN1:apc_hw02_aos_358.bin AF1:v3.5.7 AN1:apc_hw02_rpdu_357.bin MN:AP7900 HR:B2)
+# - APC Switched Rack PDU - SNMP v1
+# (MB:v3.7.0 PF:v2.7.0 PN:apc_hw02_aos_270.bin AF1:v2.7.3
+# AN1:apc_hw02_rpdu_273.bin MN:AP7951 HR:B2)
+# - Tripplite PDUMH20HVNET 12.04.0055 - SNMP v1, v2c, v3
+# - Tripplite PDU15NETLX 15.5.4 - SNMP v1, v2c, v3
+
+import sys
+import atexit
+import logging
+sys.path.append("@FENCEAGENTSLIBDIR@")
+from fencing import *
+from fencing import fail_usage
+from fencing_snmp import FencingSnmp
+
+### CONSTANTS ###
+# oid defining fence device
+OID_SYS_OBJECT_ID = '.1.3.6.1.2.1.1.2.0'
+
+### GLOBAL VARIABLES ###
+# Device - see ApcRPDU, ApcMSP, ApcMS, TripplitePDU, TrippliteLXPDU
+device = None
+
+# Port ID
+port_id = None
+# Switch ID
+switch_id = None
+
+# Classes describing Device params
+class TripplitePDU(object):
+ # Rack PDU
+ status_oid = '.1.3.6.1.4.1.850.10.2.3.5.1.2.1.%d'
+ control_oid = '.1.3.6.1.4.1.850.10.2.3.5.1.4.1.%d'
+ outlet_table_oid = '.1.3.6.1.4.1.850.10.2.3.5.1.5'
+ ident_str = "Tripplite"
+ state_on = 2
+ state_off = 1
+ turn_on = 2
+ turn_off = 1
+ has_switches = False
+
+class TrippliteLXPDU(object):
+ # WEBCARDLX-based PDU
+ status_oid = '.1.3.6.1.4.1.850.1.1.3.2.3.3.1.1.4.1.%d'
+ control_oid = '.1.3.6.1.4.1.850.1.1.3.2.3.3.1.1.6.1.%d'
+ outlet_table_oid = '.1.3.6.1.4.1.850.1.1.3.2.3.3.1.1.2.1'
+ ident_str = "Tripplite LX"
+ state_on = 2
+ state_off = 1
+ turn_on = 2
+ turn_off = 1
+ has_switches = False
+
+class ApcRPDU(object):
+ # Rack PDU
+ status_oid = '.1.3.6.1.4.1.318.1.1.12.3.5.1.1.4.%d'
+ control_oid = '.1.3.6.1.4.1.318.1.1.12.3.3.1.1.4.%d'
+ outlet_table_oid = '.1.3.6.1.4.1.318.1.1.12.3.5.1.1.2'
+ ident_str = "APC rPDU"
+ state_on = 1
+ state_off = 2
+ turn_on = 1
+ turn_off = 2
+ has_switches = False
+
+class ApcMSP(object):
+ # Master Switch+
+ status_oid = '.1.3.6.1.4.1.318.1.1.6.7.1.1.5.%d.1.%d'
+ control_oid = '.1.3.6.1.4.1.318.1.1.6.5.1.1.5.%d.1.%d'
+ outlet_table_oid = '.1.3.6.1.4.1.318.1.1.6.7.1.1.4'
+ ident_str = "APC Master Switch+"
+ state_on = 1
+ state_off = 2
+ turn_on = 1
+ turn_off = 3
+ has_switches = True
+
+class ApcMS(object):
+ # Master Switch - seems oldest, but supported on every APC PDU
+ status_oid = '.1.3.6.1.4.1.318.1.1.4.4.2.1.3.%d'
+ control_oid = '.1.3.6.1.4.1.318.1.1.4.4.2.1.3.%d'
+ outlet_table_oid = '.1.3.6.1.4.1.318.1.1.4.4.2.1.4'
+ ident_str = "APC Master Switch (fallback)"
+ state_on = 1
+ state_off = 2
+ turn_on = 1
+ turn_off = 2
+ has_switches = False
+
+class ApcMS6(object):
+ # Master Switch with 6.x firmware
+ status_oid = '.1.3.6.1.4.1.318.1.1.4.4.2.1.3.%d'
+ control_oid = '.1.3.6.1.4.1.318.1.1.12.3.3.1.1.4.%d'
+ outlet_table_oid = '1.3.6.1.4.1.318.1.1.4.4.2.1.4'
+ ident_str = "APC Master Switch with firmware v6.x"
+ state_on = 1
+ state_off = 2
+ turn_on = 1
+ turn_off = 2
+ has_switches = False
+
+### FUNCTIONS ###
+def apc_set_device(conn):
+ global device
+
+ agents_dir = {'.1.3.6.1.4.1.318.1.3.4.5':ApcRPDU,
+ '.1.3.6.1.4.1.318.1.3.4.4':ApcMSP,
+ '.1.3.6.1.4.1.850.1':TripplitePDU,
+ '.1.3.6.1.4.1.850.1.1.1':TrippliteLXPDU,
+ '.1.3.6.1.4.1.318.1.3.4.6':ApcMS6,
+ None:ApcMS}
+
+ # First resolve type of APC
+ apc_type = conn.walk(OID_SYS_OBJECT_ID)
+
+ if not ((len(apc_type) == 1) and (apc_type[0][1] in agents_dir)):
+ apc_type = [[None, None]]
+
+ device = agents_dir[apc_type[0][1]]
+
+ logging.debug("Trying %s"%(device.ident_str))
+
+def apc_resolv_port_id(conn, options):
+ global port_id, switch_id
+
+ if device == None:
+ apc_set_device(conn)
+
+ # Now we resolv port_id/switch_id
+ if (options["--plug"].isdigit()) and ((not device.has_switches) or (options["--switch"].isdigit())):
+ port_id = int(options["--plug"])
+
+ if device.has_switches:
+ switch_id = int(options["--switch"])
+ else:
+ table = conn.walk(device.outlet_table_oid, 30)
+
+ for x in table:
+ if x[1].strip('"') == options["--plug"]:
+ t = x[0].split('.')
+ if device.has_switches:
+ port_id = int(t[len(t)-1])
+ switch_id = int(t[len(t)-3])
+ else:
+ port_id = int(t[len(t)-1])
+
+ if port_id == None:
+ fail_usage("Can't find port with name %s!"%(options["--plug"]))
+
+def get_power_status(conn, options):
+ if port_id == None:
+ apc_resolv_port_id(conn, options)
+
+ oid = ((device.has_switches) and device.status_oid%(switch_id, port_id) or device.status_oid%(port_id))
+
+ (oid, status) = conn.get(oid)
+ return status == str(device.state_on) and "on" or "off"
+
+def set_power_status(conn, options):
+ if port_id == None:
+ apc_resolv_port_id(conn, options)
+
+ oid = ((device.has_switches) and device.control_oid%(switch_id, port_id) or device.control_oid%(port_id))
+
+ conn.set(oid, (options["--action"] == "on" and device.turn_on or device.turn_off))
+
+
+def get_outlets_status(conn, options):
+ result = {}
+
+ if device == None:
+ apc_set_device(conn)
+
+ res_ports = conn.walk(device.outlet_table_oid, 30)
+
+ for x in res_ports:
+ t = x[0].split('.')
+
+ port_num = ((device.has_switches) and "%s:%s"%(t[len(t)-3], t[len(t)-1]) or "%s"%(t[len(t)-1]))
+
+ port_name = x[1].strip('"')
+ port_status = ""
+ result[port_num] = (port_name, port_status)
+
+ return result
+
+# Main agent method
+def main():
+ device_opt = ["ipaddr", "login", "passwd", "no_login", "no_password", \
+ "port", "snmp_version", "snmp"]
+
+ atexit.register(atexit_handler)
+
+ all_opt["snmp_version"]["default"] = "1"
+ all_opt["community"]["default"] = "private"
+
+ options = check_input(device_opt, process_input(device_opt))
+
+ ## Support for -n [switch]:[plug] notation that was used before
+ if ("--plug" in options) and (-1 != options["--plug"].find(":")):
+ (switch, plug) = options["--plug"].split(":", 1)
+ if switch.isdigit() and plug.isdigit():
+ options["--switch"] = switch
+ options["--plug"] = plug
+
+ if "--switch" not in options:
+ options["--switch"] = "1"
+
+ docs = {}
+ docs["shortdesc"] = "Fence agent for APC, Tripplite PDU over SNMP"
+ docs["longdesc"] = "fence_apc_snmp is an I/O Fencing agent \
+which can be used with the APC network power switch or Tripplite PDU devices.\
+It logs into a device via SNMP and reboots a specified outlet. It supports \
+SNMP v1, v2c, v3 with all combinations of authenticity/privacy settings."
+ docs["vendorurl"] = "http://www.apc.com"
+ docs["symlink"] = [("fence_tripplite_snmp", "Fence agent for Tripplife over SNMP")]
+ 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()