diff --git a/cts/CIB.py b/cts/CIB.py index 9050acabb2..5afd59f7fc 100644 --- a/cts/CIB.py +++ b/cts/CIB.py @@ -1,610 +1,610 @@ '''CTS: Cluster Testing System: CIB generator ''' __copyright__=''' Author: Andrew Beekhof Copyright (C) 2008 Andrew Beekhof ''' from UserDict import UserDict import sys, time, types, syslog, os, struct, string, signal, traceback, warnings, socket from cts.CTSvars import * from cts.CTS import ClusterManager class CibBase: cts_cib = None version = "unknown" feature_set = "unknown" Factory = None def __init__(self, CM, factory, tmpfile=None): self.CM = CM self.Factory = factory if not tmpfile: warnings.filterwarnings("ignore") tmpfile=os.tmpnam() warnings.resetwarnings() self.Factory.tmpfile = tmpfile def version(self): return self.version def NextIP(self): fields = string.split(self.CM.Env["IPBase"], '.') fields[3] = str(int(fields[3])+1) ip = string.join(fields, '.') self.CM.Env["IPBase"] = ip return ip class CibXml: def __init__(self, Factory, tag, _id, **kwargs): self.tag = tag self.name = _id self.kwargs = kwargs self.children = [] self.Factory = Factory def add_child(self, child): self.children.append(child) def __setitem__(self, key, value): self.kwargs[key] = value def show(self): text = '''<%s''' % self.tag if self.name: text += ''' id="%s"''' % (self.name) for k in self.kwargs.keys(): text += ''' %s="%s"''' % (k, self.kwargs[k]) if not self.children: text += '''/>''' return text text += '''>''' for c in self.children: text += c.show() text += '''''' % self.tag return text def _run(self, operation, xml, section="all", options=""): self.Factory.debug("Writing out %s" % self.name) fixed = "HOME=/root CIB_file="+self.Factory.tmpfile fixed += " cibadmin --%s --scope %s %s --xml-text '%s'" % (operation, section, options, xml) rc = self.Factory.rsh(self.Factory.target, fixed) if rc != 0: self.Factory.log("Configure call failed: "+fixed) sys.exit(1) class FencingTopology(CibXml): def __init__(self, Factory): CibXml.__init__(self, Factory, "fencing-topology", None) def level(self, index, node, devices): self.add_child(CibXml(self.Factory, "fencing-level", "cts-%s.%d" % (node, index), target=node, index=index, devices=devices)) def commit(self): self._run("create", self.show(), "configuration", "--allow-create") class Option(CibXml): def __init__(self, Factory, name=None, value=None, section="cib-bootstrap-options"): CibXml.__init__(self, Factory, "cluster_property_set", section) if name and value: self.add_child(CibXml(Factory, "nvpair", "cts-%s" % name, name=name, value=value)) def __setitem__(self, key, value): self.add_child(CibXml(self.Factory, "nvpair", "cts-%s" % key, name=key, value=value)) def commit(self): self._run("modify", self.show(), "crm_config", "--allow-create") class Expression(CibXml): def __init__(self, Factory, name, attr, op, value=None): CibXml.__init__(self, Factory, "expression", name, attribute=attr, operation=op) if value: self["value"] = value class Rule(CibXml): def __init__(self, Factory, name, score, op="and", expr=None): CibXml.__init__(self, Factory, "rule", "%s" % name) self["boolean-op"] = op self["score"] = score if expr: self.add_child(expr) class Resource(CibXml): def __init__(self, Factory, name, rtype, standard, provider=None): CibXml.__init__(self, Factory, "native", name) self.rtype = rtype self.standard = standard self.provider = provider self.op=[] self.meta={} self.param={} self.scores={} self.needs={} self.coloc={} if self.standard == "ocf" and not provider: self.provider = "heartbeat" elif self.standard == "lsb": self.provider = None def __setitem__(self, key, value): self.add_param(key, value) def add_op(self, name, interval, **kwargs): self.op.append( CibXml(self.Factory, "op", "%s-%s" % (name, interval), name=name, interval=interval, **kwargs)) def add_param(self, name, value): self.param[name] = value def add_meta(self, name, value): self.meta[name] = value def prefer(self, node, score="INFINITY", rule=None): if not rule: rule = Rule(self.Factory, "prefer-%s-r" % node, score, expr=Expression(self.Factory, "prefer-%s-e" % node, "#uname", "eq", node)) self.scores[node] = rule def after(self, resource, kind="Mandatory", first="start", then="start", **kwargs): kargs = kwargs.copy() kargs["kind"] = kind if then: kargs["first-action"] = "start" kargs["then-action"] = then if first: kargs["first-action"] = first self.needs[resource] = kargs def colocate(self, resource, score="INFINITY", role=None, withrole=None, **kwargs): kargs = kwargs.copy() kargs["score"] = score if role: kargs["rsc-role"] = role if withrole: kargs["with-rsc-role"] = withrole self.coloc[resource] = kargs def constraints(self): text = "" for k in self.scores.keys(): text += '''''' % (k, self.name) text += self.scores[k].show() text += '''''' for k in self.needs.keys(): text += '''''' for k in self.coloc.keys(): text += '''''' text += "" return text def show(self): text = '''''' if len(self.meta) > 0: text += '''''' % self.name for p in self.meta.keys(): text += '''''' % (self.name, p, p, self.meta[p]) text += '''''' if len(self.param) > 0: text += '''''' % self.name for p in self.param.keys(): text += '''''' % (self.name, p, p, self.param[p]) text += '''''' if len(self.op) > 0: text += '''''' for o in self.op: key = o.name o.name = "%s-%s" % (self.name, key) text += o.show() o.name = key text += '''''' text += '''''' return text def commit(self): self._run("create", self.show(), "resources") self._run("modify", self.constraints()) class Group(Resource): def __init__(self, Factory, name): Resource.__init__(self, Factory, name, None, None) self.tag = "group" def __setitem__(self, key, value): self.add_meta(key, value) def show(self): text = '''<%s id="%s">''' % (self.tag, self.name) if len(self.meta) > 0: text += '''''' % self.name for p in self.meta.keys(): text += '''''' % (self.name, p, p, self.meta[p]) text += '''''' for c in self.children: text += c.show() text += '''''' % self.tag return text class Clone(Group): def __init__(self, Factory, name, child=None): Group.__init__(self, Factory, name) self.tag = "clone" if child: self.add_child(child) def add_child(self, resource): if not self.children: self.children.append(resource) else: self.Factory.log("Clones can only have a single child. Ignoring %s" % resource.name) class Master(Clone): def __init__(self, Factory, name, child=None): Clone.__init__(self, Factory, name, child) self.tag = "master" class CIB11(CibBase): feature_set = "3.0" version = "pacemaker-1.1" def _show(self, command=""): output = "" (rc, result) = self.Factory.rsh(self.Factory.target, "HOME=/root CIB_file="+self.Factory.tmpfile+" cibadmin -Ql "+command, None, ) for line in result: output += line self.Factory.debug("Generated Config: "+line) return output def NewIP(self, name=None, standard="ocf"): ip = self.NextIP() if not name: name = "r"+ip r = Resource(self.Factory, name, "IPaddr2", standard) r["ip"] = ip r["cidr_netmask"] = "32" r.add_op("monitor", "5s") return r def install(self, target): old = self.Factory.tmpfile # Force a rebuild self.cts_cib = None self.Factory.tmpfile = CTSvars.CRM_CONFIG_DIR+"/cib.xml" self.contents(target) self.Factory.rsh(self.Factory.target, "chown "+CTSvars.CRM_DAEMON_USER+" "+self.Factory.tmpfile) self.Factory.tmpfile = old def contents(self, target=None): # fencing resource if self.cts_cib: return self.cts_cib if target: self.Factory.target = target self.Factory.rsh(self.Factory.target, "HOME=/root cibadmin --empty %s > %s" % (self.version, self.Factory.tmpfile)) #cib_base = self.cib_template % (self.feature_set, self.version, ''' remote-tls-port='9898' remote-clear-port='9999' ''') nodelist = "" self.num_nodes = 0 for node in self.CM.Env["nodes"]: nodelist += node + " " self.num_nodes = self.num_nodes + 1 no_quorum = "stop" if self.num_nodes < 3: no_quorum = "ignore" self.Factory.log("Cluster only has %d nodes, configuring: no-quroum-policy=ignore" % self.num_nodes) # Fencing resource # Define first so that the shell doesn't reject every update if self.CM.Env["DoFencing"]: st = Resource(self.Factory, "Fencing", self.CM.Env["stonith-type"], "stonith") # Set a threshold for unreliable stonith devices such as the vmware one st.add_meta("migration-threshold", "5") st.add_op("monitor", "120s", timeout="120s") st.add_op("stop", "0", timeout="60s") st.add_op("start", "0", timeout="60s") entries = string.split(self.CM.Env["stonith-params"], ',') for entry in entries: (name, value) = string.split(entry, '=') if name == "hostlist" and value == "all": value = string.join(self.CM.Env["nodes"], " ") elif name == "pcmk_host_list" and value == "all": value = string.join(self.CM.Env["nodes"], " ") st[name] = value st.commit() # Test advanced fencing logic if True: stf_nodes = [] stt_nodes = [] # Create the levels stl = FencingTopology(self.Factory) for node in self.CM.Env["nodes"]: ftype = self.CM.Env.RandomGen.choice(["levels-and", "levels-or ", "broadcast "]) self.CM.log(" - Using %s fencing for node: %s" % (ftype, node)) if ftype == "levels-and": stl.level(1, node, "FencingPass,Fencing") stt_nodes.append(node) elif ftype == "levels-or ": stl.level(1, node, "FencingFail") stl.level(2, node, "Fencing") stf_nodes.append(node) # Create a Dummy agent that always passes for levels-and if len(stt_nodes): - ftype="fence_true" - self.CM.install_helper(ftype, destdir="/usr/sbin", sourcedir=CTSvars.Fencing_home) + self.CM.install_helper("fence_dummy", destdir="/usr/sbin", sourcedir=CTSvars.Fencing_home) stt = Resource(self.Factory, "FencingPass", ftype, "stonith") stt["pcmk_host_list"] = string.join(stt_nodes, " ") # Wait this many seconds before doing anything, handy for letting disks get flushed too - stt["power_timeout"] = "20" + stt["delay"] = "20" stt["random_sleep_range"] = "10" + stf["mode"] = "pass" stt.commit() # Create a Dummy agent that always fails for levels-or if len(stf_nodes): - ftype="fence_false" - self.CM.install_helper(ftype, destdir="/usr/sbin", sourcedir=CTSvars.Fencing_home) + self.CM.install_helper("fence_dummy", destdir="/usr/sbin", sourcedir=CTSvars.Fencing_home) stf = Resource(self.Factory, "FencingFail", ftype, "stonith") stf["pcmk_host_list"] = string.join(stf_nodes, " ") # Wait this many seconds before doing anything, handy for letting disks get flushed too - stf["power_timeout"] = "20" + stf["delay"] = "20" stf["random_sleep_range"] = "30" + stf["mode"] = "fail" stf.commit() # Now commit the levels themselves stl.commit() o = Option(self.Factory, "stonith-enabled", self.CM.Env["DoFencing"]) o["start-failure-is-fatal"] = "false" o["pe-input-series-max"] = "5000" o["default-action-timeout"] = "90s" o["shutdown-escalation"] = "5min" o["batch-limit"] = "10" o["dc-deadtime"] = "5s" o["no-quorum-policy"] = no_quorum o["expected-quorum-votes"] = self.num_nodes if self.CM.Env["DoBSC"] == 1: o["ident-string"] = "Linux-HA TEST configuration file - REMOVEME!!" o.commit() # Add resources? if self.CM.Env["CIBResource"] == 1: self.add_resources() if self.CM.cluster_monitor == 1: mon = Resource(self.Factory, "cluster_mon", "ocf", "ClusterMon", "pacemaker") mon.add_op("start", "0", requires="nothing") mon.add_op("monitor", "5s", requires="nothing") mon["update"] = "10" mon["extra_options"] = "-r -n" mon["user"] = "abeekhof" mon["htmlfile"] = "/suse/abeekhof/Export/cluster.html" mon.commit() #self._create('''location prefer-dc cluster_mon rule -INFINITY: \#is_dc eq false''') # generate cib self.cts_cib = self._show() if self.Factory.tmpfile != CTSvars.CRM_CONFIG_DIR+"/cib.xml": self.Factory.rsh(self.Factory.target, "rm -f "+self.Factory.tmpfile) return self.cts_cib def add_resources(self): # Per-node resources for node in self.CM.Env["nodes"]: name = "rsc_"+node r = self.NewIP(name) r.prefer(node, "100") r.commit() # Migrator # Make this slightly sticky (since we have no other location constraints) to avoid relocation during Reattach m = Resource(self.Factory, "migrator","Dummy", "ocf", "pacemaker") m.add_meta("resource-stickiness","1") m.add_meta("allow-migrate", "1") m.add_op("monitor", "P10S") m.commit() # Ping the test master p = Resource(self.Factory, "ping-1","ping", "ocf", "pacemaker") p.add_op("monitor", "60s") p["host-list"] = self.CM.Env["cts-master"] p["name"] = "connected" p["debug"] = "true" c = Clone(self.Factory, "Connectivity", p) c["globally-unique"] = "false" c.commit() #master slave resource s = Resource(self.Factory, "stateful-1", "Stateful", "ocf", "pacemaker") s.add_op("monitor", "15s", timeout="60s") s.add_op("monitor", "16s", timeout="60s", role="Master") ms = Master(self.Factory, "master-1", s) ms["clone-max"] = self.num_nodes ms["master-max"] = 1 ms["clone-node-max"] = 1 ms["master-node-max"] = 1 # Require conectivity to run the master r = Rule(self.Factory, "connected", "-INFINITY", op="or") r.add_child(Expression(self.Factory, "m1-connected-1", "connected", "lt", "1")) r.add_child(Expression(self.Factory, "m1-connected-2", "connected", "not_defined", None)) ms.prefer("connected", rule=r) ms.commit() # Group Resource g = Group(self.Factory, "group-1") g.add_child(self.NewIP()) g.add_child(self.NewIP()) g.add_child(self.NewIP()) # Group with the master g.after("master-1", first="promote", then="start") g.colocate("master-1", "INFINITY", withrole="Master") g.commit() # LSB resource lsb_agent = self.CM.install_helper("LSBDummy") lsb = Resource(self.Factory, "lsb-dummy",lsb_agent, "lsb") lsb.add_op("monitor", "5s") # LSB with group lsb.after("group-1") lsb.colocate("group-1") lsb.commit() class CIB12(CIB11): feature_set = "3.0" version = "pacemaker-1.2" #class HASI(CIB10): # def add_resources(self): # # DLM resource # self._create('''primitive dlm ocf:pacemaker:controld op monitor interval=120s''') # self._create('''clone dlm-clone dlm meta globally-unique=false interleave=true''') # O2CB resource # self._create('''primitive o2cb ocf:ocfs2:o2cb op monitor interval=120s''') # self._create('''clone o2cb-clone o2cb meta globally-unique=false interleave=true''') # self._create('''colocation o2cb-with-dlm INFINITY: o2cb-clone dlm-clone''') # self._create('''order start-o2cb-after-dlm mandatory: dlm-clone o2cb-clone''') class ConfigFactory: def __init__(self, CM): self.CM = CM self.rsh = self.CM.rsh self.register("pacemaker11", CIB11, CM, self) self.register("pacemaker12", CIB12, CM, self) # self.register("hae", HASI, CM, self) self.target = self.CM.Env["nodes"][0] self.tmpfile = None def log(self, args): self.CM.log("cib: %s" % args) def debug(self, args): self.CM.debug("cib: %s" % args) def register(self, methodName, constructor, *args, **kargs): """register a constructor""" _args = [constructor] _args.extend(args) setattr(self, methodName, apply(ConfigFactoryItem,_args, kargs)) def unregister(self, methodName): """unregister a constructor""" delattr(self, methodName) def createConfig(self, name="pacemaker-1.0"): if name == "pacemaker-1.0": name = "pacemaker10"; elif name == "pacemaker-1.1": name = "pacemaker11"; elif name == "pacemaker-1.2": name = "pacemaker12"; elif name == "hasi": name = "hae"; if hasattr(self, name): return getattr(self, name)() else: self.CM.log("Configuration variant '%s' is unknown. Defaulting to latest config" % name) return self.pacemaker12() class ConfigFactoryItem: def __init__(self, function, *args, **kargs): assert callable(function), "function should be a callable obj" self._function = function self._args = args self._kargs = kargs def __call__(self, *args, **kargs): """call function""" _args = list(self._args) _args.extend(args) _kargs = self._kargs.copy() _kargs.update(kargs) return apply(self._function,_args,_kargs) # Basic Sanity Testing if __name__ == '__main__': import CTSlab env = CTSlab.LabEnvironment() env["nodes"] = [] env["nodes"].append("pcmk-1") env["nodes"].append("pcmk-2") env["nodes"].append("pcmk-3") env["nodes"].append("pcmk-4") env["CIBResource"] = 1 env["IPBase"] = "10.0.0.10" env["DoStonith"]=1 env["stonith-type"] = "fence_xvm" env["stonith-params"] = "pcmk_arg_map=domain:uname" manager = ClusterManager(env) manager.cluster_monitor = False CibFactory = ConfigFactory(manager) cib = CibFactory.createConfig("pacemaker-1.1") print cib.contents() diff --git a/cts/Makefile.am b/cts/Makefile.am index 3c880bcdc7..e01ac103f0 100644 --- a/cts/Makefile.am +++ b/cts/Makefile.am @@ -1,47 +1,46 @@ # # heartbeat: Linux-HA heartbeat code # # Copyright (C) 2001 Michael Moerz # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # MAINTAINERCLEANFILES = Makefile.in CLEANFILES = LSBDummy EXTRA_DIST = $(cts_SCRIPTS) $(cts_DATA) ctsdir = $(datadir)/$(PACKAGE)/tests/cts ctslibdir = $(pyexecdir)/cts ctslib_PYTHON = __init__.py \ CTSvars.py \ CM_lha.py \ CM_ais.py \ CTS.py \ CTSaudits.py \ CTStests.py \ CTSscenarios.py \ CIB.py cts_DATA = README cts.supp cts_SCRIPTS = cluster_test \ CTSlab.py \ LSBDummy \ - $(top_srcdir)/fencing/fence_true \ - $(top_srcdir)/fencing/fence_false + $(top_srcdir)/fencing/fence_dummy SUBDIRS = benchmark diff --git a/fencing/fence_dummy b/fencing/fence_dummy new file mode 100644 index 0000000000..b2029778e4 --- /dev/null +++ b/fencing/fence_dummy @@ -0,0 +1,345 @@ +#!/usr/bin/python + +# The Following Agent Has Been Tested On: +# +# Virsh 0.3.3 on RHEL 5.2 with xen-3.0.3-51 +# + +import sys, time, random + +#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 + +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= Debugging to output file", + "required" : "0", + "shortdesc" : "Write debug information to given file", + "order" : 52 }, + "delay" : { + "getopt" : "f:", + "longopt" : "delay", + "help" : "--delay 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: status, reboot (default), off or on", + "required" : "1", + "shortdesc" : "Fencing Action", + "default" : "reboot", + "order" : 1 }, + "port" : { + "getopt" : "n:", + "longopt" : "plug", + "help" : "-n, --plug= 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= Physical switch number on device", + "required" : "0", + "shortdesc" : "Physical switch number on device", + "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} +} + +common_opt = [ "retry_on", "delay" ] + +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": + 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 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 "" + +def process_input(avail_opt): + global all_opt + global common_opt + + ## + ## Add options which are available for every fence agent + ##### + avail_opt.extend(common_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 + +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(EC_GENERIC_ERROR) + +def main(): + global all_opt + device_opt = [ "help", "version", "verbose", "debug", "action", "port", + "power_timeout", "random_sleep_range"] + + all_opt["random_sleep_range"] = { + "getopt" : "R:", + "longopt" : "random_sleep_range", + "help" : "--random_sleep-range=Issue a sleep between 1 and . Used for testing.", + "order" : 1 } + + all_opt["mode"] = { + "getopt" : "M:", + "longopt" : "mode", + "help" : "--mode=(pass|fail|random). Used for testing.", + "order" : 1 } + + ## Defaults for fence agent + docs = { } + docs["shortdesc"] = "Dummy fence agent" + docs["longdesc"] = "fence_dummy is a fake Fencing agent which reports success based on it's mode (pass|fail|random) without doing anything." + + atexit.register(atexit_handler) + options = process_input(device_opt) + show_docs(options, docs) + + # random sleep for testing + if options.has_key("-f"): + val = int(options["-f"]) + sys.stderr.write("delay sleep for %d seconds" % val) + time.sleep(val) + + if options.has_key("-R"): + val = int(options["-R"]) + ran = random.randint(1, val) + sys.stderr.write("random sleep for %d seconds" % ran) + time.sleep(ran) + + if options.has_key("-o") and (options["-o"] == "monitor"): + sys.exit(0) + + if options.has_key("-M"): + if options["-M"] == "pass": + sys.exit(0) + elif options["-M"] == "fail": + sys.exit(1) + + sys.exit(random.randint(0, 1)) + +if __name__ == "__main__": + main() diff --git a/fencing/fence_false b/fencing/fence_false deleted file mode 100755 index 27e06051e9..0000000000 --- a/fencing/fence_false +++ /dev/null @@ -1,97 +0,0 @@ -#!/usr/bin/python - -# The Following Agent Has Been Tested On: -# -# Virsh 0.3.3 on RHEL 5.2 with xen-3.0.3-51 -# - -import sys, time, random -sys.path.append("/usr/share/fence") -from fencing import * - - -#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 -plug_status="on" - -def get_outlets_status(conn, options): - result={} - global plug_status - - if options.has_key("-o") and options["-o"] == "on": - plug_status = "off" - - # This fake agent has no port data to list, so we have to make - # something up for the list action. - if options.has_key("-o") and options["-o"] == "list": - result["fake_port_1"]=[plug_status, "fake"] - result["fake_port_2"]=[plug_status, "fake"] - elif (options.has_key("-n") == 0): - fail_usage("Failed: You have to enter existing machine!") - else: - port=options["-n"] - result[port]=[plug_status, "fake"] - - return result - -def get_power_status(conn, options): - outlets=get_outlets_status(conn,options) - - if len(outlets) == 0 or options.has_key("-n") == 0: - fail_usage("Failed: You have to enter existing machine!") - else: - return outlets[options["-n"]][0] - -def set_power_status(conn, options): - global plug_status - plug_status = "unknown" - if options.has_key("-o") and options["-o"] == "on": - plug_status = "off" - -def main(): - global all_opt - device_opt = [ "help", "version", "agent", "verbose", "debug", "action", "port", - "no_password", "power_wait", "power_timeout", "random_sleep_range"] - - all_opt["random_sleep_range"] = { - "getopt" : "R:", - "longopt" : "random_sleep_range", - "help" : "--random_sleep_range=Issue a sleep between 1 and . Used for testing.", - "order" : 1 } - - atexit.register(atexit_handler) - - pinput = process_input(device_opt) - - # Fake options to keep the library happy - #pinput["-p"] = "none" - pinput["-a"] = "localhost" - pinput["-C"] = "," - - options = check_input(device_opt, pinput) - - # random sleep for testing - if options.has_key("-R"): - val = int(options["-R"]) - ran = random.randint(1, val) - sys.stderr.write("random sleep for %d seconds" % ran) - time.sleep(ran) - - if options.has_key("-o") and (options["-o"] == "monitor"): - sys.exit(0) - - ## Defaults for fence agent - docs = { } - docs["shortdesc"] = "Fake fence agent" - docs["longdesc"] = "fence_true is a fake Fencing agent which always reports failure without doing anything." - show_docs(options, docs) - - ## Operate the fencing device - result = fence_action(None, options, set_power_status, get_power_status, get_outlets_status) - sys.exit(result) - -if __name__ == "__main__": - main() diff --git a/fencing/fence_true b/fencing/fence_true deleted file mode 100755 index 3968158472..0000000000 --- a/fencing/fence_true +++ /dev/null @@ -1,92 +0,0 @@ -#!/usr/bin/python - -# The Following Agent Has Been Tested On: -# -# Virsh 0.3.3 on RHEL 5.2 with xen-3.0.3-51 -# - -import sys, time, random -sys.path.append("/usr/share/fence") -from fencing import * - -#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 -plug_status="on" - -def get_outlets_status(conn, options): - result={} - - # This fake agent has no port data to list, so we have to make - # something up for the list action. - if options.has_key("-o") and options["-o"] == "list": - result["fake_port_1"]=[plug_status, "fake"] - result["fake_port_2"]=[plug_status, "fake"] - elif (options.has_key("-n") == 0): - fail_usage("Failed: You have to enter existing machine!") - else: - port=options["-n"] - result[port]=[plug_status, "fake"] - - return result - -def get_power_status(conn, options): - outlets=get_outlets_status(conn,options) - - if len(outlets) == 0 or options.has_key("-n") == 0: - fail_usage("Failed: You have to enter existing machine!") - else: - return outlets[options["-n"]][0] - -def set_power_status(conn, options): - global plug_status - plug_status = "off" - if options.has_key("-o") and options["-o"] == "on": - plug_status = "on" - -def main(): - global all_opt - device_opt = [ "help", "version", "agent", "verbose", "debug", "action", "port", - "no_password", "power_wait", "power_timeout", "random_sleep_range"] - - all_opt["random_sleep_range"] = { - "getopt" : "R:", - "longopt" : "random_sleep_range", - "help" : "--random_sleep-range=Issue a sleep between 1 and . Used for testing.", - "order" : 1 } - - atexit.register(atexit_handler) - - pinput = process_input(device_opt) - - # Fake options to keep the library happy - #pinput["-p"] = "none" - pinput["-a"] = "localhost" - pinput["-C"] = "," - - options = check_input(device_opt, pinput) - - # random sleep for testing - if options.has_key("-R"): - val = int(options["-R"]) - ran = random.randint(1, val) - sys.stderr.write("random sleep for %d seconds" % ran) - time.sleep(ran) - - if options.has_key("-o") and (options["-o"] == "monitor"): - sys.exit(0) - - ## Defaults for fence agent - docs = { } - docs["shortdesc"] = "Fake fence agent" - docs["longdesc"] = "fence_true is a fake Fencing agent which always reports success without doing anything." - show_docs(options, docs) - - ## Operate the fencing device - result = fence_action(None, options, set_power_status, get_power_status, get_outlets_status) - sys.exit(result) - -if __name__ == "__main__": - main()