From mboxrd@z Thu Jan 1 00:00:00 1970 From: Marek Grac Date: Mon, 05 May 2014 10:22:33 +0200 Subject: [Cluster-devel] [PATCH] fence_dli_pc8000: introduce dli_pc8000 fence agent In-Reply-To: <1397570822-26228-1-git-send-email-andreavb@linux.vnet.ibm.com> References: <1397570822-26228-1-git-send-email-andreavb@linux.vnet.ibm.com> Message-ID: <53674A49.4090903@redhat.com> List-Id: To: cluster-devel.redhat.com MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit 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 > Signed-off-by: Eduardo Kienetz > Signed-off-by: Nathan Ozelim > Signed-off-by: Plinio Freire > --- > 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 " % program > + action = "" > + 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: