From: Marek Grac <mgrac@redhat.com>
To: cluster-devel.redhat.com
Subject: [Cluster-devel] [PATCH] fence_dli_pc8000: introduce dli_pc8000 fence agent
Date: Mon, 05 May 2014 10:22:33 +0200 [thread overview]
Message-ID: <53674A49.4090903@redhat.com> (raw)
In-Reply-To: <1397570822-26228-1-git-send-email-andreavb@linux.vnet.ibm.com>
Hi,
I have done review of that fence agent and it looks almost fine. I have
prepared a patch that have to be tested (and finished) as I do not have
access to such device.
There were two main issues: documentation (show_docs() used for XML
metadata / manual pages) and do_action() that I replaced by
fence_action. The later change was bigger one. Using that standard
function instead of non-generic one, is perhaps a liitle bit hacky but
all timetouts and sleeps works as expected. Please take a look and
finish proposed patch.
m,
On 04/15/2014 04:07 PM, Andrea Bucci wrote:
> dli-pc8000 is a fence-agent to Digital Loggers Inc's Ethernet Power Controller III (http://www.digital-loggers.com/epcr3.html)
> Based on 2007 Perl code by Andy Whitcroft
>
> Signed-off-by: Alan Evangelista <alanoe@linux.vnet.ibm.com>
> Signed-off-by: Eduardo Kienetz <ebacchi@linux.vnet.ibm.com>
> Signed-off-by: Nathan Ozelim <natoze@linux.vnet.ibm.com>
> Signed-off-by: Plinio Freire <pleirie@linux.vnet.ibm.com>
> ---
> configure.ac | 1 +
> fence/agents/dli_pc8000/Makefile.am | 16 ++
> fence/agents/dli_pc8000/fence_dli_pc8000.py | 233 +++++++++++++++++++++++++++
> 3 files changed, 250 insertions(+)
> create mode 100644 fence/agents/dli_pc8000/Makefile.am
> create mode 100755 fence/agents/dli_pc8000/fence_dli_pc8000.py
>
> diff --git a/configure.ac b/configure.ac
> index c24198c..51f86be 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -260,6 +260,7 @@ AC_CONFIG_FILES([Makefile
> fence/agents/cisco_mds/Makefile
> fence/agents/cisco_ucs/Makefile
> fence/agents/cpint/Makefile
> + fence/agents/dli_pc8000/Makefile
> fence/agents/drac/Makefile
> fence/agents/drac5/Makefile
> fence/agents/dummy/Makefile
> diff --git a/fence/agents/dli_pc8000/Makefile.am b/fence/agents/dli_pc8000/Makefile.am
> new file mode 100644
> index 0000000..ce92b6f
> --- /dev/null
> +++ b/fence/agents/dli_pc8000/Makefile.am
> @@ -0,0 +1,16 @@
> +MAINTAINERCLEANFILES = Makefile.in
> +
> +TARGET = fence_dli_pc8000
> +
> +SRC = $(TARGET).py
> +
> +EXTRA_DIST = $(SRC)
> +
> +sbin_SCRIPTS = $(TARGET)
> +
> +include $(top_srcdir)/make/fencebuild.mk
> +include $(top_srcdir)/make/fenceman.mk
> +
> +clean-local: clean-man
> + rm -f $(TARGET)
> +
> diff --git a/fence/agents/dli_pc8000/fence_dli_pc8000.py b/fence/agents/dli_pc8000/fence_dli_pc8000.py
> new file mode 100755
> index 0000000..8e2ab7c
> --- /dev/null
> +++ b/fence/agents/dli_pc8000/fence_dli_pc8000.py
> @@ -0,0 +1,233 @@
> +#!/usr/bin/python
> +
> +"""
> +Connect to dli-pc8000 remote management module via http and perform power
> +management operations.
> +"""
> +
> +import base64
> +import sys
> +import urllib2
> +
> +sys.path.append("/usr/share/fence")
> +from fencing import *
> +
> +def http_get_file(server, credentials, filename):
> + """
> + Authenticate to server and gets file
> +
> + @param string server server IP address
> + @param string credentials base64 built string with username and password
> + @param string filename name of the file to be read
> + @return tuple http status code and content/error reason
> + """
> +
> + request = urllib2.Request("http://" + server + filename)
> + request.add_header("Authorization", "Basic %s" % credentials)
> +
> + try:
> + response = urllib2.urlopen(request)
> + content = response.read()
> + return response.code, content.strip()
> + except urllib2.HTTPError, e:
> + return e.code, e.reason
> + except urllib2.URLError, e:
> + return -1, e.reason
> +
> +
> +def check_status(program, ip, credentials, port):
> + """
> + Verify if port is up and checks the url format
> +
> + @param string program program name
> + @param string ip server IP address
> + @param string credentials base64 built string with username and password
> + @param string port Port number to be tested/changed
> + @return tuple status of the port and url format
> + """
> +
> + http_code, response_body = http_get_file(ip, credentials, '/')
> +
> + if http_code != 200:
> + print "Error trying to access %s. Error is: '%s'" % (ip, response_body)
> + return "INVALID", None
> +
> + # outlet control page not found: get the new one and try again
> + if not response_body or "URL=/" in response_body:
> + prefix = "URL="
> + sufix = "\">"
> + start = response_body.index(prefix) + len(prefix)
> + end = response_body.index(sufix, start)
> + url = response_body[start:end]
> + http_code, response_body = http_get_file(ip, credentials, url)
> +
> + # outlet control page still not found: unable to proceed
> + if not response_body:
> + print "%s: unable to retrieve HTTP root from %s\n" % (program, ip)
> + return "INVALID", None
> +
> + # check both new and old url formats
> + new_string = "outlet?%s=" % port
> + old_string_on = "outletoff%s=" % port
> + old_string_off = "outleton%s=" % port
> +
> + # test if port is present and url format
> + if new_string in response_body:
> + prefix = new_string
> + link_type = "new"
> + elif old_string_on in response_body:
> + prefix = old_string_on
> + link_type = "old"
> + elif old_string_off in response_body:
> + prefix = old_string_off
> + link_type = "old"
> + else:
> + return "INVALID", None
> +
> + # get status if port if valid
> + sufix = ">Switch"
> + start = response_body.index(prefix) + len(prefix)
> + end = response_body.index(sufix, start)
> + control_table = response_body[start:end]
> +
> + # found string "Switch ON": status is OFF
> + if "ON" in control_table:
> + status = "OFF"
> + # found string "Switch OFF": status is ON
> + elif "OFF" in control_table:
> + status = "ON"
> + # found something else: status is INVALID
> + else:
> + status = "INVALID"
> +
> + return status, link_type
> +
> +
> +def get_commands_urls(program, port, link_type):
> + """
> + Build available command urls
> +
> + @param string program program name
> + @param string port port number
> + @param string link_type if link_type is old or new
> + @return triple composed strings off_cmd, on_cmd, cycle_cmd
> + """
> +
> + # compose the power management commands urls
> + if link_type == "old":
> + off_cmd = "/outletoff?%s" % port
> + on_cmd = "/outleton?%s" % port
> + cycle_cmd = "/outletccl?%s" % port
> + else:
> + off_cmd = "/outlet?%s=OFF" % port
> + on_cmd = "/outlet?%s=ON" % port
> + cycle_cmd = "/outlet?%s=CCL" % port
> +
> + return off_cmd, on_cmd, cycle_cmd
> +
> +
> +def do_action(program, ip, port, on_cmd, off_cmd, cycle_cmd, is_on, action):
> + """
> + Perform power command on system
> +
> + @param string program program name
> + @param string ip server IP address
> + @param string port port number
> + @param string on_cmd command to power system on
> + @param string off_cmd command to power system off
> + @param string cycle_cmd command to power system off and on again
> + @param string status if system is ON or OFF
> + @param string action action to be performed
> + """
> +
> + # action is not recognized
> + if action not in ("on", "off", "reboot"):
> + print "%s: %s:%s: Invalid action '%s'\n" % (program, ip, port, action)
> + return
> +
> + # system is off, requested action is turning it off
> + if not is_on and action == "off":
> + return
> +
> + # system is on, requested action is turning it on
> + if is_on and action == "on":
> + return
> +
> + # system is on, requested action is turning it off
> + if is_on and action == "off":
> + print "%s: %s:%s: outlet ON, switching OFF ... %s\n" \
> + % (program, ip, port, off_cmd)
> + status = http_get_file(ip, credentials, off_cmd)
> +
> + # system is off, requested action is turning it on
> + if not is_on and action == "on":
> + print "%s: %s:%s: switching ON ... %s\n" % (program, ip, port, on_cmd)
> + status = http_get_file(ip, credentials, on_cmd)
> +
> + # requested action is restarting it
> + if action == "reboot":
> + # Port is on, switch it off and on
> + if is_on:
> + print "%s: %s:%s: switching OFF and then ON ... %s\n" \
> + % (program, ip, port, cycle_cmd)
> + status = http_get_file(ip, credentials, cycle_cmd)
> + # Port is off, switch it on
> + else:
> + message_header = "%s: %s:%s:" % (program, ip, port)
> + print "%s switching ON... %s\n" % (message_header, cycle_cmd)
> + status = http_get_file(ip, credentials, on_cmd)
> +
> + print "%s: %s:%s: action '%s' complete\n" % (program, ip, port, action)
> +
> +
> +def usage(program):
> + """
> + Displays usage
> +
> + @param string program program name
> + """
> +
> + message_header = "Usage: %s <ip> <port> <username> <password>" % program
> + action = "<action: on|off|reboot>"
> + print "%s %s \n" % (message_header, action)
> +
> +
> +# program name
> +program = sys.argv[0]
> +
> +device_opt = [ "ipaddr", "login", "passwd", "ipport" ]
> +options = check_input(device_opt, process_input(device_opt))
> +
> +action = options['--action']
> +login = options['--username']
> +passwd = options['--password']
> +ipaddr = options['--ip']
> +port = options['--ipport']
> +
> +# build the authentication string
> +credentials = base64.encodestring('%s:%s' % (login, passwd)).strip()
> +
> +print "%s: %s:%s: checking port status\n" % (program, ipaddr, port)
> +
> +# get the status of the port and link_type
> +port_status, link_type = check_status(program, ipaddr, credentials, port)
> +
> +# port is not found: exit dli-pc8000
> +if port_status == "INVALID":
> + print "%s: %s: port not found." % (program, port)
> + sys.exit(1)
> +
> +if action == "status":
> + print "System status is %s" % (port_status)
> + sys.exit(1)
> +
> +message_header = "%s: %s:%s:" % (program, ipaddr, port)
> +print "%s port found, attempting action '%s'\n" % (message_header, action)
> +
> +# get urls of available commands
> +off_cmd, on_cmd, cycle_cmd = get_commands_urls(program, port, link_type)
> +
> +is_system_on = True if port_status == "ON" else False
> +
> +# switch port on/off
> +do_action(program, ipaddr, port, on_cmd, off_cmd, cycle_cmd, is_system_on, action)
-------------- next part --------------
A non-text attachment was scrubbed...
Name: dli_pc8000_adaptation.patch
Type: text/x-patch
Size: 8344 bytes
Desc: not available
URL: <http://listman.redhat.com/archives/cluster-devel/attachments/20140505/0a16a431/attachment.bin>
prev parent reply other threads:[~2014-05-05 8:22 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-04-15 14:07 [Cluster-devel] [PATCH] fence_dli_pc8000: introduce dli_pc8000 fence agent Andrea Bucci
2014-05-05 8:22 ` Marek Grac [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=53674A49.4090903@redhat.com \
--to=mgrac@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.