summaryrefslogtreecommitdiffstats
path: root/agents/apc
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 06:50:17 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 06:50:17 +0000
commit86ed03f8adee56c050c73018537371c230a664a6 (patch)
treeeae3d04cdf1c49848e5a671327ab38297f4acb0d /agents/apc
parentInitial commit. (diff)
downloadfence-agents-86ed03f8adee56c050c73018537371c230a664a6.tar.xz
fence-agents-86ed03f8adee56c050c73018537371c230a664a6.zip
Adding upstream version 4.12.1.upstream/4.12.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'agents/apc')
-rw-r--r--agents/apc/fence_apc.py263
1 files changed, 263 insertions, 0 deletions
diff --git a/agents/apc/fence_apc.py b/agents/apc/fence_apc.py
new file mode 100644
index 0000000..3ea0f37
--- /dev/null
+++ b/agents/apc/fence_apc.py
@@ -0,0 +1,263 @@
+#!@PYTHON@ -tt
+
+#####
+##
+## The Following Agent Has Been Tested On:
+##
+## Model Firmware
+## +---------------------------------------------+
+## AP7951 AOS v2.7.0, PDU APP v2.7.3
+## AP7941 AOS v3.5.7, PDU APP v3.5.6
+## AP9606 AOS v2.5.4, PDU APP v2.7.3
+##
+## @note: ssh is very slow on AP79XX devices protocol (1) and
+## cipher (des/blowfish) have to be defined
+#####
+
+import sys, re, time
+import logging
+import atexit
+sys.path.append("@FENCEAGENTSLIBDIR@")
+from fencing import *
+from fencing import fail, fail_usage, EC_STATUS
+
+# Fix for connection timed out issue in:
+# https://bugzilla.redhat.com/show_bug.cgi?id=1342584
+TIMEDOUT_DELAY = 0.5
+
+def get_power_status(conn, options):
+ exp_result = 0
+ outlets = {}
+
+ conn.send_eol("1")
+ conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"]))
+
+ version = 0
+ admin = 0
+ switch = 0
+
+ if None != re.compile('.* MasterSwitch plus.*', re.IGNORECASE | re.S).match(conn.before):
+ switch = 1
+ if None != re.compile('.* MasterSwitch plus 2', re.IGNORECASE | re.S).match(conn.before):
+ if "--switch" not in options:
+ fail_usage("Failed: You have to enter physical switch number")
+ else:
+ if "--switch" not in options:
+ options["--switch"] = "1"
+
+ if None == re.compile('.*Outlet Management.*', re.IGNORECASE | re.S).match(conn.before):
+ version = 2
+ else:
+ version = 3
+
+ if None == re.compile('.*Outlet Control/Configuration.*', re.IGNORECASE | re.S).match(conn.before):
+ admin = 0
+ else:
+ admin = 1
+
+ if switch == 0:
+ if version == 2:
+ if admin == 0:
+ conn.send_eol("2")
+ else:
+ conn.send_eol("3")
+ else:
+ conn.send_eol("2")
+ conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"]))
+ conn.send_eol("1")
+ else:
+ conn.send_eol(options["--switch"])
+
+ while True:
+ exp_result = conn.log_expect(
+ ["Press <ENTER>"] + options["--command-prompt"], int(options["--shell-timeout"]))
+ lines = conn.before.split("\n")
+ show_re = re.compile(r'(^|\x0D)\s*(\d+)- (.*?)\s+(ON|OFF)\s*')
+ for line in lines:
+ res = show_re.search(line)
+ if res != None:
+ outlets[res.group(2)] = (res.group(3), res.group(4))
+ time.sleep(TIMEDOUT_DELAY)
+ conn.send_eol("")
+ if exp_result != 0:
+ break
+ conn.send(chr(0o3))
+ conn.log_expect("- Logout", int(options["--shell-timeout"]))
+ conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"]))
+
+ if ["list", "monitor"].count(options["--action"]) == 1:
+ return outlets
+ else:
+ try:
+ (_, status) = outlets[options["--plug"]]
+ return status.lower().strip()
+ except KeyError as e:
+ logging.error("Failed: {}".format(str(e)))
+ fail(EC_STATUS)
+
+def set_power_status(conn, options):
+ action = {
+ 'on' : "1",
+ 'off': "2"
+ }[options["--action"]]
+
+ conn.send_eol("1")
+ conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"]))
+
+ version = 0
+ admin2 = 0
+ admin3 = 0
+ switch = 0
+
+ if None != re.compile('.* MasterSwitch plus.*', re.IGNORECASE | re.S).match(conn.before):
+ switch = 1
+ ## MasterSwitch has different schema for on/off actions
+ action = {
+ 'on' : "1",
+ 'off': "3"
+ }[options["--action"]]
+ if None != re.compile('.* MasterSwitch plus 2', re.IGNORECASE | re.S).match(conn.before):
+ if "--switch" not in options:
+ fail_usage("Failed: You have to enter physical switch number")
+ else:
+ if "--switch" not in options:
+ options["--switch"] = 1
+
+ if None == re.compile('.*Outlet Management.*', re.IGNORECASE | re.S).match(conn.before):
+ version = 2
+ else:
+ version = 3
+
+ if None == re.compile('.*Outlet Control/Configuration.*', re.IGNORECASE | re.S).match(conn.before):
+ admin2 = 0
+ else:
+ admin2 = 1
+
+ if switch == 0:
+ if version == 2:
+ if admin2 == 0:
+ conn.send_eol("2")
+ else:
+ conn.send_eol("3")
+ else:
+ conn.send_eol("2")
+ conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"]))
+ if None == re.compile('.*2- Outlet Restriction.*', re.IGNORECASE | re.S).match(conn.before):
+ admin3 = 0
+ else:
+ admin3 = 1
+ conn.send_eol("1")
+ else:
+ conn.send_eol(options["--switch"])
+
+ while 0 == conn.log_expect(
+ ["Press <ENTER>"] + options["--command-prompt"], int(options["--shell-timeout"])):
+ time.sleep(TIMEDOUT_DELAY)
+ conn.send_eol("")
+
+ conn.send_eol(options["--plug"]+"")
+ conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"]))
+
+ if switch == 0:
+ if admin2 == 1:
+ conn.send_eol("1")
+ conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"]))
+ if admin3 == 1:
+ conn.send_eol("1")
+ conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"]))
+ else:
+ conn.send_eol("1")
+ conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"]))
+
+ conn.send_eol(action)
+ conn.log_expect("Enter 'YES' to continue or <ENTER> to cancel :", int(options["--shell-timeout"]))
+ conn.send_eol("YES")
+ conn.log_expect("Press <ENTER> to continue...", int(options["--power-timeout"]))
+ time.sleep(TIMEDOUT_DELAY)
+ conn.send_eol("")
+ conn.log_expect(options["--command-prompt"], int(options["--power-timeout"]))
+ conn.send(chr(0o3))
+ conn.log_expect("- Logout", int(options["--shell-timeout"]))
+ conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"]))
+
+def get_power_status5(conn, options):
+ outlets = {}
+
+ conn.send_eol("olStatus all")
+
+ conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"]))
+ lines = conn.before.split("\n")
+
+ show_re = re.compile(r'^\s*(\d+): (.*): (On|Off)\s*$', re.IGNORECASE)
+
+ for line in lines:
+ res = show_re.search(line)
+ if res != None:
+ outlets[res.group(1)] = (res.group(2), res.group(3))
+
+ if ["list", "monitor"].count(options["--action"]) == 1:
+ return outlets
+ else:
+ try:
+ (_, status) = outlets[options["--plug"]]
+ return status.lower().strip()
+ except KeyError as e:
+ logging.error("Failed: {}".format(str(e)))
+ fail(EC_STATUS)
+
+def set_power_status5(conn, options):
+ action = {
+ 'on' : "olOn",
+ 'off': "olOff"
+ }[options["--action"]]
+
+ conn.send_eol(action + " " + options["--plug"])
+ conn.log_expect(options["--command-prompt"], int(options["--power-timeout"]))
+
+def main():
+ device_opt = ["ipaddr", "login", "passwd", "cmd_prompt", "secure", \
+ "port", "switch", "telnet"]
+
+ atexit.register(atexit_handler)
+
+ all_opt["cmd_prompt"]["default"] = ["\n>", "\napc>"]
+ all_opt["ssh_options"]["default"] = "-1 -c blowfish"
+
+ options = check_input(device_opt, process_input(device_opt))
+
+ docs = {}
+ docs["shortdesc"] = "Fence agent for APC over telnet/ssh"
+ docs["longdesc"] = "fence_apc is an I/O Fencing agent \
+which can be used with the APC network power switch. It logs into device \
+via telnet/ssh and reboots a specified outlet. Lengthy telnet/ssh connections \
+should be avoided while a GFS cluster is running because the connection \
+will block any necessary fencing actions."
+ docs["vendorurl"] = "http://www.apc.com"
+ show_docs(options, docs)
+
+ ## Support for --plug [switch]:[plug] notation that was used before
+ if (("--plug" in options) == 1) and (-1 != options["--plug"].find(":")):
+ (switch, plug) = options["--plug"].split(":", 1)
+ options["--switch"] = switch
+ options["--plug"] = plug
+
+ ##
+ ## Operate the fencing device
+ ####
+ conn = fence_login(options)
+
+ ## Detect firmware version (ASCII menu vs command-line interface)
+ ## and continue with proper action
+ ####
+ result = -1
+ firmware_version = re.compile(r'\s*v(\d)*\.').search(conn.before)
+ if (firmware_version != None) and (firmware_version.group(1) in [ "5", "6", "7" ]):
+ result = fence_action(conn, options, set_power_status5, get_power_status5, get_power_status5)
+ else:
+ result = fence_action(conn, options, set_power_status, get_power_status, get_power_status)
+
+ fence_logout(conn, "4")
+ sys.exit(result)
+
+if __name__ == "__main__":
+ main()