summaryrefslogtreecommitdiffstats
path: root/agents/lindy_pdu/fence_lindypdu.py
diff options
context:
space:
mode:
Diffstat (limited to 'agents/lindy_pdu/fence_lindypdu.py')
-rw-r--r--agents/lindy_pdu/fence_lindypdu.py206
1 files changed, 206 insertions, 0 deletions
diff --git a/agents/lindy_pdu/fence_lindypdu.py b/agents/lindy_pdu/fence_lindypdu.py
new file mode 100644
index 0000000..432b741
--- /dev/null
+++ b/agents/lindy_pdu/fence_lindypdu.py
@@ -0,0 +1,206 @@
+#!@PYTHON@ -tt
+
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library. If not, see
+# <http://www.gnu.org/licenses/>.
+
+# The Following agent has been tested on:
+# Lindy PDU model 32657
+# Firmware release s4.82-091012-1cb08s
+# Probably works on different models with same MIB .. but is better test on them
+#
+# (C) 2021 Daimonlab -- Damiano Scaramuzza (cesello) cesello@daimonlab.it
+
+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 Lindy PDU
+device = None
+
+# Port ID
+port_id = None
+# Switch ID
+switch_id = None
+
+# Classes describing Device params
+# Here I follow the MIBS specs that use "switch" and "plug" concepts but
+# the pdu really have one switch only and 8-16 plugs.
+# Probably the "switch" term is used for future uses or more advanced pdus
+class LindyPDU(object):
+ # PDU
+ status_oid = '.1.3.6.1.4.1.17420.1.2.9.%d.13.0'
+ control_oid = '.1.3.6.1.4.1.17420.1.2.9.%d.13.0'
+ outlet_table_oid = '.1.3.6.1.4.1.17420.1.2.9.%d.14'
+ pdu_table_oid = '.1.3.6.1.4.1.17420.1.2.9'
+ attached_pdus = '.1.3.6.1.4.1.17420.1.2.5.0'
+ ident_str = "Lindy 32657 PDU"
+ state_on = 1
+ state_off = 0
+ turn_on = 1
+ turn_off = 0
+ has_switches = True
+
+### FUNCTIONS ###
+def lpdu_set_device(conn, options):
+ global device
+
+ agents_dir = {'.1.3.6.1.4.1.17420':LindyPDU}
+
+ # First resolve type of PDU device
+ pdu_type = conn.walk(OID_SYS_OBJECT_ID)
+
+ if not ((len(pdu_type) == 1) and (pdu_type[0][1] in agents_dir)):
+ pdu_type = [[None, None]]
+
+ device = agents_dir[pdu_type[0][1]]
+
+ logging.debug("Trying %s"%(device.ident_str))
+
+def lpdu_resolv_port_id(conn, options):
+
+ if device == None:
+ lpdu_set_device(conn, options)
+
+ port_id=switch_id=None
+ # 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.pdu_table_oid, 30)
+
+ for x in table:
+ if x[1].strip('"').split(',')[0] == 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"]))
+
+ return (switch_id,port_id)
+
+def get_power_status(conn, options):
+
+ (switch_id,port_id)=lpdu_resolv_port_id(conn, options)
+
+ oid = ((device.has_switches) and device.status_oid%(switch_id) or device.status_oid%(port_id))
+
+
+ try:
+ (oid, status) = conn.get(oid)
+ # status is a comma separated string
+ # one line only as "1,1,1,0,1,1,1,1".
+ state=status.strip('"').split(',')[port_id-1]
+ if state == str(device.state_on):
+ return "on"
+ elif state == str(device.state_off):
+ return "off"
+ else:
+ return None
+ except Exception:
+ return None
+
+def set_power_status(conn, options):
+
+ (switch_id,port_id)=lpdu_resolv_port_id(conn, options)
+
+ oid = ((device.has_switches) and device.control_oid%(switch_id) or device.control_oid%(port_id))
+
+ (oid, status) = conn.get(oid)
+ # status is a comma separated string
+ state=status.strip('"').split(',')
+ state[port_id-1]=str((options["--action"] == "on" and device.turn_on or device.turn_off))
+ conn.set(oid, ",".join(state))
+
+
+def get_outlets_status(conn, options):
+ result = {}
+ pdu_id=[]
+
+ if device == None:
+ lpdu_set_device(conn, options)
+
+ if (device.has_switches and options["--switch"].isdigit()):
+ pdu_id.append(options["--switch"])
+
+ elif (device.has_switches):
+ #search for all pdu
+ pdus=conn.walk(device.attached_pdus, 30)
+ pdus_info=pdus[0][1].strip('"').split(',')
+ pdu_id=pdus_info[1:]
+ else:
+ #I really don't know what to do with this case. I haven't a different lindy pdu to test
+ table_oid=device.pdu_table_oid
+
+
+ for switch in pdu_id:
+ table_oid = device.outlet_table_oid % int(switch)
+ res_ports = conn.walk(table_oid, 30)
+ status_oid=device.status_oid % int(switch)
+ port_status=conn.walk(status_oid, 30)
+ state=port_status[0][1].strip('"').split(',')
+ for x in res_ports:
+ t = x[0].split('.')
+ port_num = ((device.has_switches) and "%s:%s"%(t[len(t)-4], t[len(t)-2]) or "%s"%(t[len(t)-2]))
+ port_name = x[1].strip('"').split(',')[0]
+ result[port_num] = (port_name, "on" if state[int(t[len(t)-2])-1]=='1' else "off")
+
+ return result
+
+# Main agent method
+def main():
+ global device
+
+ device_opt = ["ipaddr", "login", "passwd", "no_login", "no_password", \
+ "port", "snmp_version", "snmp","switch"]
+
+ atexit.register(atexit_handler)
+
+ all_opt["snmp_version"]["default"] = "1"
+ all_opt["community"]["default"] = "public"
+ all_opt["switch"]["default"] = "1"
+ device = LindyPDU
+
+ options = check_input(device_opt, process_input(device_opt))
+
+ docs = {}
+ docs["shortdesc"] = "Fence agent for Lindy over SNMP"
+ docs["longdesc"] = "fence_lindypdu is an I/O Fencing agent \
+which can be used with the Lindy PDU network power switch. It logs \
+into a device via SNMP and reboots a specified outlet. It supports \
+SNMP v1 with all combinations of authenticity/privacy settings."
+ docs["vendorurl"] = "http://www.lindy.co.uk"
+ 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()