|
|
217e50 |
diff -uNr a/configure.ac b/configure.ac
|
|
|
217e50 |
--- a/configure.ac 2017-01-16 16:20:32.299438841 +0100
|
|
|
217e50 |
+++ b/configure.ac 2017-01-16 16:19:09.079326886 +0100
|
|
|
217e50 |
@@ -309,6 +309,7 @@
|
|
|
217e50 |
fence/agents/xenapi/Makefile
|
|
|
217e50 |
fence/agents/hds_cb/Makefile
|
|
|
217e50 |
fence/agents/zvm/Makefile
|
|
|
217e50 |
+ fence/agents/sbd/Makefile
|
|
|
217e50 |
doc/Makefile])
|
|
|
217e50 |
|
|
|
217e50 |
AC_OUTPUT
|
|
|
217e50 |
diff -uNr a/fence/agents/sbd/fence_sbd.py b/fence/agents/sbd/fence_sbd.py
|
|
|
217e50 |
--- a/fence/agents/sbd/fence_sbd.py 1970-01-01 01:00:00.000000000 +0100
|
|
|
217e50 |
+++ b/fence/agents/sbd/fence_sbd.py 2017-01-16 16:22:39.273080656 +0100
|
|
|
217e50 |
@@ -0,0 +1,422 @@
|
|
|
217e50 |
+#!/usr/bin/python -tt
|
|
|
217e50 |
+
|
|
|
217e50 |
+import sys, stat
|
|
|
217e50 |
+import logging
|
|
|
217e50 |
+import os
|
|
|
217e50 |
+import atexit
|
|
|
217e50 |
+sys.path.append("@FENCEAGENTSLIBDIR@")
|
|
|
217e50 |
+from fencing import fail_usage, run_command, fence_action, all_opt
|
|
|
217e50 |
+from fencing import atexit_handler, check_input, process_input, show_docs
|
|
|
217e50 |
+from fencing import run_delay
|
|
|
217e50 |
+
|
|
|
217e50 |
+#BEGIN_VERSION_GENERATION
|
|
|
217e50 |
+RELEASE_VERSION=""
|
|
|
217e50 |
+REDHAT_COPYRIGHT=""
|
|
|
217e50 |
+BUILD_DATE=""
|
|
|
217e50 |
+#END_VERSION_GENERATION
|
|
|
217e50 |
+
|
|
|
217e50 |
+DEVICE_INIT = 1
|
|
|
217e50 |
+DEVICE_NOT_INIT = -3
|
|
|
217e50 |
+PATH_NOT_EXISTS = -1
|
|
|
217e50 |
+PATH_NOT_BLOCK = -2
|
|
|
217e50 |
+
|
|
|
217e50 |
+def is_block_device(filename):
|
|
|
217e50 |
+ """Checks if a given path is a valid block device
|
|
|
217e50 |
+
|
|
|
217e50 |
+ Key arguments:
|
|
|
217e50 |
+ filename -- the file to check
|
|
|
217e50 |
+
|
|
|
217e50 |
+ Return codes:
|
|
|
217e50 |
+ True if it's a valid block device
|
|
|
217e50 |
+ False, otherwise
|
|
|
217e50 |
+ """
|
|
|
217e50 |
+
|
|
|
217e50 |
+ try:
|
|
|
217e50 |
+ mode = os.lstat(filename).st_mode
|
|
|
217e50 |
+ except OSError:
|
|
|
217e50 |
+ return False
|
|
|
217e50 |
+ else:
|
|
|
217e50 |
+ return stat.S_ISBLK(mode)
|
|
|
217e50 |
+
|
|
|
217e50 |
+def is_link(filename):
|
|
|
217e50 |
+ """Checks if a given path is a link.
|
|
|
217e50 |
+
|
|
|
217e50 |
+ Key arguments:
|
|
|
217e50 |
+ filename -- the file to check
|
|
|
217e50 |
+
|
|
|
217e50 |
+ Return codes:
|
|
|
217e50 |
+ True if it's a link
|
|
|
217e50 |
+ False, otherwise
|
|
|
217e50 |
+ """
|
|
|
217e50 |
+
|
|
|
217e50 |
+ try:
|
|
|
217e50 |
+ mode = os.lstat(filename).st_mode
|
|
|
217e50 |
+ except OSError:
|
|
|
217e50 |
+ return False
|
|
|
217e50 |
+ else:
|
|
|
217e50 |
+ return stat.S_ISLNK(mode)
|
|
|
217e50 |
+
|
|
|
217e50 |
+def check_sbd_device(options, device_path):
|
|
|
217e50 |
+ """checks that a given sbd device exists and is initialized
|
|
|
217e50 |
+
|
|
|
217e50 |
+ Key arguments:
|
|
|
217e50 |
+ options -- options dictionary
|
|
|
217e50 |
+ device_path -- device path to check
|
|
|
217e50 |
+
|
|
|
217e50 |
+ Return Codes:
|
|
|
217e50 |
+ 1 / DEVICE_INIT if the device exists and is initialized
|
|
|
217e50 |
+ -1 / PATH_NOT_EXISTS if the path does not exists
|
|
|
217e50 |
+ -2 / PATH_NOT_BLOCK if the path exists but is not a valid block device
|
|
|
217e50 |
+ -3 / DEVICE_NOT_INIT if the sbd device is not initialized
|
|
|
217e50 |
+ """
|
|
|
217e50 |
+
|
|
|
217e50 |
+ # First of all we need to check if the device is valid
|
|
|
217e50 |
+ if not os.path.exists(device_path):
|
|
|
217e50 |
+ return PATH_NOT_EXISTS
|
|
|
217e50 |
+
|
|
|
217e50 |
+ # We need to check if device path is a symbolic link. If so we resolve that
|
|
|
217e50 |
+ # link.
|
|
|
217e50 |
+ if is_link(device_path):
|
|
|
217e50 |
+ link_target = os.readlink(device_path)
|
|
|
217e50 |
+ device_path = os.path.join(os.path.dirname(device_path), link_target)
|
|
|
217e50 |
+
|
|
|
217e50 |
+ # As second step we make sure it's a valid block device
|
|
|
217e50 |
+ if not is_block_device(device_path):
|
|
|
217e50 |
+ return PATH_NOT_BLOCK
|
|
|
217e50 |
+
|
|
|
217e50 |
+ cmd = "%s -d %s dump" % (options["--sbd-path"], device_path)
|
|
|
217e50 |
+
|
|
|
217e50 |
+ (return_code, out, err) = run_command(options, cmd)
|
|
|
217e50 |
+
|
|
|
217e50 |
+ for line in out.split("\n"):
|
|
|
217e50 |
+ if len(line) == 0:
|
|
|
217e50 |
+ continue
|
|
|
217e50 |
+
|
|
|
217e50 |
+ # If we read "NOT dumped" something went wrong, e.g. the device is not
|
|
|
217e50 |
+ # initialized.
|
|
|
217e50 |
+ if "NOT dumped" in line:
|
|
|
217e50 |
+ return DEVICE_NOT_INIT
|
|
|
217e50 |
+
|
|
|
217e50 |
+ return DEVICE_INIT
|
|
|
217e50 |
+
|
|
|
217e50 |
+def generate_sbd_command(options, command, arguments=None):
|
|
|
217e50 |
+ """Generates a sbd command based on given arguments.
|
|
|
217e50 |
+
|
|
|
217e50 |
+ Return Value:
|
|
|
217e50 |
+ generated sbd command (string)
|
|
|
217e50 |
+ """
|
|
|
217e50 |
+ cmd = options["--sbd-path"]
|
|
|
217e50 |
+
|
|
|
217e50 |
+ # add "-d" for each sbd device
|
|
|
217e50 |
+ for device in parse_sbd_devices(options):
|
|
|
217e50 |
+ cmd += " -d %s" % device
|
|
|
217e50 |
+
|
|
|
217e50 |
+ cmd += " %s %s" % (command, arguments)
|
|
|
217e50 |
+
|
|
|
217e50 |
+ return cmd
|
|
|
217e50 |
+
|
|
|
217e50 |
+def send_sbd_message(conn, options, plug, message):
|
|
|
217e50 |
+ """Sends a message to all sbd devices.
|
|
|
217e50 |
+
|
|
|
217e50 |
+ Key arguments:
|
|
|
217e50 |
+ conn -- connection structure
|
|
|
217e50 |
+ options -- options dictionary
|
|
|
217e50 |
+ plug -- plug to sent the message to
|
|
|
217e50 |
+ message -- message to send
|
|
|
217e50 |
+
|
|
|
217e50 |
+ Return Value:
|
|
|
217e50 |
+ (return_code, out, err) Tuple containing the error code,
|
|
|
217e50 |
+ """
|
|
|
217e50 |
+
|
|
|
217e50 |
+ del conn
|
|
|
217e50 |
+
|
|
|
217e50 |
+ arguments = "%s %s" % (plug, message)
|
|
|
217e50 |
+ cmd = generate_sbd_command(options, "message", arguments)
|
|
|
217e50 |
+
|
|
|
217e50 |
+ (return_code, out, err) = run_command(options, cmd)
|
|
|
217e50 |
+
|
|
|
217e50 |
+ return (return_code, out, err)
|
|
|
217e50 |
+
|
|
|
217e50 |
+def get_msg_timeout(options):
|
|
|
217e50 |
+ """Reads the configured sbd message timeout from each device.
|
|
|
217e50 |
+
|
|
|
217e50 |
+ Key arguments:
|
|
|
217e50 |
+ options -- options dictionary
|
|
|
217e50 |
+
|
|
|
217e50 |
+ Return Value:
|
|
|
217e50 |
+ msg_timeout (integer, seconds)
|
|
|
217e50 |
+ """
|
|
|
217e50 |
+
|
|
|
217e50 |
+ # get the defined msg_timeout
|
|
|
217e50 |
+ msg_timeout = -1 # default sbd msg timeout
|
|
|
217e50 |
+
|
|
|
217e50 |
+ cmd = generate_sbd_command(options, "dump")
|
|
|
217e50 |
+
|
|
|
217e50 |
+ (return_code, out, err) = run_command(options, cmd)
|
|
|
217e50 |
+
|
|
|
217e50 |
+ for line in out.split("\n"):
|
|
|
217e50 |
+ if len(line) == 0:
|
|
|
217e50 |
+ continue
|
|
|
217e50 |
+
|
|
|
217e50 |
+ if "msgwait" in line:
|
|
|
217e50 |
+ tmp_msg_timeout = int(line.split(':')[1])
|
|
|
217e50 |
+ if -1 != msg_timeout and tmp_msg_timeout != msg_timeout:
|
|
|
217e50 |
+ logging.warn(\
|
|
|
217e50 |
+ "sbd message timeouts differ in different devices")
|
|
|
217e50 |
+ # we only save the highest timeout
|
|
|
217e50 |
+ if tmp_msg_timeout > msg_timeout:
|
|
|
217e50 |
+ msg_timeout = tmp_msg_timeout
|
|
|
217e50 |
+
|
|
|
217e50 |
+ return msg_timeout
|
|
|
217e50 |
+
|
|
|
217e50 |
+def set_power_status(conn, options):
|
|
|
217e50 |
+ """send status to sbd device (poison pill)
|
|
|
217e50 |
+
|
|
|
217e50 |
+ Key arguments:
|
|
|
217e50 |
+ conn -- connection structure
|
|
|
217e50 |
+ options -- options dictionary
|
|
|
217e50 |
+
|
|
|
217e50 |
+ Return Value:
|
|
|
217e50 |
+ return_code -- action result (bool)
|
|
|
217e50 |
+ """
|
|
|
217e50 |
+
|
|
|
217e50 |
+ target_status = options["--action"]
|
|
|
217e50 |
+ plug = options["--plug"]
|
|
|
217e50 |
+ return_code = 99
|
|
|
217e50 |
+ out = ""
|
|
|
217e50 |
+ err = ""
|
|
|
217e50 |
+
|
|
|
217e50 |
+ # Map fencing actions to sbd messages
|
|
|
217e50 |
+ if "on" == target_status:
|
|
|
217e50 |
+ (return_code, out, err) = send_sbd_message(conn, options, plug, "clear")
|
|
|
217e50 |
+ elif "off" == target_status:
|
|
|
217e50 |
+ (return_code, out, err) = send_sbd_message(conn, options, plug, "off")
|
|
|
217e50 |
+ elif "reboot" == target_status:
|
|
|
217e50 |
+ (return_code, out, err) = send_sbd_message(conn, options, plug, "reset")
|
|
|
217e50 |
+
|
|
|
217e50 |
+ if 0 != return_code:
|
|
|
217e50 |
+ logging.error("sending message to sbd device(s) \
|
|
|
217e50 |
+ failed with return code %d", return_code)
|
|
|
217e50 |
+ logging.error("DETAIL: output on stdout was \"%s\"", out)
|
|
|
217e50 |
+ logging.error("DETAIL: output on stderr was \"%s\"", err)
|
|
|
217e50 |
+
|
|
|
217e50 |
+ return not bool(return_code)
|
|
|
217e50 |
+
|
|
|
217e50 |
+def reboot_cycle(conn, options):
|
|
|
217e50 |
+ """" trigger reboot by sbd messages
|
|
|
217e50 |
+
|
|
|
217e50 |
+ Key arguments:
|
|
|
217e50 |
+ conn -- connection structure
|
|
|
217e50 |
+ options -- options dictionary
|
|
|
217e50 |
+
|
|
|
217e50 |
+ Return Value:
|
|
|
217e50 |
+ return_code -- action result (bool)
|
|
|
217e50 |
+ """
|
|
|
217e50 |
+
|
|
|
217e50 |
+ plug = options["--plug"]
|
|
|
217e50 |
+ return_code = 99
|
|
|
217e50 |
+ out = ""
|
|
|
217e50 |
+ err = ""
|
|
|
217e50 |
+
|
|
|
217e50 |
+ (return_code, out, err) = send_sbd_message(conn, options, plug, "reset")
|
|
|
217e50 |
+ return not bool(return_code)
|
|
|
217e50 |
+
|
|
|
217e50 |
+def get_power_status(conn, options):
|
|
|
217e50 |
+ """Returns the status of a specific node.
|
|
|
217e50 |
+
|
|
|
217e50 |
+ Key arguments:
|
|
|
217e50 |
+ conn -- connection structure
|
|
|
217e50 |
+ options -- option dictionary
|
|
|
217e50 |
+
|
|
|
217e50 |
+ Return Value:
|
|
|
217e50 |
+ status -- status code (string)
|
|
|
217e50 |
+ """
|
|
|
217e50 |
+
|
|
|
217e50 |
+ status = "UNKWNOWN"
|
|
|
217e50 |
+ plug = options["--plug"]
|
|
|
217e50 |
+
|
|
|
217e50 |
+ nodelist = get_node_list(conn, options)
|
|
|
217e50 |
+
|
|
|
217e50 |
+ # We need to check if the specified plug / node a already a allocated slot
|
|
|
217e50 |
+ # on the device.
|
|
|
217e50 |
+ if plug not in nodelist:
|
|
|
217e50 |
+ logging.error("node \"%s\" not found in node list", plug)
|
|
|
217e50 |
+ else:
|
|
|
217e50 |
+ status = nodelist[plug][1]
|
|
|
217e50 |
+
|
|
|
217e50 |
+
|
|
|
217e50 |
+ return status
|
|
|
217e50 |
+
|
|
|
217e50 |
+def translate_status(sbd_status):
|
|
|
217e50 |
+ """Translates the sbd status to fencing status.
|
|
|
217e50 |
+
|
|
|
217e50 |
+ Key arguments:
|
|
|
217e50 |
+ sbd_status -- status to translate (string)
|
|
|
217e50 |
+
|
|
|
217e50 |
+ Return Value:
|
|
|
217e50 |
+ status -- fencing status (string)
|
|
|
217e50 |
+ """
|
|
|
217e50 |
+
|
|
|
217e50 |
+ status = "UNKNOWN"
|
|
|
217e50 |
+
|
|
|
217e50 |
+
|
|
|
217e50 |
+ # Currently we only accept "clear" to be marked as online. Eventually we
|
|
|
217e50 |
+ # should also check against "test"
|
|
|
217e50 |
+ online_status = ["clear"]
|
|
|
217e50 |
+
|
|
|
217e50 |
+ offline_status = ["reset", "off"]
|
|
|
217e50 |
+
|
|
|
217e50 |
+ if any(online_status_element in sbd_status \
|
|
|
217e50 |
+ for online_status_element in online_status):
|
|
|
217e50 |
+ status = "on"
|
|
|
217e50 |
+
|
|
|
217e50 |
+ if any(offline_status_element in sbd_status \
|
|
|
217e50 |
+ for offline_status_element in offline_status):
|
|
|
217e50 |
+ status = "off"
|
|
|
217e50 |
+
|
|
|
217e50 |
+ return status
|
|
|
217e50 |
+
|
|
|
217e50 |
+def get_node_list(conn, options):
|
|
|
217e50 |
+ """Returns a list of hostnames, registerd on the sbd device.
|
|
|
217e50 |
+
|
|
|
217e50 |
+ Key arguments:
|
|
|
217e50 |
+ conn -- connection options
|
|
|
217e50 |
+ options -- options
|
|
|
217e50 |
+
|
|
|
217e50 |
+ Return Value:
|
|
|
217e50 |
+ nodelist -- dictionary wich contains all node names and there status
|
|
|
217e50 |
+ """
|
|
|
217e50 |
+
|
|
|
217e50 |
+ del conn
|
|
|
217e50 |
+
|
|
|
217e50 |
+ nodelist = {}
|
|
|
217e50 |
+
|
|
|
217e50 |
+ cmd = generate_sbd_command(options, "list")
|
|
|
217e50 |
+
|
|
|
217e50 |
+ (return_code, out, err) = run_command(options, cmd)
|
|
|
217e50 |
+
|
|
|
217e50 |
+ for line in out.split("\n"):
|
|
|
217e50 |
+ if len(line) == 0:
|
|
|
217e50 |
+ continue
|
|
|
217e50 |
+
|
|
|
217e50 |
+ # if we read "unreadable" something went wrong
|
|
|
217e50 |
+ if "NOT dumped" in line:
|
|
|
217e50 |
+ return nodelist
|
|
|
217e50 |
+
|
|
|
217e50 |
+ words = line.split()
|
|
|
217e50 |
+ port = words[1]
|
|
|
217e50 |
+ sbd_status = words[2]
|
|
|
217e50 |
+ nodelist[port] = (port, translate_status(sbd_status))
|
|
|
217e50 |
+
|
|
|
217e50 |
+ return nodelist
|
|
|
217e50 |
+
|
|
|
217e50 |
+def parse_sbd_devices(options):
|
|
|
217e50 |
+ """Returns an array of all sbd devices.
|
|
|
217e50 |
+
|
|
|
217e50 |
+ Key arguments:
|
|
|
217e50 |
+ options -- options dictionary
|
|
|
217e50 |
+
|
|
|
217e50 |
+ Return Value:
|
|
|
217e50 |
+ devices -- array of device paths
|
|
|
217e50 |
+ """
|
|
|
217e50 |
+
|
|
|
217e50 |
+ devices = [str.strip(dev) \
|
|
|
217e50 |
+ for dev in str.split(options["--devices"], ",")]
|
|
|
217e50 |
+
|
|
|
217e50 |
+ return devices
|
|
|
217e50 |
+
|
|
|
217e50 |
+def define_new_opts():
|
|
|
217e50 |
+ """Defines the all opt list
|
|
|
217e50 |
+ """
|
|
|
217e50 |
+ all_opt["devices"] = {
|
|
|
217e50 |
+ "getopt" : ":",
|
|
|
217e50 |
+ "longopt" : "devices",
|
|
|
217e50 |
+ "help":"--devices=[device_a,device_b] \
|
|
|
217e50 |
+Comma separated list of sbd devices",
|
|
|
217e50 |
+ "required" : "1",
|
|
|
217e50 |
+ "shortdesc" : "SBD Device",
|
|
|
217e50 |
+ "order": 1
|
|
|
217e50 |
+ }
|
|
|
217e50 |
+
|
|
|
217e50 |
+ all_opt["sbd_path"] = {
|
|
|
217e50 |
+ "getopt" : ":",
|
|
|
217e50 |
+ "longopt" : "sbd-path",
|
|
|
217e50 |
+ "help" : "--sbd-path=[path] Path to SBD binary",
|
|
|
217e50 |
+ "required" : "0",
|
|
|
217e50 |
+ "default" : "/usr/sbin/sbd",
|
|
|
217e50 |
+ "shortdesc" : "Path to SBD binary",
|
|
|
217e50 |
+ "order": 200
|
|
|
217e50 |
+ }
|
|
|
217e50 |
+
|
|
|
217e50 |
+def main():
|
|
|
217e50 |
+ """Main function
|
|
|
217e50 |
+ """
|
|
|
217e50 |
+ # We need to define "no_password" otherwise we will be ask about it if
|
|
|
217e50 |
+ # we don't provide any password.
|
|
|
217e50 |
+ device_opt = ["no_password", "devices", "port", "method", "sbd_path"]
|
|
|
217e50 |
+
|
|
|
217e50 |
+ # close stdout if we get interrupted
|
|
|
217e50 |
+ atexit.register(atexit_handler)
|
|
|
217e50 |
+
|
|
|
217e50 |
+ define_new_opts()
|
|
|
217e50 |
+
|
|
|
217e50 |
+ all_opt["method"]["default"] = "cycle"
|
|
|
217e50 |
+ all_opt["method"]["help"] = "-m, --method=[method] Method to fence (onoff|cycle) (Default: cycle)"
|
|
|
217e50 |
+
|
|
|
217e50 |
+ options = check_input(device_opt, process_input(device_opt))
|
|
|
217e50 |
+
|
|
|
217e50 |
+ # fill the needed variables to generate metadata and help text output
|
|
|
217e50 |
+ docs = {}
|
|
|
217e50 |
+ docs["shortdesc"] = "Fence agent for sbd"
|
|
|
217e50 |
+ docs["longdesc"] = "fence_sbd is I/O Fencing agent \
|
|
|
217e50 |
+which can be used in environments where sbd can be used (shared storage)."
|
|
|
217e50 |
+ docs["vendorurl"] = ""
|
|
|
217e50 |
+ show_docs(options, docs)
|
|
|
217e50 |
+
|
|
|
217e50 |
+ # We need to check if --devices is given and not empty.
|
|
|
217e50 |
+ if "--devices" not in options:
|
|
|
217e50 |
+ fail_usage("No SBD devices specified. \
|
|
|
217e50 |
+ At least one SBD device is required.")
|
|
|
217e50 |
+
|
|
|
217e50 |
+ run_delay(options)
|
|
|
217e50 |
+
|
|
|
217e50 |
+ # We need to check if the provided sbd_devices exists. We need to do
|
|
|
217e50 |
+ # that for every given device.
|
|
|
217e50 |
+ for device_path in parse_sbd_devices(options):
|
|
|
217e50 |
+ logging.debug("check device \"%s\"", device_path)
|
|
|
217e50 |
+
|
|
|
217e50 |
+ return_code = check_sbd_device(options, device_path)
|
|
|
217e50 |
+ if PATH_NOT_EXISTS == return_code:
|
|
|
217e50 |
+ logging.error("\"%s\" does not exist", device_path)
|
|
|
217e50 |
+ elif PATH_NOT_BLOCK == return_code:
|
|
|
217e50 |
+ logging.error("\"%s\" is not a valid block device", device_path)
|
|
|
217e50 |
+ elif DEVICE_NOT_INIT == return_code:
|
|
|
217e50 |
+ logging.error("\"%s\" is not initialized", device_path)
|
|
|
217e50 |
+ elif DEVICE_INIT != return_code:
|
|
|
217e50 |
+ logging.error("UNKNOWN error while checking \"%s\"", device_path)
|
|
|
217e50 |
+
|
|
|
217e50 |
+ # If we get any error while checking the device we need to exit at this
|
|
|
217e50 |
+ # point.
|
|
|
217e50 |
+ if DEVICE_INIT != return_code:
|
|
|
217e50 |
+ exit(return_code)
|
|
|
217e50 |
+
|
|
|
217e50 |
+ # we check against the defined timeouts. If the pacemaker timeout is smaller
|
|
|
217e50 |
+ # then that defined within sbd we should report this.
|
|
|
217e50 |
+ power_timeout = int(options["--power-timeout"])
|
|
|
217e50 |
+ sbd_msg_timeout = get_msg_timeout(options)
|
|
|
217e50 |
+ if power_timeout <= sbd_msg_timeout:
|
|
|
217e50 |
+ logging.warn("power timeout needs to be \
|
|
|
217e50 |
+ greater then sbd message timeout")
|
|
|
217e50 |
+
|
|
|
217e50 |
+ result = fence_action(\
|
|
|
217e50 |
+ None, \
|
|
|
217e50 |
+ options, \
|
|
|
217e50 |
+ set_power_status, \
|
|
|
217e50 |
+ get_power_status, \
|
|
|
217e50 |
+ get_node_list, \
|
|
|
217e50 |
+ reboot_cycle)
|
|
|
217e50 |
+
|
|
|
217e50 |
+ sys.exit(result)
|
|
|
217e50 |
+
|
|
|
217e50 |
+if __name__ == "__main__":
|
|
|
217e50 |
+ main()
|
|
|
217e50 |
diff -uNr a/fence/agents/sbd/Makefile.am b/fence/agents/sbd/Makefile.am
|
|
|
217e50 |
--- a/fence/agents/sbd/Makefile.am 1970-01-01 01:00:00.000000000 +0100
|
|
|
217e50 |
+++ b/fence/agents/sbd/Makefile.am 2017-01-16 16:19:09.079326886 +0100
|
|
|
217e50 |
@@ -0,0 +1,17 @@
|
|
|
217e50 |
+MAINTAINERCLEANFILES = Makefile.in
|
|
|
217e50 |
+
|
|
|
217e50 |
+TARGET = fence_sbd
|
|
|
217e50 |
+
|
|
|
217e50 |
+SRC = $(TARGET).py
|
|
|
217e50 |
+
|
|
|
217e50 |
+EXTRA_DIST = $(SRC)
|
|
|
217e50 |
+
|
|
|
217e50 |
+sbin_SCRIPTS = $(TARGET)
|
|
|
217e50 |
+
|
|
|
217e50 |
+man_MANS = $(TARGET).8
|
|
|
217e50 |
+
|
|
|
217e50 |
+FENCE_TEST_ARGS = -n test --devices test
|
|
|
217e50 |
+
|
|
|
217e50 |
+include $(top_srcdir)/make/fencebuild.mk
|
|
|
217e50 |
+include $(top_srcdir)/make/fenceman.mk
|
|
|
217e50 |
+include $(top_srcdir)/make/agentpycheck.mk
|
|
|
217e50 |
diff -uNr a/tests/data/metadata/fence_sbd.xml b/tests/data/metadata/fence_sbd.xml
|
|
|
217e50 |
--- a/tests/data/metadata/fence_sbd.xml 1970-01-01 01:00:00.000000000 +0100
|
|
|
217e50 |
+++ b/tests/data/metadata/fence_sbd.xml 2017-01-16 16:31:45.855219543 +0100
|
|
|
217e50 |
@@ -0,0 +1,101 @@
|
|
|
217e50 |
+
|
|
|
217e50 |
+<resource-agent name="fence_sbd" shortdesc="Fence agent for sbd" >
|
|
|
217e50 |
+<longdesc>fence_sbd is I/O Fencing agent which can be used in environments where sbd can be used (shared storage).</longdesc>
|
|
|
217e50 |
+<vendor-url></vendor-url>
|
|
|
217e50 |
+<parameters>
|
|
|
217e50 |
+ <parameter name="action" unique="0" required="1">
|
|
|
217e50 |
+ <getopt mixed="-o, --action=[action]" />
|
|
|
217e50 |
+ <content type="string" default="reboot" />
|
|
|
217e50 |
+ <shortdesc lang="en">Fencing action</shortdesc>
|
|
|
217e50 |
+ </parameter>
|
|
|
217e50 |
+ <parameter name="devices" unique="0" required="1">
|
|
|
217e50 |
+ <getopt mixed="--devices=[device_a,device_b]" />
|
|
|
217e50 |
+ <content type="string" />
|
|
|
217e50 |
+ <shortdesc lang="en">SBD Device</shortdesc>
|
|
|
217e50 |
+ </parameter>
|
|
|
217e50 |
+ <parameter name="method" unique="0" required="0">
|
|
|
217e50 |
+ <getopt mixed="-m, --method=[method]" />
|
|
|
217e50 |
+ <content type="select" default="cycle" >
|
|
|
217e50 |
+ <option value="onoff" />
|
|
|
217e50 |
+ <option value="cycle" />
|
|
|
217e50 |
+ </content>
|
|
|
217e50 |
+ <shortdesc lang="en">Method to fence</shortdesc>
|
|
|
217e50 |
+ </parameter>
|
|
|
217e50 |
+ <parameter name="port" unique="0" required="1">
|
|
|
217e50 |
+ <getopt mixed="-n, --plug=[id]" />
|
|
|
217e50 |
+ <content type="string" />
|
|
|
217e50 |
+ <shortdesc lang="en">Physical plug number on device, UUID or identification of machine</shortdesc>
|
|
|
217e50 |
+ </parameter>
|
|
|
217e50 |
+ <parameter name="verbose" unique="0" required="0">
|
|
|
217e50 |
+ <getopt mixed="-v, --verbose" />
|
|
|
217e50 |
+ <content type="boolean" />
|
|
|
217e50 |
+ <shortdesc lang="en">Verbose mode</shortdesc>
|
|
|
217e50 |
+ </parameter>
|
|
|
217e50 |
+ <parameter name="debug" unique="0" required="0">
|
|
|
217e50 |
+ <getopt mixed="-D, --debug-file=[debugfile]" />
|
|
|
217e50 |
+ <content type="string" />
|
|
|
217e50 |
+ <shortdesc lang="en">Write debug information to given file</shortdesc>
|
|
|
217e50 |
+ </parameter>
|
|
|
217e50 |
+ <parameter name="version" unique="0" required="0">
|
|
|
217e50 |
+ <getopt mixed="-V, --version" />
|
|
|
217e50 |
+ <content type="boolean" />
|
|
|
217e50 |
+ <shortdesc lang="en">Display version information and exit</shortdesc>
|
|
|
217e50 |
+ </parameter>
|
|
|
217e50 |
+ <parameter name="help" unique="0" required="0">
|
|
|
217e50 |
+ <getopt mixed="-h, --help" />
|
|
|
217e50 |
+ <content type="boolean" />
|
|
|
217e50 |
+ <shortdesc lang="en">Display help and exit</shortdesc>
|
|
|
217e50 |
+ </parameter>
|
|
|
217e50 |
+ <parameter name="separator" unique="0" required="0">
|
|
|
217e50 |
+ <getopt mixed="-C, --separator=[char]" />
|
|
|
217e50 |
+ <content type="string" default="," />
|
|
|
217e50 |
+ <shortdesc lang="en">Separator for CSV created by 'list' operation</shortdesc>
|
|
|
217e50 |
+ </parameter>
|
|
|
217e50 |
+ <parameter name="delay" unique="0" required="0">
|
|
|
217e50 |
+ <getopt mixed="--delay=[seconds]" />
|
|
|
217e50 |
+ <content type="string" default="0" />
|
|
|
217e50 |
+ <shortdesc lang="en">Wait X seconds before fencing is started</shortdesc>
|
|
|
217e50 |
+ </parameter>
|
|
|
217e50 |
+ <parameter name="login_timeout" unique="0" required="0">
|
|
|
217e50 |
+ <getopt mixed="--login-timeout=[seconds]" />
|
|
|
217e50 |
+ <content type="string" default="5" />
|
|
|
217e50 |
+ <shortdesc lang="en">Wait X seconds for cmd prompt after login</shortdesc>
|
|
|
217e50 |
+ </parameter>
|
|
|
217e50 |
+ <parameter name="power_timeout" unique="0" required="0">
|
|
|
217e50 |
+ <getopt mixed="--power-timeout=[seconds]" />
|
|
|
217e50 |
+ <content type="string" default="20" />
|
|
|
217e50 |
+ <shortdesc lang="en">Test X seconds for status change after ON/OFF</shortdesc>
|
|
|
217e50 |
+ </parameter>
|
|
|
217e50 |
+ <parameter name="power_wait" unique="0" required="0">
|
|
|
217e50 |
+ <getopt mixed="--power-wait=[seconds]" />
|
|
|
217e50 |
+ <content type="string" default="0" />
|
|
|
217e50 |
+ <shortdesc lang="en">Wait X seconds after issuing ON/OFF</shortdesc>
|
|
|
217e50 |
+ </parameter>
|
|
|
217e50 |
+ <parameter name="sbd_path" unique="0" required="0">
|
|
|
217e50 |
+ <getopt mixed="--sbd-path=[path]" />
|
|
|
217e50 |
+ <content type="string" default="/usr/sbin/sbd" />
|
|
|
217e50 |
+ <shortdesc lang="en">Path to SBD binary</shortdesc>
|
|
|
217e50 |
+ </parameter>
|
|
|
217e50 |
+ <parameter name="shell_timeout" unique="0" required="0">
|
|
|
217e50 |
+ <getopt mixed="--shell-timeout=[seconds]" />
|
|
|
217e50 |
+ <content type="string" default="3" />
|
|
|
217e50 |
+ <shortdesc lang="en">Wait X seconds for cmd prompt after issuing command</shortdesc>
|
|
|
217e50 |
+ </parameter>
|
|
|
217e50 |
+ <parameter name="retry_on" unique="0" required="0">
|
|
|
217e50 |
+ <getopt mixed="--retry-on=[attempts]" />
|
|
|
217e50 |
+ <content type="string" default="1" />
|
|
|
217e50 |
+ <shortdesc lang="en">Count of attempts to retry power on</shortdesc>
|
|
|
217e50 |
+ </parameter>
|
|
|
217e50 |
+</parameters>
|
|
|
217e50 |
+<actions>
|
|
|
217e50 |
+ <action name="on" automatic="0"/>
|
|
|
217e50 |
+ <action name="off" />
|
|
|
217e50 |
+ <action name="reboot" />
|
|
|
217e50 |
+ <action name="status" />
|
|
|
217e50 |
+ <action name="list" />
|
|
|
217e50 |
+ <action name="list-status" />
|
|
|
217e50 |
+ <action name="monitor" />
|
|
|
217e50 |
+ <action name="metadata" />
|
|
|
217e50 |
+ <action name="validate-all" />
|
|
|
217e50 |
+</actions>
|
|
|
217e50 |
+</resource-agent>
|