[Cluster-devel] [PATCH] fencing: fix parsing issue with options which don't have short opt
There was problem with options which have value, but we don't want short opt for them. In this case we can now use getopt = :. --- fence/agents/lib/fencing.py.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fence/agents/lib/fencing.py.py b/fence/agents/lib/fencing.py.py index 5084f24..2cfa046 100644 --- a/fence/agents/lib/fencing.py.py +++ b/fence/agents/lib/fencing.py.py @@ -559,7 +559,8 @@ def process_input(avail_opt): getopt_string = longopt_list = [] for k in avail_opt: - if all_opt.has_key(k): + if all_opt.has_key(k) and all_opt[k][getopt] != :: + # getopt == : means that opt is without short getopt, but has value getopt_string += all_opt[k][getopt] else: fail_usage(Parse error: unknown option '+k+') -- 1.8.3.1
Re: [Cluster-devel] [PATCH] fence_docker: new fence agent for Docker containers
With support for TLS authentication. --- .gitignore | 1 + configure.ac | 1 + fence/agents/docker/Makefile.am | 20 + fence/agents/docker/fence_docker.py | 152 +++ tests/data/metadata/fence_docker.xml | 129 + 5 files changed, 303 insertions(+) create mode 100644 fence/agents/docker/Makefile.am create mode 100644 fence/agents/docker/fence_docker.py create mode 100644 tests/data/metadata/fence_docker.xml diff --git a/.gitignore b/.gitignore index 75b9aa7..8bcae2b 100644 --- a/.gitignore +++ b/.gitignore @@ -39,6 +39,7 @@ fence/agents/bullpap/fence_bullpap fence/agents/cisco_mds/fence_cisco_mds fence/agents/cisco_ucs/fence_cisco_ucs fence/agents/cpint/fence_cpint +fence/agents/docker/fence_docker fence/agents/drac/fence_drac fence/agents/drac5/fence_drac5 fence/agents/eaton_snmp/fence_eaton_snmp diff --git a/configure.ac b/configure.ac index 4d0aa6a..bc9785b 100644 --- a/configure.ac +++ b/configure.ac @@ -264,6 +264,7 @@ AC_CONFIG_FILES([Makefile fence/agents/brocade/Makefile fence/agents/cisco_mds/Makefile fence/agents/cisco_ucs/Makefile +fence/agents/docker/Makefile fence/agents/drac/Makefile fence/agents/drac5/Makefile fence/agents/dummy/Makefile diff --git a/fence/agents/docker/Makefile.am b/fence/agents/docker/Makefile.am new file mode 100644 index 000..a232902 --- /dev/null +++ b/fence/agents/docker/Makefile.am @@ -0,0 +1,20 @@ +MAINTAINERCLEANFILES = Makefile.in + +TARGET = fence_docker + +SRC= $(TARGET).py + +EXTRA_DIST = $(SRC) + +sbin_SCRIPTS = $(TARGET) + +man_MANS = $(TARGET).8 + +FENCE_TEST_ARGS= -a test -n 1 + +include $(top_srcdir)/make/fencebuild.mk +include $(top_srcdir)/make/fenceman.mk +include $(top_srcdir)/make/agentpycheck.mk + +clean-local: clean-man + rm -f $(TARGET) diff --git a/fence/agents/docker/fence_docker.py b/fence/agents/docker/fence_docker.py new file mode 100644 index 000..7363611 --- /dev/null +++ b/fence/agents/docker/fence_docker.py @@ -0,0 +1,152 @@ +#!/usr/bin/python -tt + +import atexit +import sys +import StringIO +import logging +import pycurl +import json + +sys.path.append(@FENCEAGENTSLIBDIR@) +from fencing import fail_usage, all_opt, fence_action, atexit_handler, check_input, process_input, show_docs, run_delay + +#BEGIN_VERSION_GENERATION +RELEASE_VERSION = +REDHAT_COPYRIGHT = +BUILD_DATE = +#END_VERSION_GENERATION + +def get_power_status(conn, options): + del conn + status = send_cmd(options, containers/%s/json % options[--plug]) + if status is None: + return None + return on if status[State][Running] else off + + +def set_power_status(conn, options): + del conn + if options[--action] == on: + send_cmd(options, containers/%s/start % options[--plug], True) + else: + send_cmd(options, containers/%s/kill % options[--plug], True) + return + + +def reboot_cycle(conn, options): + del conn + send_cmd(options, containers/%s/restart % options[--plug], True) + return get_power_status(conn, options) + + +def get_list(conn, options): + del conn + output = send_cmd(options, containers/json?all=1) + containers = {} + for container in output: + containers[container[Id]] = (container[Names][0], {True:off, False: on}[container[Status][:4].lower() == exit]) + return containers + + +def send_cmd(options, cmd, post = False): + url = http%s://%s:%s/v1.11/%s % (s if --ssl in options else , options[--ip], options[--ipport], cmd) + conn = pycurl.Curl() + output_buffer = StringIO.StringIO() + if logging.getLogger().getEffectiveLevel() logging.WARNING: + conn.setopt(pycurl.VERBOSE, True) + conn.setopt(pycurl.HTTPGET, 1) + conn.setopt(pycurl.URL, str(url)) + if post: + conn.setopt(pycurl.POST, 1) + conn.setopt(pycurl.POSTFIELDSIZE, 0) + conn.setopt(pycurl.WRITEFUNCTION, output_buffer.write) + conn.setopt(pycurl.TIMEOUT, int(options[--shell-timeout])) + if --ssl in options: + if not (set((--tlscert, --tlskey, --tlscacert)) = set(options)): + fail_usage(Failed. If --ssl option is used, You have to also \ +specify: --tlscert, --tlskey and --tlscacert) + conn.setopt(pycurl.SSL_VERIFYPEER, 1) + conn.setopt(pycurl.SSLCERT, options[--tlscert]) + conn.setopt(pycurl.SSLKEY, options[--tlskey]) + conn.setopt(pycurl.CAINFO, options[--tlscacert]) + else: + conn.setopt(pycurl.SSL_VERIFYPEER, 0) + conn.setopt(pycurl.SSL_VERIFYHOST, 0) + +
[Cluster-devel] [PATCH] fence_docker: new fence agent for Docker containers
--- .gitignore | 1 + configure.ac | 1 + fence/agents/docker/Makefile.am | 18 ++ fence/agents/docker/fence_docker.py | 72 +++ tests/data/metadata/fence_docker.xml | 109 +++ 5 files changed, 201 insertions(+) create mode 100644 fence/agents/docker/Makefile.am create mode 100644 fence/agents/docker/fence_docker.py create mode 100644 tests/data/metadata/fence_docker.xml diff --git a/.gitignore b/.gitignore index 75b9aa7..8bcae2b 100644 --- a/.gitignore +++ b/.gitignore @@ -39,6 +39,7 @@ fence/agents/bullpap/fence_bullpap fence/agents/cisco_mds/fence_cisco_mds fence/agents/cisco_ucs/fence_cisco_ucs fence/agents/cpint/fence_cpint +fence/agents/docker/fence_docker fence/agents/drac/fence_drac fence/agents/drac5/fence_drac5 fence/agents/eaton_snmp/fence_eaton_snmp diff --git a/configure.ac b/configure.ac index 4d0aa6a..bc9785b 100644 --- a/configure.ac +++ b/configure.ac @@ -264,6 +264,7 @@ AC_CONFIG_FILES([Makefile fence/agents/brocade/Makefile fence/agents/cisco_mds/Makefile fence/agents/cisco_ucs/Makefile +fence/agents/docker/Makefile fence/agents/drac/Makefile fence/agents/drac5/Makefile fence/agents/dummy/Makefile diff --git a/fence/agents/docker/Makefile.am b/fence/agents/docker/Makefile.am new file mode 100644 index 000..f3d53be --- /dev/null +++ b/fence/agents/docker/Makefile.am @@ -0,0 +1,18 @@ +MAINTAINERCLEANFILES = Makefile.in + +TARGET = fence_docker + +SRC= $(TARGET).py + +EXTRA_DIST = $(SRC) + +sbin_SCRIPTS = $(TARGET) + +man_MANS = $(TARGET).8 + +include $(top_srcdir)/make/fencebuild.mk +include $(top_srcdir)/make/fenceman.mk +include $(top_srcdir)/make/agentpycheck.mk + +clean-local: clean-man + rm -f $(TARGET) diff --git a/fence/agents/docker/fence_docker.py b/fence/agents/docker/fence_docker.py new file mode 100644 index 000..63ce6b8 --- /dev/null +++ b/fence/agents/docker/fence_docker.py @@ -0,0 +1,72 @@ +#!/usr/bin/python -tt + +import atexit +import sys +import docker +import logging + +sys.path.append(@FENCEAGENTSLIBDIR@) +from fencing import fail_usage, all_opt, fence_action, atexit_handler, check_input, process_input, show_docs, run_delay, fail, EC_LOGIN_DENIED + +#BEGIN_VERSION_GENERATION +RELEASE_VERSION = +REDHAT_COPYRIGHT = +BUILD_DATE = +#END_VERSION_GENERATION + +def get_power_status(conn, options): + try: + status = conn.inspect_container(container=options[--plug]) + return on if status[State][Running] else off + except Exception: + return None + + +def set_power_status(conn, options): + if options[--action] == on: + conn.start(container=options[--plug]) + else: + conn.kill(container=options[--plug]) + return + + +def reboot_cycle(conn, options): + conn.restart(container=options[--plug], timeout=float(options[--power-timeout])) + return get_power_status(conn, options) + + +def get_list(conn, options): + output = conn.containers(all=True) + containers = {} + for container in output: + containers[container[Id]] = (; .join(container[Names]), {True:off, False: on}[container[Status][:4].lower() == exit]) + return containers + + +def main(): + atexit.register(atexit_handler) + + device_opt = [ipaddr, no_password, port, method] + + options = check_input(device_opt, process_input(device_opt)) + + docs = { } + docs[shortdesc] = Fence agent for Docker + docs[longdesc] = fence_docker is I/O fencing agent which can be used with the Docker Engine containers. + docs[vendorurl] = www.docker.io + show_docs(options, docs) + + run_delay(options) + + conn = docker.Client(base_url = http://; + options[--ip] + : + str(options[--ipport]), version = 1.9, timeout = float(options[--shell-timeout])) + + try: + result = fence_action(conn, options, set_power_status, get_power_status, get_list, reboot_cycle) + except IOError as ex: + logging.debug(ex.message) + fail(EC_LOGIN_DENIED) + + sys.exit(result) + +if __name__ == __main__: + main() diff --git a/tests/data/metadata/fence_docker.xml b/tests/data/metadata/fence_docker.xml new file mode 100644 index 000..19cdd0a --- /dev/null +++ b/tests/data/metadata/fence_docker.xml @@ -0,0 +1,109 @@ +?xml version=1.0 ? +resource-agent name=fence_docker shortdesc=Fence agent for Docker +longdescfence_docker is I/O fencing agent which can be used with the Docker Engine containers./longdesc +vendor-urlwww.docker.io/vendor-url +parameters + parameter name=ipport unique=0 required=0 + getopt mixed=-u, --ipport=[port] / +
Re: [Cluster-devel] [PATCH 2/3] fence_scsi: port to fencing library
I did few small changes and fix a problem in function register_dev. --- configure.ac | 8 + fence/agents/scsi/Makefile.am | 20 +- fence/agents/scsi/fence_scsi.8| 119 - fence/agents/scsi/fence_scsi.pl | 875 -- fence/agents/scsi/fence_scsi.py | 452 ++ fence/agents/scsi/fence_scsi_check.pl | 170 --- make/fencebuild.mk| 4 + 7 files changed, 475 insertions(+), 1173 deletions(-) delete mode 100644 fence/agents/scsi/fence_scsi.8 delete mode 100644 fence/agents/scsi/fence_scsi.pl create mode 100644 fence/agents/scsi/fence_scsi.py delete mode 100644 fence/agents/scsi/fence_scsi_check.pl diff --git a/configure.ac b/configure.ac index 5e37ee5..f208bef 100644 --- a/configure.ac +++ b/configure.ac @@ -163,6 +163,10 @@ CLUSTERDATA=${datadir}/cluster AC_PATH_PROG([IPMITOOL_PATH], [ipmitool], [/usr/bin/ipmitool]) AC_PATH_PROG([AMTTOOL_PATH], [amttool], [/usr/bin/amttool]) AC_PATH_PROG([GNUTLSCLI_PATH], [gnutlscli], [/usr/bin/gnutls-cli]) +AC_PATH_PROG([COROSYNC_CMAPCTL_PATH], [corosync-cmapctl], [/usr/sbin/corosync-cmapctl]) +AC_PATH_PROG([SG_PERSIST_PATH], [sg_persist], [/usr/bin/sg_persist]) +AC_PATH_PROG([SG_TURS_PATH], [sg_turs], [/usr/bin/sg_turs]) +AC_PATH_PROG([VGS_PATH], [vgs], [/usr/sbin/vgs]) ## do subst AC_SUBST([DEFAULT_CONFIG_DIR]) @@ -189,6 +193,10 @@ AM_CONDITIONAL(BUILD_XENAPILIB, test $XENAPILIB -eq 1) AC_SUBST([IPMITOOL_PATH]) AC_SUBST([AMTTOOL_PATH]) +AC_SUBST([COROSYNC_CMAPCTL_PATH]) +AC_SUBST([SG_PERSIST_PATH]) +AC_SUBST([SG_TURS_PATH]) +AC_SUBST([VGS_PATH]) ## *FLAGS handling diff --git a/fence/agents/scsi/Makefile.am b/fence/agents/scsi/Makefile.am index 5652bda..896406a 100644 --- a/fence/agents/scsi/Makefile.am +++ b/fence/agents/scsi/Makefile.am @@ -2,20 +2,22 @@ MAINTAINERCLEANFILES = Makefile.in TARGET = fence_scsi -SRC= $(TARGET).pl +SYMTARGET = fence_scsi_check -EXTRA_DIST = $(SRC) \ - $(TARGET)_check.pl +SRC= $(TARGET).py -scsidatadir= $(CLUSTERDATA) +EXTRA_DIST = $(SRC) -scsidata_SCRIPTS = $(TARGET)_check.pl +sbin_SCRIPTS = $(TARGET) $(SYMTARGET) -sbin_SCRIPTS = $(TARGET) +man_MANS = $(TARGET).8 -dist_man_MANS = $(TARGET).8 +$(SYMTARGET): $(TARGET) + ln -s $^ $@ include $(top_srcdir)/make/fencebuild.mk +include $(top_srcdir)/make/fenceman.mk +include $(top_srcdir)/make/agentpycheck.mk -clean-local: - rm -f $(TARGET) +clean-local: clean-man + rm -f $(TARGET) $(SYMTARGET) diff --git a/fence/agents/scsi/fence_scsi.8 b/fence/agents/scsi/fence_scsi.8 deleted file mode 100644 index 180de4f..000 --- a/fence/agents/scsi/fence_scsi.8 +++ /dev/null @@ -1,119 +0,0 @@ -.TH fence_scsi 8 - -.SH NAME -fence_scsi - I/O fencing agent for SCSI persistent reservations - -.SH SYNOPSIS -.B -fence_scsi -[\fIOPTION\fR]... - -.SH DESCRIPTION -fence_scsi is an I/O fencing agent that uses SCSI-3 persistent -reservations to control access to shared storage devices. These -devices must support SCSI-3 persistent reservations (SPC-3 or greater) -as well as the preempt-and-abort subcommand. - -The fence_scsi agent works by having each node in the cluster register -a unique key with the SCSI devive(s). Once registered, a single node -will become the reservation holder by creating a write exclusive, -registrants only reservation on the device(s). The result is that -only registered nodes may write to the device(s). When a node failure -occurs, the fence_scsi agent will remove the key belonging to the -failed node from the device(s). The failed node will no longer be able -to write to the device(s). A manual reboot is required. In the cluster -environment unfence action should be configured also. - -Keys are either be specified manually (see -k option) or generated -automatically (see -n option). Automatic key generation requires that -cman be running. Keys will then be generated using the cluster ID and -node ID such that each node has a unique key that can be determined by -any other node in the cluster. - -Devices can either be specified manually (see -d option) or discovered -automatically. Multiple devices can be specified manually by using a -comma-separated list. If no devices are specified, the fence_scsi -agent will attempt to discover devices by looking for cluster volumes -and extracting the underlying devices. Devices may be device-mapper -multipath devices or raw devices. If using a device-mapper multipath -device, the fence_scsi agent will find the underlying devices (paths) -and created registrations for each path. - -.SH OPTIONS -.TP -\fB-o\fP \fIaction\fR -Fencing action. This value can be on, off, status, or -metadata. The on, off, and status actions require either a key -(see -k option) or node name (see -n option). For on,
[Cluster-devel] [PATCH 3/3] fence_pve: new fence-agent for Proxmox VE
Thanks to Frank Brendel (author of original perl fence_pve) for help with writing and testing this agent. --- .gitignore| 1 + configure.ac | 1 + fence/agents/pve/Makefile.am | 18 fence/agents/pve/fence_pve.py | 178 ++ tests/data/metadata/fence_pve.xml | 121 ++ 5 files changed, 319 insertions(+) create mode 100644 fence/agents/pve/Makefile.am create mode 100644 fence/agents/pve/fence_pve.py create mode 100644 tests/data/metadata/fence_pve.xml diff --git a/.gitignore b/.gitignore index 74198b2..75b9aa7 100644 --- a/.gitignore +++ b/.gitignore @@ -65,6 +65,7 @@ fence/agents/node_assassin/fence_na.conf fence/agents/node_assassin/fence_na.lib fence/agents/node_assassin/fence_na.pod fence/agents/nss_wrapper/fence_nss_wrapper +fence/agents/pve/fence_pve fence/agents/rackswitch/fence_rackswitch fence/agents/rhevm/fence_rhevm fence/agents/raritan/fence_raritan diff --git a/configure.ac b/configure.ac index c24198c..5e37ee5 100644 --- a/configure.ac +++ b/configure.ac @@ -283,6 +283,7 @@ AC_CONFIG_FILES([Makefile fence/agents/netio/Makefile fence/agents/rackswitch/Makefile fence/agents/ovh/Makefile +fence/agents/pve/Makefile fence/agents/raritan/Makefile fence/agents/rhevm/Makefile fence/agents/rsa/Makefile diff --git a/fence/agents/pve/Makefile.am b/fence/agents/pve/Makefile.am new file mode 100644 index 000..9ac184e --- /dev/null +++ b/fence/agents/pve/Makefile.am @@ -0,0 +1,18 @@ +MAINTAINERCLEANFILES = Makefile.in + +TARGET = fence_pve + +SRC= $(TARGET).py + +EXTRA_DIST = $(SRC) + +sbin_SCRIPTS = $(TARGET) + +man_MANS = $(TARGET).8 + +include $(top_srcdir)/make/fencebuild.mk +include $(top_srcdir)/make/fenceman.mk +include $(top_srcdir)/make/agentpycheck.mk + +clean-local: clean-man + rm -f $(TARGET) diff --git a/fence/agents/pve/fence_pve.py b/fence/agents/pve/fence_pve.py new file mode 100644 index 000..132234e --- /dev/null +++ b/fence/agents/pve/fence_pve.py @@ -0,0 +1,178 @@ +#!/usr/bin/python -tt + +# This agent uses Proxmox VE API +# Thanks to Frank Brendel (author of original perl fence_pve) +# for help with writing and testing this agent. + +import sys +import json +import pycurl +import StringIO +import urllib +import atexit +import logging +sys.path.append(@FENCEAGENTSLIBDIR@) +from fencing import fail, EC_LOGIN_DENIED, atexit_handler, all_opt, check_input, process_input, show_docs, fence_action, run_delay + +#BEGIN_VERSION_GENERATION +RELEASE_VERSION= +BUILD_DATE= +REDHAT_COPYRIGHT= +#END_VERSION_GENERATION + + +def get_power_status(conn, options): + del conn + state = {running : on, stopped : off} + if options[--nodename] is None: + nodes = send_cmd(options, nodes) + if type(nodes) is not dict or data not in nodes or type(nodes[data]) is not list: + return None + for node in nodes[data]: # lookup the node holding the vm + if type(node) is not dict or node not in node: + return None + options[--nodename] = node[node] + status = get_power_status(None, options) + if status is not None: + logging.info(vm found on node: + options[--nodename]) + break + else: + options[--nodename] = None + return status + else: + cmd = nodes/ + options[--nodename] + /qemu/ + options[--plug] + /status/current + result = send_cmd(options, cmd) + if type(result) is dict and data in result: + if type(result[data]) is dict and status in result[data]: + if result[data][status] in state: + return state[result[data][status]] + return None + + +def set_power_status(conn, options): + del conn + action = { + 'on' : start, + 'off': stop + }[options[--action]] + cmd = nodes/ + options[--nodename] + /qemu/ + options[--plug] + /status/ + action + send_cmd(options, cmd, post={skiplock:1}) + + +def get_outlet_list(conn, options): + del conn + nodes = send_cmd(options, nodes) + outlets = dict() + if type(nodes) is not dict or data not in nodes or type(nodes[data]) is not list: + return None + for node in nodes[data]: + if type(node) is not dict or node not in node: + return None + vms = send_cmd(options, nodes/ + node[node] + /qemu) + if type(vms) is not
[Cluster-devel] [PATCH 1/3] fencing: added timeout and env parameters to run_command function
Now, we can set enviromant variables and maximum execution time for subprocess. --- fence/agents/lib/fencing.py.py | 21 + 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/fence/agents/lib/fencing.py.py b/fence/agents/lib/fencing.py.py index 32040db..31155ac 100644 --- a/fence/agents/lib/fencing.py.py +++ b/fence/agents/lib/fencing.py.py @@ -4,6 +4,7 @@ import sys, getopt, time, os, uuid, pycurl, stat import pexpect, re, atexit, syslog import logging import subprocess +import threading import shlex import __main__ @@ -1094,20 +1095,32 @@ def is_executable(path): return True return False -def run_command(options, command): - # @todo: Use timeouts from options[] +def run_command(options, command, timeout = None, env = None): + if timeout is None and --power-timeout in options: + timeout = options[--power-timeout] + if timeout is not None: + timeout = float(timeout) + logging.info(Executing: %s\n % command) try: - process = subprocess.Popen(shlex.split(command), stdout=subprocess.PIPE, stderr=subprocess.PIPE) + process = subprocess.Popen(shlex.split(command), stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env) except OSError, ex: fail_usage(Unable to run %s\n % command) + thread = threading.Thread(target = process.wait) + thread.start() + thread.join(timeout) + if (thread.is_alive()): + process.kill() + fail(EC_TIMED_OUT) + status = process.wait() + (pipe_stdout, pipe_stderr) = process.communicate() process.stdout.close() process.stderr.close() - logging.debug(%s %s %s\n % str(status), str(pipe_stdout), str(pipe_stderr)) + logging.debug(%s %s %s\n % (str(status), str(pipe_stdout), str(pipe_stderr))) return (status, pipe_stdout, pipe_stderr) -- 1.8.3.1
[Cluster-devel] [PATCH] fencing: fixed pexpect TypeError exception, when using identity file for login via ssh
Previously, fence-agent failed to log in (ssh) using identity file. This caused fence-agent failure because of uncaught exception. Resolves: rhbz#1073947 --- fence/agents/lib/fencing.py.py | 9 - 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/fence/agents/lib/fencing.py.py b/fence/agents/lib/fencing.py.py index 2006f0d..76855e1 100644 --- a/fence/agents/lib/fencing.py.py +++ b/fence/agents/lib/fencing.py.py @@ -1022,13 +1022,12 @@ def fence_login(options, re_login_string = (login\s*: )|(Login Name: )|(userna 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])) + result = conn.log_expect(options, [ Enter passphrase for key ' + options[--identity-file] + ':,\ + Are you sure you want to continue connecting (yes/no)? ] + options[--command-prompt], 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: + result = conn.log_expect(options, [ Enter passphrase for key '+options[--identity-file]+':] + options[--command-prompt], 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])) -- 1.8.3.1
[Cluster-devel] [PATCH 2/2] fence_scsi: port to fencing lib
Port of fence_scsi to fencing library --- fence/agents/scsi/fence_scsi.py | 328 1 file changed, 328 insertions(+) create mode 100644 fence/agents/scsi/fence_scsi.py diff --git a/fence/agents/scsi/fence_scsi.py b/fence/agents/scsi/fence_scsi.py new file mode 100644 index 000..18b5e60 --- /dev/null +++ b/fence/agents/scsi/fence_scsi.py @@ -0,0 +1,328 @@ +#!/usr/bin/python + +import sys, stat, shlex, subprocess, re, os +sys.path.append(@FENCEAGENTSLIBDIR@) +from fencing import * + +#BEGIN_VERSION_GENERATION +RELEASE_VERSION= +REDHAT_COPYRIGHT= +BUILD_DATE= +#END_VERSION_GENERATION + +def get_status(_, options): + status = off + for dev in options[devices]: + is_block_device(dev) + reset_dev(dev) + if options[--key] in get_registration_keys(dev): + status = on + elif options[log] = LOG_MODE_VERBOSE: + options[debug_fh].write(No registration for key \ + + options[--key] + on device + dev + \n) + return status + +def set_status(_, options): + count = 0 + if options[--action] == on: + set_key(options) + for dev in options[devices]: + is_block_device(dev) + + register_dev(options[--key], dev, options.has_key(--atptl)) + if options[--key] not in get_registration_keys(dev): + count += 1 + if options[log] = LOG_MODE_VERBOSE: + options[debug_fh].write(Failed to register key \ + + options[--key] + on device + dev + \n) + continue + dev_write(dev, options) + + if get_reservation_key(dev) is None \ + and not reserve_dev(options[--key], dev) \ + and get_reservation_key(dev) is None: + count += 1 + if options[log] = LOG_MODE_VERBOSE: + options[debug_fh].write(Failed to create reservation (key=\ + + options[--key] + , device= + dev + )\n) + + else: + host_key = get_key(options) + if host_key == options[--key].lower(): + fail_usage(Failed: keys cannot be same) + for dev in options[devices]: + is_block_device(dev) + + if get_reservation_key(dev) == options[--key]: + release_dev(options[--key], dev) + + if options[--key] in get_registration_keys(dev): + preempt(host_key, options[--key], dev) + + if get_reservation_key(dev) == options[--key]: + count += 1 + if options[log] = LOG_MODE_VERBOSE: + options[debug_fh].write(Failed to release device \ + + dev + from key + options[--key] + \n) + + if options[--key] in get_registration_keys(dev): + count += 1 + if options[log] = LOG_MODE_VERBOSE: + options[debug_fh].write(Failed to remove key \ + + options[--key] + on device + dev + \n) + if count: + fail_usage(Failed to verify + count + device(s)) + +#run command, returns dict, ret[err] = exit code; ret[out] = output +def run_cmd(cmd): + cmd = shlex.split(cmd) + cmd[0] = find_binary(cmd[0]) + ret = {} + null = open(/dev/null, w) + try: + process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=null) + except OSError: + null.close() + fail_usage(Failed: Cannot run ' + cmd + ') + + ret[err] = process.wait() + ret[out] = .join([i for i in process.communicate() if i is not None]) + + process.stdout.close() + null.close() + return ret + +# check if device exist and is block device +def is_block_device(dev): + if not os.path.exists(dev): + fail_usage(Failed: device \ + dev + \ does not exist) + if not stat.S_ISBLK(os.stat(dev).st_mode): + fail_usage(Failed: device \ + dev + \ is not a block device) + +# cancel registration +def preempt(host, node, dev): + cmd = sg_persist -n -o -A -T 5 -K + host + -S + node + -d + dev + return not bool(run_cmd(cmd)[err]) + +def reset_dev(dev): + return run_cmd(sg_turs + dev)[err] + +def register_dev(node_key, dev, atptl): + dev = os.path.realpath(dev) + if re.search(^dm, dev[5:]): +
[Cluster-devel] [PATCH] fencing: correct default values in manual pages for symlinks
--- make/fenceman.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/make/fenceman.mk b/make/fenceman.mk index d4f0377..163fe88 100644 --- a/make/fenceman.mk +++ b/make/fenceman.mk @@ -1,7 +1,7 @@ %.8: $(TARGET) $(top_srcdir)/fence/agents/lib/fence2man.xsl set -e \ PYTHONPATH=$(abs_srcdir)/../lib:$(abs_builddir)/../lib \ - python $^ -o metadata .$@.tmp \ + python $(@:%.8=%) -o metadata .$@.tmp \ xmllint --noout --relaxng $(abs_srcdir)/../lib/metadata.rng .$@.tmp \ xsltproc $(top_srcdir)/fence/agents/lib/fence2man.xsl .$@.tmp $@ -- 1.8.3.1
[Cluster-devel] [PATCH 2/4] fencing: add function is_executale
New function is_executable added to fencing library. Function checks if path is reachable and executable. Used for example in fence_amt to check path to amttool. --- fence/agents/lib/fencing.py.py | 9 - 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/fence/agents/lib/fencing.py.py b/fence/agents/lib/fencing.py.py index ab14cb7..f4150ff 100644 --- a/fence/agents/lib/fencing.py.py +++ b/fence/agents/lib/fencing.py.py @@ -1,6 +1,6 @@ #!/usr/bin/python -import sys, getopt, time, os, uuid, pycurl +import sys, getopt, time, os, uuid, pycurl, stat import pexpect, re, atexit, syslog import __main__ @@ -1065,3 +1065,10 @@ def fence_login(options, re_login_string = (login\s*: )|(Login Name: )|(userna except pexpect.TIMEOUT: fail(EC_LOGIN_DENIED) return conn + +def is_executable(path): + if os.path.exists(path): + stats = os.stat(path) + if stat.S_ISREG(stats.st_mode) and os.access(path, os.X_OK): + return True + return False -- 1.8.3.1
[Cluster-devel] [PATCH 1/4] fencing: new option --method
Add new option method --method for cycle reboot Checks input for invalid usage of cycle (method cycle and plug) --- fence/agents/lib/fencing.py.py | 62 -- 1 file changed, 42 insertions(+), 20 deletions(-) diff --git a/fence/agents/lib/fencing.py.py b/fence/agents/lib/fencing.py.py index 2b914f2..ab14cb7 100644 --- a/fence/agents/lib/fencing.py.py +++ b/fence/agents/lib/fencing.py.py @@ -342,7 +342,16 @@ all_opt = { 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} + order : 205}, + method : { + getopt : m:, + longopt : method, + help : -m, --method=[method] Method to fence (offon|cycle) (Default: offon), + required : 0, + shortdesc : Method to fence (offon|cycle) (Default: offon), + default : offon, + choices : [ offon, cycle ], + order : 1} } # options which are added automatically if 'key' is encountered (default is always added) @@ -723,6 +732,9 @@ def check_input(device_opt, opt): else: options[--ipport] = 23 + if options.has_key(--plug) and options.has_key(--method) and options[--method] == cycle: + fail_usage(Failed: Cannot use --method cycle and --plug together) + for opt in device_opt: if all_opt[opt].has_key(choices): long = -- + all_opt[opt][longopt] @@ -804,7 +816,7 @@ def show_docs(options, docs = None): print __main__.REDHAT_COPYRIGHT sys.exit(0) -def fence_action(tn, options, set_power_fn, get_power_fn, get_outlet_list = None): +def fence_action(tn, options, set_power_fn, get_power_fn, get_outlet_list = None, reboot_cycle_fn = None): result = 0 try: @@ -863,28 +875,38 @@ def fence_action(tn, options, set_power_fn, get_power_fn, get_outlet_list = None 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: + if options.has_key(--method) and options[--method].lower() == cycle and reboot_cycle_fn is not None: 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: + if reboot_cycle_fn(tn, options): 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 not power_on: + fail(EC_TIMED_OUT) + + else: + 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 + + 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: +
[Cluster-devel] [PATCH 1/2] fence_ipmilan: port to fencing library
Port of fence_ipmilan to fencing library. --- fence/agents/ipmilan/fence_ipmilan.py | 207 ++ 1 file changed, 207 insertions(+) create mode 100644 fence/agents/ipmilan/fence_ipmilan.py diff --git a/fence/agents/ipmilan/fence_ipmilan.py b/fence/agents/ipmilan/fence_ipmilan.py new file mode 100644 index 000..1cb26d0 --- /dev/null +++ b/fence/agents/ipmilan/fence_ipmilan.py @@ -0,0 +1,207 @@ +#!/usr/bin/python + +import sys, shlex, stat, subprocess, re, os +from pipes import quote +sys.path.append(@FENCEAGENTSLIBDIR@) +from fencing import * + +#BEGIN_VERSION_GENERATION +RELEASE_VERSION= +REDHAT_COPYRIGHT= +BUILD_DATE= +#END_VERSION_GENERATION + +def get_power_status(_, options): + +cmd = create_command(options, status) + +if options[log] = LOG_MODE_VERBOSE: +options[debug_fh].write(executing: + cmd + \n) + +try: +process = subprocess.Popen(shlex.split(cmd), stdout=subprocess.PIPE, stderr=subprocess.PIPE) +except OSError: +fail_usage(Ipmitool not found or not accessible) + +process.wait() + +out = process.communicate() +process.stdout.close() + +match = re.search('[Cc]hassis [Pp]ower is [\\s]*([a-zA-Z]{2,3})', str(out)) +status = match.group(1) if match else None + +return status + +def set_power_status(_, options): + +cmd = create_command(options, options[--action]) + +if options[log] = LOG_MODE_VERBOSE: +options[debug_fh].write(executing: + cmd + \n) + +null = open('/dev/null', 'w') +try: +process = subprocess.Popen(shlex.split(cmd), stdout=null, stderr=null) +except OSError: +null.close() +fail_usage(Ipmitool not found or not accessible) + +process.wait() +null.close() + +return + +def reboot_cycle(_, options): +cmd = create_command(options, cycle) + +if options[log] = LOG_MODE_VERBOSE: +options[debug_fh].write(executing: + cmd + \n) + +try: +process = subprocess.Popen(shlex.split(cmd), stdout=subprocess.PIPE, stderr=subprocess.PIPE) +except OSError: +fail_usage(Ipmitool not found or not accessible) + +process.wait() + +out = process.communicate() +process.stdout.close() + +return bool(re.search('chassis power control: cycle', str(out).lower())) + +def is_executable(path): + if os.path.exists(path): + stats = os.stat(path) + if stat.S_ISREG(stats.st_mode) and os.access(path, os.X_OK): + return True + return False + +def create_command(options, action): +cmd = options[--ipmitool-path] + +# --lanplus / -L +if options.has_key(--lanplus) and options[--lanplus] in [, 1]: +cmd += -I lanplus +else: +cmd += -I lan +# --ip / -a +cmd += -H + options[--ip] + +# --username / -l +if options.has_key(--username) and len(options[--username]) != 0: +cmd += -U + quote(options[--username]) + +# --auth / -A +if options.has_key(--auth): +cmd += -A + options[--auth] + +# --password / -p +if options.has_key(--password): +cmd += -P + quote(options[--password]) + +# --cipher / -C +cmd += -C + options[--cipher] + +# --port / -n +if options.has_key(--ipport): +cmd += -p + options[--ipport] + +if options.has_key(--privlvl): +cmd += -L + options[--privlvl] + +# --action / -o +cmd += chassis power + action + + # --use-sudo / -d +if options.has_key(--use-sudo): +cmd = SUDO_PATH + + cmd + +return cmd + +def define_new_opts(): +all_opt[lanplus] = { +getopt : L, +longopt : lanplus, +help : -L, --lanplus Use Lanplus to improve security of connection, +required : 0, +default : 0, +shortdesc : Use Lanplus to improve security of connection, +order: 1 +} +all_opt[auth] = { +getopt : A:, +longopt : auth, +help : -A, --auth=[auth] IPMI Lan Auth type (md5|password|none), +required : 0, +shortdesc : IPMI Lan Auth type., +default : none, +choices : [md5, password, none], +order: 1 +} +all_opt[cipher] = { +getopt : C:, +longopt : cipher, +help : -C, --cipher=[cipher] Ciphersuite to use (same as ipmitool -C parameter), +required : 0, +shortdesc : Ciphersuite to use (same as ipmitool -C parameter), +default : 0, +order: 1 +} +all_opt[privlvl] = { +getopt : P:, +longopt : privlvl, +help : -P, --privlvl=[level] Privilege level on IPMI device (callback|user|operator|administrator), +required : 0, +shortdesc : Privilege level on IPMI device, +default : administrator, +choices : [callback, user, operator, administrator], +order: 1 +} +all_opt[ipmitool_path] = { +
[Cluster-devel] [PATCH 2/2] fence_amt: new fence agent for Intel AMT
New fence agent for Intel AMT. --- fence/agents/amt/fence_amt.py | 161 ++ 1 file changed, 161 insertions(+) create mode 100755 fence/agents/amt/fence_amt.py diff --git a/fence/agents/amt/fence_amt.py b/fence/agents/amt/fence_amt.py new file mode 100755 index 000..6f00727 --- /dev/null +++ b/fence/agents/amt/fence_amt.py @@ -0,0 +1,161 @@ +#!/usr/bin/python + +import sys, subprocess, re, os, stat +from pipes import quote +sys.path.append(@FENCEAGENTSLIBDIR@) +from fencing import * + +#BEGIN_VERSION_GENERATION +RELEASE_VERSION=Fence agent for Intel AMT +REDHAT_COPYRIGHT= +BUILD_DATE= +#END_VERSION_GENERATION + +def get_power_status(_, options): + +cmd = create_command(options, status) + +if options[log] = LOG_MODE_VERBOSE: +options[debug_fh].write(executing: + cmd + \n) + +try: +process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) +except OSError: +fail_usage(Amttool not found or not accessible) + +process.wait() + +output = process.communicate() +process.stdout.close() + +match = re.search('Powerstate:[\\s]*(..)', str(output)) +status = match.group(1) if match else None + +if (status == None): +return fail +elif (status == S0): # SO = on; S3 = sleep; S5 = off +return on +else: +return off + +def set_power_status(_, options): + +cmd = create_command(options, options[--action]) + +if options[log] = LOG_MODE_VERBOSE: +options[debug_fh].write(executing: + cmd + \n) + +null = open('/dev/null', 'w') +try: +process = subprocess.Popen(cmd, stdout=null, stderr=null, shell=True) +except OSError: +null.close() +fail_usage(Amttool not found or not accessible) + +process.wait() +null.close() + +return + +def reboot_cycle(_, options): +cmd = create_command(options, cycle) + +if options[log] = LOG_MODE_VERBOSE: +options[debug_fh].write(executing: + cmd + \n) + +null = open('/dev/null', 'w') +try: +process = subprocess.Popen(cmd, stdout=null, stderr=null, shell=True) +except OSError: +null.close() +fail_usage(Amttool not found or not accessible) + +status = process.wait() +null.close() + +return not bool(status) + +def is_executable(path): +if os.path.exists(path): +stats = os.stat(path) +if stat.S_ISREG(stats.st_mode) and os.access(path, os.X_OK): +return True +return False + +def create_command(options, action): + +# --password / -p +cmd = AMT_PASSWORD= + quote(options[--password]) + +cmd += + options[--amttool-path] + +# --ip / -a +cmd += + options[--ip] + +# --action / -o +if action == status: +cmd += info +elif action == on: +cmd = echo \y\| + cmd +cmd += powerup +elif action == off: +cmd = echo \y\| + cmd +cmd += powerdown +elif action == cycle: +cmd = echo \y\| + cmd +cmd += powercycle +if action in [on, off, cycle] and options.has_key(--boot-option): +cmd += options[--boot-option] + +# --use-sudo / -d +if options.has_key(--use-sudo): +cmd = SUDO_PATH + + cmd + +return cmd + +def define_new_opts(): +all_opt[boot_option] = { +getopt : b:, +longopt : boot-option, +help : -b, --boot-option=[option] Change the default boot behavior of the machine. (pxe|hd|hdsafe|cd|diag), +required : 0, +shortdesc : Change the default boot behavior of the machine., +choices : [pxe, hd, hdsafe, cd, diag], +order : 1 +} +all_opt[amttool_path] = { +getopt : i:, +longopt : amttool-path, +help : --amttool-path=[path] Path to amttool binary, +required : 0, +shortdesc : Path to amttool binary, +default : @AMTTOOL_PATH@, +order: 200 +} + +def main(): + +atexit.register(atexit_handler) + +device_opt = [ ipaddr, no_login, passwd, boot_option, no_port, + sudo, amttool_path, method ] + +define_new_opts() + +options = check_input(device_opt, process_input(device_opt)) + +docs = { } +docs[shortdesc] = Fence agent for AMT +docs[longdesc] = Fence agent for AMT +docs[vendorurl] = http://www.intel.com/; +show_docs(options, docs) + +if not is_executable(options[--amttool-path]): +fail_usage(Amttool not found or not accessible) + +result = fence_action(None, options, set_power_status, get_power_status, None, reboot_cycle) + +sys.exit(result) + +if __name__ == __main__: +main() -- 1.8.3.1
[Cluster-devel] [PATCH 1/3] fencing: new option --method
Add new option method --method for cycle reboot --- fence/agents/lib/fencing.py.py | 80 ++ 1 file changed, 57 insertions(+), 23 deletions(-) diff --git a/fence/agents/lib/fencing.py.py b/fence/agents/lib/fencing.py.py index b4abfb2..59ab91b 100644 --- a/fence/agents/lib/fencing.py.py +++ b/fence/agents/lib/fencing.py.py @@ -25,7 +25,6 @@ EC_STATUS = 8 EC_STATUS_HMC = 9 EC_PASSWORD_MISSING = 10 EC_INVALID_PRIVILEGES = 11 -EC_TOOL_FAIL = 12 TELNET_PATH = /usr/bin/telnet SSH_PATH= /usr/bin/ssh @@ -343,7 +342,16 @@ all_opt = { 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} + order : 205}, + method : { + getopt : m:, + longopt : method, + help : -m, --method=[method] Method to fence (onoff|cycle) (Default: onoff), + required : 0, + shortdesc : Method to fence (onoff|cycle) (Default: onoff), + default : onoff, + choices : [ onoff, cycle ], + order : 1} } # options which are added automatically if 'key' is encountered (default is always added) @@ -413,8 +421,7 @@ def fail(error_code): 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, - EC_INVALID_PRIVILEGES : Failed: The user does not have the correct privileges to do the requested action., - EC_TOOL_FAIL: Failed: Required tool not found or not accessible. + EC_INVALID_PRIVILEGES : Failed: The user does not have the correct privileges to do the requested action. }[error_code] + \n sys.stderr.write(message) syslog.syslog(syslog.LOG_ERR, message) @@ -782,6 +789,23 @@ def set_multi_power_fn(tn, options, set_power_fn): else: set_power_fn(tn, options) +def multi_reboot_cycle_fn(tn, options, reboot_cycle_fn): + success = False; + 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 = reboot_cycle_fn(tn, options) + if plug_status: + success = plug_status + else: + success = reboot_cycle_fn(tn, options) + return success def show_docs(options, docs = None): device_opt = options[device_opt] @@ -806,7 +830,7 @@ def show_docs(options, docs = None): print __main__.REDHAT_COPYRIGHT sys.exit(0) -def fence_action(tn, options, set_power_fn, get_power_fn, get_outlet_list = None): +def fence_action(tn, options, set_power_fn, get_power_fn, get_outlet_list = None, reboot_cycle_fn = None): result = 0 try: @@ -865,28 +889,38 @@ def fence_action(tn, options, set_power_fn, get_power_fn, get_outlet_list = None 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: + if options.has_key(--method) and options[--method].lower() == cycle: 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: + if multi_reboot_cycle_fn(tn, options, reboot_cycle_fn): power_on = True break - except Exception, ex: - # an error occured during power ON phase in reboot - #
[Cluster-devel] [PATCH 3/3] fence_amt: option --method and new option --amttool-path
Add support for option --method and new option --amttool-path --- fence/agents/amt/fence_amt.py | 72 ++- 1 file changed, 57 insertions(+), 15 deletions(-) diff --git a/fence/agents/amt/fence_amt.py b/fence/agents/amt/fence_amt.py index 8fe2dbc..7077828 100755 --- a/fence/agents/amt/fence_amt.py +++ b/fence/agents/amt/fence_amt.py @@ -1,6 +1,6 @@ #!/usr/bin/python -import sys, subprocess, re +import sys, subprocess, re, os, stat from pipes import quote sys.path.append(@FENCEAGENTSLIBDIR@) from fencing import * @@ -21,12 +21,11 @@ def get_power_status(_, options): try: process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) except OSError: -fail(EC_TOOL_FAIL) +fail_usage(Amttool not found or not accessible) process.wait() output = process.communicate() - process.stdout.close() match = re.search('Powerstate:[\\s]*(..)', str(output)) @@ -51,19 +50,44 @@ def set_power_status(_, options): process = subprocess.Popen(cmd, stdout=null, stderr=null, shell=True) except OSError: null.close() -fail(EC_TOOL_FAIL) +fail_usage(Amttool not found or not accessible) process.wait() null.close() return +def reboot_cycle(_, options): +cmd = create_command(options, cycle) + +if options[log] = LOG_MODE_VERBOSE: +options[debug_fh].write(executing: + cmd + \n) + +null = open('/dev/null', 'w') +try: +process = subprocess.Popen(cmd, stdout=null, stderr=null, shell=True) +except OSError: +null.close() +fail_usage(Amttool not found or not accessible) + +status = process.wait() +null.close() + +return not bool(status) + +def is_executable(path): +if os.path.exists(path): +stats = os.stat(path) +if stat.S_ISREG(stats.st_mode) and os.access(path, os.X_OK): +return True +return False + def create_command(options, action): # --password / -p cmd = AMT_PASSWORD= + quote(options[--password]) -cmd += + options[amttool_path] +cmd += + options[--amttool-path] # --ip / -a cmd += + options[--ip] @@ -77,7 +101,10 @@ def create_command(options, action): elif action == off: cmd = echo \y\| + cmd cmd += powerdown -if action in [on, off] and options.has_key(--boot-options): +elif action == cycle: +cmd = echo \y\| + cmd +cmd += powercycle +if action in [on, off, cycle] and options.has_key(--boot-options): cmd += options[--boot-options] # --use-sudo / -d @@ -86,25 +113,40 @@ def create_command(options, action): return cmd -def main(): - -atexit.register(atexit_handler) - -device_opt = [ ipaddr, no_login, passwd, boot_option, no_port, sudo] - +def define_new_opts(): all_opt[boot_option] = { getopt : b:, longopt : boot-option, -help:-b, --boot-option=[option] Change the default boot behavior of the machine. (pxe|hd|hdsafe|cd|diag), +help:-b, --boot-option=[option] Change the default boot behavior of the machine. (pxe|hd|hdsafe|cd|diag), required : 0, shortdesc : Change the default boot behavior of the machine., choices : [pxe, hd, hdsafe, cd, diag], order : 1 } +all_opt[amttool_path] = { +getopt : i:, +longopt : amttool-path, +help : --amttool-path=[path] Path to amttool binary, +required : 0, +shortdesc : Path to amttool binary, +default : /usr/bin/amttool, +order: 200 +} + + +def main(): + +atexit.register(atexit_handler) + +device_opt = [ ipaddr, no_login, passwd, boot_option, no_port, + sudo, amttool_path, method ] + +define_new_opts() options = check_input(device_opt, process_input(device_opt)) -options[amttool_path] = /usr/bin/amttool +if not is_executable(options[--amttool-path]): +fail_usage(Amttool not found or not accessible) docs = { } docs[shortdesc] = Fence agent for AMT @@ -112,7 +154,7 @@ def main(): docs[vendorurl] = http://www.intel.com/; show_docs(options, docs) -result = fence_action(None, options, set_power_status, get_power_status, None) +result = fence_action(None, options, set_power_status, get_power_status, None, reboot_cycle) sys.exit(result) -- 1.8.3.1
[Cluster-devel] [PATCH 2/3] fence_ipmilan: option --method and new option --ipmitool-path
Add support for option --method and new option --ipmitool-path --- fence/agents/ipmilan/fence_ipmilan.py | 80 +++ 1 file changed, 54 insertions(+), 26 deletions(-) diff --git a/fence/agents/ipmilan/fence_ipmilan.py b/fence/agents/ipmilan/fence_ipmilan.py index 5c32690..4d33234 100644 --- a/fence/agents/ipmilan/fence_ipmilan.py +++ b/fence/agents/ipmilan/fence_ipmilan.py @@ -11,14 +11,6 @@ REDHAT_COPYRIGHT= BUILD_DATE= #END_VERSION_GENERATION -PATHS = [/usr/local/bull/NSMasterHW/bin/ipmitool, -/usr/bin/ipmitool, -/usr/sbin/ipmitool, -/bin/ipmitool, -/sbin/ipmitool, -/usr/local/bin/ipmitool, -/usr/local/sbin/ipmitool] - def get_power_status(_, options): cmd = create_command(options, status) @@ -28,9 +20,8 @@ def get_power_status(_, options): try: process = subprocess.Popen(shlex.split(cmd), stdout=subprocess.PIPE, stderr=subprocess.PIPE) -except OSError, ex: -print ex -fail(EC_TOOL_FAIL) +except OSError: +fail_usage(Ipmitool not found or not accessible) process.wait() @@ -54,13 +45,31 @@ def set_power_status(_, options): process = subprocess.Popen(shlex.split(cmd), stdout=null, stderr=null) except OSError: null.close() -fail(EC_TOOL_FAIL) +fail_usage(Ipmitool not found or not accessible) process.wait() null.close() return +def reboot_cycle(_, options): +cmd = create_command(options, cycle) + +if options[log] = LOG_MODE_VERBOSE: +options[debug_fh].write(executing: + cmd + \n) + +try: +process = subprocess.Popen(shlex.split(cmd), stdout=subprocess.PIPE, stderr=subprocess.PIPE) +except OSError: +fail_usage(Ipmitool not found or not accessible) + +process.wait() + +out = process.communicate() +process.stdout.close() + +return bool(re.search('chassis power control: cycle', str(out).lower())) + def is_executable(path): if os.path.exists(path): stats = os.stat(path) @@ -68,13 +77,17 @@ def is_executable(path): return True return False -def get_ipmitool_path(): -for path in PATHS: -if is_executable(path): -return path +def get_ipmitool_path(options): +if type(options[--ipmitool-path]) == type(list()): +for path in options[--ipmitool-path]: +if is_executable(path): +return path +else: +if is_executable(options[--ipmitool-path]): +return options[--ipmitool-path] return None -def create_command(options, action): +def create_command(options, action): cmd = options[ipmitool_path] # --lanplus / -L @@ -120,7 +133,7 @@ def define_new_opts(): all_opt[lanplus] = { getopt : L, longopt : lanplus, -help : -L, --lanplusUse Lanplus to improve security of connection, +help : -L, --lanplus Use Lanplus to improve security of connection, required : 0, shortdesc : Use Lanplus to improve security of connection, order: 1 @@ -128,7 +141,7 @@ def define_new_opts(): all_opt[auth] = { getopt : A:, longopt : auth, -help : -A, --auth=[auth]IPMI Lan Auth type (md5|password|none), +help : -A, --auth=[auth] IPMI Lan Auth type (md5|password|none), required : 0, shortdesc : IPMI Lan Auth type., default : none, @@ -138,7 +151,7 @@ def define_new_opts(): all_opt[cipher] = { getopt : C:, longopt : cipher, -help : -C, --cipher=[cipher]Ciphersuite to use (same as ipmitool -C parameter), +help : -C, --cipher=[cipher] Ciphersuite to use (same as ipmitool -C parameter), required : 0, shortdesc : Ciphersuite to use (same as ipmitool -C parameter), default : 0, @@ -147,28 +160,44 @@ def define_new_opts(): all_opt[privlvl] = { getopt : P:, longopt : privlvl, -help : -P, --privlvl=[level]Privilege level on IPMI device (callback|user|operator|administrator), +help : -P, --privlvl=[level] Privilege level on IPMI device (callback|user|operator|administrator), required : 0, shortdesc : Privilege level on IPMI device, default : administrator, choices : [callback, user, operator, administrator], order: 1 } +all_opt[ipmitool_path] = { +getopt : i:, +longopt : ipmitool-path, +help : --ipmitool-path=[path] Path to ipmitool binary, +required : 0, +shortdesc : Path to ipmitool binary, +default : [/usr/local/bull/NSMasterHW/bin/ipmitool, +/usr/bin/ipmitool, +/usr/sbin/ipmitool, +/bin/ipmitool, +/sbin/ipmitool, +/usr/local/bin/ipmitool, +/usr/local/sbin/ipmitool], +order: 200 +}
[Cluster-devel] [PATCH 2/2] fence_amt: new fence agent for Intel AMT
New fence agent for Intel AMT. --- fence/agents/amt/fence_amt.py | 120 ++ 1 file changed, 120 insertions(+) create mode 100755 fence/agents/amt/fence_amt.py diff --git a/fence/agents/amt/fence_amt.py b/fence/agents/amt/fence_amt.py new file mode 100755 index 000..8fe2dbc --- /dev/null +++ b/fence/agents/amt/fence_amt.py @@ -0,0 +1,120 @@ +#!/usr/bin/python + +import sys, subprocess, re +from pipes import quote +sys.path.append(@FENCEAGENTSLIBDIR@) +from fencing import * + +#BEGIN_VERSION_GENERATION +RELEASE_VERSION=Fence agent for Intel AMT +REDHAT_COPYRIGHT= +BUILD_DATE= +#END_VERSION_GENERATION + +def get_power_status(_, options): + +cmd = create_command(options, status) + +if options[log] = LOG_MODE_VERBOSE: +options[debug_fh].write(executing: + cmd + \n) + +try: +process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) +except OSError: +fail(EC_TOOL_FAIL) + +process.wait() + +output = process.communicate() + +process.stdout.close() + +match = re.search('Powerstate:[\\s]*(..)', str(output)) +status = match.group(1) if match else None + +if (status == None): +return fail +elif (status == S0): # SO = on; S3 = sleep; S5 = off +return on +else: +return off + +def set_power_status(_, options): + +cmd = create_command(options, options[--action]) + +if options[log] = LOG_MODE_VERBOSE: +options[debug_fh].write(executing: + cmd + \n) + +null = open('/dev/null', 'w') +try: +process = subprocess.Popen(cmd, stdout=null, stderr=null, shell=True) +except OSError: +null.close() +fail(EC_TOOL_FAIL) + +process.wait() +null.close() + +return + +def create_command(options, action): + +# --password / -p +cmd = AMT_PASSWORD= + quote(options[--password]) + +cmd += + options[amttool_path] + +# --ip / -a +cmd += + options[--ip] + +# --action / -o +if action == status: +cmd += info +elif action == on: +cmd = echo \y\| + cmd +cmd += powerup +elif action == off: +cmd = echo \y\| + cmd +cmd += powerdown +if action in [on, off] and options.has_key(--boot-options): +cmd += options[--boot-options] + +# --use-sudo / -d +if options.has_key(--use-sudo): +cmd = SUDO_PATH + + cmd + +return cmd + +def main(): + +atexit.register(atexit_handler) + +device_opt = [ ipaddr, no_login, passwd, boot_option, no_port, sudo] + +all_opt[boot_option] = { +getopt : b:, +longopt : boot-option, +help:-b, --boot-option=[option] Change the default boot behavior of the machine. (pxe|hd|hdsafe|cd|diag), +required : 0, +shortdesc : Change the default boot behavior of the machine., +choices : [pxe, hd, hdsafe, cd, diag], + order : 1 +} + +options = check_input(device_opt, process_input(device_opt)) + +options[amttool_path] = /usr/bin/amttool + +docs = { } +docs[shortdesc] = Fence agent for AMT +docs[longdesc] = Fence agent for AMT +docs[vendorurl] = http://www.intel.com/; +show_docs(options, docs) + +result = fence_action(None, options, set_power_status, get_power_status, None) + +sys.exit(result) + +if __name__ == __main__: +main() -- 1.8.3.1
[Cluster-devel] [PATCH 1/2] fence_ipmilan: port fencing agent to fencing library
This is port of fence_ipmilan to fencing library. Also added fail message to fencing library if tool (e.g. impitool, amttool...) is not accessible. --- fence/agents/ipmilan/fence_ipmilan.py | 184 ++ fence/agents/lib/fencing.py.py| 4 +- 2 files changed, 187 insertions(+), 1 deletion(-) create mode 100644 fence/agents/ipmilan/fence_ipmilan.py diff --git a/fence/agents/ipmilan/fence_ipmilan.py b/fence/agents/ipmilan/fence_ipmilan.py new file mode 100644 index 000..5c32690 --- /dev/null +++ b/fence/agents/ipmilan/fence_ipmilan.py @@ -0,0 +1,184 @@ +#!/usr/bin/python + +import sys, shlex, stat, subprocess, re, os +from pipes import quote +sys.path.append(@FENCEAGENTSLIBDIR@) +from fencing import * + +#BEGIN_VERSION_GENERATION +RELEASE_VERSION= +REDHAT_COPYRIGHT= +BUILD_DATE= +#END_VERSION_GENERATION + +PATHS = [/usr/local/bull/NSMasterHW/bin/ipmitool, +/usr/bin/ipmitool, +/usr/sbin/ipmitool, +/bin/ipmitool, +/sbin/ipmitool, +/usr/local/bin/ipmitool, +/usr/local/sbin/ipmitool] + +def get_power_status(_, options): + +cmd = create_command(options, status) + +if options[log] = LOG_MODE_VERBOSE: +options[debug_fh].write(executing: + cmd + \n) + +try: +process = subprocess.Popen(shlex.split(cmd), stdout=subprocess.PIPE, stderr=subprocess.PIPE) +except OSError, ex: +print ex +fail(EC_TOOL_FAIL) + +process.wait() + +out = process.communicate() +process.stdout.close() + +match = re.search('[Cc]hassis [Pp]ower is [\\s]*([a-zA-Z]{2,3})', str(out)) +status = match.group(1) if match else None + +return status + +def set_power_status(_, options): + +cmd = create_command(options, options[--action]) + +if options[log] = LOG_MODE_VERBOSE: +options[debug_fh].write(executing: + cmd + \n) + +null = open('/dev/null', 'w') +try: +process = subprocess.Popen(shlex.split(cmd), stdout=null, stderr=null) +except OSError: +null.close() +fail(EC_TOOL_FAIL) + +process.wait() +null.close() + +return + +def is_executable(path): +if os.path.exists(path): +stats = os.stat(path) +if stat.S_ISREG(stats.st_mode) and os.access(path, os.X_OK): +return True +return False + +def get_ipmitool_path(): +for path in PATHS: +if is_executable(path): +return path +return None + +def create_command(options, action): +cmd = options[ipmitool_path] + +# --lanplus / -L +if options.has_key(--lanplus): +cmd += -I lanplus +else: +cmd += -I lan +# --ip / -a +cmd += -H + options[--ip] + +# --username / -l +if options.has_key(--username) and len(options[--username]) != 0: +cmd += -U + quote(options[--username]) + +# --auth / -A +if options.has_key(--auth): +cmd += -A + options[--auth] + +# --password / -p +if options.has_key(--password): +cmd += -P + quote(options[--password]) + +# --cipher / -C +cmd += -C + options[--cipher] + +# --port / -n +if options.has_key(--ipport): +cmd += -p + options[--ipport] + +if options.has_key(--privlvl): +cmd += -L + options[--privlvl] + +# --action / -o +cmd += chassis power + action + + # --use-sudo / -d +if options.has_key(--use-sudo): +cmd = SUDO_PATH + + cmd + +return cmd + +def define_new_opts(): +all_opt[lanplus] = { +getopt : L, +longopt : lanplus, +help : -L, --lanplusUse Lanplus to improve security of connection, +required : 0, +shortdesc : Use Lanplus to improve security of connection, +order: 1 +} +all_opt[auth] = { +getopt : A:, +longopt : auth, +help : -A, --auth=[auth]IPMI Lan Auth type (md5|password|none), +required : 0, +shortdesc : IPMI Lan Auth type., +default : none, +choices : [md5, password, none], +order: 1 +} +all_opt[cipher] = { +getopt : C:, +longopt : cipher, +help : -C, --cipher=[cipher]Ciphersuite to use (same as ipmitool -C parameter), +required : 0, +shortdesc : Ciphersuite to use (same as ipmitool -C parameter), +default : 0, +order: 1 +} +all_opt[privlvl] = { +getopt : P:, +longopt : privlvl, +help : -P, --privlvl=[level]Privilege level on IPMI device (callback|user|operator|administrator), +required : 0, +shortdesc : Privilege level on IPMI device, +default : administrator, +choices : [callback, user, operator, administrator], +order: 1 +} + +def main(): + +atexit.register(atexit_handler) + +device_opt = [ ipaddr, login, no_login, no_password, passwd, lanplus, auth, cipher, privlvl, sudo] +define_new_opts() + +all_opt[ipport][default] = 623 + +