diff --git a/fence/agents/lib/fencing.py.py b/fence/agents/lib/fencing.py.py index bb144bb6..d6b02d39 100644 --- a/fence/agents/lib/fencing.py.py +++ b/fence/agents/lib/fencing.py.py @@ -1,1025 +1,1029 @@ #!/usr/bin/python import sys, getopt, time, os, uuid, pycurl import pexpect, re, atexit, syslog import __main__ ## do not add code here. #BEGIN_VERSION_GENERATION RELEASE_VERSION = "New fence lib agent - test release on steroids" REDHAT_COPYRIGHT = "" BUILD_DATE = "March, 2008" #END_VERSION_GENERATION LOG_MODE_VERBOSE = 100 LOG_MODE_QUIET = 0 EC_GENERIC_ERROR = 1 EC_BAD_ARGS = 2 EC_LOGIN_DENIED = 3 EC_CONNECTION_LOST = 4 EC_TIMED_OUT = 5 EC_WAITING_ON = 6 EC_WAITING_OFF = 7 EC_STATUS = 8 EC_STATUS_HMC = 9 EC_PASSWORD_MISSING = 10 TELNET_PATH = "/usr/bin/telnet" SSH_PATH = "/usr/bin/ssh" SSL_PATH = "@LIBEXECDIR@/fence_nss_wrapper" SUDO_PATH = "/usr/bin/sudo" 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 }, "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 }, "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 }, "agent" : { "getopt" : "", "help" : "", "order" : 1 }, "web" : { "getopt" : "", "help" : "", "order" : 1 }, "action" : { "getopt" : "o:", "longopt" : "action", "help" : "-o, --action=[action] Action: status, reboot (default), off or on", "required" : "1", "shortdesc" : "Fencing Action", "default" : "reboot", "order" : 1 }, "fabric_fencing" : { "getopt" : "", "help" : "", "order" : 1 }, "ipaddr" : { "getopt" : "a:", "longopt" : "ip", "help" : "-a, --ip=[ip] IP address or hostname of fencing device", "required" : "1", "shortdesc" : "IP Address or Hostname", "order" : 1 }, "ipport" : { "getopt" : "u:", "longopt" : "ipport", "help" : "-u, --ipport=[port] TCP/UDP port to use", "required" : "0", "shortdesc" : "TCP/UDP port to use for connection with device", "order" : 1 }, "login" : { "getopt" : "l:", "longopt" : "username", "help" : "-l, --username=[name] Login name", "required" : "?", "shortdesc" : "Login Name", "order" : 1 }, "no_login" : { "getopt" : "", "help" : "", "order" : 1 }, "no_password" : { "getopt" : "", "help" : "", "order" : 1 }, "no_port" : { "getopt" : "", "help" : "", "order" : 1 }, "passwd" : { "getopt" : "p:", "longopt" : "password", "help" : "-p, --password=[password] Login password or passphrase", "required" : "0", "shortdesc" : "Login password or passphrase", "order" : 1 }, "passwd_script" : { "getopt" : "S:", "longopt" : "password-script", "help" : "-S, --password-script=[script] Script to run to retrieve password", "required" : "0", "shortdesc" : "Script to retrieve password", "order" : 1 }, "identity_file" : { "getopt" : "k:", "longopt" : "identity-file", "help" : "-k, --identity-file=[filename] Identity file (private key) for ssh ", "required" : "0", "shortdesc" : "Identity file for ssh", "order" : 1 }, "drac_version" : { "getopt" : "d:", "longopt" : "drac-version", "help" : "-d, --drac-version=[version] Force DRAC version to use", "required" : "0", "shortdesc" : "Force DRAC version to use", "order" : 1 }, "cmd_prompt" : { "getopt" : "c:", "longopt" : "command-prompt", "help" : "-c, --command-prompt=[prompt] Force Python regex for command prompt", "shortdesc" : "Force Python regex for command prompt", "required" : "0", "order" : 1 }, "secure" : { "getopt" : "x", "longopt" : "ssh", "help" : "-x, --ssh Use ssh connection", "shortdesc" : "SSH connection", "required" : "0", "order" : 1 }, "ssh_options" : { "getopt" : "X:", "longopt" : "ssh-options", "help" : "--ssh-options=[options] SSH options to use", "shortdesc" : "SSH options to use", "required" : "0", "order" : 1 }, "ssl" : { "getopt" : "z", "longopt" : "ssl", "help" : "-z, --ssl Use ssl connection", "required" : "0", "shortdesc" : "SSL connection", "order" : 1 }, "port" : { "getopt" : "n:", "longopt" : "plug", "help" : "-n, --plug=[id] Physical plug number on device, UUID or\n" + " identification of machine", "required" : "1", "shortdesc" : "Physical plug number, name of virtual machine or UUID", "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 }, "exec" : { "getopt" : "e:", "longopt" : "exec", "help" : "-e, --exec=[command] Command to execute", "required" : "0", "shortdesc" : "Command to execute", "order" : 1 }, "vmware_type" : { "getopt" : "d:", "longopt" : "vmware_type", "help" : "-d, --vmware_type=[type] Type of VMware to connect", "required" : "0", "shortdesc" : "Type of VMware to connect", "order" : 1 }, "vmware_datacenter" : { "getopt" : "s:", "longopt" : "vmware-datacenter", "help" : "-s, --vmware-datacenter=[dc] VMWare datacenter filter", "required" : "0", "shortdesc" : "Show only machines in specified datacenter", "order" : 2 }, "snmp_version" : { "getopt" : "d:", "longopt" : "snmp-version", "help" : "-d, --snmp-version=[version] Specifies SNMP version to use", "required" : "0", "shortdesc" : "Specifies SNMP version to use (1,2c,3)", "order" : 1 }, "community" : { "getopt" : "c:", "longopt" : "community", "help" : "-c, --community=[community] Set the community string", "required" : "0", "shortdesc" : "Set the community string", "order" : 1}, "snmp_auth_prot" : { "getopt" : "b:", "longopt" : "snmp-auth-prot", "help" : "-b, --snmp-auth-prot=[prot] Set authentication protocol (MD5|SHA)", "required" : "0", "shortdesc" : "Set authentication protocol (MD5|SHA)", "order" : 1}, "snmp_sec_level" : { "getopt" : "E:", "longopt" : "snmp-sec-level", "help" : "-E, --snmp-sec-level=[level] Set security level\n"+ " (noAuthNoPriv|authNoPriv|authPriv)", "required" : "0", "shortdesc" : "Set security level (noAuthNoPriv|authNoPriv|authPriv)", "order" : 1}, "snmp_priv_prot" : { "getopt" : "B:", "longopt" : "snmp-priv-prot", "help" : "-B, --snmp-priv-prot=[prot] Set privacy protocol (DES|AES)", "required" : "0", "shortdesc" : "Set privacy protocol (DES|AES)", "order" : 1}, "snmp_priv_passwd" : { "getopt" : "P:", "longopt" : "snmp-priv-passwd", "help" : "-P, --snmp-priv-passwd=[pass] Set privacy protocol password", "required" : "0", "shortdesc" : "Set privacy protocol password", "order" : 1}, "snmp_priv_passwd_script" : { "getopt" : "R:", "longopt" : "snmp-priv-passwd-script", "help" : "-R, --snmp-priv-passwd-script Script to run to retrieve privacy password", "required" : "0", "shortdesc" : "Script to run to retrieve privacy password", "order" : 1}, "inet4_only" : { "getopt" : "4", "longopt" : "inet4-only", "help" : "-4, --inet4-only Forces agent to use IPv4 addresses only", "required" : "0", "shortdesc" : "Forces agent to use IPv4 addresses only", "order" : 1 }, "inet6_only" : { "getopt" : "6", "longopt" : "inet6-only", "help" : "-6, --inet6-only Forces agent to use IPv6 addresses only", "required" : "0", "shortdesc" : "Forces agent to use IPv6 addresses only", "order" : 1 }, "separator" : { "getopt" : "C:", "longopt" : "separator", "help" : "-C, --separator=[char] Separator for CSV created by 'list' operation", "default" : ",", "required" : "0", "shortdesc" : "Separator for CSV created by operation list", "order" : 100 }, "login_timeout" : { "getopt" : "y:", "longopt" : "login-timeout", "help" : "--login-timeout=[seconds] Wait X seconds for cmd prompt after login", "default" : "5", "required" : "0", "shortdesc" : "Wait X seconds for cmd prompt after login", "order" : 200 }, "shell_timeout" : { "getopt" : "Y:", "longopt" : "shell-timeout", "help" : "--shell-timeout=[seconds] Wait X seconds for cmd prompt after issuing command", "default" : "3", "required" : "0", "shortdesc" : "Wait X seconds for cmd prompt after issuing command", "order" : 200 }, "power_timeout" : { "getopt" : "g:", "longopt" : "power-timeout", "help" : "--power-timeout=[seconds] Test X seconds for status change after ON/OFF", "default" : "20", "required" : "0", "shortdesc" : "Test X seconds for status change after ON/OFF", "order" : 200 }, "power_wait" : { "getopt" : "G:", "longopt" : "power-wait", "help" : "--power-wait=[seconds] Wait X seconds after issuing ON/OFF", "default" : "0", "required" : "0", "shortdesc" : "Wait X seconds after issuing ON/OFF", "order" : 200 }, "missing_as_off" : { "getopt" : "M", "longopt" : "missing-as-off", "help" : "--missing-as-off Missing port returns OFF instead of failure", "required" : "0", "shortdesc" : "Missing port returns OFF instead of failure", "order" : 200 }, "retry_on" : { "getopt" : "F:", "longopt" : "retry-on", "help" : "--retry-on=[attempts] Count of attempts to retry power on", "default" : "1", "required" : "0", "shortdesc" : "Count of attempts to retry power on", "order" : 201 }, "session_url" : { "getopt" : "s:", "longopt" : "session-url", "help" : "-s, --session-url URL to connect to XenServer on", "required" : "1", "shortdesc" : "The URL of the XenServer host.", "order" : 1}, "sudo" : { "getopt" : "d", "longopt" : "use-sudo", "help" : "--use-sudo Use sudo (without password) when calling 3rd party software", "required" : "0", "shortdesc" : "Use sudo (without password) when calling 3rd party sotfware.", "order" : 205} } # options which are added automatically if 'key' is encountered ("default" is always added) DEPENDENCY_OPT = { "default" : [ "help", "debug", "verbose", "version", "action", "agent", \ "power_timeout", "shell_timeout", "login_timeout", "power_wait", "retry_on", "delay" ], "passwd" : [ "passwd_script" ], "secure" : [ "identity_file", "ssh_options" ], "ipaddr" : [ "ipport", "inet4_only", "inet6_only" ], "port" : [ "separator" ], "community" : [ "snmp_auth_prot", "snmp_sec_level", "snmp_priv_prot", \ "snmp_priv_passwd", "snmp_priv_passwd_script" ] } class fspawn(pexpect.spawn): def __init__(self, options, command): pexpect.spawn.__init__(self, command) self.opt = options def log_expect(self, options, pattern, timeout): result = self.expect(pattern, timeout) if options["log"] >= LOG_MODE_VERBOSE: options["debug_fh"].write(self.before + self.after) return result # send EOL according to what was detected in login process (telnet) def send_eol(self, message): self.send(message + self.opt["eol"]) 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])) syslog.syslog(syslog.LOG_ERR, "Failed to close standard output") sys.exit(EC_GENERIC_ERROR) def add_dependency_options(options): ## Add options which are available for every fence agent added_opt = [] for x in options + ["default"]: if DEPENDENCY_OPT.has_key(x): added_opt.extend([y for y in DEPENDENCY_OPT[x] if options.count(y) == 0]) return added_opt def version(command, release, build_date, copyright_notice): print command, " ", release, " ", build_date if len(copyright_notice) > 0: print copyright_notice def fail_usage(message = ""): if len(message) > 0: sys.stderr.write(message+"\n") sys.stderr.write("Please use '-h' for usage\n") sys.exit(EC_GENERIC_ERROR) def fail(error_code): message = { EC_LOGIN_DENIED : "Unable to connect/login to fencing device", EC_CONNECTION_LOST : "Connection lost", EC_TIMED_OUT : "Connection timed out", EC_WAITING_ON : "Failed: Timed out waiting to power ON", EC_WAITING_OFF : "Failed: Timed out waiting to power OFF", EC_STATUS : "Failed: Unable to obtain correct plug status or plug is not available", EC_STATUS_HMC : "Failed: Either unable to obtain correct plug status, partition is not available or incorrect HMC version used", EC_PASSWORD_MISSING : "Failed: You have to set login password" }[error_code] + "\n" sys.stderr.write(message) syslog.syslog(syslog.LOG_ERR, message) sys.exit(EC_GENERIC_ERROR) def usage(avail_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): 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 "" if "symlink" in docs: for (symlink, desc) in docs["symlink"]: 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 = str(all_opt[option]["default"]) elif options.has_key("--" + all_opt[option]["longopt"]) and all_opt[option]["getopt"].endswith(":"): if options["--" + all_opt[option]["longopt"]]: try: default = options["--" + all_opt[option]["longopt"]] 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 = str(options["--" + all_opt[option]["longopt"]]) elif options.has_key("--" + all_opt[option]["longopt"]): default = "true" if default: default = default.replace("&", "&" ) default = default.replace('"', """ ) default = default.replace('<', "<" ) default = default.replace('>', ">" ) default = default.replace("'", "'" ) default = "default=\"" + default + "\" " 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 "" - print "\t" + if avail_opt.count("fabric_fencing") == 1: + ## do 'unfence' at the start + print "\t" + else: + print "\t" print "\t" if avail_opt.count("fabric_fencing") == 0: print "\t" print "\t" print "\t" print "\t" print "\t" print "" print "" def process_input(avail_opt): avail_opt.extend(add_dependency_options(avail_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"]) ## ## 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 short getopt to long 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]["longopt"]] = dict(old_opt)[o] else: for x in all_opt.keys(): if all_opt[x].has_key("getopt") and all_opt[x].has_key("longopt") and \ ("-" + all_opt[x]["getopt"] == o or "-" + all_opt[x]["getopt"].rstrip(":") == o): opt["--" + all_opt[x]["longopt"]] = dict(old_opt)[o] opt[o] = dict(old_opt)[o] ## Compatibility Layer ##### z = dict(opt) if z.has_key("--plug") == 1: z["-m"] = z["--plug"] 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] if avail_opt.count(name) == 0: sys.stderr.write("Parse error: Ignoring unknown option '"+line+"'\n") syslog.syslog(syslog.LOG_WARNING, "Parse error: Ignoring unknown option '"+line) continue if all_opt[name]["getopt"].endswith(":"): opt["--"+all_opt[name]["longopt"].rstrip(":")] = value elif value.lower() in [ "1", "yes", "on", "true" ]: opt["--"+all_opt[name]["longopt"]] = "1" return opt ## ## This function checks input and answers if we want to have same answers ## in each of the fencing agents. It looks for possible errors and run ## password script to set a correct password ###### def check_input(device_opt, opt): device_opt.extend(add_dependency_options(device_opt)) options = dict(opt) options["device_opt"] = device_opt ## Set requirements that should be included in metadata ##### if device_opt.count("login") and device_opt.count("no_login") == 0: all_opt["login"]["required"] = "1" else: all_opt["login"]["required"] = "0" ## Set default values ##### for opt in device_opt: if all_opt[opt].has_key("default"): getopt_long = "--" + all_opt[opt]["longopt"] if 0 == options.has_key(getopt_long): options[getopt_long] = all_opt[opt]["default"] if device_opt.count("ipport"): if options.has_key("--ipport"): all_opt["ipport"]["help"] = "-u, --ipport=[port] TCP/UDP port to use (default "+ options["--ipport"] +")" elif options.has_key("--ssh"): all_opt["ipport"]["default"] = 22 all_opt["ipport"]["help"] = "-u, --ipport=[port] TCP/UDP port to use (default 22)" elif options.has_key("--ssl"): all_opt["ipport"]["default"] = 443 all_opt["ipport"]["help"] = "-u, --ipport=[port] TCP/UDP port to use (default 443)" elif device_opt.count("web"): all_opt["ipport"]["default"] = 80 if device_opt.count("ssl") == 0: all_opt["ipport"]["help"] = "-u, --ipport=[port] TCP/UDP port to use (default 80)" else: all_opt["ipport"]["help"] = "-u, --ipport=[port] TCP/UDP port to use\n\ (default 80, 443 if --ssl option is used)" else: all_opt["ipport"]["default"] = 23 if device_opt.count("secure") == 0: all_opt["ipport"]["help"] = "-u, --ipport=[port] TCP/UDP port to use (default 23)" else: all_opt["ipport"]["help"] = "-u, --ipport=[port] TCP/UDP port to use\n\ (default 23, 22 if --ssh option is used)" ## In special cases (show help, metadata or version) we don't need to check anything ##### if options.has_key("--help") or options.has_key("--version") or (options.has_key("--action") and options["--action"].lower() == "metadata"): return options options["--action"] = options["--action"].lower() if options.has_key("--verbose"): options["log"] = LOG_MODE_VERBOSE else: options["log"] = LOG_MODE_QUIET acceptable_actions = [ "on", "off", "status", "list", "monitor" ] if 1 == device_opt.count("fabric_fencing"): ## Compatibility layer ##### acceptable_actions.extend(["enable", "disable"]) else: acceptable_actions.extend(["reboot"]) if 0 == acceptable_actions.count(options["--action"]): fail_usage("Failed: Unrecognised action '" + options["--action"] + "'") ## Compatibility layer ##### if options["--action"] == "enable": options["--action"] = "on" if options["--action"] == "disable": options["--action"] = "off" ## automatic detection and set of valid UUID from --plug if (0 == options.has_key("--username")) and device_opt.count("login") and (device_opt.count("no_login") == 0): fail_usage("Failed: You have to set login name") if device_opt.count("ipaddr") and 0 == options.has_key("--ip") and 0 == options.has_key("--managed"): fail_usage("Failed: You have to enter fence address") if (device_opt.count("no_password") == 0): if 0 == device_opt.count("identity_file"): if 0 == (options.has_key("--password") or options.has_key("--password-script")): fail_usage("Failed: You have to enter password or password script") else: if 0 == (options.has_key("--password") or options.has_key("--password-script") or options.has_key("--identity-file")): fail_usage("Failed: You have to enter password, password script or identity file") if 0 == options.has_key("--ssh") and 1 == options.has_key("--identity-file"): fail_usage("Failed: You have to use identity file together with ssh connection (-x)") if 1 == options.has_key("--identity-file"): if 0 == os.path.isfile(options["--identity-file"]): fail_usage("Failed: Identity file " + options["--identity-file"] + " does not exist") if (0 == ["list", "monitor"].count(options["--action"].lower())) and \ 0 == options.has_key("--plug") and device_opt.count("port") and device_opt.count("no_port") == 0: fail_usage("Failed: You have to enter plug number or machine identification") if options.has_key("--password-script"): options["--password"] = os.popen(options["--password-script"]).read().rstrip() if options.has_key("--debug-file"): try: options["debug_fh"] = file (options["--debug-file"], "w") except IOError: fail_usage("Failed: Unable to create file " + options["--debug-file"]) if options.has_key("--verbose") and options.has_key("debug_fh") == 0: options["debug_fh"] = sys.stderr if options.has_key("--snmp-priv-passwd-script"): options["--snmp-priv-passwd"] = os.popen(options["--snmp-priv-passwd-script"]).read().rstrip() if options.has_key("--ipport") == False: if options.has_key("--ssh"): options["--ipport"] = 22 elif options.has_key("--ssl"): options["--ipport"] = 443 elif device_opt.count("web"): options["--ipport"] = 80 else: options["--ipport"] = 23 return options def wait_power_status(tn, options, get_power_fn): for dummy in xrange(int(options["--power-timeout"])): if get_multi_power_fn(tn, options, get_power_fn) != options["--action"]: time.sleep(1) else: return 1 return 0 ## Obtain a power status from possibly more than one plug ## "on" is returned if at least one plug is ON ###### def get_multi_power_fn(tn, options, get_power_fn): status = "off" if options.has_key("--plugs"): for plug in options["--plugs"]: try: options["--uuid"] = str(uuid.UUID(plug)) except ValueError: pass except KeyError: pass options["--plug"] = plug plug_status = get_power_fn(tn, options) if plug_status != "off": status = plug_status else: status = get_power_fn(tn, options) return status def set_multi_power_fn(tn, options, set_power_fn): if options.has_key("--plugs"): for plug in options["--plugs"]: try: options["--uuid"] = str(uuid.UUID(plug)) except ValueError: pass except KeyError: pass options["--plug"] = plug set_power_fn(tn, options) else: set_power_fn(tn, options) 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("--help"): usage(device_opt) sys.exit(0) if options.has_key("--action") and options["--action"].lower() == "metadata": metadata(device_opt, options, docs) sys.exit(0) if options.has_key("--version"): print __main__.RELEASE_VERSION, __main__.BUILD_DATE print __main__.REDHAT_COPYRIGHT sys.exit(0) def fence_action(tn, options, set_power_fn, get_power_fn, get_outlet_list = None): result = 0 try: if options.has_key("--plug"): options["--plugs"] = options["--plug"].split(",") ## Process options that manipulate fencing device ##### if (options["--action"] == "list") and 0 == options["device_opt"].count("port"): print "N/A" return elif (options["--action"] == "list" and get_outlet_list == None): ## @todo: exception? ## This is just temporal solution, we will remove default value ## None as soon as all existing agent will support this operation print "NOTICE: List option is not working on this device yet" return elif (options["--action"] == "list") or ((options["--action"] == "monitor") and 1 == options["device_opt"].count("port")): outlets = get_outlet_list(tn, options) ## keys can be numbers (port numbers) or strings (names of VM) for o in outlets.keys(): (alias, status) = outlets[o] if options["--action"] != "monitor": print o + options["--separator"] + alias return status = get_multi_power_fn(tn, options, get_power_fn) if status != "on" and status != "off": fail(EC_STATUS) if options["--action"] == "on": if status == "on": print "Success: Already ON" else: power_on = False for _ in range(1, 1 + int(options["--retry-on"])): set_multi_power_fn(tn, options, set_power_fn) time.sleep(int(options["--power-wait"])) if wait_power_status(tn, options, get_power_fn): power_on = True break if power_on: print "Success: Powered ON" else: fail(EC_WAITING_ON) elif options["--action"] == "off": if status == "off": print "Success: Already OFF" else: set_multi_power_fn(tn, options, set_power_fn) time.sleep(int(options["--power-wait"])) if wait_power_status(tn, options, get_power_fn): print "Success: Powered OFF" else: fail(EC_WAITING_OFF) elif options["--action"] == "reboot": if status != "off": options["--action"] = "off" set_multi_power_fn(tn, options, set_power_fn) time.sleep(int(options["--power-wait"])) if wait_power_status(tn, options, get_power_fn) == 0: fail(EC_WAITING_OFF) options["--action"] = "on" power_on = False try: for _ in range(1, 1 + int(options["--retry-on"])): set_multi_power_fn(tn, options, set_power_fn) time.sleep(int(options["--power-wait"])) if wait_power_status(tn, options, get_power_fn) == 1: power_on = True break except Exception, ex: # an error occured during power ON phase in reboot # fence action was completed succesfully even in that case sys.stderr.write(str(ex)) syslog.syslog(syslog.LOG_NOTICE, str(ex)) pass if power_on == False: # this should not fail as node was fenced succesfully sys.stderr.write('Timed out waiting to power ON\n') syslog.syslog(syslog.LOG_NOTICE, "Timed out waiting to power ON") print "Success: Rebooted" elif options["--action"] == "status": print "Status: " + status.upper() if status.upper() == "OFF": result = 2 elif options["--action"] == "monitor": pass except pexpect.EOF: fail(EC_CONNECTION_LOST) except pexpect.TIMEOUT: fail(EC_TIMED_OUT) except pycurl.error, ex: sys.stderr.write(ex[1] + "\n") syslog.syslog(syslog.LOG_ERR, ex[1]) fail(EC_TIMED_OUT) return result def fence_login(options, re_login_string = "(login\s*: )|(Login Name: )|(username: )|(User Name :)"): force_ipvx="" if (options.has_key("--inet6-only")): force_ipvx = "-6 " if (options.has_key("--inet4-only")): force_ipvx = "-4 " if (options.has_key("eol") == False): options["eol"] = "\r\n" if options.has_key("--command-prompt") and type(options["--command-prompt"]) is not list: options["--command-prompt"] = [ options["--command-prompt"] ] ## Do the delay of the fence device before logging in ## Delay is important for two-node clusters fencing but we do not need to delay 'status' operations if options["--action"] in ["off", "reboot"]: time.sleep(int(options["--delay"])) try: re_login = re.compile(re_login_string, re.IGNORECASE) re_pass = re.compile("(password)|(pass phrase)", re.IGNORECASE) if options.has_key("--ssl"): command = '%s %s %s %s' % (SSL_PATH, force_ipvx, options["--ip"], options["--ipport"]) try: conn = fspawn(options, command) except pexpect.ExceptionPexpect, ex: ## SSL telnet is part of the fencing package sys.stderr.write(str(ex) + "\n") syslog.syslog(syslog.LOG_ERR, str(ex)) sys.exit(EC_GENERIC_ERROR) elif options.has_key("--ssh") and 0 == options.has_key("--identity-file"): command = '%s %s %s@%s -p %s' % (SSH_PATH, force_ipvx, options["--username"], options["--ip"], options["--ipport"]) if options.has_key("--ssh-options"): command += ' ' + options["--ssh-options"] try: conn = fspawn(options, command) except pexpect.ExceptionPexpect, ex: sys.stderr.write(str(ex) + "\n") syslog.syslog(syslog.LOG_ERR, str(ex)) sys.stderr.write("Due to limitations, binary dependencies on fence agents " "are not in the spec file and must be installed separately." + "\n") sys.exit(EC_GENERIC_ERROR) if options.has_key("telnet_over_ssh"): #This is for stupid ssh servers (like ALOM) which behave more like telnet (ignore name and display login prompt) result = conn.log_expect(options, [ re_login, "Are you sure you want to continue connecting (yes/no)?" ], int(options["--login-timeout"])) if result == 1: conn.sendline("yes") # Host identity confirm conn.log_expect(options, re_login, int(options["--login-timeout"])) conn.sendline(options["--username"]) conn.log_expect(options, re_pass, int(options["--login-timeout"])) else: result = conn.log_expect(options, [ "ssword:", "Are you sure you want to continue connecting (yes/no)?" ], int(options["--login-timeout"])) if result == 1: conn.sendline("yes") conn.log_expect(options, "ssword:", int(options["--login-timeout"])) conn.sendline(options["--password"]) conn.log_expect(options, options["--command-prompt"], int(options["--login-timeout"])) elif options.has_key("--ssh") and options.has_key("--identity-file"): command = '%s %s %s@%s -i %s -p %s' % (SSH_PATH, force_ipvx, options["--username"], options["--ip"], options["--identity-file"], options["--ipport"]) if options.has_key("--ssh-options"): command += ' ' + options["--ssh-options"] try: conn = fspawn(options, command) except pexpect.ExceptionPexpect, ex: sys.stderr.write(str(ex) + "\n") syslog.syslog(syslog.LOG_ERR, str(ex)) sys.stderr.write("Due to limitations, binary dependencies on fence agents " "are not in the spec file and must be installed separately." + "\n") sys.exit(EC_GENERIC_ERROR) result = conn.log_expect(options, [ options["--command-prompt"], \ "Are you sure you want to continue connecting (yes/no)?", \ "Enter passphrase for key '" + options["--identity-file"] + "':" ], int(options["--login-timeout"])) if result == 1: conn.sendline("yes") conn.log_expect(options, [ options["--command-prompt"], "Enter passphrase for key '"+options["--identity-file"]+"':"] , int(options["--login-timeout"])) if result != 0: if options.has_key("--password"): conn.sendline(options["--password"]) conn.log_expect(options, options["--command-prompt"], int(options["--login-timeout"])) else: fail_usage("Failed: You have to enter passphrase (-p) for identity file") else: try: conn = fspawn(options, TELNET_PATH) conn.send("set binary\n") conn.send("open %s -%s\n"%(options["--ip"], options["--ipport"])) except pexpect.ExceptionPexpect, ex: sys.stderr.write(str(ex) + "\n") syslog.syslog(syslog.LOG_ERR, str(ex)) sys.stderr.write("Due to limitations, binary dependencies on fence agents " "are not in the spec file and must be installed separately." + "\n") sys.exit(EC_GENERIC_ERROR) result = conn.log_expect(options, re_login, int(options["--login-timeout"])) conn.send_eol(options["--username"]) ## automatically change end of line separator screen = conn.read_nonblocking(size=100, timeout=int(options["--shell-timeout"])) if (re_login.search(screen) != None): options["eol"] = "\n" conn.send_eol(options["--username"]) result = conn.log_expect(options, re_pass, int(options["--login-timeout"])) elif (re_pass.search(screen) == None): conn.log_expect(options, re_pass, int(options["--shell-timeout"])) try: conn.send_eol(options["--password"]) valid_password = conn.log_expect(options, [ re_login_string ] + options["--command-prompt"], int(options["--shell-timeout"])) if valid_password == 0: ## password is invalid or we have to change EOL separator options["eol"] = "\r" conn.send_eol("") conn.send_eol("") conn.send_eol(options["--username"]) conn.log_expect(options, re_pass, int(options["--login-timeout"])) conn.send_eol(options["--password"]) conn.log_expect(options, options["--command-prompt"], int(options["--login-timeout"])) except KeyError: fail(EC_PASSWORD_MISSING) except pexpect.EOF: fail(EC_LOGIN_DENIED) except pexpect.TIMEOUT: fail(EC_LOGIN_DENIED) return conn diff --git a/fence/agents/scsi/fence_scsi.pl b/fence/agents/scsi/fence_scsi.pl index 4e5cc964..2585f9e9 100644 --- a/fence/agents/scsi/fence_scsi.pl +++ b/fence/agents/scsi/fence_scsi.pl @@ -1,868 +1,868 @@ #!/usr/bin/perl use Cwd 'realpath'; use File::Basename; use File::Path; use Getopt::Std; use POSIX; #BEGIN_VERSION_GENERATION $RELEASE_VERSION=""; $REDHAT_COPYRIGHT=""; $BUILD_DATE=""; #END_VERSION_GENERATION my $ME = fileparse ($0, ".pl"); ################################################################################ sub log_debug ($) { my $time = strftime "%b %e %T", localtime; my ($msg) = @_; print STDOUT "$time $ME: [debug] $msg\n" unless defined ($opt_q); return; } sub log_error ($) { my $time = strftime "%b %e %T", localtime; my ($msg) = @_; print STDERR "$time $ME: [error] $msg\n" unless defined ($opt_q); exit (1); } sub do_action_on ($@) { my $self = (caller(0))[3]; my ($node_key, @devices) = @_; key_write ($node_key); foreach $dev (@devices) { log_error ("device $dev does not exist") if (! -e $dev); log_error ("device $dev is not a block device") if (! -b $dev); if (do_register_ignore ($node_key, $dev) != 0) { log_error ("failed to create registration (key=$node_key, device=$dev)"); } if (!get_reservation_key ($dev)) { if (do_reserve ($node_key, $dev) != 0) { if (!get_reservation_key ($dev)) { log_error ("failed to create reservation (key=$node_key, device=$dev)"); } } } } return; } sub do_action_off ($@) { my $self = (caller(0))[3]; my ($node_key, @devices) = @_; my $host_key = key_read (); if ($host_key eq $node_key) { log_error ($self); } foreach $dev (@devices) { log_error ("device $dev does not exist") if (! -e $dev); log_error ("device $dev is not a block device") if (! -b $dev); my @keys = grep { /^$node_key$/i } get_registration_keys ($dev); if (scalar (@keys) != 0) { do_preempt_abort ($host_key, $node_key, $dev); } } return; } sub do_action_status ($@) { my $self = (caller(0))[3]; my ($node_key, @devices) = @_; my $dev_count = 0; my $key_count = 0; foreach $dev (@devices) { log_error ("device $dev does not exist") if (! -e $dev); log_error ("device $dev is not a block device") if (! -b $dev); do_reset ($dev); my @keys = grep { /^$node_key$/i } get_registration_keys ($dev); if (scalar (@keys) != 0) { $dev_count++; } } if ($dev_count != 0) { exit (0); } else { exit (2); } } sub do_verify_on ($@) { my $self = (caller(0))[3]; my ($node_key, @devices) = @_; my $count = 0; for $dev (@devices) { my @keys = grep { /^$node_key$/i } get_registration_keys ($dev); ## check that our key is registered if (scalar (@keys) == 0) { log_debug ("failed to register key $node_key on device $dev"); $count++; next; } ## write dev to device file once registration is verified dev_write ($dev); ## check that a reservation exists if (!get_reservation_key ($dev)) { log_debug ("no reservation exists on device $dev"); $count++; } } if ($count != 0) { log_error ("$self: failed to verify $count devices"); } } sub do_verify_off ($@) { my $self = (caller(0))[3]; my ($node_key, @devices) = @_; my $count = 0; for $dev (@devices) { my @keys = grep { /^$node_key$/i } get_registration_keys ($dev); ## check that our key is not registered if (scalar (@keys) != 0) { log_debug ("failed to remove key $node_key from device $dev"); $count++; next; } ## check that a reservation exists if (!get_reservation_key ($dev)) { log_debug ("no reservation exists on device $dev"); $count++; } } if ($count != 0) { log_error ("$self: failed to verify $count devices"); } } sub do_register ($$$) { my $self = (caller(0))[3]; my ($host_key, $node_key, $dev) = @_; $dev = realpath ($dev); if (substr ($dev, 5) =~ /^dm/) { my @slaves = get_mpath_slaves ($dev); foreach (@slaves) { do_register ($node_key, $_); } return; } log_debug ("$self (host_key=$host_key, node_key=$node_key, dev=$dev)"); my $cmd; my $out; my $err; do_reset ($dev); $cmd = "sg_persist -n -o -G -K $host_key -S $node_key -d $dev"; $cmd .= " -Z" if (defined $opt_a); $out = qx { $cmd 2> /dev/null }; $err = ($?>>8); # if ($err != 0) { # log_error ("$self (err=$err)"); # } log_debug ("$self (err=$err)"); return ($err); } sub do_register_ignore ($$) { my $self = (caller(0))[3]; my ($node_key, $dev) = @_; $dev = realpath ($dev); if (substr ($dev, 5) =~ /^dm/) { my @slaves = get_mpath_slaves ($dev); foreach (@slaves) { do_register_ignore ($node_key, $_); } return; } log_debug ("$self (node_key=$node_key, dev=$dev)"); my $cmd; my $out; my $err; do_reset ($dev); $cmd = "sg_persist -n -o -I -S $node_key -d $dev"; $cmd .= " -Z" if (defined $opt_a); $out = qx { $cmd 2> /dev/null }; $err = ($?>>8); # if ($err != 0) { # log_error ("$self (err=$err)"); # } log_debug ("$self (err=$err)"); return ($err); } sub do_reserve ($$) { my $self = (caller(0))[3]; my ($host_key, $dev) = @_; log_debug ("$self (host_key=$host_key, dev=$dev)"); my $cmd = "sg_persist -n -o -R -T 5 -K $host_key -d $dev"; my $out = qx { $cmd 2> /dev/null }; my $err = ($?>>8); # if ($err != 0) { # log_error ("$self (err=$err)"); # } log_debug ("$self (err=$err)"); return ($err); } sub do_release ($$) { my $self = (caller(0))[3]; my ($host_key, $dev) = @_; log_debug ("$self (host_key=$host_key, dev=$dev)"); my $cmd = "sg_persist -n -o -L -T 5 -K $host_key -d $dev"; my $out = qx { $cmd 2> /dev/null }; my $err = ($?>>8); # if ($err != 0) { # log_error ("$self (err=$err)"); # } log_debug ("$self (err=$err)"); return ($err); } sub do_preempt ($$$) { my $self = (caller(0))[3]; my ($host_key, $node_key, $dev) = @_; log_debug ("$self (host_key=$host_key, node_key=$node_key, dev=$dev)"); my $cmd = "sg_persist -n -o -P -T 5 -K $host_key -S $node_key -d $dev"; my $out = qx { $cmd 2> /dev/null }; my $err = ($?>>8); # if ($err != 0) { # log_error ("$self (err=$err)"); # } log_debug ("$self (err=$err)"); return ($err); } sub do_preempt_abort ($$$) { my $self = (caller(0))[3]; my ($host_key, $node_key, $dev) = @_; log_debug ("$self (host_key=$host_key, node_key=$node_key, dev=$dev)"); my $cmd = "sg_persist -n -o -A -T 5 -K $host_key -S $node_key -d $dev"; my $out = qx { $cmd 2> /dev/null }; my $err = ($?>>8); # if ($err != 0) { # log_error ("$self (err=$err)"); # } log_debug ("$self (err=$err)"); return ($err); } sub do_reset (S) { my $self = (caller(0))[3]; my ($dev) = @_; my $cmd = "sg_turs $dev"; my @out = qx { $cmd 2> /dev/null }; my $err = ($?>>8); ## note that it is not necessarily an error is $err is non-zero, ## so just log the device and status and continue. log_debug ("$self (dev=$dev, status=$err)"); return ($err); } sub dev_unlink () { my $self = (caller(0))[3]; my $file = "/var/run/cluster/fence_scsi.dev"; if (-e $file) { unlink ($file) or die "$!\n"; } return; } sub dev_write ($) { my $self = (caller(0))[3]; my $file = "/var/run/cluster/fence_scsi.dev"; my $dev = shift; if (! -d "/var/run/cluster") { mkpath ("/var/run/cluster"); } open (\*FILE, "+>>$file") or die "$!\n"; ## since the file is opened for read, write and append, ## we need to seek to the beginning of the file before grep. seek (FILE, 0, 0); if (! grep { /^$dev$/ } ) { print FILE "$dev\n"; } close (FILE); return; } sub key_read () { my $self = (caller(0))[3]; my $file = "/var/run/cluster/fence_scsi.key"; my $key; open (\*FILE, "<$file") or die "$!\n"; chomp ($key = ); close (FILE); return ($key); } sub key_write ($) { my $self = (caller(0))[3]; my $file = "/var/run/cluster/fence_scsi.key"; my $key = shift; if (! -d "/var/run/cluster") { mkpath ("/var/run/cluster"); } open (\*FILE, ">$file") or die "$!\n"; print FILE "$key\n"; close (FILE); return; } sub get_key ($) { my $self = (caller(0))[3]; my $key = sprintf ("%.4x%.4x", get_cluster_id (), get_node_id ($_[0])); return ($key); } sub get_node_id ($) { my $self = (caller(0))[3]; my $node_id; my $cmd = "cman_tool nodes -n $_[0] -F id"; my $out = qx { $cmd 2> /dev/null }; my $err = ($?>>8); if ($err != 0) { log_error ("$self (err=$err)"); } # die "[error]: $self\n" if ($?>>8); chomp ($out); $node_id = $out; return ($node_id); } sub get_cluster_id () { my $self = (caller(0))[3]; my $cluster_id; my $cmd = "cman_tool status"; my @out = qx { $cmd 2> /dev/null }; my $err = ($?>>8); if ($err != 0) { log_error ("$self (err=$err)"); } # die "[error]: $self\n" if ($?>>8); foreach (@out) { chomp; my ($param, $value) = split (/\s*:\s*/, $_); if ($param =~ /^cluster\s+id/i) { $cluster_id = $value; } } return ($cluster_id); } sub get_devices_clvm () { my $self = (caller(0))[3]; my @devices; my $cmd = "vgs --noheadings " . " --separator : " . " --sort pv_uuid " . " --options vg_attr,pv_name " . " --config 'global { locking_type = 0 } " . " devices { preferred_names = [ \"^/dev/dm\" ] }'"; my @out = qx { $cmd 2> /dev/null }; my $err = ($?>>8); if ($err != 0) { log_error ("$self (err=$err)"); } # die "[error]: $self\n" if ($?>>8); foreach (@out) { chomp; my ($vg_attr, $pv_name) = split (/:/, $_); if ($vg_attr =~ /c$/) { push (@devices, $pv_name); } } return (@devices); } sub get_devices_scsi () { my $self = (caller(0))[3]; my @devices; opendir (\*DIR, "/sys/block/") or die "$!\n"; @devices = grep { /^sd/ } readdir (DIR); closedir (DIR); return (@devices); } sub get_mpath_name ($) { my $self = (caller(0))[3]; my ($dev) = @_; my $name; if ($dev =~ /^\/dev\//) { $dev = substr ($dev, 5); } open (\*FILE, "/sys/block/$dev/dm/name") or die "$!\n"; chomp ($name = ); close (FILE); return ($name); } sub get_mpath_uuid ($) { my $self = (caller(0))[3]; my ($dev) = @_; my $uuid; if ($dev =~ /^\/dev\//) { $dev = substr ($dev, 5); } open (\*FILE, "/sys/block/$dev/dm/uuid") or die "$!\n"; chomp ($uuid = ); close (FILE); return ($name); } sub get_mpath_slaves ($) { my $self = (caller(0))[3]; my ($dev) = @_; my @slaves; if ($dev =~ /^\/dev\//) { $dev = substr ($dev, 5); } opendir (\*DIR, "/sys/block/$dev/slaves/") or die "$!\n"; @slaves = grep { !/^\./ } readdir (DIR); if ($slaves[0] =~ /^dm/) { @slaves = get_mpath_slaves ($slaves[0]); } else { @slaves = map { "/dev/$_" } @slaves; } closedir (DIR); return (@slaves); } sub get_registration_keys ($) { my $self = (caller(0))[3]; my ($dev) = @_; my @keys; my $cmd = "sg_persist -n -i -k -d $dev"; my @out = qx { $cmd 2> /dev/null }; my $err = ($?>>8); if ($err != 0) { log_error ("$self (err=$err)"); } # die "[error]: $self\n" if ($?>>8); foreach (@out) { chomp; if ($_ =~ s/^\s+0x//i) { push (@keys, $_); } } return (@keys); } sub get_reservation_key ($) { my $self = (caller(0))[3]; my ($dev) = @_; my $key; my $cmd = "sg_persist -n -i -r -d $dev"; my @out = qx { $cmd 2> /dev/null }; my $err = ($?>>8); if ($err != 0) { log_error ("$self (err=$err)"); } # die "[error]: $self\n" if ($?>>8); foreach (@out) { chomp; if ($_ =~ s/^\s+key=0x//i) { $key = $_; last; } } return ($key) } sub get_options_stdin () { my $num = 0; while () { chomp; s/^\s*//; s/\s*$//; next if (/^#/); $num++; next unless ($_); my ($opt, $arg) = split (/\s*=\s*/, $_); if ($opt eq "") { exit (1); } elsif ($opt eq "aptpl") { $opt_a = $arg; } elsif ($opt eq "devices") { $opt_d = $arg; } elsif ($opt eq "logfile") { $opt_f = $arg; } elsif ($opt eq "key") { $opt_k = $arg; } elsif ($opt eq "nodename") { $opt_n = $arg; } elsif ($opt eq "action") { $opt_o = $arg; } elsif ($opt eq "delay") { $opt_H = $arg; } } } sub print_usage () { print "Usage:\n"; print "\n"; print "$ME [options]\n"; print "\n"; print "Options:\n"; print " -a Use APTPL flag\n"; print " -d Devices to be used for action\n"; print " -f File to write debug/error output\n"; print " -H Wait X seconds before fencing is started\n"; print " -h Usage\n"; print " -k Key to be used for current action\n"; print " -n Name of node to operate on\n"; print " -o Action: off (default), on, or status\n"; print " -q Quiet mode\n"; print " -V Version\n"; exit (0); } sub print_version () { print "$ME $RELEASE_VERSION $BUILD_DATE\n"; print "$REDHAT_COPYRIGHT\n" if ( $REDHAT_COPYRIGHT ); exit (0); } sub print_metadata () { print "\n"; print "\n"; print "fence_scsi\n"; print "\n"; print "\t\n"; print "\t\t\n"; print "\t\t\n"; print "\t\t" . "Use APTPL flag for registrations" . "\n"; print "\t\n"; print "\t\n"; print "\t\t\n"; print "\t\t\n"; print "\t\t" . "List of devices to be used for fencing action" . "\n"; print "\t\n"; print "\t\n"; print "\t\t\n"; print "\t\t\n"; print "\t\t" . "File to write error/debug messages" . "\n"; print "\t\n"; print "\t\n"; print "\t\t\n"; print "\t\t\n"; print "\t\t" . "Wait X seconds before fencing is started" . "\n"; print "\t\n"; print "\t\n"; print "\t\t\n"; print "\t\t\n"; print "\t\t" . "Key value to be used for fencing action" . "\n"; print "\t\n"; print "\t\n"; print "\t\t\n"; print "\t\t\n"; print "\t\t" . "Fencing action" . "\n"; print "\t\n"; print "\t\n"; print "\t\t\n"; print "\t\t\n"; print "\t\t" . "Name of node" . "\n"; print "\t\n"; print "\n"; print "\n"; - print "\t\n"; + print "\t\n"; print "\t\n"; print "\t\n"; print "\t\n"; print "\n"; print "\n"; exit (0); } ################################################################################ if (@ARGV > 0) { getopts ("ad:f:H:hk:n:o:qV") or print_usage; print_usage if (defined $opt_h); print_version if (defined $opt_V); } else { get_options_stdin (); } ## handle the metadata action here to avoid other parameter checks ## if ($opt_o =~ /^metadata$/i) { print_metadata; } ## if the logfile (-f) parameter was specified, open the logfile ## and redirect STDOUT and STDERR to the logfile. ## if (defined $opt_f) { open (LOG, ">>$opt_f") or die "$!\n"; open (STDOUT, ">&LOG"); open (STDERR, ">&LOG"); } ## verify that either key or nodename have been specified ## if ((!defined $opt_n) && (!defined $opt_k)) { print_usage (); } ## determine key value ## if (defined $opt_k) { $key = $opt_k; } else { $key = get_key ($opt_n); } ## verify that key is not zero ## if (hex($key) == 0) { log_error ("key cannot be zero"); } ## remove any leading zeros from key ## if ($key =~ /^0/) { $key =~ s/^0+//; } ## get devices ## if (defined $opt_d) { @devices = split (/\s*,\s*/, $opt_d); } else { @devices = get_devices_clvm (); } ## verify that device list is not empty ## if (scalar (@devices) == 0) { log_error ("no devices found"); } ## default action is "off" ## if (!defined $opt_o) { $opt_o = "off"; } ## Wait for defined period (-H / delay= ) ## if ((defined $opt_H) && ($opt_H =~ /^[0-9]+/)) { sleep($opt_H); } ## determine the action to perform ## if ($opt_o =~ /^on$/i) { do_action_on ($key, @devices); do_verify_on ($key, @devices); } elsif ($opt_o =~ /^off$/i) { do_action_off ($key, @devices); do_verify_off ($key, @devices); } elsif ($opt_o =~ /^status/i) { do_action_status ($key, @devices); } else { log_error ("unknown action '$opt_o'"); exit (1); } ## close the logfile ## if (defined $opt_f) { close (LOG); }