Hello. Description for suggested patches: fence_virsh: I believe the uuid support is a good idea, cuz every spawned VM would have an UUID in its dmidecode, equal to its `virsh domuuid`. Thus, to fence it, we should not either know the domain name, nor query libvirt to find it out.
fence_apc: As I can see from my research activities, fence_apc is quite a vendor specific agent, thus it would require custom options for command-prompt as well as ssh-options. -- Best regards, Bogdan Dobrelya, Researcher TechLead, Mirantis, Inc. +38 (066) 051 07 53 Skype bogdando_at_yahoo.com 38, Lenina ave. Kharkov, Ukraine www.mirantis.com www.mirantis.ru bdobre...@mirantis.com
From d95896825c89085b7d516547406454b7b21ffc17 Mon Sep 17 00:00:00 2001 From: Bogdan Dobrelya <bogda...@mail.ru> Date: Tue, 10 Dec 2013 14:32:26 +0200 Subject: [PATCH 1/2] Add uuid support for fence_virsh Signed-off-by: Bogdan Dobrelya <bogda...@mail.ru> --- fence/agents/virsh/fence_virsh.py | 89 +++++++++++++++++++++++++++++++++---- 1 file changed, 80 insertions(+), 9 deletions(-) diff --git a/fence/agents/virsh/fence_virsh.py b/fence/agents/virsh/fence_virsh.py index 13099da..80242ab 100644 --- a/fence/agents/virsh/fence_virsh.py +++ b/fence/agents/virsh/fence_virsh.py @@ -3,6 +3,7 @@ # The Following Agent Has Been Tested On: # # Virsh 0.3.3 on RHEL 5.2 with xen-3.0.3-51 +# Virsh 0.9.13,0.10.2 on Ubuntu 12.10 with qemu-kvm-1.2.0 # import sys, re, pexpect, exceptions @@ -13,11 +14,15 @@ from fencing import * RELEASE_VERSION="Virsh fence agent" REDHAT_COPYRIGHT="" BUILD_DATE="" +UUID_PATTERN=r"^\w{8}-\w{4}-\w{4}-\w{4}-\w{12}$" +STATE_PATTERN=r"^(\b\w+)\s?(\b\w+)?$" #END_VERSION_GENERATION def get_outlets_status(conn, options): - try: - conn.sendline("virsh list --all") + if options.has_key("-n"): + try: + #Restrict virsh list by header and by matched domain name only (if any), assumes it would be unique + conn.sendline("virsh list --all|awk '/Name|%s/'"%(options["-n"])) conn.log_expect(options, options["-c"], int(options["-Y"])) except pexpect.EOF: fail(EC_CONNECTION_LOST) @@ -38,32 +43,98 @@ def get_outlets_status(conn, options): elif (fa_status==1): result[domain.group(2)]=("",(domain.group(3).lower() in ["running","blocked","idle","no state","paused"] and "on" or "off")) return result + elif options.has_key("-U"): + return get_outlets_status_by_uuid(conn, options) + else: # other cases , f.e. action list + try: + conn.sendline("virsh list --all") + conn.log_expect(options, options["-c"], int(options["-Y"])) + except pexpect.EOF: + fail(EC_CONNECTION_LOST) + except pexpect.TIMEOUT: + fail(EC_TIMED_OUT) + + result={} + + #This is status of mini finite automata. 0 = we didn't found Id and Name, 1 = we did + fa_status=0 + + for line in conn.before.splitlines(): + domain=re.search("^\s*(\S+)\s+(\S+)\s+(\S+).*$",line) + if (domain!=None): + if ((fa_status==0) and (domain.group(1).lower()=="id") and (domain.group(2).lower()=="name")): + fa_status=1 + elif (fa_status==1): + result[domain.group(2)]=("",(domain.group(3).lower() in ["running","blocked","idle","no state","paused"] and "on" or "off")) + return result + +#Do the same as get_outlets_status, but using -U <uuid> option +def get_outlets_status_by_uuid(conn, options): + try: + #Restrict virsh list by matched domain uuid only (if any), assumes it would be unique + conn.sendline("virsh list --all --uuid|awk '/%s/'"%(options["-U"].lower())) + conn.log_expect(options, options["-c"], int(options["-Y"])) + except pexpect.EOF: + fail(EC_CONNECTION_LOST) + except pexpect.TIMEOUT: + fail(EC_TIMED_OUT) + + result={} + + for line in conn.before.splitlines(): + uuid=re.search(UUID_PATTERN,line) + if (uuid!=None): + result[uuid.group().lower()]=("",get_domstate(conn,options,uuid.group().lower()).lower() in ["running","blocked","idle","no state","paused"] and "on" or "off") + return result + +#Get virsh domstate by uuid +def get_domstate(conn, options, uuid): + try: + conn.sendline("virsh domstate %s"%(uuid)) + conn.log_expect(options, options["-c"], int(options["-Y"])) + except pexpect.EOF: + fail(EC_CONNECTION_LOST) + except pexpect.TIMEOUT: + fail(EC_TIMED_OUT) + + for line in conn.before.splitlines(): + #Search for domain state + state=re.search(STATE_PATTERN,line) + if (state!=None): + return state.group() + +#Return domain name/port, if -n was specified, otherwise assume -U was used instead and return domain uuid. +def get_name_or_uuid(options): + if options.has_key("-n"): + return options["-n"] + else: + return options["-U"].lower() def get_power_status(conn, options): outlets=get_outlets_status(conn,options) - - if (not (options["-n"] in outlets)): - fail_usage("Failed: You have to enter existing name of virtual machine!") + if (not (get_name_or_uuid(options) in outlets)): + fail_usage("Failed: You have to enter existing name/uuid of virtual machine!") else: - return outlets[options["-n"]][1] + return outlets[get_name_or_uuid(options)][1] def set_power_status(conn, options): try: - conn.sendline("virsh %s "%(options["-o"] == "on" and "start" or "destroy")+options["-n"]) + conn.sendline("virsh %s "%(options["-o"] == "on" and "start" or "destroy")+get_name_or_uuid(options)) conn.log_expect(options, options["-c"], int(options["-g"])) - time.sleep(1) + time.sleep(int(options["-G"])) except pexpect.EOF: fail(EC_CONNECTION_LOST) except pexpect.TIMEOUT: fail(EC_TIMED_OUT) +# Add uuid support def main(): device_opt = [ "help", "version", "agent", "quiet", "verbose", "debug", "action", "ipaddr", "login", "passwd", "passwd_script", "secure", "identity_file", "test", "port", "separator", - "inet4_only", "inet6_only", "ipport", + "inet4_only", "inet6_only", "ipport", "uuid", "power_timeout", "shell_timeout", "login_timeout", "power_wait" ] atexit.register(atexit_handler) -- 1.7.10.4
From 199b1374e0d6fcd70e0275ad6ecd0af2271293b3 Mon Sep 17 00:00:00 2001 From: Bogdan Dobrelya <bogda...@mail.ru> Date: Mon, 9 Dec 2013 19:16:56 +0200 Subject: [PATCH 2/2] Add command_prompt, ssh-options to fence_apc Signed-off-by: Bogdan Dobrelya <bogda...@mail.ru> Conflicts: usr/sbin/fence_apc Signed-off-by: Bogdan Dobrelya <bogda...@mail.ru> Conflicts: README.md Signed-off-by: Bogdan Dobrelya <bogda...@mail.ru> --- fence/agents/apc/fence_apc.py | 7 ++++--- fence/agents/lib/fencing.py.py | 7 +++++++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/fence/agents/apc/fence_apc.py b/fence/agents/apc/fence_apc.py index 78e709f..cf56a65 100644 --- a/fence/agents/apc/fence_apc.py +++ b/fence/agents/apc/fence_apc.py @@ -218,18 +218,19 @@ def main(): device_opt = [ "help", "version", "agent", "quiet", "verbose", "debug", "action", "ipaddr", "login", "passwd", "passwd_script", "secure", "port", "identity_file", "switch", "test", "separator", - "inet4_only", "inet6_only", "ipport", "cmd_prompt", + "inet4_only", "inet6_only", "ipport", "cmd_prompt", "ssh_options", "power_timeout", "shell_timeout", "login_timeout", "power_wait" ] atexit.register(atexit_handler) - all_opt["cmd_prompt"]["default"] = [ "\n>", "\napc>" ] + all_opt["cmd_prompt"]["default"] = [ "\n>", "\napc>" ] + all_opt["ssh_options"]["default"] = "-1 -c blowfish" + options = check_input(device_opt, process_input(device_opt)) ## ## Fence agent specific defaults ##### - options["ssh_options"] = "-1 -c blowfish" docs = { } docs["shortdesc"] = "Fence agent for APC over telnet/ssh" diff --git a/fence/agents/lib/fencing.py.py b/fence/agents/lib/fencing.py.py index 1de9a15..a7f1548 100644 --- a/fence/agents/lib/fencing.py.py +++ b/fence/agents/lib/fencing.py.py @@ -189,6 +189,13 @@ all_opt = { "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", -- 1.7.10.4