diff --git a/agents/raritan_px3/fence_raritan_px3.py b/agents/raritan_px3/fence_raritan_px3.py new file mode 100644 index 00000000..137f1609 --- /dev/null +++ b/agents/raritan_px3/fence_raritan_px3.py @@ -0,0 +1,195 @@ +#!@PYTHON@ -tt + +import logging +import sys +import atexit +sys.path.append("@FENCEAGENTSLIBDIR@") +from fencing import * +from fencing import EC_STATUS + +""" +Raritan PX3 family is totaly different the PX family (PX2 seem to be +compatible with PX3 and seem to share the same BIOS, so this fence should +work with PX2 as well). +It has another command line prompt and totally other commands +and output. + +It follows the concept of separating outlets and outletgroups (if created). +You can reach outlets via a fixed, not changeble "plug" number +(from 1-20 on my device). +Additionally one can, but does not need to assign names to each plug. + +Plugs/outlets can be combined to outletgroups. +There can be zero to N (N = No. outlets) outletgroups. + +While it's possible to create outletgroups with one plug, this does not +make sense and might slow things down. + +--plug=X paramter can be: +1. X == outlet No +2. X == outlet Name (if one got assigned) +3. X == outlet group Name + +-> One cannot reach a group by number +-> Groups need an extra call (first single outlet devices are + searched for given No/Name, then OutletGroups +""" + + +class FenceRaritanPX3: + outlets={} + # Plug id of outlet + plug=None + outletgroups={} + # Group name if outlet plug id/name have not been found + group_name=None + +def px3_get_outlet_group(conn, options): + + conn.send_eol("show outletgroups") + conn.expect(options["--command-prompt"], int(options["--shell-timeout"])) + for line in conn.after.splitlines(): + split_line = line.split(" ") + """ + Groups always have a name assigned: + ``` + Outlet Group 1 - test: + Member outlets: 10-11 + State: 2 on + ``` + """ + if len(split_line) == 5 and split_line[0] == "Outlet" and split_line[1] == "Group": + group_no = split_line[2] + group_name = split_line[4][:-1] + + if len(split_line) > 0 and split_line[0] == "State:": + group_state = split_line[-1] + FenceRaritanPX3.outletgroups[group_no] = [ group_name, group_state ] + logging.debug("Outletgroups found:\n%s", FenceRaritanPX3.outletgroups) + return FenceRaritanPX3.outletgroups + +def px3_get_outlet_list(conn, options): + + conn.send_eol("show outlets") + conn.expect(options["--command-prompt"], int(options["--shell-timeout"])) + for line in conn.after.splitlines(): + split_line = line.split(" ") + """ + Plug with no name assigned: + ``` + Outlet 1: + Power state: On + ``` + """ + if len(split_line) == 2 and split_line[0] == "Outlet": + outlet_no = split_line[1][:-1] + outlet_name = "" + """ + Plug with name assigned: + ``` + Outlet 8 - Test: + Power state: On + ``` + """ + if len(split_line) == 4 and split_line[0] == "Outlet": + outlet_no = split_line[1] + outlet_name = split_line[3][:-1] + + # fetch state of previously parsed outlet from next line/iter + if len(split_line) == 3 and split_line[0] == "Power" and split_line[1] == "state:": + outlet_state = split_line[2] + FenceRaritanPX3.outlets[outlet_no] = [outlet_name, outlet_state] + logging.debug("Outlets found:\n%s", FenceRaritanPX3.outlets) + return FenceRaritanPX3.outlets + +def get_power_status(conn, options): + + if FenceRaritanPX3.plug: + return FenceRaritanPX3.outlets[str(FenceRaritanPX3.plug)][1].lower() + elif FenceRaritanPX3.group_name: + return FenceRaritanPX3.outletgroups[FenceRaritanPX3.group_name][1].lower() + sys.exit(EC_STATUS) + +def set_power_status(conn, options): + action = { + "on" : "on", + "off" : "off", + "reboot" : "cycle", + }[options["--action"]] + + if FenceRaritanPX3.plug: + conn.send_eol("power outlets %s %s" % (FenceRaritanPX3.plug, action)) + # Do you wish to turn outlet 5 off? [y/n] + elif FenceRaritanPX3.group_name: + conn.send_eol("power outletgroup %s %s" % (FenceRaritanPX3.group_name, action)) + # Do you wish to turn on all 2 outlets in group 1? [y/n] + conn.log_expect("Do you wish to turn.*", int(options["--shell-timeout"])) + conn.send_eol("y") + print("YYYYY") + conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) + print("XXXXXXXX") + +def disconnect(conn): + conn.sendline("EXIT") + conn.close() + +def main(): + device_opt = ["ipaddr", "login", "passwd", "port", "telnet", "cmd_prompt", "secure"] + + atexit.register(atexit_handler) + + opt = process_input(device_opt) + all_opt["cmd_prompt"]["default"] = ".*\[My PDU\] #" + all_opt["ipport"]["default"] = "23" + all_opt["shell_timeout"]["default"] = "8" + + opt["eol"] = "\r\n" + options = check_input(device_opt, opt) + + docs = {} + docs["shortdesc"] = "I/O Fencing agent for Raritan Dominion PX2 and PX3" + docs["longdesc"] = "fence_raritan is an I/O Fencing agent which can be \ +used with the Raritan PX2 and PX3 Power Distribution Unit series. It logs into \ +device via telnet or ssh and reboots a specified outlet. Single outlets and \ +grouped outlets are supported. The fence is tested on this model: PX3-5466V. \ +There have been issues seen with the telnet prompt on 3.4.x and 3.5.x Raritan \ +firmware versions. It's recommended to update to at least version 3.6.x" + docs["vendorurl"] = "http://www.raritan.com/" + show_docs(options, docs) + + conn = fence_login(options, re_login_string="Username.*") + + px3_get_outlet_list(conn, options) + try: + FenceRaritanPX3.plug = int(options["--plug"]) + if FenceRaritanPX3.plug > len(FenceRaritanPX3.outlets): + logging.error("Plug no exceeds no of outlets") + sys.exit(EC_STATUS) + except ValueError: + for no, values in FenceRaritanPX3.outlets.items(): + if values[0] == options["--plug"]: + FenceRaritanPX3.plug = no + break + if not FenceRaritanPX3.plug: + px3_get_outlet_group(conn, options) + for no, values in FenceRaritanPX3.outletgroups.items(): + if values[0] == options["--plug"]: + FenceRaritanPX3.group_name = no + break + if not FenceRaritanPX3.group_name: + logging.error("Plug %s not found", options["--plug"]) + sys.exit(EC_STATUS) + + logging.debug("\nSingle outlet: %s\nGroup outlet: %s" % (FenceRaritanPX3.plug, FenceRaritanPX3.group_name)) + + result = 0 + if options["--action"] != "monitor": + result = fence_action(conn, options, set_power_status, get_power_status, + get_outlet_list=px3_get_outlet_list, reboot_cycle_fn=set_power_status) + + atexit.register(disconnect, conn) + + sys.exit(result) + +if __name__ == "__main__": + main() diff --git a/doc/COPYRIGHT b/doc/COPYRIGHT index cad95eac..7aac93c4 100644 --- a/doc/COPYRIGHT +++ b/doc/COPYRIGHT @@ -1,78 +1,82 @@ Unless specified otherwise in the "exceptions section" below: Copyright (C) 1997-2003 Sistina Software, Inc. All rights reserved. Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved. Exceptions: +agents/raritan_px3/*: + Copyright (c) 2021 SUSE LLC + Contributed by Thomas Renninger + agents/ibmz/*: Copyright (c) 2020 IBM Corp. Contributed by Paulo de Rezende Pinatti agents/hds_cb/*: Copyright (C) 2012 Matthew Clark. Author: Matthew Clark agents/xenapi/*: Copyright (C) 2011 Matthew Clark. Author: Matthew Clark agents/apc_snmp/powernet369.mib: Copyright (c) 2005 American Power Conversion, Inc. PowerNet is a Trademark of American Power Conversion Corp. agents/eaton_snmp/fence_eaton_snmp.py: Copyright (c) 2011 eaton.com Author: Arnaud Quette agents/ifmib/fence_ifmib.py: Copyright (C) 2008-2011 Ross Vandegrift. Written by Ross Vandegrift agents/intelmodular/fence_intelmodular.pl: Contributed by Matthew Kent agents/ipmilan/expect.{c,h}: Copyright (C) 2000 Alan Robertson agents/node_assassin/* Copyright (C) 2009-2011 Madison Kelly/Alteeve's Niche! Author: Digimer man/fence_ifmib.8: Copyright (C) 2008-2011 Ross Vandegrift. Written by Ross Vandegrift Authors as known by current RCS as of the time of writing: Abhijith Das Adam Manthei A. J. Lewis Alasdair G. Kergon Andrew Price Benjamin Marzinski Bob Peterson Chris Feist Christine Caulfield Daniel Phillips David Teigland Fabio M. Di Nitto James Parsons Joel Becker Jonathan Brassow jparsons Ken Preslan Klaus Wenninger Lon Hohberger Marc - A. Dahlhaus Marek 'marx' Grac Mark Hlawatschek Michael Conrad Tadpol Tilstra Patrick Caulfield Robert Peterson Ross Vandegrift Ryan McCabe Ryan O'Hara Stanko Kupcevic Steven Whitehouse Wendy Cheng diff --git a/tests/data/metadata/fence_raritan_px3.xml b/tests/data/metadata/fence_raritan_px3.xml new file mode 100644 index 00000000..56ea554a --- /dev/null +++ b/tests/data/metadata/fence_raritan_px3.xml @@ -0,0 +1,207 @@ + + +fence_raritan is an I/O Fencing agent which can be used with the Raritan PX2 and PX3 Power Distribution Unit series. It logs into device via telnet or ssh and reboots a specified outlet. Single outlets and grouped outlets are supported. The fence is tested on this model: PX3-5466V. There have been issues seen with the telnet prompt on 3.4.x and 3.5.x Raritan firmware versions. It's recommended to update to at least version 3.6.x +http://www.raritan.com/ + + + + + Fencing action + + + + + Force Python regex for command prompt + + + + + Force Python regex for command prompt + + + + + Identity file (private key) for SSH + + + + + Forces agent to use IPv4 addresses only + + + + + Forces agent to use IPv6 addresses only + + + + + IP address or hostname of fencing device + + + + + IP address or hostname of fencing device + + + + + TCP/UDP port to use for connection with device + + + + + Login name + + + + + Login password or passphrase + + + + + Script to run to retrieve password + + + + + Login password or passphrase + + + + + Script to run to retrieve password + + + + + Physical plug number on device, UUID or identification of machine + + + + + Physical plug number on device, UUID or identification of machine + + + + + Use SSH connection + + + + + Use SSH connection + + + + + SSH options to use + + + + + Login name + + + + + Disable logging to stderr. Does not affect --verbose or --debug-file or logging to syslog. + + + + + Verbose mode. Multiple -v flags can be stacked on the command line (e.g., -vvv) to increase verbosity. + + + + + Level of debugging detail in output. Defaults to the number of --verbose flags specified on the command line, or to 1 if verbose=1 in a stonith device configuration (i.e., on stdin). + + + + + Write debug information to given file + + + + + Write debug information to given file + + + + + Display version information and exit + + + + + Display help and exit + + + + + Separator for CSV created by 'list' operation + + + + + Wait X seconds before fencing is started + + + + + Disable timeout (true/false) (default: true when run from Pacemaker 2.0+) + + + + + Wait X seconds for cmd prompt after login + + + + + Test X seconds for status change after ON/OFF + + + + + Wait X seconds after issuing ON/OFF + + + + + Wait X seconds for cmd prompt after issuing command + + + + + Sleep X seconds between status calls during a STONITH action + + + + + Count of attempts to retry power on + + + + Path to ssh binary + + + + Path to telnet binary + + + + + + + + + + + + + + +