From c928a8056ae45053970bbd7cf3aa51cd1c21c11d Mon Sep 17 00:00:00 2001 From: Kumabuchi Kenji Date: Thu, 12 Sep 2019 11:37:19 +0900 Subject: [PATCH] Add fence_heuristics_resource agent Signed-off-by: Kumabuchi Kenji --- .../fence_heuristics_resource.py | 125 ++++++++++++++++++ configure.ac | 1 + fence-agents.spec.in | 14 ++ make/fencebuild.mk | 1 + .../metadata/fence_heuristics_resource.xml | 105 +++++++++++++++ 5 files changed, 246 insertions(+) create mode 100755 agents/heuristics_resource/fence_heuristics_resource.py create mode 100644 tests/data/metadata/fence_heuristics_resource.xml diff --git a/agents/heuristics_resource/fence_heuristics_resource.py b/agents/heuristics_resource/fence_heuristics_resource.py new file mode 100755 index 000000000..84f98649a --- /dev/null +++ b/agents/heuristics_resource/fence_heuristics_resource.py @@ -0,0 +1,125 @@ +#!/usr/libexec/platform-python -tt + +import io +import re +import subprocess +import shlex +import sys, stat +import logging +import os +import atexit +import time +sys.path.append("/usr/share/fence") +from fencing import fail_usage, run_command, fence_action, all_opt +from fencing import atexit_handler, check_input, process_input, show_docs +from fencing import run_delay + +def heuristics_resource(con, options): + + if options["--action"] == "on": + return True + + if not "--resource" in options or options["--resource"] == "": + logging.error("resource parameter required") + return False + + crm_resource_path = options["--crm-resource-path"] + resource = options["--resource"] + standby_wait = int(options["--standby-wait"]) + p = None + cmd = "%s -r %s -W" % (crm_resource_path, resource) + search_str = re.compile(r"\s%s$" % os.uname()[1]) + + logging.info("Running command: %s", cmd) + try: + p = subprocess.Popen(shlex.split(cmd), + stdout=subprocess.PIPE); + except OSError: + logging.error("Command failed on OS level"); + return False + + if p != None: + p.wait() + if p.returncode == 0: + for line in p.stdout: + searchres = search_str.search(line.decode().strip()) + if searchres: + # This node is ACT! Continue fencing. + return True + logging.info("Resource %s NOT found on this node" % resource); + else: + logging.error("Command failed. rc=%s" % p.returncode); + + if standby_wait > 0: + # The SBY node waits for fencing from the ACT node, and + # tries to fencing to the ACT node when waking up from sleep. + logging.info("Standby wait %s sec" % standby_wait); + time.sleep(standby_wait) + return True + + return False + + +def define_new_opts(): + all_opt["resource"] = { + "getopt" : ":", + "longopt" : "resource", + "required" : "1", + "help" : "--resource=[resource-id] ID of the resource that should be running in the ACT node", + "shortdesc" : "Resource ID", + "default" : "", + "order" : 1 + } + all_opt["standby_wait"] = { + "getopt" : ":", + "longopt" : "standby-wait", + "required" : "0", + "help" : "--standby-wait=[seconds] Wait X seconds on SBY node. If a positive number is specified, fencing action of this agent will always succeed after waits.", + "shortdesc" : "Wait X seconds on SBY node. If a positive number is specified, fencing action of this agent will always succeed after waits.", + "default" : "0", + "order" : 1 + } + all_opt["crm_resource_path"] = { + "getopt" : ":", + "longopt" : "crm-resource-path", + "required" : "0", + "help" : "--crm-resource-path=[path] Path to crm_resource", + "shortdesc" : "Path to crm_resource", + "default" : "@CRM_RESOURCE_PATH@", + "order" : 1 + } + + +def main(): + device_opt = ["no_status", "no_password", "resource", "standby_wait", "crm_resource_path", "method"] + define_new_opts() + atexit.register(atexit_handler) + + all_opt["method"]["default"] = "cycle" + all_opt["method"]["help"] = "-m, --method=[method] Method to fence (cycle|onoff) (Default: cycle)" + + options = check_input(device_opt, process_input(device_opt)) + + docs = {} + docs["shortdesc"] = "Fence agent for resource-heuristic based fencing" + docs["longdesc"] = "fence_heuristics_resource uses resource-heuristics to control execution of another fence agent on the same fencing level.\ +\n.P\n\ +This is not a fence agent by itself! \ +Its only purpose is to enable/disable another fence agent that lives on the same fencing level but after fence_heuristic_resource." + docs["vendorurl"] = "" + show_docs(options, docs) + + run_delay(options) + + result = fence_action(\ + None, \ + options, \ + None, \ + None, \ + reboot_cycle_fn = heuristics_resource, + sync_set_power_fn = heuristics_resource) + + sys.exit(result) + +if __name__ == "__main__": + main() diff --git a/configure.ac b/configure.ac index 9b88d5f62..830a05dee 100644 --- a/configure.ac +++ b/configure.ac @@ -279,6 +279,7 @@ AC_PATH_PROG([SNMPSET_PATH], [snmpset], [/usr/bin/snmpset]) AC_PATH_PROG([SNMPGET_PATH], [snmpget], [/usr/bin/snmpget]) AC_PATH_PROG([NOVA_PATH], [nova], [/usr/bin/nova]) AC_PATH_PROG([POWERMAN_PATH], [powerman], [/usr/bin/powerman]) +AC_PATH_PROG([CRM_RESOURCE_PATH], [crm_resource], [/usr/sbin/crm_resource]) AC_PATH_PROG([PING_CMD], [ping]) AC_PATH_PROG([PING6_CMD], [ping6]) diff --git a/fence-agents.spec.in b/fence-agents.spec.in index 9be8a9440..aed2f97b1 100644 --- a/fence-agents.spec.in +++ b/fence-agents.spec.in @@ -50,6 +50,7 @@ fence-agents-emerson \\ fence-agents-eps \\ fence-agents-hds-cb \\ fence-agents-heuristics-ping \\ +fence-agents-heuristics-resource \\ fence-agents-hpblade \\ fence-agents-ibmblade \\ fence-agents-ifmib \\ @@ -536,6 +537,19 @@ ping-heuristics. %{_sbindir}/fence_heuristics_ping %{_mandir}/man8/fence_heuristics_ping.8* +%package heuristics-resource +License: GPLv2+ and LGPLv2+ +Summary: Pseudo fence agent to affect other agents based on resource-heuristics +Requires: fence-agents-common = %{version}-%{release} +BuildArch: noarch +Obsoletes: fence-agents +%description heuristics-resource +Fence pseudo agent used to affect other agents based on +resource-heuristics. +%files heuristics-resource +%{_sbindir}/fence_heuristics_resource +%{_mandir}/man8/fence_heuristics_resource.8* + %package hpblade License: GPLv2+ and LGPLv2+ Summary: Fence agent for HP BladeSystem devices diff --git a/make/fencebuild.mk b/make/fencebuild.mk index 819e03e6b..bf754e03f 100644 --- a/make/fencebuild.mk +++ b/make/fencebuild.mk @@ -28,6 +28,7 @@ define gen_agent_from_py -e 's#@''SNMPGET_PATH@#${SNMPGET_PATH}#g' \ -e 's#@''NOVA_PATH@#${NOVA_PATH}#g' \ -e 's#@''POWERMAN_PATH@#${POWERMAN_PATH}#g' \ + -e 's#@''CRM_RESOURCE_PATH@#${CRM_RESOURCE_PATH}#g' \ -e 's#@''PING_CMD@#${PING_CMD}#g' \ -e 's#@''PING6_CMD@#${PING6_CMD}#g' \ -e 's#@''PING4_CMD@#${PING4_CMD}#g' \ diff --git a/tests/data/metadata/fence_heuristics_resource.xml b/tests/data/metadata/fence_heuristics_resource.xml new file mode 100644 index 000000000..381049397 --- /dev/null +++ b/tests/data/metadata/fence_heuristics_resource.xml @@ -0,0 +1,105 @@ + + +fence_heuristics_resource uses resource-heuristics to control execution of another fence agent on the same fencing level. + +This is not a fence agent by itself! Its only purpose is to enable/disable another fence agent that lives on the same fencing level but after fence_heuristic_resource. + + + + + + Fencing action + + + + Path to crm_resource + + + + + + Method to fence + + + + + Resource ID + + + + + Wait X seconds on SBY node. If a positive number is specified, fencing action of this agent will always succeed after waits. + + + + + Disable logging to stderr. Does not affect --verbose or --debug-file or logging to syslog. + + + + + Verbose mode + + + + + Write debug information to given file + + + + + Write debug information to given file + + + + + Display version information and exit + + + + + Display help and exit + + + + + Wait X seconds before fencing is started + + + + + 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 + + + + + Count of attempts to retry power on + + + + + + + + + + + +