diff --git a/fencing/fence_dummy b/fencing/fence_dummy index c3c4604131..8d8639def0 100755 --- a/fencing/fence_dummy +++ b/fencing/fence_dummy @@ -1,362 +1,380 @@ #!/usr/bin/python +"""Dummy fence agent for testing +""" + +# Pacemaker targets compatibility with python 2.6+ and 3.2+ +from __future__ import print_function, unicode_literals, absolute_import, division + +import io +import os +import re +import sys +import time +import random +import atexit +import getopt + +AGENT_VERSION = "4.0.0" +OCF_VERSION = "1.0" +SHORT_DESC = "Dummy fence agent" +LONG_DESC = """fence_dummy is a fake fencing agent which reports success +based on its mode (pass|fail|random) without doing anything.""" -# The Following Agent Has Been Tested On: -# -# Virsh 0.3.3 on RHEL 5.2 with xen-3.0.3-51 -# +all_opt = { + "help" : { + "getopt" : "h", + "longopt" : "help", + "help" : "-h, --help Display this help and exit", + "required" : "0", + "shortdesc" : "Display help and exit", + "order" : 54 }, + "version" : { + "getopt" : "V", + "longopt" : "version", + "help" : "-V, --version Display version information and exit", + "required" : "0", + "shortdesc" : "Display version information and exit", + "order" : 53 }, + "quiet" : { + "getopt" : "q", + "help" : "", + "order" : 50 }, + "verbose" : { + "getopt" : "v", + "longopt" : "verbose", + "help" : "-v, --verbose Verbose mode", + "required" : "0", + "shortdesc" : "Verbose mode", + "order" : 51 }, + "debug" : { + "getopt" : "D:", + "longopt" : "debug-file", + "help" : "-D, --debug-file=[debugfile] Debugging to output file", + "required" : "0", + "shortdesc" : "Write debug information to given file", + "order" : 52 }, + "random_sleep_range": { + "getopt" : "R:", + "required" : "0", + "longopt" : "random_sleep_range", + "help" : "--random_sleep_range=[seconds] Sleep between 1 and [seconds] before returning", + "shortdesc" : "Issue a sleep between 1 and [seconds]", + "order" : 1 }, + "mode": { + "getopt" : "M:", + "longopt" : "mode", + "required" : "0", + "help" : "--mode=(pass|fail|random) What exit status should be returned for this operation", + "shortdesc" : "Should operations always pass, always fail or fail at random", + "order" : 1 }, + "delay" : { + "getopt" : "f:", + "longopt" : "delay", + "help" : "--delay [seconds] Wait X seconds before fencing is started", + "required" : "0", + "shortdesc" : "Wait X seconds before fencing is started", + "default" : "0", + "order" : 200 }, + "action" : { + "getopt" : "o:", + "longopt" : "action", + "help" : "-o, --action=[action] Action: status, list, reboot (default), off or on", + "required" : "1", + "shortdesc" : "Fencing Action", + "default" : "reboot", + "order" : 1 }, + "port" : { + "getopt" : "n:", + "longopt" : "plug", + "help" : "-n, --plug=[id] Physical plug number on device", + "required" : "1", + "shortdesc" : "Physical plug number or name of virtual machine", + "order" : 1 }, + "switch" : { + "getopt" : "s:", + "longopt" : "switch", + "help" : "-s, --switch=[id] Physical switch number on device", + "required" : "0", + "shortdesc" : "Physical switch number on device", + "order" : 1 }, + "nodename" : { + "getopt" : "N:", + "longopt" : "nodename", + "help" : "-N, --nodename Node name of fence victim", + "required" : "0", + "shortdesc" : "The node name of fence victim", + "order" : 1}, + "nodeid" : { + "getopt" : "i:", + "longopt" : "nodeid", + "help" : "-i, --nodeid Corosync id of fence victim", + "required" : "0", + "shortdesc" : "The corosync id of fence victim", + "order" : 1}, + "uuid" : { + "getopt" : "U:", + "longopt" : "uuid", + "help" : "-U, --uuid UUID of the VM to fence", + "required" : "0", + "shortdesc" : "The UUID of the virtual machine to fence", + "order" : 1}, + "mock_dynamic_hosts" : { + "getopt" : "H:", + "longopt" : "mock_dynamic_hosts", + "help" : "-H, --mock_dynamic_hosts=[list] What to return when dynamically queried for possible targets", + "required" : "0", + "shortdesc" : "A list of hosts we can fence.", + "order" : 1} +} -import sys, time, random, os, atexit, getopt, re -#BEGIN_VERSION_GENERATION -RELEASE_VERSION="3.1.6" -BUILD_DATE="(built Mon Oct 24 12:14:08 UTC 2011)" -REDHAT_COPYRIGHT="Copyright (C) Red Hat, Inc. 2004-2010 All rights reserved." -#END_VERSION_GENERATION +def fail_usage(message): + sys.stderr.write("%s\nPlease use '-h' for usage\n" % message) + sys.exit(1) -all_opt = { - "help" : { - "getopt" : "h", - "longopt" : "help", - "help" : "-h, --help Display this help and exit", - "required" : "0", - "shortdesc" : "Display help and exit", - "order" : 54 }, - "version" : { - "getopt" : "V", - "longopt" : "version", - "help" : "-V, --version Output version information and exit", - "required" : "0", - "shortdesc" : "Display version information and exit", - "order" : 53 }, - "quiet" : { - "getopt" : "q", - "help" : "", - "order" : 50 }, - "verbose" : { - "getopt" : "v", - "longopt" : "verbose", - "help" : "-v, --verbose Verbose mode", - "required" : "0", - "shortdesc" : "Verbose mode", - "order" : 51 }, - "debug" : { - "getopt" : "D:", - "longopt" : "debug-file", - "help" : "-D, --debug-file=[debugfile] Debugging to output file", - "required" : "0", - "shortdesc" : "Write debug information to given file", - "order" : 52 }, - "random_sleep_range": { - "getopt" : "R:", - "required" : "0", - "longopt" : "random_sleep_range", - "help" : "--random_sleep-range=[seconds] Issue a sleep between 1 and [seconds]. Used for testing.", - "shortdesc" : "Issue a sleep between 1 and [seconds]", - "order" : 1 }, - "mode": { - "getopt" : "M:", - "longopt" : "mode", - "required" : "0", - "help" : "--mode=(pass|fail|random). Used for testing.", - "shortdesc" : "Should operations always pass, always fail or fail at random", - "order" : 1 }, - "delay" : { - "getopt" : "f:", - "longopt" : "delay", - "help" : "--delay [seconds] Wait X seconds before fencing is started", - "required" : "0", - "shortdesc" : "Wait X seconds before fencing is started", - "default" : "0", - "order" : 200 }, - "action" : { - "getopt" : "o:", - "longopt" : "action", - "help" : "-o, --action=[action] Action: status, list, reboot (default), off or on", - "required" : "1", - "shortdesc" : "Fencing Action", - "default" : "reboot", - "order" : 1 }, - "port" : { - "getopt" : "n:", - "longopt" : "plug", - "help" : "-n, --plug=[id] Physical plug number on device or\n" + - " name of virtual machine", - "required" : "1", - "shortdesc" : "Physical plug number or name of virtual machine", - "order" : 1 }, - "switch" : { - "getopt" : "s:", - "longopt" : "switch", - "help" : "-s, --switch=[id] Physical switch number on device", - "required" : "0", - "shortdesc" : "Physical switch number on device", - "order" : 1 }, - "nodeid" : { - "getopt" : "i:", - "longopt" : "nodeid", - "help" : "-i, --nodeid corosync id of fence victim", - "required" : "0", - "shortdesc" : "The corosync id of fence victim", - "order" : 1}, - "uuid" : { - "getopt" : "U:", - "longopt" : "uuid", - "help" : "-U, --uuid UUID of the VM to fence.", - "required" : "0", - "shortdesc" : "The UUID of the virtual machine to fence.", - "order" : 1}, - "mock_dynamic_hosts" : { - "getopt" : "H:", - "longopt" : "mock_dynamic_hosts", - "help" : "-H, --mock_dynamic_hosts=[hostlist] List of hosts we can fence.", - "required" : "0", - "shortdesc" : "A list of hosts we can fence.", - "order" : 1} -} -def show_docs(options, docs = None): - device_opt = options["device_opt"] - - if docs == None: - docs = { } - docs["shortdesc"] = "Fence agent" - docs["longdesc"] = "" - - ## Process special options (and exit) - ##### - if options.has_key("-h"): - usage(device_opt) - sys.exit(0) - - if options.has_key("-o") and options["-o"].lower() == "metadata": - sys.stderr.write("asked for fence_dummy metadata\n") - metadata(device_opt, options, docs) - sys.exit(0) - - if options.has_key("-V"): - print __main__.RELEASE_VERSION, __main__.BUILD_DATE - print __main__.REDHAT_COPYRIGHT - sys.exit(0) +def show_docs(options): + """ Handle informational options (display info and exit). """ + + device_opt = options["device_opt"] + + if "-h" in options: + usage(device_opt) + sys.exit(0) + + if "-o" in options and options["-o"].lower() == "metadata": + metadata(device_opt, options) + sys.exit(0) + + if "-V" in options: + print(AGENT_VERSION) + sys.exit(0) + def usage(avail_opt): - global all_opt - - print "Usage:" - print "\t" + os.path.basename(sys.argv[0]) + " [options]" - print "Options:" - - sorted_list = [ (key, all_opt[key]) for key in avail_opt ] - sorted_list.sort(lambda x, y: cmp(x[1]["order"], y[1]["order"])) - - for key, value in sorted_list: - if len(value["help"]) != 0: - print " " + value["help"] - -def metadata(avail_opt, options, docs): - global all_opt - - sorted_list = [ (key, all_opt[key]) for key in avail_opt ] - sorted_list.sort(lambda x, y: cmp(x[1]["order"], y[1]["order"])) - - print "" - print "" - print "" + docs["longdesc"] + "" - if docs.has_key("vendorurl"): - print "" + docs["vendorurl"] + "" - print "" - for option, value in sorted_list: - if all_opt[option].has_key("shortdesc"): - print "\t" - - default = "" - if all_opt[option].has_key("default"): - default = "default=\""+str(all_opt[option]["default"])+"\"" - elif options.has_key("-" + all_opt[option]["getopt"][:-1]): - if options["-" + all_opt[option]["getopt"][:-1]]: - try: - default = "default=\"" + options["-" + all_opt[option]["getopt"][:-1]] + "\"" - except TypeError: - ## @todo/@note: Currently there is no clean way how to handle lists - ## we can create a string from it but we can't set it on command line - default = "default=\"" + str(options["-" + all_opt[option]["getopt"][:-1]]) +"\"" - elif options.has_key("-" + all_opt[option]["getopt"]): - default = "default=\"true\" " - - mixed = all_opt[option]["help"] - ## split it between option and help text - res = re.compile("^(.*--\S+)\s+", re.IGNORECASE | re.S).search(mixed) - if (None != res): - mixed = res.group(1) - mixed = mixed.replace("<", "<").replace(">", ">") - print "\t\t" - - if all_opt[option]["getopt"].count(":") > 0: - print "\t\t" - else: - print "\t\t" - - print "\t\t" + all_opt[option]["shortdesc"] + "" - print "\t" - print "" - print "" - if avail_opt.count("io_fencing") == 0: - print "\t" - print "\t" - print "\t" - else: - print "\t" - print "\t" - - print "\t" - print "\t" - print "\t" - print "\t" - print "" - print "" + global all_opt + + print("Usage:") + print("\t" + os.path.basename(sys.argv[0]) + " [options]") + print("Options:") + + sorted_list = [ (key, all_opt[key]) for key in avail_opt ] + sorted_list.sort(key=lambda x: x[1]["order"]) + + for key, value in sorted_list: + if len(value["help"]) != 0: + print(" " + value["help"]) + + +def metadata(avail_opt, options): + global all_opt + + # This log is just for testing handling of stderr output + sys.stderr.write("asked for fence_dummy metadata\n") + + sorted_list = [ (key, all_opt[key]) for key in avail_opt ] + sorted_list.sort(key=lambda x: x[1]["order"]) + + print(""" + +%s +%s +""" % (os.path.basename(sys.argv[0]), SHORT_DESC, + AGENT_VERSION, OCF_VERSION, LONG_DESC)) + + for option, value in sorted_list: + if "shortdesc" in all_opt[option]: + print("\t") + + default = "" + if "default" in all_opt[option]: + default = "default=\""+str(all_opt[option]["default"])+"\"" + elif ("-" + all_opt[option]["getopt"][:-1]) in options: + if options["-" + all_opt[option]["getopt"][:-1]]: + try: + default = "default=\"" + options["-" + all_opt[option]["getopt"][:-1]] + "\"" + except TypeError: + ## @todo/@note: Currently there is no clean way how to handle lists + ## we can create a string from it but we can't set it on command line + default = "default=\"" + str(options["-" + all_opt[option]["getopt"][:-1]]) +"\"" + elif ("-" + all_opt[option]["getopt"]) in options: + default = "default=\"true\" " + + mixed = all_opt[option]["help"] + ## split it between option and help text + res = re.compile("^(.*--\S+)\s+", re.IGNORECASE | re.S).search(mixed) + if (None != res): + mixed = res.group(1) + mixed = mixed.replace("<", "<").replace(">", ">") + print("\t\t") + + if all_opt[option]["getopt"].count(":") > 0: + print("\t\t") + else: + print("\t\t") + + print("\t\t" + all_opt[option]["shortdesc"] + "") + print("\t") + + print(""" + +\t +\t +\t +\t +\t +\t +\t + +""") def process_input(avail_opt): - global all_opt - - ## - ## Set standard environment - ##### - os.putenv("LANG", "C") - os.putenv("LC_ALL", "C") - - ## - ## Prepare list of options for getopt - ##### - getopt_string = "" - longopt_list = [ ] - for k in avail_opt: - if all_opt.has_key(k): - getopt_string += all_opt[k]["getopt"] - else: - fail_usage("Parse error: unknown option '"+k+"'") - - if all_opt.has_key(k) and all_opt[k].has_key("longopt"): - if all_opt[k]["getopt"].endswith(":"): - longopt_list.append(all_opt[k]["longopt"] + "=") - else: - longopt_list.append(all_opt[k]["longopt"]) - - ## Compatibility layer - if avail_opt.count("module_name") == 1: - getopt_string += "n:" - longopt_list.append("plug=") - - ## - ## Read options from command line or standard input - ##### - if len(sys.argv) > 1: - try: - opt, args = getopt.gnu_getopt(sys.argv[1:], getopt_string, longopt_list) - except getopt.GetoptError, error: - fail_usage("Parse error: " + error.msg) - - ## Transform longopt to short one which are used in fencing agents - ##### - old_opt = opt - opt = { } - for o in dict(old_opt).keys(): - if o.startswith("--"): - for x in all_opt.keys(): - if all_opt[x].has_key("longopt") and "--" + all_opt[x]["longopt"] == o: - opt["-" + all_opt[x]["getopt"].rstrip(":")] = dict(old_opt)[o] - else: - opt[o] = dict(old_opt)[o] - - ## Compatibility Layer - ##### - z = dict(opt) - if z.has_key("-T") == 1: - z["-o"] = "status" - if z.has_key("-n") == 1: - z["-m"] = z["-n"] - - opt = z - ## - ##### - else: - opt = { } - name = "" - for line in sys.stdin.readlines(): - line = line.strip() - if ((line.startswith("#")) or (len(line) == 0)): - continue - - (name, value) = (line + "=").split("=", 1) - value = value[:-1] - - ## Compatibility Layer - ###### - if name == "option": - name = "action" - - ## - ###### - if avail_opt.count(name) == 0: - sys.stderr.write("Parse error: Ignoring unknown option '"+line+"'\n") - continue - - if all_opt[name]["getopt"].endswith(":"): - opt["-"+all_opt[name]["getopt"].rstrip(":")] = value - elif ((value == "1") or (value.lower() == "yes") or (value.lower() == "on") or (value.lower() == "true")): - opt["-"+all_opt[name]["getopt"]] = "1" - return opt + global all_opt + + ## + ## Set standard environment + ##### + os.putenv("LANG", "C") + os.putenv("LC_ALL", "C") + + ## + ## Prepare list of options for getopt + ##### + getopt_string = "" + longopt_list = [ ] + for k in avail_opt: + if k in all_opt: + getopt_string += all_opt[k]["getopt"] + else: + fail_usage("Parse error: unknown option '"+k+"'") + + if k in all_opt and "longopt" in all_opt[k]: + if all_opt[k]["getopt"].endswith(":"): + longopt_list.append(all_opt[k]["longopt"] + "=") + else: + longopt_list.append(all_opt[k]["longopt"]) + + ## + ## Read options from command line or standard input + ##### + if len(sys.argv) > 1: + try: + opt, args = getopt.gnu_getopt(sys.argv[1:], getopt_string, longopt_list) + except getopt.GetoptError as error: + fail_usage("Parse error: " + error.msg) + + ## Transform longopt to short one which are used in fencing agents + ##### + old_opt = opt + opt = { } + for o in dict(old_opt).keys(): + if o.startswith("--"): + for x in all_opt.keys(): + if "longopt" in all_opt[x] and "--" + all_opt[x]["longopt"] == o: + opt["-" + all_opt[x]["getopt"].rstrip(":")] = dict(old_opt)[o] + else: + opt[o] = dict(old_opt)[o] + + ## Compatibility Layer + ##### + z = dict(opt) + if "-T" in z: + z["-o"] = "status" + if "-n" in z: + z["-m"] = z["-n"] + + opt = z + ## + ##### + else: + opt = { } + name = "" + for line in sys.stdin.readlines(): + line = line.strip() + if ((line.startswith("#")) or (len(line) == 0)): + continue + + (name, value) = (line + "=").split("=", 1) + value = value[:-1] + + ## Compatibility Layer + ###### + if name == "option": + name = "action" + + ## + ###### + if avail_opt.count(name) == 0: + sys.stderr.write("Parse error: Ignoring unknown option '"+line+"'\n") + continue + + if all_opt[name]["getopt"].endswith(":"): + opt["-"+all_opt[name]["getopt"].rstrip(":")] = value + elif ((value == "1") or (value.lower() == "yes") or (value.lower() == "on") or (value.lower() == "true")): + opt["-"+all_opt[name]["getopt"]] = "1" + return opt def atexit_handler(): - try: - sys.stdout.close() - os.close(1) - except IOError: - sys.stderr.write("%s failed to close standard output\n"%(sys.argv[0])) - sys.exit(1) + try: + sys.stdout.close() + os.close(1) + except IOError: + sys.stderr.write("%s failed to close standard output\n"%(sys.argv[0])) + sys.exit(1) def main(): global all_opt device_opt = all_opt.keys() ## Defaults for fence agent - docs = { } - docs["shortdesc"] = "Dummy fence agent" - docs["longdesc"] = "fence_dummy is a fake fencing agent which reports success based on its mode (pass|fail|random) without doing anything." - atexit.register(atexit_handler) options = process_input(device_opt) options["device_opt"] = device_opt - show_docs(options, docs) + show_docs(options) + + + # dump input to file + if "-D" in options: + try: + f = io.open(options["-D"], 'at') + f.write("### %s ###\n" % (time.strftime("%Y-%m-%d %H:%M:%S"))) + for v in sorted(options): + f.write("%s=%s\n" % (v, options[v])) + f.write("###\n") + f.close() + except IOError: + pass # random sleep for testing - if options.has_key("-f"): + if "-f" in options: val = int(options["-f"]) sys.stderr.write("delay sleep for %d seconds\n" % val) time.sleep(val) - if options.has_key("-R"): + if "-R" in options: val = int(options["-R"]) ran = random.randint(1, val) sys.stderr.write("random sleep for %d seconds\n" % ran) time.sleep(ran) - if options.has_key("-o") and (options["-o"] == "monitor"): + if "-o" in options and (options["-o"] == "monitor"): sys.stderr.write("fence_dummy monitor called\n") sys.exit(0) - if options.has_key("-o") and (options["-o"] == "list"): + if "-o" in options and (options["-o"] == "list"): sys.stderr.write("fence_dummy action (list) called\n") - if options.has_key("-H"): - print options["-H"] + if "-H" in options: + print(options["-H"]) else: sys.stderr.write("were asked for hostlist but attribute mock_dynamic_hosts wasn't set\n") - if options.has_key("-M"): + if "-M" in options: if options["-M"] == "pass": sys.exit(0) elif options["-M"] == "fail": sys.exit(1) sys.exit(random.randint(0, 1)) if __name__ == "__main__": main()