Page MenuHomeClusterLabs Projects

No OneTemporary

diff --git a/agents/mpath/fence_mpath.py b/agents/mpath/fence_mpath.py
index 25aeb052..73517851 100644
--- a/agents/mpath/fence_mpath.py
+++ b/agents/mpath/fence_mpath.py
@@ -1,305 +1,307 @@
#!@PYTHON@ -tt
import sys
import stat
import re
import os
import logging
import atexit
import ctypes
sys.path.append("@FENCEAGENTSLIBDIR@")
from fencing import fail_usage, run_command, atexit_handler, check_input, process_input, show_docs
from fencing import fence_action, all_opt, run_delay
def get_status(conn, options):
del conn
status = "off"
for dev in options["devices"]:
is_block_device(dev)
if options["--plug"] in get_registration_keys(options, dev):
status = "on"
else:
logging.debug("No registration for key "\
+ options["--plug"] + " on device " + dev + "\n")
if options["--action"] == "monitor":
dev_read(options)
return status
def set_status(conn, options):
del conn
count = 0
if options["--action"] == "on":
for dev in options["devices"]:
is_block_device(dev)
register_dev(options, dev)
if options["--plug"] not in get_registration_keys(options, dev):
count += 1
logging.debug("Failed to register key "\
+ options["--plug"] + "on device " + dev + "\n")
continue
dev_write(options, dev)
if get_reservation_key(options, dev) is None \
and not reserve_dev(options, dev) \
and get_reservation_key(options, dev) is None:
count += 1
logging.debug("Failed to create reservation (key="\
+ options["--plug"] + ", device=" + dev + ")\n")
else:
dev_keys = dev_read(options)
for dev in options["devices"]:
is_block_device(dev)
if options["--plug"] in get_registration_keys(options, dev):
preempt_abort(options, dev_keys[dev], dev)
for dev in options["devices"]:
if options["--plug"] in get_registration_keys(options, dev):
count += 1
logging.debug("Failed to remove key "\
+ options["--plug"] + " on device " + dev + "\n")
continue
if not get_reservation_key(options, dev):
count += 1
logging.debug("No reservation exists on device " + dev + "\n")
if count:
logging.error("Failed to verify " + str(count) + " device(s)")
sys.exit(1)
#run command, returns dict, ret["err"] = exit code; ret["out"] = output
def run_cmd(options, cmd):
ret = {}
if "--use-sudo" in options:
prefix = options["--sudo-path"] + " "
else:
prefix = ""
(ret["err"], ret["out"], _) = run_command(options, prefix + cmd)
ret["out"] = "".join([i for i in ret["out"] if i is not None])
return ret
# check if device exist and is block device
def is_block_device(dev):
if not os.path.exists(dev):
fail_usage("Failed: device \"" + dev + "\" does not exist")
if not stat.S_ISBLK(os.stat(dev).st_mode):
fail_usage("Failed: device \"" + dev + "\" is not a block device")
# cancel registration
def preempt_abort(options, host, dev):
cmd = options["--mpathpersist-path"] + " -o --preempt-abort --prout-type=5 --param-rk=" + host +" --param-sark=" + options["--plug"] +" -d " + dev
return not bool(run_cmd(options, cmd)["err"])
def register_dev(options, dev):
cmd = options["--mpathpersist-path"] + " -o --register --param-sark=" + options["--plug"] + " -d " + dev
#cmd return code != 0 but registration can be successful
return not bool(run_cmd(options, cmd)["err"])
def reserve_dev(options, dev):
cmd = options["--mpathpersist-path"] + " -o --reserv --prout-type=5 --param-rk=" + options["--plug"] + " -d " + dev
return not bool(run_cmd(options, cmd)["err"])
def get_reservation_key(options, dev):
cmd = options["--mpathpersist-path"] + " -i -r -d " + dev
out = run_cmd(options, cmd)
if out["err"]:
fail_usage("Cannot get reservation key")
match = re.search(r"\s+key\s*=\s*0x(\S+)\s+", out["out"], re.IGNORECASE)
return match.group(1) if match else None
def get_registration_keys(options, dev, fail=True):
keys = []
cmd = options["--mpathpersist-path"] + " -i -k -d " + dev
out = run_cmd(options, cmd)
if out["err"]:
fail_usage("Cannot get registration keys", fail)
if not fail:
return []
for line in out["out"].split("\n"):
match = re.search(r"\s+0x(\S+)\s*", line)
if match:
keys.append(match.group(1))
return keys
def dev_write(options, dev):
file_path = options["--store-path"] + "/mpath.devices"
if not os.path.isdir(options["--store-path"]):
os.makedirs(options["--store-path"])
try:
store_fh = open(file_path, "a+")
except IOError:
fail_usage("Failed: Cannot open file \""+ file_path + "\"")
out = store_fh.read()
if not re.search(r"^" + dev + r"\s+", out):
store_fh.write(dev + "\t" + options["--plug"] + "\n")
store_fh.close()
def dev_read(options, fail=True):
dev_key = {}
file_path = options["--store-path"] + "/mpath.devices"
try:
store_fh = open(file_path, "r")
except IOError:
if fail:
fail_usage("Failed: Cannot open file \"" + file_path + "\"")
else:
return None
# get not empty lines from file
for (device, key) in [line.strip().split() for line in store_fh if line.strip()]:
dev_key[device] = key
store_fh.close()
return dev_key
def mpath_check_get_verbose():
try:
f = open("/etc/sysconfig/watchdog", "r")
except IOError:
return False
match = re.search(r"^\s*verbose=yes", "".join(f.readlines()), re.MULTILINE)
f.close()
return bool(match)
def mpath_check(hardreboot=False):
if len(sys.argv) >= 3 and sys.argv[1] == "repair":
return int(sys.argv[2])
options = {}
options["--mpathpersist-path"] = "/usr/sbin/mpathpersist"
options["--store-path"] = "/var/run/cluster"
options["--power-timeout"] = "5"
if mpath_check_get_verbose():
logging.getLogger().setLevel(logging.DEBUG)
devs = dev_read(options, fail=False)
if not devs:
logging.error("No devices found")
return 0
for dev, key in list(devs.items()):
if key in get_registration_keys(options, dev, fail=False):
logging.debug("key " + key + " registered with device " + dev)
return 0
else:
logging.debug("key " + key + " not registered with device " + dev)
logging.debug("key " + key + " registered with any devices")
if hardreboot == True:
libc = ctypes.cdll['libc.so.6']
libc.reboot(0x1234567)
return 2
def define_new_opts():
all_opt["devices"] = {
"getopt" : "d:",
"longopt" : "devices",
"help" : "-d, --devices=[devices] List of devices to use for current operation",
"required" : "0",
"shortdesc" : "List of devices to use for current operation. Devices can \
be comma-separated list of device-mapper multipath devices (eg. /dev/mapper/3600508b400105df70000e00000ac0000 or /dev/mapper/mpath1). \
Each device must support SCSI-3 persistent reservations.",
"order": 1
}
all_opt["key"] = {
"getopt" : "k:",
"longopt" : "key",
"help" : "-k, --key=[key] Replaced by -n, --plug",
"required" : "0",
- "shortdesc" : "Replaced by -n, --plug",
+ "shortdesc" : "Replaced by port/-n/--plug",
"order": 1
}
all_opt["mpathpersist_path"] = {
"getopt" : ":",
"longopt" : "mpathpersist-path",
"help" : "--mpathpersist-path=[path] Path to mpathpersist binary",
"required" : "0",
"shortdesc" : "Path to mpathpersist binary",
"default" : "@MPATH_PATH@",
"order": 200
}
all_opt["store_path"] = {
"getopt" : ":",
"longopt" : "store-path",
"help" : "--store-path=[path] Path to directory containing cached keys",
"required" : "0",
"shortdesc" : "Path to directory where fence agent can store information",
"default" : "@STORE_PATH@",
"order": 200
}
def main():
atexit.register(atexit_handler)
device_opt = ["no_login", "no_password", "devices", "key", "sudo", \
"fabric_fencing", "on_target", "store_path", \
"mpathpersist_path", "force_on", "port", "no_port"]
define_new_opts()
- all_opt["port"]["help"] = "Key to use for the current operation"
+ all_opt["port"]["required"] = "0"
+ all_opt["port"]["help"] = "-n, --plug=[key] Key to use for the current operation"
all_opt["port"]["shortdesc"] = "Key to use for the current operation. \
This key should be unique to a node and have to be written in \
/etc/multipath.conf. For the \"on\" action, the key specifies the key use to \
register the local node. For the \"off\" action, this key specifies the key to \
be removed from the device(s)."
# fence_mpath_check
if os.path.basename(sys.argv[0]) == "fence_mpath_check":
sys.exit(mpath_check())
elif os.path.basename(sys.argv[0]) == "fence_mpath_check_hardreboot":
sys.exit(mpath_check(hardreboot=True))
options = check_input(device_opt, process_input(device_opt), other_conditions=True)
# hack to remove list/list-status actions which are not supported
options["device_opt"] = [ o for o in options["device_opt"] if o != "separator" ]
# workaround to avoid regressions
if "--key" in options:
options["--plug"] = options["--key"]
del options["--key"]
- elif options["--action"] in ["off", "on", "reboot", "status"] \
- and "--plug" not in options:
- fail_usage("Failed: You have to enter plug number or machine identification", stop)
+ elif "--help" not in options and options["--action"] in ["off", "on", \
+ "reboot", "status", "validate-all"] and "--plug" not in options:
+ stop_after_error = False if options["--action"] == "validate-all" else True
+ fail_usage("Failed: You have to enter plug number or machine identification", stop_after_error)
docs = {}
docs["shortdesc"] = "Fence agent for multipath persistent reservation"
docs["longdesc"] = "fence_mpath is an I/O fencing agent that uses SCSI-3 \
persistent reservations to control access multipath devices. Underlying \
devices must support SCSI-3 persistent reservations (SPC-3 or greater) as \
well as the \"preempt-and-abort\" subcommand.\nThe fence_mpath agent works by \
having a unique key for each node that has to be set in /etc/multipath.conf. \
Once registered, a single node will become the reservation holder \
by creating a \"write exclusive, registrants only\" reservation on the \
device(s). The result is that only registered nodes may write to the \
device(s). When a node failure occurs, the fence_mpath agent will remove the \
key belonging to the failed node from the device(s). The failed node will no \
longer be able to write to the device(s). A manual reboot is required."
docs["vendorurl"] = "https://www.sourceware.org/dm/"
show_docs(options, docs)
run_delay(options)
# Input control BEGIN
if options["--action"] == "validate-all":
sys.exit(0)
if not ("--devices" in options and options["--devices"]):
fail_usage("Failed: No devices found")
options["devices"] = options["--devices"].split(",")
# Input control END
result = fence_action(None, options, set_status, get_status)
sys.exit(result)
if __name__ == "__main__":
main()
diff --git a/tests/data/metadata/fence_mpath.xml b/tests/data/metadata/fence_mpath.xml
index fe9378df..f5e60823 100644
--- a/tests/data/metadata/fence_mpath.xml
+++ b/tests/data/metadata/fence_mpath.xml
@@ -1,124 +1,124 @@
<?xml version="1.0" ?>
<resource-agent name="fence_mpath" shortdesc="Fence agent for multipath persistent reservation" >
<longdesc>fence_mpath is an I/O fencing agent that uses SCSI-3 persistent reservations to control access multipath devices. Underlying devices must support SCSI-3 persistent reservations (SPC-3 or greater) as well as the "preempt-and-abort" subcommand.
The fence_mpath agent works by having a unique key for each node that has to be set in /etc/multipath.conf. Once registered, a single node will become the reservation holder by creating a "write exclusive, registrants only" reservation on the device(s). The result is that only registered nodes may write to the device(s). When a node failure occurs, the fence_mpath agent will remove the key belonging to the failed node from the device(s). The failed node will no longer be able to write to the device(s). A manual reboot is required.</longdesc>
<vendor-url>https://www.sourceware.org/dm/</vendor-url>
<parameters>
<parameter name="action" unique="0" required="1">
<getopt mixed="-o, --action=[action]" />
<content type="string" default="off" />
<shortdesc lang="en">Fencing action</shortdesc>
</parameter>
<parameter name="devices" unique="0" required="0">
<getopt mixed="-d, --devices=[devices]" />
<content type="string" />
<shortdesc lang="en">List of devices to use for current operation. Devices can be comma-separated list of device-mapper multipath devices (eg. /dev/mapper/3600508b400105df70000e00000ac0000 or /dev/mapper/mpath1). Each device must support SCSI-3 persistent reservations.</shortdesc>
</parameter>
<parameter name="key" unique="0" required="0">
<getopt mixed="-k, --key=[key]" />
<content type="string" />
- <shortdesc lang="en">Replaced by -n, --plug</shortdesc>
+ <shortdesc lang="en">Replaced by port/-n/--plug</shortdesc>
</parameter>
- <parameter name="plug" unique="0" required="1" obsoletes="port">
- <getopt mixed="Key to use for the current operation" />
+ <parameter name="plug" unique="0" required="0" obsoletes="port">
+ <getopt mixed="-n, --plug=[key]" />
<content type="string" />
<shortdesc lang="en">Key to use for the current operation. This key should be unique to a node and have to be written in /etc/multipath.conf. For the "on" action, the key specifies the key use to register the local node. For the "off" action, this key specifies the key to be removed from the device(s).</shortdesc>
</parameter>
- <parameter name="port" unique="0" required="1" deprecated="1">
- <getopt mixed="Key to use for the current operation" />
+ <parameter name="port" unique="0" required="0" deprecated="1">
+ <getopt mixed="-n, --plug=[key]" />
<content type="string" />
<shortdesc lang="en">Key to use for the current operation. This key should be unique to a node and have to be written in /etc/multipath.conf. For the "on" action, the key specifies the key use to register the local node. For the "off" action, this key specifies the key to be removed from the device(s).</shortdesc>
</parameter>
<parameter name="quiet" unique="0" required="0">
<getopt mixed="-q, --quiet" />
<content type="boolean" />
<shortdesc lang="en">Disable logging to stderr. Does not affect --verbose or --debug-file or logging to syslog.</shortdesc>
</parameter>
<parameter name="verbose" unique="0" required="0">
<getopt mixed="-v, --verbose" />
<content type="boolean" />
<shortdesc lang="en">Verbose mode</shortdesc>
</parameter>
<parameter name="debug" unique="0" required="0" deprecated="1">
<getopt mixed="-D, --debug-file=[debugfile]" />
<content type="string" />
<shortdesc lang="en">Write debug information to given file</shortdesc>
</parameter>
<parameter name="debug_file" unique="0" required="0" obsoletes="debug">
<getopt mixed="-D, --debug-file=[debugfile]" />
<content type="string" />
<shortdesc lang="en">Write debug information to given file</shortdesc>
</parameter>
<parameter name="version" unique="0" required="0">
<getopt mixed="-V, --version" />
<content type="boolean" />
<shortdesc lang="en">Display version information and exit</shortdesc>
</parameter>
<parameter name="help" unique="0" required="0">
<getopt mixed="-h, --help" />
<content type="boolean" />
<shortdesc lang="en">Display help and exit</shortdesc>
</parameter>
<parameter name="delay" unique="0" required="0">
<getopt mixed="--delay=[seconds]" />
<content type="second" default="0" />
<shortdesc lang="en">Wait X seconds before fencing is started</shortdesc>
</parameter>
<parameter name="login_timeout" unique="0" required="0">
<getopt mixed="--login-timeout=[seconds]" />
<content type="second" default="5" />
<shortdesc lang="en">Wait X seconds for cmd prompt after login</shortdesc>
</parameter>
<parameter name="mpathpersist_path" unique="0" required="0">
<getopt mixed="--mpathpersist-path=[path]" />
<shortdesc lang="en">Path to mpathpersist binary</shortdesc>
</parameter>
<parameter name="power_timeout" unique="0" required="0">
<getopt mixed="--power-timeout=[seconds]" />
<content type="second" default="20" />
<shortdesc lang="en">Test X seconds for status change after ON/OFF</shortdesc>
</parameter>
<parameter name="power_wait" unique="0" required="0">
<getopt mixed="--power-wait=[seconds]" />
<content type="second" default="0" />
<shortdesc lang="en">Wait X seconds after issuing ON/OFF</shortdesc>
</parameter>
<parameter name="shell_timeout" unique="0" required="0">
<getopt mixed="--shell-timeout=[seconds]" />
<content type="second" default="3" />
<shortdesc lang="en">Wait X seconds for cmd prompt after issuing command</shortdesc>
</parameter>
<parameter name="store_path" unique="0" required="0">
<getopt mixed="--store-path=[path]" />
<shortdesc lang="en">Path to directory where fence agent can store information</shortdesc>
</parameter>
<parameter name="retry_on" unique="0" required="0">
<getopt mixed="--retry-on=[attempts]" />
<content type="integer" default="1" />
<shortdesc lang="en">Count of attempts to retry power on</shortdesc>
</parameter>
<parameter name="sudo" unique="0" required="0" deprecated="1">
<getopt mixed="--use-sudo" />
<content type="boolean" />
<shortdesc lang="en">Use sudo (without password) when calling 3rd party software</shortdesc>
</parameter>
<parameter name="use_sudo" unique="0" required="0" obsoletes="sudo">
<getopt mixed="--use-sudo" />
<content type="boolean" />
<shortdesc lang="en">Use sudo (without password) when calling 3rd party software</shortdesc>
</parameter>
<parameter name="sudo_path" unique="0" required="0">
<getopt mixed="--sudo-path=[path]" />
<shortdesc lang="en">Path to sudo binary</shortdesc>
</parameter>
</parameters>
<actions>
<action name="on" on_target="1" automatic="1"/>
<action name="off" />
<action name="status" />
<action name="monitor" />
<action name="metadata" />
<action name="manpage" />
<action name="validate-all" />
</actions>
</resource-agent>

File Metadata

Mime Type
text/x-diff
Expires
Tue, Feb 25, 4:21 AM (1 d, 13 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1464670
Default Alt Text
(17 KB)

Event Timeline