diff --git a/configure.ac b/configure.ac index b81d9184..33939b99 100644 --- a/configure.ac +++ b/configure.ac @@ -1,325 +1,331 @@ # Process this file with autoconf to produce a configure script. AC_PREREQ([2.63]) AC_INIT([fence-agents], m4_esyscmd([make/git-version-gen .tarball-version]), [linux-cluster@redhat.com]) AM_INIT_AUTOMAKE([-Wno-portability dist-bzip2 dist-xz]) LT_PREREQ([2.2.6]) LT_INIT AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_SRCDIR([fence/agents/lib/fencing.py.py]) AC_CONFIG_HEADERS([make/clusterautoconfig.h]) AC_CANONICAL_HOST AC_PROG_LIBTOOL AC_LANG([C]) # Sanitize path if test "$prefix" = "NONE"; then prefix="/usr" if test "$localstatedir" = "\${prefix}/var"; then localstatedir="/var" fi if test "$sysconfdir" = "\${prefix}/etc"; then sysconfdir="/etc" fi if test "$libdir" = "\${exec_prefix}/lib"; then if test -e /usr/lib64; then libdir="/usr/lib64" else libdir="/usr/lib" fi fi fi case $exec_prefix in NONE) exec_prefix=$prefix;; prefix) exec_prefix=$prefix;; esac # Checks for programs. # check stolen from gnulib/m4/gnu-make.m4 if ! ${MAKE-make} --version /cannot/make/this >/dev/null 2>&1; then AC_MSG_ERROR([you don't seem to have GNU make; it is required]) fi AC_PROG_CC AM_PROG_CC_C_O AC_PROG_LN_S AC_PROG_INSTALL AC_PROG_MAKE_SET AC_PROG_AWK AC_PROG_CXX AC_PROG_RANLIB ## local helper functions # this function checks if CC support options passed as # args. Global CFLAGS are ignored during this test. cc_supports_flag() { local CFLAGS="$@" AC_MSG_CHECKING([whether $CC supports "$@"]) AC_COMPILE_IFELSE([int main(){return 0;}] , [RC=0; AC_MSG_RESULT([yes])], [RC=1; AC_MSG_RESULT([no])]) return $RC } # this function tests if a library has a certain function # by using AC_CHECK_LIB but restores the original LIBS global # envvar. This is required to avoid libtool to link everything # with everything. check_lib_no_libs() { AC_CHECK_LIB([$1], [$2],, [AC_MSG_ERROR([Unable to find $1 library])]) LIBS=$ac_check_lib_save_LIBS } # Checks for header files. AC_CHECK_HEADERS([arpa/inet.h fcntl.h libintl.h limits.h netdb.h stddef.h sys/socket.h sys/time.h syslog.h]) # Checks for typedefs, structures, and compiler characteristics. AC_C_INLINE AC_TYPE_SIZE_T AC_TYPE_SSIZE_T AC_TYPE_UINT32_T # Checks for library functions. AC_FUNC_FORK AC_FUNC_MALLOC AC_CHECK_FUNCS([alarm atexit bzero dup2 memmove memset select socket strcasecmp strchr strdup strerror strtol]) # local options AC_ARG_ENABLE([debug], [ --enable-debug enable debug build. ], [ default="no" ]) AC_ARG_WITH([fenceagentslibdir], [ --with-fenceagentslibdir=PATH installation path for fence library. ], [ FENCEAGENTSLIBDIR="$withval" ], [ FENCEAGENTSLIBDIR="${datadir}/fence" ]) AC_ARG_WITH([default-config-dir], [ --with-default-config-dir=DIR cluster config directory. ], [ DEFAULT_CONFIG_DIR="$withval" ], [ DEFAULT_CONFIG_DIR="$sysconfdir/cluster" ]) AC_ARG_WITH([default-config-file], [ --with-default-config-file=FILE cluster config file. ], [ DEFAULT_CONFIG_FILE="$withval" ], [ DEFAULT_CONFIG_FILE="cluster.conf" ]) AC_ARG_WITH([agents], [ --with-agents=LIST list of agents to build/ship (default: all). ], [ AGENTS_LIST="$withval" ], [ AGENTS_LIST="all" ]) if test "x$AGENTS_LIST" = x; then AC_ERROR([No agents selected]) fi if test "x$AGENTS_LIST" != xall; then for j in $AGENTS_LIST; do if ! test -d fence/agents/$j; then AC_ERROR([Agent $j does not exists]) fi done fi if test "x$AGENTS_LIST" = xall; then AGENTS_LIST=`find $srcdir/fence/agents -mindepth 2 -maxdepth 2 -name Makefile.am -printf '%h ' | sed -e 's#'$srcdir'/fence/agents/##g' -e 's#lib ##g' -e 's#nss_wrapper ##g'` fi XENAPILIB=0 if echo "$AGENTS_LIST" | grep -q xenapi; then XENAPILIB=1 fi ## random vars LOGDIR=${localstatedir}/log/cluster CLUSTERVARRUN=${localstatedir}/run/cluster CLUSTERDATA=${datadir}/cluster +AM_PATH_PYTHON +if test -z "$PYTHON"; then + echo "*** Essential program python not found" 1>&2 + exit 1 +fi + AC_PYTHON_MODULE(suds, 1) AC_PYTHON_MODULE(pexpect, 1) AC_PYTHON_MODULE(pycurl, 1) AC_PYTHON_MODULE(requests, 1) ## path to 3rd-party binaries 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]) AC_PATH_PROG([SUDO_PATH], [sudo], [/usr/bin/sudo]) AC_PATH_PROG([SSH_PATH], [ssh], [/usr/bin/ssh]) AC_PATH_PROG([TELNET_PATH], [telnet], [/usr/bin/telnet]) AC_PATH_PROG([MPATH_PATH], [mpathpersist], [/usr/sbin/mpathpersist]) AC_PATH_PROG([SBD_PATH], [sbd], [/sbin/sbd]) AC_PATH_PROG([SUDO_PATH], [sudo], [/usr/bin/sudo]) AC_PATH_PROG([SNMPWALK_PATH], [snmpwalk], [/usr/bin/snmpwalk]) AC_PATH_PROG([SNMPSET_PATH], [snmpset], [/usr/bin/snmpset]) AC_PATH_PROG([SNMPGET_PATH], [snmpget], [/usr/bin/snmpget]) AC_PATH_PROG([NOVA_PATH], [nova], [/usr/bin/nova]) ## do subst AC_SUBST([DEFAULT_CONFIG_DIR]) AC_DEFINE_UNQUOTED([DEFAULT_CONFIG_DIR], "$(eval echo ${DEFAULT_CONFIG_DIR})", [Default config directory]) AC_SUBST([DEFAULT_CONFIG_FILE]) AC_DEFINE_UNQUOTED([DEFAULT_CONFIG_FILE], "$(eval echo ${DEFAULT_CONFIG_FILE})", [Default config file]) AC_SUBST([LOGDIR]) AC_DEFINE_UNQUOTED([LOGDIR], "$(eval echo ${LOGDIR})", [Default logging directory]) AC_SUBST([CLUSTERVARRUN]) AC_DEFINE_UNQUOTED([CLUSTERVARRUN], "$(eval echo ${CLUSTERVARRUN})", [Default cluster var/run directory]) AC_SUBST([CLUSTERDATA]) AC_SUBST([FENCEAGENTSLIBDIR]) AC_SUBST([SNMPBIN]) AC_SUBST([AGENTS_LIST]) 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 ENV_CFLAGS="$CFLAGS" ENV_CPPFLAGS="$CPPFLAGS" ENV_LDFLAGS="$LDFLAGS" # debug build stuff if test "x${enable_debug}" = xyes; then AC_DEFINE_UNQUOTED([DEBUG], [1], [Compiling Debugging code]) OPT_CFLAGS="-O0" else OPT_CFLAGS="-O2" fi # gdb flags if test "x${GCC}" = xyes; then GDB_FLAGS="-ggdb3" else GDB_FLAGS="-g" fi # extra warnings EXTRA_WARNINGS="" WARNLIST=" all shadow missing-prototypes missing-declarations strict-prototypes declaration-after-statement pointer-arith write-strings cast-align bad-function-cast missing-format-attribute format=2 format-security format-nonliteral no-long-long unsigned-char gnu89-inline no-strict-aliasing " for j in $WARNLIST; do if cc_supports_flag -W$j; then EXTRA_WARNINGS="$EXTRA_WARNINGS -W$j"; fi done CFLAGS="$ENV_CFLAGS $OPT_CFLAGS $GDB_FLAGS \ $EXTRA_WARNINGS $WERROR_CFLAGS" CPPFLAGS="-I\$(top_builddir)/make -I\$(top_srcdir)/make -I. $ENV_CPPFLAGS" LDFLAGS="$ENV_LDFLAGS" AC_CONFIG_FILES([Makefile fence/Makefile fence/agents/Makefile fence/agents/alom/Makefile fence/agents/apc/Makefile fence/agents/apc_snmp/Makefile fence/agents/amt/Makefile fence/agents/amt_ws/Makefile fence/agents/bladecenter/Makefile fence/agents/brocade/Makefile fence/agents/cisco_mds/Makefile fence/agents/cisco_ucs/Makefile fence/agents/compute/Makefile fence/agents/docker/Makefile fence/agents/drac/Makefile fence/agents/drac5/Makefile fence/agents/dummy/Makefile fence/agents/eaton_snmp/Makefile fence/agents/emerson/Makefile fence/agents/eps/Makefile fence/agents/hpblade/Makefile fence/agents/ibmblade/Makefile fence/agents/ipdu/Makefile fence/agents/ifmib/Makefile fence/agents/ilo/Makefile fence/agents/ilo_moonshot/Makefile fence/agents/ilo_mp/Makefile fence/agents/ilo_ssh/Makefile fence/agents/intelmodular/Makefile fence/agents/ipmilan/Makefile fence/agents/kdump/Makefile fence/agents/ldom/Makefile fence/agents/lib/Makefile fence/agents/lpar/Makefile fence/agents/manual/Makefile fence/agents/mpath/Makefile fence/agents/netio/Makefile fence/agents/ovh/Makefile fence/agents/pve/Makefile fence/agents/raritan/Makefile fence/agents/rcd_serial/Makefile fence/agents/rhevm/Makefile fence/agents/rsa/Makefile fence/agents/rsb/Makefile fence/agents/sbd/Makefile fence/agents/sanbox2/Makefile fence/agents/scsi/Makefile fence/agents/vbox/Makefile fence/agents/virsh/Makefile fence/agents/vmware/Makefile fence/agents/vmware_soap/Makefile fence/agents/wti/Makefile fence/agents/xenapi/Makefile fence/agents/hds_cb/Makefile fence/agents/zvm/Makefile doc/Makefile]) AC_OUTPUT diff --git a/fence/agents/alom/fence_alom.py b/fence/agents/alom/fence_alom.py index 1e95ac4d..62ffd7d0 100644 --- a/fence/agents/alom/fence_alom.py +++ b/fence/agents/alom/fence_alom.py @@ -1,59 +1,59 @@ -#!/usr/bin/python -tt +#!@PYTHON@ -tt # The Following Agent Has Been Tested On: # # Sun(tm) Advanced Lights Out Manager CMT v1.6.1 # as found on SUN T2000 Niagara import sys, re, time import atexit sys.path.append("@FENCEAGENTSLIBDIR@") from fencing import * #BEGIN_VERSION_GENERATION RELEASE_VERSION="Sun Advanced Lights Out Manager (ALOM)" REDHAT_COPYRIGHT="" BUILD_DATE="" #END_VERSION_GENERATION def get_power_status(conn, options): conn.send_eol("showplatform") conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) status = re.search("standby", conn.before.lower()) result = (status != None and "off" or "on") return result def set_power_status(conn, options): cmd_line = (options["--action"] == "on" and "poweron" or "poweroff -f -y") conn.send_eol(cmd_line) conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) # Get the machine some time between poweron and poweroff time.sleep(int(options["--power-timeout"])) def main(): device_opt = ["ipaddr", "login", "passwd", "cmd_prompt", "secure"] atexit.register(atexit_handler) all_opt["secure"]["default"] = "1" all_opt["cmd_prompt"]["default"] = [r"sc\>\ "] options = check_input(device_opt, process_input(device_opt)) options["telnet_over_ssh"] = 1 docs = {} docs["shortdesc"] = "Fence agent for Sun ALOM" docs["longdesc"] = "fence_alom is an I/O Fencing \ agent which can be used with ALOM connected machines." docs["vendorurl"] = "http://www.sun.com" show_docs(options, docs) # Operate the fencing device conn = fence_login(options) result = fence_action(conn, options, set_power_status, get_power_status, None) fence_logout(conn, "logout") sys.exit(result) if __name__ == "__main__": main() diff --git a/fence/agents/amt/fence_amt.py b/fence/agents/amt/fence_amt.py index 0283dc22..082f5d09 100644 --- a/fence/agents/amt/fence_amt.py +++ b/fence/agents/amt/fence_amt.py @@ -1,134 +1,134 @@ -#!/usr/bin/python -tt +#!@PYTHON@ -tt import sys, re, os import atexit from pipes import quote sys.path.append("@FENCEAGENTSLIBDIR@") from fencing import * from fencing import fail_usage, is_executable, run_command, run_delay #BEGIN_VERSION_GENERATION RELEASE_VERSION="Fence agent for Intel AMT" REDHAT_COPYRIGHT="" BUILD_DATE="" #END_VERSION_GENERATION def get_power_status(_, options): output = amt_run_command(options, create_command(options, "status")) 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): amt_run_command(options, create_command(options, options["--action"])) return def reboot_cycle(_, options): (status, _, _) = run_command(options, create_command(options, "cycle")) return not bool(status) def amt_run_command(options, command, timeout=None): env = os.environ.copy() x = quote(options["--password"]) x = x[:-1] if x.endswith("'") else x x = x[1:] if x.startswith("'") else x env["AMT_PASSWORD"] = x # This is needed because setting the AMT_PASSWORD env # variable only works when no pipe is involved. E.g.: # - Broken: # $ AMT_PASSWORD='foobar' echo 'y' | /usr/bin/amttool nuc2 powerdown # 401 Unauthorized at /usr/bin/amttool line 129. # - Working: # $ AMT_PASSWORD='foobar' sh -c "(echo 'y' | /usr/bin/amttool nuc2 powerdown)" # execute: powerdown # result: pt_status: success newcommand = "sh -c \"(%s)\"" % command return run_command(options, newcommand, timeout, env) def create_command(options, action): 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"): + if action in ["on", "off", "cycle"] and "--boot-option" in options: cmd += options["--boot-option"] # --use-sudo / -d - if options.has_key("--use-sudo"): + if "--use-sudo" in options: cmd = options["--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" : ":", "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() all_opt["ipport"]["default"] = "16994" options = check_input(device_opt, process_input(device_opt)) docs = {} docs["shortdesc"] = "Fence agent for AMT" docs["longdesc"] = "fence_amt is an I/O Fencing agent \ which can be used with Intel AMT. This agent calls support software amttool\ (http://www.kraxel.org/cgit/amtterm/)." docs["vendorurl"] = "http://www.intel.com/" show_docs(options, docs) run_delay(options) 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() diff --git a/fence/agents/amt_ws/fence_amt_ws.py b/fence/agents/amt_ws/fence_amt_ws.py index 06846d9a..5284a77a 100755 --- a/fence/agents/amt_ws/fence_amt_ws.py +++ b/fence/agents/amt_ws/fence_amt_ws.py @@ -1,243 +1,243 @@ -#!/usr/bin/python -tt +#!@PYTHON@ -tt # # Fence agent for Intel AMT (WS) based on code from the openstack/ironic project: # https://github.com/openstack/ironic/blob/master/ironic/drivers/modules/amt/power.py # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. # import sys import atexit import logging sys.path.append("@FENCEAGENTSLIBDIR@") from fencing import * from fencing import run_delay, fail_usage, fail, EC_STATUS import pywsman from xml.etree import ElementTree #BEGIN_VERSION_GENERATION RELEASE_VERSION="Fence agent for Intel AMT (WS)" REDHAT_COPYRIGHT="" BUILD_DATE="" #END_VERSION_GENERATION POWER_ON='2' POWER_OFF='8' POWER_CYCLE='10' RET_SUCCESS = '0' CIM_PowerManagementService = ('http://schemas.dmtf.org/wbem/wscim/1/' 'cim-schema/2/CIM_PowerManagementService') CIM_ComputerSystem = ('http://schemas.dmtf.org/wbem/wscim/' '1/cim-schema/2/CIM_ComputerSystem') CIM_AssociatedPowerManagementService = ('http://schemas.dmtf.org/wbem/wscim/' '1/cim-schema/2/' 'CIM_AssociatedPowerManagementService') CIM_BootConfigSetting = ('http://schemas.dmtf.org/wbem/wscim/' '1/cim-schema/2/CIM_BootConfigSetting') CIM_BootSourceSetting = ('http://schemas.dmtf.org/wbem/wscim/' '1/cim-schema/2/CIM_BootSourceSetting') def xml_find(doc, namespace, item): if doc is None: return tree = ElementTree.fromstring(doc.root().string()) query = ('.//{%(namespace)s}%(item)s' % {'namespace': namespace, 'item': item}) return tree.find(query) def _generate_power_action_input(action): method_input = "RequestPowerStateChange_INPUT" address = 'http://schemas.xmlsoap.org/ws/2004/08/addressing' anonymous = ('http://schemas.xmlsoap.org/ws/2004/08/addressing/' 'role/anonymous') wsman = 'http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd' namespace = CIM_PowerManagementService doc = pywsman.XmlDoc(method_input) root = doc.root() root.set_ns(namespace) root.add(namespace, 'PowerState', action) child = root.add(namespace, 'ManagedElement', None) child.add(address, 'Address', anonymous) grand_child = child.add(address, 'ReferenceParameters', None) grand_child.add(wsman, 'ResourceURI', CIM_ComputerSystem) g_grand_child = grand_child.add(wsman, 'SelectorSet', None) g_g_grand_child = g_grand_child.add(wsman, 'Selector', 'ManagedSystem') g_g_grand_child.attr_add(wsman, 'Name', 'Name') return doc def get_power_status(_, options): client = pywsman.Client(options["--ip"], int(options["--ipport"]), \ '/wsman', 'http', 'admin', options["--password"]) namespace = CIM_AssociatedPowerManagementService client_options = pywsman.ClientOptions() doc = client.get(client_options, namespace) _SOAP_ENVELOPE = 'http://www.w3.org/2003/05/soap-envelope' item = 'Fault' fault = xml_find(doc, _SOAP_ENVELOPE, item) if fault is not None: logging.error("Failed to get power state for: %s port:%s", \ options["--ip"], options["--ipport"]) fail(EC_STATUS) item = "PowerState" try: power_state = xml_find(doc, namespace, item).text except AttributeError: logging.error("Failed to get power state for: %s port:%s", \ options["--ip"], options["--ipport"]) fail(EC_STATUS) if power_state == POWER_ON: return "on" elif power_state == POWER_OFF: return "off" else: fail(EC_STATUS) def set_power_status(_, options): client = pywsman.Client(options["--ip"], int(options["--ipport"]), \ '/wsman', 'http', 'admin', options["--password"]) method = 'RequestPowerStateChange' client_options = pywsman.ClientOptions() client_options.add_selector('Name', 'Intel(r) AMT Power Management Service') if options["--action"] == "on": target_state = POWER_ON elif options["--action"] == "off": target_state = POWER_OFF elif options["--action"] == "reboot": target_state = POWER_CYCLE if options["--action"] in ["on", "off", "reboot"] \ - and options.has_key("--boot-option"): + and "--boot-option" in options: set_boot_order(_, client, options) doc = _generate_power_action_input(target_state) client_doc = client.invoke(client_options, CIM_PowerManagementService, \ method, doc) item = "ReturnValue" return_value = xml_find(client_doc, CIM_PowerManagementService, item).text if return_value != RET_SUCCESS: logging.error("Failed to set power state: %s for: %s", \ options["--action"], options["--ip"]) fail(EC_STATUS) def set_boot_order(_, client, options): method_input = "ChangeBootOrder_INPUT" address = 'http://schemas.xmlsoap.org/ws/2004/08/addressing' anonymous = ('http://schemas.xmlsoap.org/ws/2004/08/addressing/' 'role/anonymous') wsman = 'http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd' namespace = CIM_BootConfigSetting if options["--boot-option"] == "pxe": device = "Intel(r) AMT: Force PXE Boot" elif options["--boot-option"] == "hd" or "hdsafe": device = "Intel(r) AMT: Force Hard-drive Boot" elif options["--boot-option"] == "cd": device = "Intel(r) AMT: Force CD/DVD Boot" elif options["--boot-option"] == "diag": device = "Intel(r) AMT: Force Diagnostic Boot" else: logging.error('Boot device: %s not supported.', \ options["--boot-option"]) return method = 'ChangeBootOrder' client_options = pywsman.ClientOptions() client_options.add_selector('InstanceID', \ 'Intel(r) AMT: Boot Configuration 0') doc = pywsman.XmlDoc(method_input) root = doc.root() root.set_ns(namespace) child = root.add(namespace, 'Source', None) child.add(address, 'Address', anonymous) grand_child = child.add(address, 'ReferenceParameters', None) grand_child.add(wsman, 'ResourceURI', CIM_BootSourceSetting) g_grand_child = grand_child.add(wsman, 'SelectorSet', None) g_g_grand_child = g_grand_child.add(wsman, 'Selector', device) g_g_grand_child.attr_add(wsman, 'Name', 'InstanceID') if options["--boot-option"] == "hdsafe": g_g_grand_child = g_grand_child.add(wsman, 'Selector', 'True') g_g_grand_child.attr_add(wsman, 'Name', 'UseSafeMode') client_doc = client.invoke(client_options, CIM_BootConfigSetting, \ method, doc) item = "ReturnValue" return_value = xml_find(client_doc, CIM_BootConfigSetting, item).text if return_value != RET_SUCCESS: logging.error("Failed to set boot device to: %s for: %s", \ options["--boot-option"], options["--ip"]) fail(EC_STATUS) def reboot_cycle(_, options): status = set_power_status(_, options) return not bool(status) 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\n" " 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 } def main(): atexit.register(atexit_handler) device_opt = ["ipaddr", "no_login", "passwd", "boot_option", "no_port", "method"] define_new_opts() all_opt["ipport"]["default"] = "16992" options = check_input(device_opt, process_input(device_opt)) docs = {} docs["shortdesc"] = "Fence agent for AMT (WS)" docs["longdesc"] = "fence_amt_ws is an I/O Fencing agent \ which can be used with Intel AMT (WS). This agent requires \ the pywsman Python library which is included in OpenWSMAN. \ (http://openwsman.github.io/)." docs["vendorurl"] = "http://www.intel.com/" show_docs(options, docs) run_delay(options) result = fence_action(None, options, set_power_status, get_power_status, \ None, reboot_cycle) sys.exit(result) if __name__ == "__main__": main() diff --git a/fence/agents/apc/fence_apc.py b/fence/agents/apc/fence_apc.py index c6dd106e..ea89f29c 100644 --- a/fence/agents/apc/fence_apc.py +++ b/fence/agents/apc/fence_apc.py @@ -1,259 +1,259 @@ -#!/usr/bin/python -tt +#!@PYTHON@ -tt ##### ## ## The Following Agent Has Been Tested On: ## ## Model Firmware ## +---------------------------------------------+ ## AP7951 AOS v2.7.0, PDU APP v2.7.3 ## AP7941 AOS v3.5.7, PDU APP v3.5.6 ## AP9606 AOS v2.5.4, PDU APP v2.7.3 ## ## @note: ssh is very slow on AP79XX devices protocol (1) and ## cipher (des/blowfish) have to be defined ##### import sys, re import atexit sys.path.append("@FENCEAGENTSLIBDIR@") from fencing import * from fencing import fail, fail_usage, EC_STATUS #BEGIN_VERSION_GENERATION RELEASE_VERSION="New APC Agent - test release on steroids" REDHAT_COPYRIGHT="" BUILD_DATE="March, 2008" #END_VERSION_GENERATION def get_power_status(conn, options): exp_result = 0 outlets = {} conn.send_eol("1") conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) version = 0 admin = 0 switch = 0 if None != re.compile('.* MasterSwitch plus.*', re.IGNORECASE | re.S).match(conn.before): switch = 1 if None != re.compile('.* MasterSwitch plus 2', re.IGNORECASE | re.S).match(conn.before): - if not options.has_key("--switch"): + if "--switch" not in options: fail_usage("Failed: You have to enter physical switch number") else: - if not options.has_key("--switch"): + if "--switch" not in options: options["--switch"] = "1" if None == re.compile('.*Outlet Management.*', re.IGNORECASE | re.S).match(conn.before): version = 2 else: version = 3 if None == re.compile('.*Outlet Control/Configuration.*', re.IGNORECASE | re.S).match(conn.before): admin = 0 else: admin = 1 if switch == 0: if version == 2: if admin == 0: conn.send_eol("2") else: conn.send_eol("3") else: conn.send_eol("2") conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) conn.send_eol("1") else: conn.send_eol(options["--switch"]) while True: exp_result = conn.log_expect( ["Press "] + options["--command-prompt"], int(options["--shell-timeout"])) lines = conn.before.split("\n") show_re = re.compile(r'(^|\x0D)\s*(\d+)- (.*?)\s+(ON|OFF)\s*') for line in lines: res = show_re.search(line) if res != None: outlets[res.group(2)] = (res.group(3), res.group(4)) conn.send_eol("") if exp_result != 0: break - conn.send(chr(03)) + conn.send(chr(0o3)) conn.log_expect("- Logout", int(options["--shell-timeout"])) conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) if ["list", "monitor"].count(options["--action"]) == 1: return outlets else: try: (_, status) = outlets[options["--plug"]] return status.lower().strip() except KeyError: fail(EC_STATUS) def set_power_status(conn, options): action = { 'on' : "1", 'off': "2" }[options["--action"]] conn.send_eol("1") conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) version = 0 admin2 = 0 admin3 = 0 switch = 0 if None != re.compile('.* MasterSwitch plus.*', re.IGNORECASE | re.S).match(conn.before): switch = 1 ## MasterSwitch has different schema for on/off actions action = { 'on' : "1", 'off': "3" }[options["--action"]] if None != re.compile('.* MasterSwitch plus 2', re.IGNORECASE | re.S).match(conn.before): - if not options.has_key("--switch"): + if "--switch" not in options: fail_usage("Failed: You have to enter physical switch number") else: - if not options.has_key("--switch"): + if "--switch" not in options: options["--switch"] = 1 if None == re.compile('.*Outlet Management.*', re.IGNORECASE | re.S).match(conn.before): version = 2 else: version = 3 if None == re.compile('.*Outlet Control/Configuration.*', re.IGNORECASE | re.S).match(conn.before): admin2 = 0 else: admin2 = 1 if switch == 0: if version == 2: if admin2 == 0: conn.send_eol("2") else: conn.send_eol("3") else: conn.send_eol("2") conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) if None == re.compile('.*2- Outlet Restriction.*', re.IGNORECASE | re.S).match(conn.before): admin3 = 0 else: admin3 = 1 conn.send_eol("1") else: conn.send_eol(options["--switch"]) while 0 == conn.log_expect( ["Press "] + options["--command-prompt"], int(options["--shell-timeout"])): conn.send_eol("") conn.send_eol(options["--plug"]+"") conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) if switch == 0: if admin2 == 1: conn.send_eol("1") conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) if admin3 == 1: conn.send_eol("1") conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) else: conn.send_eol("1") conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) conn.send_eol(action) conn.log_expect("Enter 'YES' to continue or to cancel :", int(options["--shell-timeout"])) conn.send_eol("YES") conn.log_expect("Press to continue...", int(options["--power-timeout"])) conn.send_eol("") conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) - conn.send(chr(03)) + conn.send(chr(0o3)) conn.log_expect("- Logout", int(options["--shell-timeout"])) conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) def get_power_status5(conn, options): outlets = {} conn.send_eol("olStatus all") conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) lines = conn.before.split("\n") show_re = re.compile(r'^\s*(\d+): (.*): (On|Off)\s*$', re.IGNORECASE) for line in lines: res = show_re.search(line) if res != None: outlets[res.group(1)] = (res.group(2), res.group(3)) if ["list", "monitor"].count(options["--action"]) == 1: return outlets else: try: (_, status) = outlets[options["--plug"]] return status.lower().strip() except KeyError: fail(EC_STATUS) def set_power_status5(conn, options): action = { 'on' : "olOn", 'off': "olOff" }[options["--action"]] conn.send_eol(action + " " + options["--plug"]) conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) def main(): device_opt = ["ipaddr", "login", "passwd", "cmd_prompt", "secure", \ "port", "switch", "telnet"] atexit.register(atexit_handler) all_opt["cmd_prompt"]["default"] = ["\n>", "\napc>"] all_opt["ssh_options"]["default"] = "-1 -c blowfish" options = check_input(device_opt, process_input(device_opt)) docs = {} docs["shortdesc"] = "Fence agent for APC over telnet/ssh" docs["longdesc"] = "fence_apc is an I/O Fencing agent \ which can be used with the APC network power switch. It logs into device \ via telnet/ssh and reboots a specified outlet. Lengthy telnet/ssh connections \ should be avoided while a GFS cluster is running because the connection \ will block any necessary fencing actions." docs["vendorurl"] = "http://www.apc.com" show_docs(options, docs) ## Support for --plug [switch]:[plug] notation that was used before - if (options.has_key("--plug") == 1) and (-1 != options["--plug"].find(":")): + if (("--plug" in options) == 1) and (-1 != options["--plug"].find(":")): (switch, plug) = options["--plug"].split(":", 1) options["--switch"] = switch options["--plug"] = plug ## ## Operate the fencing device #### conn = fence_login(options) ## Detect firmware version (ASCII menu vs command-line interface) ## and continue with proper action #### result = -1 firmware_version = re.compile(r'\s*v(\d)*\.').search(conn.before) if (firmware_version != None) and (firmware_version.group(1) in [ "5", "6" ]): result = fence_action(conn, options, set_power_status5, get_power_status5, get_power_status5) else: result = fence_action(conn, options, set_power_status, get_power_status, get_power_status) fence_logout(conn, "4") sys.exit(result) if __name__ == "__main__": main() diff --git a/fence/agents/apc_snmp/fence_apc_snmp.py b/fence/agents/apc_snmp/fence_apc_snmp.py index 8bb3d482..6a6698f0 100644 --- a/fence/agents/apc_snmp/fence_apc_snmp.py +++ b/fence/agents/apc_snmp/fence_apc_snmp.py @@ -1,223 +1,223 @@ -#!/usr/bin/python -tt +#!@PYTHON@ -tt # The Following agent has been tested on: # - APC Switched Rack PDU - SNMP v1 # (MB:v3.7.0 PF:v2.7.0 PN:apc_hw02_aos_270.bin AF1:v2.7.3 # AN1:apc_hw02_aos_270.bin AF1:v2.7.3 AN1:apc_hw02_rpdu_273.bin MN:AP7930 HR:B2) # - APC Web/SNMP Management Card - SNMP v1 and v3 (noAuthNoPrivacy,authNoPrivacy, authPrivacy) # (MB:v3.8.6 PF:v3.5.8 PN:apc_hw02_aos_358.bin AF1:v3.5.7 # AN1:apc_hw02_aos_358.bin AF1:v3.5.7 AN1:apc_hw02_rpdu_357.bin MN:AP7900 HR:B2) # - APC Switched Rack PDU - SNMP v1 # (MB:v3.7.0 PF:v2.7.0 PN:apc_hw02_aos_270.bin AF1:v2.7.3 # AN1:apc_hw02_rpdu_273.bin MN:AP7951 HR:B2) # - Tripplite PDUMH20HVNET 12.04.0055 - SNMP v1, v2c, v3 import sys import atexit import logging sys.path.append("@FENCEAGENTSLIBDIR@") from fencing import * from fencing import fail_usage from fencing_snmp import FencingSnmp #BEGIN_VERSION_GENERATION RELEASE_VERSION="APC SNMP fence agent" REDHAT_COPYRIGHT="" BUILD_DATE="" #END_VERSION_GENERATION ### CONSTANTS ### # oid defining fence device OID_SYS_OBJECT_ID = '.1.3.6.1.2.1.1.2.0' ### GLOBAL VARIABLES ### # Device - see ApcRPDU, ApcMSP, ApcMS, TripplitePDU device = None # Port ID port_id = None # Switch ID switch_id = None # Classes describing Device params class TripplitePDU(object): # Rack PDU status_oid = '.1.3.6.1.4.1.850.10.2.3.5.1.2.1.%d' control_oid = '.1.3.6.1.4.1.850.10.2.3.5.1.4.1.%d' outlet_table_oid = '.1.3.6.1.4.1.850.10.2.3.5.1.5' ident_str = "Tripplite" state_on = 2 state_off = 1 turn_on = 2 turn_off = 1 has_switches = False class ApcRPDU(object): # Rack PDU status_oid = '.1.3.6.1.4.1.318.1.1.12.3.5.1.1.4.%d' control_oid = '.1.3.6.1.4.1.318.1.1.12.3.3.1.1.4.%d' outlet_table_oid = '.1.3.6.1.4.1.318.1.1.12.3.5.1.1.2' ident_str = "APC rPDU" state_on = 1 state_off = 2 turn_on = 1 turn_off = 2 has_switches = False class ApcMSP(object): # Master Switch+ status_oid = '.1.3.6.1.4.1.318.1.1.6.7.1.1.5.%d.1.%d' control_oid = '.1.3.6.1.4.1.318.1.1.6.5.1.1.5.%d.1.%d' outlet_table_oid = '.1.3.6.1.4.1.318.1.1.6.7.1.1.4' ident_str = "APC Master Switch+" state_on = 1 state_off = 2 turn_on = 1 turn_off = 3 has_switches = True class ApcMS(object): # Master Switch - seems oldest, but supported on every APC PDU status_oid = '.1.3.6.1.4.1.318.1.1.4.4.2.1.3.%d' control_oid = '.1.3.6.1.4.1.318.1.1.4.4.2.1.3.%d' outlet_table_oid = '.1.3.6.1.4.1.318.1.1.4.4.2.1.4' ident_str = "APC Master Switch (fallback)" state_on = 1 state_off = 2 turn_on = 1 turn_off = 2 has_switches = False class ApcMS6(object): # Master Switch with 6.x firmware status_oid = '.1.3.6.1.4.1.318.1.1.4.4.2.1.3.%d' control_oid = '.1.3.6.1.4.1.318.1.1.12.3.3.1.1.4.%d' outlet_table_oid = '1.3.6.1.4.1.318.1.1.4.4.2.1.4' ident_str = "APC Master Switch with firmware v6.x" state_on = 1 state_off = 2 turn_on = 1 turn_off = 2 has_switches = False ### FUNCTIONS ### def apc_set_device(conn): global device agents_dir = {'.1.3.6.1.4.1.318.1.3.4.5':ApcRPDU, '.1.3.6.1.4.1.318.1.3.4.4':ApcMSP, '.1.3.6.1.4.1.850.1':TripplitePDU, '.1.3.6.1.4.1.318.1.3.4.6':ApcMS6, None:ApcMS} # First resolve type of APC apc_type = conn.walk(OID_SYS_OBJECT_ID) - if not ((len(apc_type) == 1) and (agents_dir.has_key(apc_type[0][1]))): + if not ((len(apc_type) == 1) and (apc_type[0][1] in agents_dir)): apc_type = [[None, None]] device = agents_dir[apc_type[0][1]] logging.debug("Trying %s"%(device.ident_str)) def apc_resolv_port_id(conn, options): global port_id, switch_id if device == None: apc_set_device(conn) # Now we resolv port_id/switch_id if (options["--plug"].isdigit()) and ((not device.has_switches) or (options["--switch"].isdigit())): port_id = int(options["--plug"]) if device.has_switches: switch_id = int(options["--switch"]) else: table = conn.walk(device.outlet_table_oid, 30) for x in table: if x[1].strip('"') == options["--plug"]: t = x[0].split('.') if device.has_switches: port_id = int(t[len(t)-1]) switch_id = int(t[len(t)-3]) else: port_id = int(t[len(t)-1]) if port_id == None: fail_usage("Can't find port with name %s!"%(options["--plug"])) def get_power_status(conn, options): if port_id == None: apc_resolv_port_id(conn, options) oid = ((device.has_switches) and device.status_oid%(switch_id, port_id) or device.status_oid%(port_id)) (oid, status) = conn.get(oid) return status == str(device.state_on) and "on" or "off" def set_power_status(conn, options): if port_id == None: apc_resolv_port_id(conn, options) oid = ((device.has_switches) and device.control_oid%(switch_id, port_id) or device.control_oid%(port_id)) conn.set(oid, (options["--action"] == "on" and device.turn_on or device.turn_off)) def get_outlets_status(conn, options): result = {} if device == None: apc_set_device(conn) res_ports = conn.walk(device.outlet_table_oid, 30) for x in res_ports: t = x[0].split('.') port_num = ((device.has_switches) and "%s:%s"%(t[len(t)-3], t[len(t)-1]) or "%s"%(t[len(t)-1])) port_name = x[1].strip('"') port_status = "" result[port_num] = (port_name, port_status) return result # Main agent method def main(): device_opt = ["ipaddr", "login", "passwd", "no_login", "no_password", \ "port", "snmp_version", "snmp"] atexit.register(atexit_handler) all_opt["snmp_version"]["default"] = "1" all_opt["community"]["default"] = "private" options = check_input(device_opt, process_input(device_opt)) ## Support for -n [switch]:[plug] notation that was used before - if (options.has_key("--plug")) and (-1 != options["--plug"].find(":")): + if ("--plug" in options) and (-1 != options["--plug"].find(":")): (switch, plug) = options["--plug"].split(":", 1) if switch.isdigit() and plug.isdigit(): options["--switch"] = switch options["--plug"] = plug - if not options.has_key("--switch"): + if "--switch" not in options: options["--switch"] = "1" docs = {} docs["shortdesc"] = "Fence agent for APC, Tripplite PDU over SNMP" docs["longdesc"] = "fence_apc_snmp is an I/O Fencing agent \ which can be used with the APC network power switch or Tripplite PDU devices.\ It logs into a device via SNMP and reboots a specified outlet. It supports \ SNMP v1, v2c, v3 with all combinations of authenticity/privacy settings." docs["vendorurl"] = "http://www.apc.com" show_docs(options, docs) # Operate the fencing device result = fence_action(FencingSnmp(options), options, set_power_status, get_power_status, get_outlets_status) sys.exit(result) if __name__ == "__main__": main() diff --git a/fence/agents/bladecenter/fence_bladecenter.py b/fence/agents/bladecenter/fence_bladecenter.py index d72c07f1..b45f3157 100644 --- a/fence/agents/bladecenter/fence_bladecenter.py +++ b/fence/agents/bladecenter/fence_bladecenter.py @@ -1,111 +1,111 @@ -#!/usr/bin/python -tt +#!@PYTHON@ -tt ##### ## ## The Following Agent Has Been Tested On: ## ## Model Firmware ## +--------------------+---------------------------+ ## (1) Main application BRET85K, rev 16 ## Boot ROM BRBR67D, rev 16 ## Remote Control BRRG67D, rev 16 ## ##### import sys, re import atexit sys.path.append("@FENCEAGENTSLIBDIR@") from fencing import * from fencing import fail, EC_STATUS, EC_GENERIC_ERROR #BEGIN_VERSION_GENERATION RELEASE_VERSION="New Bladecenter Agent - test release on steroids" REDHAT_COPYRIGHT="" BUILD_DATE="March, 2008" #END_VERSION_GENERATION def get_power_status(conn, options): node_cmd = r"system:blade\[" + options["--plug"] + r"\]>" conn.send_eol("env -T system:blade[" + options["--plug"] + "]") i = conn.log_expect([node_cmd, "system>"], int(options["--shell-timeout"])) if i == 1: ## Given blade number does not exist - if options.has_key("--missing-as-off"): + if "--missing-as-off" in options: return "off" else: fail(EC_STATUS) conn.send_eol("power -state") conn.log_expect(node_cmd, int(options["--shell-timeout"])) status = conn.before.splitlines()[-1] conn.send_eol("env -T system") conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) return status.lower().strip() def set_power_status(conn, options): node_cmd = r"system:blade\[" + options["--plug"] + r"\]>" conn.send_eol("env -T system:blade[" + options["--plug"] + "]") i = conn.log_expect([node_cmd, "system>"], int(options["--shell-timeout"])) if i == 1: ## Given blade number does not exist - if options.has_key("--missing-as-off"): + if "--missing-as-off" in options: return else: fail(EC_GENERIC_ERROR) conn.send_eol("power -"+options["--action"]) conn.log_expect(node_cmd, int(options["--shell-timeout"])) conn.send_eol("env -T system") conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) def get_blades_list(conn, options): outlets = {} node_cmd = "system>" conn.send_eol("env -T system") conn.log_expect(node_cmd, int(options["--shell-timeout"])) conn.send_eol("list -l 2") conn.log_expect(node_cmd, int(options["--shell-timeout"])) lines = conn.before.split("\r\n") filter_re = re.compile(r"^\s*blade\[(\d+)\]\s+(.*?)\s*$") for blade_line in lines: res = filter_re.search(blade_line) if res != None: outlets[res.group(1)] = (res.group(2), "") return outlets def main(): device_opt = ["ipaddr", "login", "passwd", "cmd_prompt", "secure", \ "port", "missing_as_off", "telnet"] atexit.register(atexit_handler) all_opt["power_wait"]["default"] = "10" all_opt["cmd_prompt"]["default"] = ["system>"] options = check_input(device_opt, process_input(device_opt)) docs = {} docs["shortdesc"] = "Fence agent for IBM BladeCenter" docs["longdesc"] = "fence_bladecenter is an I/O Fencing agent \ which can be used with IBM Bladecenters with recent enough firmware that \ includes telnet support. It logs into a Brocade chasis via telnet or ssh \ and uses the command line interface to power on and off blades." docs["vendorurl"] = "http://www.ibm.com" show_docs(options, docs) ## ## Operate the fencing device ###### conn = fence_login(options, "(username\s*:\s*)") result = fence_action(conn, options, set_power_status, get_power_status, get_blades_list) fence_logout(conn, "exit") sys.exit(result) if __name__ == "__main__": main() diff --git a/fence/agents/brocade/fence_brocade.py b/fence/agents/brocade/fence_brocade.py index 5257bccb..4cf039a9 100644 --- a/fence/agents/brocade/fence_brocade.py +++ b/fence/agents/brocade/fence_brocade.py @@ -1,78 +1,78 @@ -#!/usr/bin/python -tt +#!@PYTHON@ -tt import sys, re import atexit sys.path.append("@FENCEAGENTSLIBDIR@") from fencing import * from fencing import fail, EC_STATUS #BEGIN_VERSION_GENERATION RELEASE_VERSION="New Brocade Agent - test release on steroids" REDHAT_COPYRIGHT="" BUILD_DATE="March, 20013" #END_VERSION_GENERATION def set_power_status(conn, options): action = { 'on' : "portCfgPersistentEnable", 'off': "portCfgPersistentDisable" }[options["--action"]] conn.send_eol(action + " " + options["--plug"]) conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) def get_power_status(conn, options): line_re = re.compile(r'=========', re.IGNORECASE) outlets = {} in_index = False conn.send_eol("switchshow") conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) for line in str(conn.before).split("\n"): if line_re.search(line): in_index = True elif in_index and line.lstrip()[0].isdigit(): tokens = line.lstrip().split() status = "off" if len(tokens) > 7 and tokens[7] == "Disabled" else "on" outlets[tokens[0]] = ("", status) if ["list", "monitor"].count(options["--action"]) == 0: (_, status) = outlets[options["--plug"]] return status else: return outlets def main(): device_opt = ["ipaddr", "login", "passwd", "cmd_prompt", "secure", \ "port", "fabric_fencing", "telnet"] atexit.register(atexit_handler) all_opt["cmd_prompt"]["default"] = ["> "] options = check_input(device_opt, process_input(device_opt)) options["eol"] = "\n" docs = {} docs["shortdesc"] = "Fence agent for HP Brocade over telnet/ssh" docs["longdesc"] = "fence_brocade is an I/O Fencing agent which can be used with Brocade FC switches. \ It logs into a Brocade switch via telnet and disables a specified port. Disabling the port which a machine is \ connected to effectively fences that machine. Lengthy telnet connections to the switch should be avoided while \ a GFS cluster is running because the connection will block any necessary fencing actions. \ \ After a fence operation has taken place the fenced machine can no longer connect to the Brocade FC switch. \ When the fenced machine is ready to be brought back into the GFS cluster (after reboot) the port on the Brocade \ FC switch needs to be enabled. This can be done by running fence_brocade and specifying the enable action" docs["vendorurl"] = "http://www.brocade.com" show_docs(options, docs) ## ## Operate the fencing device #### conn = fence_login(options) result = fence_action(conn, options, set_power_status, get_power_status, get_power_status) fence_logout(conn, "exit") sys.exit(result) if __name__ == "__main__": main() diff --git a/fence/agents/cisco_mds/fence_cisco_mds.py b/fence/agents/cisco_mds/fence_cisco_mds.py index ba9d9175..cb3c9605 100644 --- a/fence/agents/cisco_mds/fence_cisco_mds.py +++ b/fence/agents/cisco_mds/fence_cisco_mds.py @@ -1,100 +1,100 @@ -#!/usr/bin/python -tt +#!@PYTHON@ -tt # The Following agent has been tested on: # - Cisco MDS UROS 9134 FC (1 Slot) Chassis ("1/2/4 10 Gbps FC/Supervisor-2") Motorola, e500v2 # with BIOS 1.0.16, kickstart 4.1(1c), system 4.1(1c) # - Cisco MDS 9124 (1 Slot) Chassis ("1/2/4 Gbps FC/Supervisor-2") Motorola, e500 # with BIOS 1.0.16, kickstart 4.1(1c), system 4.1(1c) import sys, re import atexit sys.path.append("@FENCEAGENTSLIBDIR@") from fencing import * from fencing import fail_usage, array_to_dict from fencing_snmp import FencingSnmp #BEGIN_VERSION_GENERATION RELEASE_VERSION="Cisco MDS 9xxx SNMP fence agent" REDHAT_COPYRIGHT="" BUILD_DATE="" #END_VERSION_GENERATION ### CONSTANTS ### # Cisco admin status PORT_ADMIN_STATUS_OID = ".1.3.6.1.2.1.75.1.2.2.1.1" # IF-MIB trees for alias, status and port ALIASES_OID = ".1.3.6.1.2.1.31.1.1.1.18" PORTS_OID = ".1.3.6.1.2.1.2.2.1.2" ### GLOBAL VARIABLES ### # OID converted from fc port name (fc(x)/(y)) PORT_OID = "" ### FUNCTIONS ### # Convert cisco port name (fc(x)/(y)) to OID def cisco_port2oid(port): port = port.lower() nums = re.match(r'^fc(\d+)/(\d+)$', port) if nums and len(nums.groups()) == 2: return "%s.%d.%d"% (PORT_ADMIN_STATUS_OID, int(nums.group(1))+21, int(nums.group(2))-1) else: fail_usage("Mangled port number: %s"%(port)) def get_power_status(conn, options): (_, status) = conn.get(PORT_OID) return status == "1" and "on" or "off" def set_power_status(conn, options): conn.set(PORT_OID, (options["--action"] == "on" and 1 or 2)) def get_outlets_status(conn, options): result = {} res_fc = conn.walk(PORTS_OID, 30) res_aliases = array_to_dict(conn.walk(ALIASES_OID, 30)) fc_re = re.compile(r'^"fc\d+/\d+"$') for x in res_fc: if fc_re.match(x[1]): port_num = x[0].split('.')[-1] port_name = x[1].strip('"') - port_alias = (res_aliases.has_key(port_num) and res_aliases[port_num].strip('"') or "") + port_alias = (port_num in res_aliases and res_aliases[port_num].strip('"') or "") port_status = "" result[port_name] = (port_alias, port_status) return result # Main agent method def main(): global PORT_OID device_opt = ["fabric_fencing", "ipaddr", "login", "passwd", "no_login", "no_password", \ "port", "snmp_version", "snmp"] atexit.register(atexit_handler) options = check_input(device_opt, process_input(device_opt)) docs = {} docs["shortdesc"] = "Fence agent for Cisco MDS" docs["longdesc"] = "fence_cisco_mds is an I/O Fencing agent \ which can be used with any Cisco MDS 9000 series with SNMP enabled device." docs["vendorurl"] = "http://www.cisco.com" show_docs(options, docs) if not options["--action"] in ["list", "monitor"]: PORT_OID = cisco_port2oid(options["--plug"]) # Operate the fencing device result = fence_action(FencingSnmp(options), options, set_power_status, get_power_status, get_outlets_status) sys.exit(result) if __name__ == "__main__": main() diff --git a/fence/agents/cisco_ucs/fence_cisco_ucs.py b/fence/agents/cisco_ucs/fence_cisco_ucs.py index 24a96a1c..648e45fd 100644 --- a/fence/agents/cisco_ucs/fence_cisco_ucs.py +++ b/fence/agents/cisco_ucs/fence_cisco_ucs.py @@ -1,192 +1,192 @@ -#!/usr/bin/python -tt +#!@PYTHON@ -tt import sys, re -import pycurl, StringIO +import pycurl, io import logging import atexit sys.path.append("@FENCEAGENTSLIBDIR@") from fencing import * from fencing import fail, EC_STATUS, EC_LOGIN_DENIED, run_delay #BEGIN_VERSION_GENERATION RELEASE_VERSION="New Cisco UCS Agent - test release on steroids" REDHAT_COPYRIGHT="" BUILD_DATE="March, 2008" #END_VERSION_GENERATION RE_COOKIE = re.compile("", int(options["--shell-timeout"])) result = RE_GET_PNDN.search(res) if result == None: pndn = "" else: pndn = result.group(1) if pndn.strip() == "": if "--missing-as-off" in options: return "off" else: fail(EC_STATUS) res = send_command(options, "", int(options["--shell-timeout"])) result = RE_GET_PRESENCE.search(res) if result == None: fail(EC_STATUS) else: status = result.group(1) if status in ["missing", "mismatch"]: return "off" else: return "on" def set_power_status(conn, options): del conn action = { 'on' : "up", 'off' : "down" }[options["--action"]] send_command(options, "" + "" + "" + "", int(options["--shell-timeout"])) return def get_list(conn, options): del conn outlets = {} try: res = send_command(options, "", int(options["--shell-timeout"])) lines = res.split("", int(options_global["--shell-timeout"])) except Exception: pass def main(): global options_global device_opt = ["ipaddr", "login", "passwd", "ssl", "notls", "port", "web", "suborg", "missing_as_off"] atexit.register(atexit_handler) atexit.register(logout) define_new_opts() options_global = check_input(device_opt, process_input(device_opt)) docs = {} docs["shortdesc"] = "Fence agent for Cisco UCS" docs["longdesc"] = "fence_cisco_ucs is an I/O Fencing agent which can be \ used with Cisco UCS to fence machines." docs["vendorurl"] = "http://www.cisco.com" show_docs(options_global, docs) run_delay(options_global) ### Login try: res = send_command(options_global, "", int(options_global["--login-timeout"])) result = RE_COOKIE.search(res) if result == None: ## Cookie is absenting in response fail(EC_LOGIN_DENIED) except Exception: fail(EC_LOGIN_DENIED) options_global["cookie"] = result.group(1) ## ## Modify suborg to format /suborg if options_global["--suborg"] != "": options_global["--suborg"] = "/" + options_global["--suborg"].lstrip("/").rstrip("/") ## ## Fence operations #### result = fence_action(None, options_global, set_power_status, get_power_status, get_list) ## Logout is done every time at atexit phase sys.exit(result) if __name__ == "__main__": main() diff --git a/fence/agents/compute/fence_compute.py b/fence/agents/compute/fence_compute.py index be7fc226..8f4128e7 100644 --- a/fence/agents/compute/fence_compute.py +++ b/fence/agents/compute/fence_compute.py @@ -1,446 +1,446 @@ -#!/usr/bin/python -tt +#!@PYTHON@ -tt import sys import time import atexit import logging import requests.exceptions sys.path.append("@FENCEAGENTSLIBDIR@") from fencing import * from fencing import fail_usage, is_executable, run_command, run_delay #BEGIN_VERSION_GENERATION RELEASE_VERSION="4.0.11" BUILD_DATE="(built Wed Nov 12 06:33:38 EST 2014)" REDHAT_COPYRIGHT="Copyright (C) Red Hat, Inc. 2004-2010 All rights reserved." #END_VERSION_GENERATION override_status = "" nova = None EVACUABLE_TAG = "evacuable" TRUE_TAGS = ['true'] def get_power_status(_, options): global override_status status = "unknown" logging.debug("get action: " + options["--action"]) if len(override_status): logging.debug("Pretending we're " + override_status) return override_status if nova: try: services = nova.services.list(host=options["--plug"]) for service in services: logging.debug("Status of %s is %s" % (service.binary, service.state)) if service.binary == "nova-compute": if service.state == "up": status = "on" elif service.state == "down": status = "off" else: logging.debug("Unknown status detected from nova: " + service.state) break - except ConnectionError as (err): + except ConnectionError as err: logging.warning("Nova connection failed: " + str(err)) return status # NOTE(sbauza); We mimic the host-evacuate module since it's only a contrib # module which is not stable def _server_evacuate(server, on_shared_storage): success = False error_message = "" try: logging.debug("Resurrecting instance: %s" % server) (response, dictionary) = nova.servers.evacuate(server=server, on_shared_storage=on_shared_storage) if response == None: error_message = "No response while evacuating instance" elif response.status_code == 200: success = True error_message = response.reason else: error_message = response.reason except Exception as e: error_message = "Error while evacuating instance: %s" % e return { "uuid": server, "accepted": success, "reason": error_message, } def _is_server_evacuable(server, evac_flavors, evac_images): if server.flavor.get('id') in evac_flavors: return True if server.image.get('id') in evac_images: return True logging.debug("Instance %s is not evacuable" % server.image.get('id')) return False def _get_evacuable_flavors(): result = [] flavors = nova.flavors.list() # Since the detailed view for all flavors doesn't provide the extra specs, # we need to call each of the flavor to get them. for flavor in flavors: if flavor.get_keys().get(EVACUABLE_TAG).strip().lower() in TRUE_TAGS: result.append(flavor.id) return result def _get_evacuable_images(): result = [] images = nova.images.list(detailed=True) for image in images: if hasattr(image, 'metadata'): if image.metadata.get(EVACUABLE_TAG).strip.lower() in TRUE_TAGS: result.append(image.id) return result def _host_evacuate(options): result = True servers = nova.servers.list(search_opts={'host': options["--plug"], 'all_tenants': 1 }) if options["--instance-filtering"] == "False": logging.debug("Evacuating all images and flavors") evacuables = servers else: logging.debug("Filtering images and flavors") flavors = _get_evacuable_flavors() images = _get_evacuable_images() # Identify all evacuable servers evacuables = [server for server in servers if _is_server_evacuable(server, flavors, images)] if options["--no-shared-storage"] != "False": on_shared_storage = False else: on_shared_storage = True for server in evacuables: logging.debug("Processing %s" % server) if hasattr(server, 'id'): response = _server_evacuate(server.id, on_shared_storage) if response["accepted"]: logging.debug("Evacuated %s from %s: %s" % (response["uuid"], options["--plug"], response["reason"])) else: logging.error("Evacuation of %s on %s failed: %s" % (response["uuid"], options["--plug"], response["reason"])) result = False else: logging.error("Could not evacuate instance: %s" % server.to_dict()) # Should a malformed instance result in a failed evacuation? # result = False return result def set_attrd_status(host, status, options): logging.debug("Setting fencing status for %s to %s" % (host, status)) run_command(options, "attrd_updater -p -n evacuate -Q -N %s -U %s" % (host, status)) def set_power_status(_, options): global override_status override_status = "" logging.debug("set action: " + options["--action"]) if not nova: return if options["--action"] == "on": if get_power_status(_, options) == "on": # Forcing the service back up in case it was disabled nova.services.enable(options["--plug"], 'nova-compute') try: # Forcing the host back up nova.services.force_down( options["--plug"], "nova-compute", force_down=False) except Exception as e: # In theory, if foce_down=False fails, that's for the exact # same possible reasons that below with force_down=True # eg. either an incompatible version or an old client. # Since it's about forcing back to a default value, there is # no real worries to just consider it's still okay even if the # command failed logging.info("Exception from attempt to force " "host back up via nova API: " "%s: %s" % (e.__class__.__name__, e)) else: # Pretend we're 'on' so that the fencing library doesn't loop forever waiting for the node to boot override_status = "on" return try: nova.services.force_down( options["--plug"], "nova-compute", force_down=True) except Exception as e: # Something went wrong when we tried to force the host down. # That could come from either an incompatible API version # eg. UnsupportedVersion or VersionNotFoundForAPIMethod # or because novaclient is old and doesn't include force_down yet # eg. AttributeError # In that case, fallbacking to wait for Nova to catch the right state. logging.error("Exception from attempt to force host down via nova API: " "%s: %s" % (e.__class__.__name__, e)) # need to wait for nova to update its internal status or we # cannot call host-evacuate while get_power_status(_, options) != "off": # Loop forever if need be. # # Some callers (such as Pacemaker) will have a timer # running and kill us if necessary logging.debug("Waiting for nova to update it's internal state for %s" % options["--plug"]) time.sleep(1) if not _host_evacuate(options): sys.exit(1) return def fix_domain(options): domains = {} last_domain = None if nova: # Find it in nova hypervisors = nova.hypervisors.list() for hypervisor in hypervisors: shorthost = hypervisor.hypervisor_hostname.split('.')[0] if shorthost == hypervisor.hypervisor_hostname: # Nova is not using FQDN calculated = "" else: # Compute nodes are named as FQDN, strip off the hostname calculated = hypervisor.hypervisor_hostname.replace(shorthost+".", "") domains[calculated] = shorthost if calculated == last_domain: # Avoid complaining for each compute node with the same name # One hopes they don't appear interleaved as A.com B.com A.com B.com logging.debug("Calculated the same domain from: %s" % hypervisor.hypervisor_hostname) - elif options.has_key("--domain") and options["--domain"] == calculated: + elif "--domain" in options and options["--domain"] == calculated: # Supplied domain name is valid return - elif options.has_key("--domain"): + elif "--domain" in options: # Warn in case nova isn't available at some point logging.warning("Supplied domain '%s' does not match the one calculated from: %s" % (options["--domain"], hypervisor.hypervisor_hostname)) last_domain = calculated - if len(domains) == 0 and not options.has_key("--domain"): + if len(domains) == 0 and "--domain" not in options: logging.error("Could not calculate the domain names used by compute nodes in nova") - elif len(domains) == 1 and not options.has_key("--domain"): + elif len(domains) == 1 and "--domain" not in options: options["--domain"] = last_domain elif len(domains) == 1: logging.error("Overriding supplied domain '%s' does not match the one calculated from: %s" % (options["--domain"], hypervisor.hypervisor_hostname)) options["--domain"] = last_domain elif len(domains) > 1: logging.error("The supplied domain '%s' did not match any used inside nova: %s" % (options["--domain"], repr(domains))) sys.exit(1) def fix_plug_name(options): if options["--action"] == "list": return - if not options.has_key("--plug"): + if "--plug" not in options: return fix_domain(options) short_plug = options["--plug"].split('.')[0] logging.debug("Checking target '%s' against calculated domain '%s'"% (options["--plug"], calculated)) - if not options.has_key("--domain"): + if "--domain" not in options: # Nothing supplied and nova not available... what to do... nothing return elif options["--domain"] == "": # Ensure any domain is stripped off since nova isn't using FQDN options["--plug"] = short_plug elif options["--plug"].find(options["--domain"]): # Plug already contains the domain, don't re-add return else: # Add the domain to the plug options["--plug"] = short_plug + "." + options["--domain"] def get_plugs_list(_, options): result = {} if nova: hypervisors = nova.hypervisors.list() for hypervisor in hypervisors: longhost = hypervisor.hypervisor_hostname shorthost = longhost.split('.')[0] result[longhost] = ("", None) result[shorthost] = ("", None) return result def define_new_opts(): all_opt["endpoint-type"] = { "getopt" : "e:", "longopt" : "endpoint-type", "help" : "-e, --endpoint-type=[endpoint] Nova Endpoint type (publicURL, internalURL, adminURL)", "required" : "0", "shortdesc" : "Nova Endpoint type", "default" : "internalURL", "order": 1, } all_opt["tenant-name"] = { "getopt" : "t:", "longopt" : "tenant-name", "help" : "-t, --tenant-name=[tenant] Keystone Admin Tenant", "required" : "0", "shortdesc" : "Keystone Admin Tenant", "default" : "", "order": 1, } all_opt["auth-url"] = { "getopt" : "k:", "longopt" : "auth-url", "help" : "-k, --auth-url=[tenant] Keystone Admin Auth URL", "required" : "0", "shortdesc" : "Keystone Admin Auth URL", "default" : "", "order": 1, } all_opt["region-name"] = { "getopt" : "", "longopt" : "region-name", "help" : "--region-name=[region] Region Name", "required" : "0", "shortdesc" : "Region Name", "default" : "", "order": 1, } all_opt["insecure"] = { "getopt" : "", "longopt" : "insecure", "help" : "--insecure Explicitly allow agent to perform \"insecure\" TLS (https) requests", "required" : "0", "shortdesc" : "Allow Insecure TLS Requests", "default" : "False", "order": 2, } all_opt["domain"] = { "getopt" : "d:", "longopt" : "domain", "help" : "-d, --domain=[string] DNS domain in which hosts live, useful when the cluster uses short names and nova uses FQDN", "required" : "0", "shortdesc" : "DNS domain in which hosts live", "order": 5, } all_opt["record-only"] = { "getopt" : "r:", "longopt" : "record-only", "help" : "--record-only Record the target as needing evacuation but as yet do not intiate it", "required" : "0", "shortdesc" : "Only record the target as needing evacuation", "default" : "False", "order": 5, } all_opt["instance-filtering"] = { "getopt" : "", "longopt" : "instance-filtering", "help" : "--instance-filtering Only evacuate instances create from images and flavors with evacuable=true", "required" : "0", "shortdesc" : "Only evacuate flagged instances", "default" : "False", "order": 5, } all_opt["no-shared-storage"] = { "getopt" : "", "longopt" : "no-shared-storage", "help" : "--no-shared-storage Disable functionality for shared storage", "required" : "0", "shortdesc" : "Disable functionality for dealing with shared storage", "default" : "False", "order": 5, } def main(): global override_status global nova atexit.register(atexit_handler) device_opt = ["login", "passwd", "tenant-name", "auth-url", "fabric_fencing", "on_target", "no_login", "no_password", "port", "domain", "no-shared-storage", "endpoint-type", "record-only", "instance-filtering", "insecure", "region-name"] define_new_opts() all_opt["shell_timeout"]["default"] = "180" options = check_input(device_opt, process_input(device_opt)) docs = {} docs["shortdesc"] = "Fence agent for the automatic resurrection of OpenStack compute instances" docs["longdesc"] = "Used to tell Nova that compute nodes are down and to reschedule flagged instances" docs["vendorurl"] = "" show_docs(options, docs) run_delay(options) try: from novaclient import client as nova_client except ImportError: fail_usage("nova not found or not accessible") fix_plug_name(options) if options["--record-only"] in [ "2", "Disabled", "disabled" ]: sys.exit(0) elif options["--record-only"] in [ "1", "True", "true", "Yes", "yes"]: if options["--action"] == "on": set_attrd_status(options["--plug"], "no", options) sys.exit(0) elif options["--action"] in ["off", "reboot"]: set_attrd_status(options["--plug"], "yes", options) sys.exit(0) elif options["--action"] in ["monitor", "status"]: sys.exit(0) # The first argument is the Nova client version nova = nova_client.Client('2', options["--username"], options["--password"], options["--tenant-name"], options["--auth-url"], insecure=options["--insecure"], region_name=options["--region-name"], endpoint_type=options["--endpoint-type"]) if options["--action"] in ["off", "reboot"]: # Pretend we're 'on' so that the fencing library will always call set_power_status(off) override_status = "on" if options["--action"] == "on": # Pretend we're 'off' so that the fencing library will always call set_power_status(on) override_status = "off" result = fence_action(None, options, set_power_status, get_power_status, get_plugs_list, None) sys.exit(result) if __name__ == "__main__": main() diff --git a/fence/agents/docker/fence_docker.py b/fence/agents/docker/fence_docker.py index a27ecb19..453a987f 100644 --- a/fence/agents/docker/fence_docker.py +++ b/fence/agents/docker/fence_docker.py @@ -1,164 +1,164 @@ -#!/usr/bin/python -tt +#!@PYTHON@ -tt import atexit import sys -import StringIO +import io 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/v%s/%s" % ("s" if "--ssl" in options else "", options["--ip"], options["--ipport"], options["--api-version"], cmd) conn = pycurl.Curl() - output_buffer = StringIO.StringIO() + output_buffer = io.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) logging.debug("URL: " + url) try: conn.perform() result = output_buffer.getvalue() return_code = conn.getinfo(pycurl.RESPONSE_CODE) logging.debug("RESULT [" + str(return_code) + \ "]: " + result) conn.close() if return_code == 200: return json.loads(result) except pycurl.error: logging.error("Connection failed") except: if result is not None: logging.error(result) logging.error("Cannot parse json") return None def main(): atexit.register(atexit_handler) all_opt["tlscert"] = { "getopt" : ":", "longopt" : "tlscert", "help" : "--tlscert " "Path to client certificate for TLS authentication", "required" : "0", "shortdesc" : "Path to client certificate (PEM format) \ for TLS authentication. Required if --ssl option is used.", "order": 2 } all_opt["tlskey"] = { "getopt" : ":", "longopt" : "tlskey", "help" : "--tlskey " "Path to client key for TLS authentication", "required" : "0", "shortdesc" : "Path to client key (PEM format) for TLS \ authentication. Required if --ssl option is used.", "order": 2 } all_opt["tlscacert"] = { "getopt" : ":", "longopt" : "tlscacert", "help" : "--tlscacert " "Path to CA certificate for TLS authentication", "required" : "0", "shortdesc" : "Path to CA certificate (PEM format) for \ TLS authentication. Required if --ssl option is used.", "order": 2 } all_opt["api_version"] = { "getopt" : ":", "longopt" : "api-version", "help" : "--api-version " "Version of Docker Remote API (default: 1.11)", "required" : "0", - "order" : "2", + "order" : 2, "default" : "1.11", } device_opt = ["ipaddr", "no_password", "no_login", "port", "method", "web", "tlscert", "tlskey", "tlscacert", "ssl", "api_version"] 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. You can use this \ fence-agent without any authentication, or you can use TLS authentication \ (use --ssl option, more info about TLS authentication in docker: \ http://docs.docker.com/examples/https/)." docs["vendorurl"] = "www.docker.io" show_docs(options, docs) run_delay(options) result = fence_action(None, options, set_power_status, get_power_status, get_list, reboot_cycle) sys.exit(result) if __name__ == "__main__": main() diff --git a/fence/agents/drac/fence_drac.py b/fence/agents/drac/fence_drac.py index 2bac539a..f698b398 100644 --- a/fence/agents/drac/fence_drac.py +++ b/fence/agents/drac/fence_drac.py @@ -1,68 +1,68 @@ -#!/usr/bin/python -tt +#!@PYTHON@ -tt import sys, re import atexit sys.path.append("@FENCEAGENTSLIBDIR@") from fencing import * #BEGIN_VERSION_GENERATION RELEASE_VERSION="" REDHAT_COPYRIGHT="" BUILD_DATE="" #END_VERSION_GENERATION def get_power_status(conn, options): conn.send_eol("getmodinfo") conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) status = re.compile(r"\s+(on|off)\s+", re.IGNORECASE).search(conn.before).group(1) return status.lower().strip() def set_power_status(conn, options): action = { 'on' : "powerup", 'off': "powerdown" }[options["--action"]] conn.send_eol("serveraction -d 0 " + action) conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) def main(): device_opt = ["ipaddr", "login", "passwd", "cmd_prompt", "telnet"] atexit.register(atexit_handler) opt = process_input(device_opt) if "--username" in opt: all_opt["cmd_prompt"]["default"] = ["\\[" + opt["--username"] + "\\]# "] else: all_opt["cmd_prompt"]["default"] = ["\\[" "username" + "\\]# "] options = check_input(device_opt, opt) docs = {} docs["shortdesc"] = "I/O Fencing agent for Dell DRAC IV" docs["longdesc"] = "fence_drac is an I/O Fencing agent which can be used with \ the Dell Remote Access Card (DRAC). This card provides remote access to controlling \ power to a server. It logs into the DRAC through the telnet interface of the card. By \ default, the telnet interface is not enabled. To enable the interface, you will need \ to use the racadm command in the racser-devel rpm available from Dell. \ \ To enable telnet on the DRAC: \ \ [root]# racadm config -g cfgSerial -o cfgSerialTelnetEnable 1 \ \ [root]# racadm racreset \ " docs["vendorurl"] = "http://www.dell.com" show_docs(options, docs) ## ## Operate the fencing device #### conn = fence_login(options) result = fence_action(conn, options, set_power_status, get_power_status, None) fence_logout(conn, "exit") sys.exit(result) if __name__ == "__main__": main() diff --git a/fence/agents/drac5/fence_drac5.py b/fence/agents/drac5/fence_drac5.py index 76dc97dd..df113fea 100644 --- a/fence/agents/drac5/fence_drac5.py +++ b/fence/agents/drac5/fence_drac5.py @@ -1,153 +1,153 @@ -#!/usr/bin/python -tt +#!@PYTHON@ -tt ##### ## ## The Following Agent Has Been Tested On: ## ## DRAC Version Firmware ## +-----------------+---------------------------+ ## DRAC 5 1.0 (Build 06.05.12) ## DRAC 5 1.21 (Build 07.05.04) ## ## @note: drac_version was removed ##### import sys, re, time import atexit sys.path.append("@FENCEAGENTSLIBDIR@") from fencing import * from fencing import fail_usage #BEGIN_VERSION_GENERATION RELEASE_VERSION="New Drac5 Agent - test release on steroids" REDHAT_COPYRIGHT="" BUILD_DATE="March, 2008" #END_VERSION_GENERATION def get_power_status(conn, options): if options["--drac-version"] == "DRAC MC": (_, status) = get_list_devices(conn, options)[options["--plug"]] else: if options["--drac-version"] == "DRAC CMC": conn.send_eol("racadm serveraction powerstatus -m " + options["--plug"]) elif options["--drac-version"] == "DRAC 5": conn.send_eol("racadm serveraction powerstatus") conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) status = re.compile(r"(^|: )(ON|OFF|Powering ON|Powering OFF)\s*$", re.IGNORECASE | re.MULTILINE).search(conn.before).group(2) if status.lower().strip() in ["on", "powering on", "powering off"]: return "on" else: return "off" def set_power_status(conn, options): action = { 'on' : "powerup", 'off': "powerdown" }[options["--action"]] if options["--drac-version"] == "DRAC CMC": conn.send_eol("racadm serveraction " + action + " -m " + options["--plug"]) elif options["--drac-version"] == "DRAC 5": conn.send_eol("racadm serveraction " + action) elif options["--drac-version"] == "DRAC MC": conn.send_eol("racadm serveraction -s " + options["--plug"] + " " + action) ## Fix issue with double-enter [CR/LF] ## We need to read two additional command prompts (one from get + one from set command) conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) if len(conn.before.strip()) == 0: options["eol"] = options["eol"][:-1] conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) def get_list_devices(conn, options): outlets = {} if options["--drac-version"] == "DRAC CMC": conn.send_eol("getmodinfo") list_re = re.compile(r"^([^\s]*?)\s+Present\s*(ON|OFF)\s*.*$") conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) for line in conn.before.splitlines(): if list_re.search(line): outlets[list_re.search(line).group(1)] = ("", list_re.search(line).group(2)) elif options["--drac-version"] == "DRAC MC": conn.send_eol("getmodinfo") list_re = re.compile(r"^\s*([^\s]*)\s*---->\s*(.*?)\s+Present\s*(ON|OFF)\s*.*$") conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) for line in conn.before.splitlines(): if list_re.search(line): outlets[list_re.search(line).group(2)] = ("", list_re.search(line).group(3)) elif options["--drac-version"] == "DRAC 5": ## DRAC 5 can be used only for one computer ## standard fence library can't handle correctly situation ## when some fence devices supported by fence agent ## works with 'list' and other should returns 'N/A' - print "N/A" + print("N/A") return outlets def define_new_opts(): all_opt["drac_version"] = { "getopt" : "d:", "longopt" : "drac-version", "help" : "-d, --drac-version=[version] Force DRAC version to use (DRAC 5|DRAC CMC|DRAC MC)", "required" : "0", "shortdesc" : "Force DRAC version to use", "choices" : ["DRAC CMC", "DRAC MC", "DRAC 5"], "order" : 1} def main(): device_opt = ["ipaddr", "login", "passwd", "cmd_prompt", "secure", \ "drac_version", "port", "no_port", "telnet"] atexit.register(atexit_handler) define_new_opts() all_opt["cmd_prompt"]["default"] = [r"\$", r"DRAC\/MC:"] options = check_input(device_opt, process_input(device_opt)) docs = {} docs["shortdesc"] = "Fence agent for Dell DRAC CMC/5" docs["longdesc"] = "fence_drac5 is an I/O Fencing agent \ which can be used with the Dell Remote Access Card v5 or CMC (DRAC). \ This device provides remote access to controlling power to a server. \ It logs into the DRAC through the telnet/ssh interface of the card. \ By default, the telnet interface is not enabled." docs["vendorurl"] = "http://www.dell.com" show_docs(options, docs) ## ## Operate the fencing device ###### conn = fence_login(options) - if not options.has_key("--drac-version"): + if "--drac-version" not in options: ## autodetect from text issued by fence device if conn.before.find("CMC") >= 0: options["--drac-version"] = "DRAC CMC" elif conn.before.find("DRAC 5") >= 0: options["--drac-version"] = "DRAC 5" elif conn.after.find("DRAC/MC") >= 0: options["--drac-version"] = "DRAC MC" else: ## Assume this is DRAC 5 by default as we don't want to break anything options["--drac-version"] = "DRAC 5" if options["--drac-version"] in ["DRAC MC", "DRAC CMC"]: - if not options.has_key("--plug") and 0 == ["monitor", "list"].count(options["--action"]): + if "--plug" not in options and 0 == ["monitor", "list"].count(options["--action"]): fail_usage("Failed: You have to enter module name (-n)") result = fence_action(conn, options, set_power_status, get_power_status, get_list_devices) fence_logout(conn, "exit", 1) sys.exit(result) if __name__ == "__main__": main() diff --git a/fence/agents/dummy/fence_dummy.py b/fence/agents/dummy/fence_dummy.py index 932009eb..77d7d348 100644 --- a/fence/agents/dummy/fence_dummy.py +++ b/fence/agents/dummy/fence_dummy.py @@ -1,145 +1,145 @@ -#!/usr/bin/python -tt +#!@PYTHON@ -tt import sys, random import logging import time import atexit sys.path.append("@FENCEAGENTSLIBDIR@") from fencing import * from fencing import fail_usage, run_delay #BEGIN_VERSION_GENERATION RELEASE_VERSION="New Dummy Agent - test release on steroids" REDHAT_COPYRIGHT="" BUILD_DATE="" #END_VERSION_GENERATION plug_status = "on" def get_power_status_file(conn, options): del conn try: status_file = open(options["--status-file"], 'r') except Exception: return "off" status = status_file.read() status_file.close() return status.lower() def set_power_status_file(conn, options): del conn if not (options["--action"] in ["on", "off"]): return status_file = open(options["--status-file"], 'w') status_file.write(options["--action"]) status_file.close() def get_power_status_fail(conn, options): outlets = get_outlets_fail(conn, options) - if len(outlets) == 0 or not options.has_key("--plug"): + if len(outlets) == 0 or "--plug" not in options: fail_usage("Failed: You have to enter existing machine!") else: return outlets[options["--plug"]][0] def set_power_status_fail(conn, options): global plug_status del conn plug_status = "unknown" if options["--action"] == "on": plug_status = "off" def get_outlets_fail(conn, options): del conn result = {} global plug_status if options["--action"] == "on": plug_status = "off" # This fake agent has no port data to list, so we have to make # something up for the list action. if options.get("--action", None) == "list": result["fake_port_1"] = [plug_status, "fake"] result["fake_port_2"] = [plug_status, "fake"] - elif not options.has_key("--plug"): + elif "--plug" not in options: fail_usage("Failed: You have to enter existing machine!") else: port = options["--plug"] result[port] = [plug_status, "fake"] return result def main(): device_opt = ["no_password", "status_file", "random_sleep_range", "type", "port"] atexit.register(atexit_handler) all_opt["status_file"] = { "getopt" : ":", "longopt" : "status-file", "help":"--status-file=[file] Name of file that holds current status", "required" : "0", "shortdesc" : "File with status", "default" : "/tmp/fence_dummy.status", "order": 1 } all_opt["random_sleep_range"] = { "getopt" : ":", "longopt" : "random_sleep_range", "help":"--random_sleep_range=[seconds] Issue a sleep between 1 and [seconds]", "required" : "0", "shortdesc" : "Issue a sleep between 1 and X seconds. Used for testing.", "order": 1 } all_opt["type"] = { "getopt" : ":", "longopt" : "type", "help":"--type=[type] Possible types are: file and fail", "required" : "0", "shortdesc" : "Type of the dummy fence agent", "default" : "file", "order": 1 } pinput = process_input(device_opt) - if (pinput.has_key("--type") and pinput["--type"] == "file") or (pinput.has_key("--type") == False): + if ("--type" in pinput and pinput["--type"] == "file") or (("--type" in pinput) == False): # hack to have fence agents that require ports 'fail' and one that do not 'file' device_opt.remove("port") device_opt.remove("separator") options = check_input(device_opt, process_input(device_opt)) docs = {} docs["shortdesc"] = "Dummy fence agent" docs["longdesc"] = "fence_dummy" docs["vendorurl"] = "http://www.example.com" show_docs(options, docs) run_delay(options) # random sleep for testing - if options.has_key("--random_sleep_range"): + if "--random_sleep_range" in options: val = int(options["--random_sleep_range"]) ran = random.randint(1, val) logging.info("Random sleep for %d seconds\n", ran) time.sleep(ran) if options["--type"] == "fail": result = fence_action(None, options, set_power_status_fail, get_power_status_fail, get_outlets_fail) else: result = fence_action(None, options, set_power_status_file, get_power_status_file, None) sys.exit(result) if __name__ == "__main__": main() diff --git a/fence/agents/eaton_snmp/fence_eaton_snmp.py b/fence/agents/eaton_snmp/fence_eaton_snmp.py index 812790d3..dfd540c0 100644 --- a/fence/agents/eaton_snmp/fence_eaton_snmp.py +++ b/fence/agents/eaton_snmp/fence_eaton_snmp.py @@ -1,235 +1,235 @@ -#!/usr/bin/python -tt +#!@PYTHON@ -tt # The Following agent has been tested on: # - Eaton ePDU Managed - SNMP v1 # EATON | Powerware ePDU model: Managed ePDU (PW104MA0UB99), firmware: 01.01.01 # - Eaton ePDU Switched - SNMP v1 # EATON | Powerware ePDU model: Switched ePDU (IPV3600), firmware: 2.0.K import sys import atexit import logging sys.path.append("@FENCEAGENTSLIBDIR@") from fencing import * from fencing import fail_usage from fencing_snmp import FencingSnmp #BEGIN_VERSION_GENERATION RELEASE_VERSION="Eaton SNMP fence agent" REDHAT_COPYRIGHT="" BUILD_DATE="" #END_VERSION_GENERATION ### CONSTANTS ### # oid defining fence device OID_SYS_OBJECT_ID = '.1.3.6.1.2.1.1.2.0' ### GLOBAL VARIABLES ### # Device - see EatonManagedePDU, EatonSwitchedePDU device = None # Port ID port_id = None # Switch ID switch_id = None # Did we issue a set before get (to adjust OID with Switched ePDU) after_set = False # Classes describing Device params # Managed ePDU class EatonManagedePDU(object): status_oid = '.1.3.6.1.4.1.534.6.6.6.1.2.2.1.3.%d' control_oid = '.1.3.6.1.4.1.534.6.6.6.1.2.2.1.3.%d' outlet_table_oid = '.1.3.6.1.4.1.534.6.6.6.1.2.2.1.1' ident_str = "Eaton Managed ePDU" state_off = 0 state_on = 1 state_cycling = 2 # FIXME: not usable with fence-agents turn_off = 0 turn_on = 1 turn_cycle = 2 # FIXME: not usable with fence-agents has_switches = False # Switched ePDU (Pulizzi 2) # NOTE: sysOID reports "20677.1", while data are actually at "20677.2" class EatonSwitchedePDU(object): status_oid = '.1.3.6.1.4.1.20677.2.6.3.%d.0' control_oid = '.1.3.6.1.4.1.20677.2.6.2.%d.0' outlet_table_oid = '.1.3.6.1.4.1.20677.2.6.3' ident_str = "Eaton Switched ePDU" state_off = 2 state_on = 1 state_cycling = 0 # Note: this status doesn't exist on this device turn_off = 2 turn_on = 1 turn_cycle = 3 # FIXME: not usable with fence-agents has_switches = False ### FUNCTIONS ### def eaton_set_device(conn): global device agents_dir = {'.1.3.6.1.4.1.534.6.6.6':EatonManagedePDU, '.1.3.6.1.4.1.20677.1':EatonSwitchedePDU, '.1.3.6.1.4.1.20677.2':EatonSwitchedePDU} # First resolve type of Eaton eaton_type = conn.walk(OID_SYS_OBJECT_ID) - if not ((len(eaton_type) == 1) and (agents_dir.has_key(eaton_type[0][1]))): + if not ((len(eaton_type) == 1) and (eaton_type[0][1] in agents_dir)): eaton_type = [[None, None]] device = agents_dir[eaton_type[0][1]] logging.debug("Trying %s"%(device.ident_str)) def eaton_resolv_port_id(conn, options): global port_id, switch_id if device == None: eaton_set_device(conn) # Restore the increment, that was removed in main for ePDU Managed if device.ident_str == "Eaton Switched ePDU": options["--plug"] = str(int(options["--plug"]) + 1) # Now we resolv port_id/switch_id if options["--plug"].isdigit() and ((not device.has_switches) or (options["--switch"].isdigit())): port_id = int(options["--plug"]) if device.has_switches: switch_id = int(options["--switch"]) else: table = conn.walk(device.outlet_table_oid, 30) for x in table: if x[1].strip('"') == options["--plug"]: t = x[0].split('.') if device.has_switches: port_id = int(t[len(t)-1]) switch_id = int(t[len(t)-3]) else: if device.ident_str == "Eaton Switched ePDU": port_id = int(t[len(t)-3]) else: port_id = int(t[len(t)-1]) if port_id == None: # Restore index offset, to provide a valid error output on Managed ePDU if device.ident_str != "Eaton Switched ePDU": options["--plug"] = str(int(options["--plug"]) + 1) fail_usage("Can't find port with name %s!"%(options["--plug"])) def get_power_status(conn, options): global port_id, after_set if port_id == None: eaton_resolv_port_id(conn, options) # Ajust OID for Switched ePDU when the get is after a set if after_set and device.ident_str == "Eaton Switched ePDU": port_id -= 1 after_set = False oid = ((device.has_switches) and device.status_oid%(switch_id, port_id) or device.status_oid%(port_id)) try: (oid, status) = conn.get(oid) if status == str(device.state_on): return "on" elif status == str(device.state_off): return "off" else: return None except Exception: return None def set_power_status(conn, options): global port_id, after_set after_set = True if port_id == None: eaton_resolv_port_id(conn, options) # Controls start at #2 on Switched ePDU, since #1 is the global command if device.ident_str == "Eaton Switched ePDU": port_id = int(port_id)+1 oid = ((device.has_switches) and device.control_oid%(switch_id, port_id) or device.control_oid%(port_id)) conn.set(oid, (options["--action"] == "on" and device.turn_on or device.turn_off)) def get_outlets_status(conn, options): outletCount = 0 result = {} if device == None: eaton_set_device(conn) res_ports = conn.walk(device.outlet_table_oid, 30) for x in res_ports: outletCount += 1 status = x[1] t = x[0].split('.') # Plug indexing start from zero, so we substract '1' from the # user's given plug number if device.ident_str == "Eaton Managed ePDU": port_num = str(int(((device.has_switches) and "%s:%s"%(t[len(t)-3], t[len(t)-1]) or "%s"%(t[len(t)-1]))) + 1) # Plug indexing start from zero, so we add '1' # for the user's exposed plug number port_name = str(int(x[1].strip('"')) + 1) port_status = "" result[port_num] = (port_name, port_status) else: # Switched ePDU do not propose an outletCount OID! # Invalid status (ie value == '0'), retrieved via the walk, # means the outlet is absent port_num = str(outletCount) port_name = str(outletCount) port_status = "" if status != '0': result[port_num] = (port_name, port_status) return result # Main agent method def main(): device_opt = ["ipaddr", "login", "passwd", "no_login", "no_password", \ "port", "snmp_version", "snmp"] atexit.register(atexit_handler) all_opt["switch"]["default"] = 1 all_opt["power_wait"]["default"] = 2 all_opt["snmp_version"]["default"] = "1" all_opt["community"]["default"] = "private" options = check_input(device_opt, process_input(device_opt)) # Plug indexing start from zero on ePDU Managed, so we substract '1' from # the user's given plug number. # For Switched ePDU, we will add this back again later. - if options.has_key("--plug") and options["--plug"].isdigit(): + if "--plug" in options and options["--plug"].isdigit(): options["--plug"] = str(int(options["--plug"]) - 1) docs = {} docs["shortdesc"] = "Fence agent for Eaton over SNMP" docs["longdesc"] = "fence_eaton_snmp is an I/O Fencing agent \ which can be used with the Eaton network power switch. It logs \ into a device via SNMP and reboots a specified outlet. It supports \ SNMP v1 and v3 with all combinations of authenticity/privacy settings." docs["vendorurl"] = "http://powerquality.eaton.com" show_docs(options, docs) # Operate the fencing device result = fence_action(FencingSnmp(options), options, set_power_status, get_power_status, get_outlets_status) sys.exit(result) if __name__ == "__main__": main() diff --git a/fence/agents/emerson/fence_emerson.py b/fence/agents/emerson/fence_emerson.py index a98351a0..ed5b5ae5 100644 --- a/fence/agents/emerson/fence_emerson.py +++ b/fence/agents/emerson/fence_emerson.py @@ -1,68 +1,68 @@ -#!/usr/bin/python -tt +#!@PYTHON@ -tt import sys import atexit sys.path.append("@FENCEAGENTSLIBDIR@") from fencing import * from fencing_snmp import FencingSnmp #BEGIN_VERSION_GENERATION RELEASE_VERSION="Emerson SNMP fence agent" REDHAT_COPYRIGHT="" BUILD_DATE="" #END_VERSION_GENERATION ### CONSTANTS ### STATUSES_OID = ".1.3.6.1.4.1.476.1.42.3.8.50.20.1.95" CONTROL_OID = ".1.3.6.1.4.1.476.1.42.3.8.50.20.1.100" NAMES_OID = ".1.3.6.1.4.1.476.1.42.3.8.50.20.1.10" # Status constants returned as value from SNMP STATUS_DOWN = 1 STATUS_UP = 2 # Status constants to set as value to SNMP STATUS_SET_OFF = 0 STATUS_SET_ON = 1 def get_power_status(conn, options): (_, status) = conn.get("%s.%s"% (STATUSES_OID, options["--plug"])) return status == str(STATUS_UP) and "on" or "off" def set_power_status(conn, options): conn.set("%s.%s" % (CONTROL_OID, options["--plug"]), (options["--action"] == "on" and STATUS_SET_ON or STATUS_SET_OFF)) def get_outlets_status(conn, _): result = {} res_outlet = conn.walk(STATUSES_OID, 30) for outlet_info in res_outlet: port_num = ".".join(outlet_info[0].split('.')[-3:]) port_alias = conn.get("%s.%s"% (NAMES_OID, port_num))[1] port_status = (outlet_info[1] == str(STATUS_UP) and "on" or "off") result[port_num] = (port_alias, port_status) return result def main(): device_opt = ["ipaddr", "login", "passwd", "no_login", "no_password", \ "port", "snmp_version", "snmp"] atexit.register(atexit_handler) all_opt["power_wait"]["default"] = "5" options = check_input(device_opt, process_input(device_opt)) docs = {} docs["shortdesc"] = "Fence agent for Emerson over SNMP" docs["longdesc"] = "fence_emerson is an I/O Fencing agent \ which can be used with MPX and MPH2 managed rack PDU." docs["vendorurl"] = "http://www.emersonnetworkpower.com" show_docs(options, docs) # Operate the fencing device result = fence_action(FencingSnmp(options), options, set_power_status, get_power_status, get_outlets_status) sys.exit(result) if __name__ == "__main__": main() diff --git a/fence/agents/eps/fence_eps.py b/fence/agents/eps/fence_eps.py index e4fb1e94..dcdacb86 100644 --- a/fence/agents/eps/fence_eps.py +++ b/fence/agents/eps/fence_eps.py @@ -1,129 +1,134 @@ -#!/usr/bin/python -tt +#!@PYTHON@ -tt # The Following Agent Has Been Tested On: # ePowerSwitch 8M+ version 1.0.0.4 import sys, re -import httplib, base64, string, socket +import base64, string, socket import logging import atexit sys.path.append("@FENCEAGENTSLIBDIR@") from fencing import * from fencing import fail, fail_usage, EC_LOGIN_DENIED, EC_TIMED_OUT, run_delay +if sys.version_info.major > 2: + import http.client as httplib +else: + import httplib + #BEGIN_VERSION_GENERATION RELEASE_VERSION="ePowerSwitch 8M+ (eps)" REDHAT_COPYRIGHT="" BUILD_DATE="" #END_VERSION_GENERATION # Run command on EPS device. # @param options Device options # @param params HTTP GET parameters (without ?) def eps_run_command(options, params): try: # New http connection conn = httplib.HTTPConnection(options["--ip"]) request_str = "/"+options["--page"] if params != "": request_str += "?"+params logging.debug("GET %s\n", request_str) conn.putrequest('GET', request_str) - if options.has_key("--username"): - if not options.has_key("--password"): + if "--username" in options: + if "--password" not in options: options["--password"] = "" # Default is empty password # String for Authorization header auth_str = 'Basic ' + string.strip(base64.encodestring(options["--username"]+':'+options["--password"])) logging.debug("Authorization: %s\n", auth_str) conn.putheader('Authorization', auth_str) conn.endheaders() response = conn.getresponse() logging.debug("%d %s\n", response.status, response.reason) #Response != OK -> couldn't login if response.status != 200: fail(EC_LOGIN_DENIED) result = response.read() logging.debug("%s \n", result) conn.close() except socket.timeout: fail(EC_TIMED_OUT) except socket.error: fail(EC_LOGIN_DENIED) return result def get_power_status(conn, options): del conn ret_val = eps_run_command(options, "") result = {} status = re.findall(r"p(\d{2})=(0|1)\s*\", ret_val.lower()) for out_num, out_stat in status: result[out_num] = ("", (out_stat == "1" and "on" or "off")) if not options["--action"] in ['monitor', 'list']: if not options["--plug"] in result: fail_usage("Failed: You have to enter existing physical plug!") else: return result[options["--plug"]][1] else: return result def set_power_status(conn, options): del conn eps_run_command(options, "P%s=%s"%(options["--plug"], (options["--action"] == "on" and "1" or "0"))) # Define new option def eps_define_new_opts(): all_opt["hidden_page"] = { "getopt" : "c:", "longopt" : "page", "help":"-c, --page=[page] Name of hidden page (default: hidden.htm)", "required" : "0", "shortdesc" : "Name of hidden page", "default" : "hidden.htm", "order": 1 } # Starting point of fence agent def main(): device_opt = ["ipaddr", "login", "passwd", "no_login", "no_password", \ "port", "hidden_page", "web"] atexit.register(atexit_handler) eps_define_new_opts() options = check_input(device_opt, process_input(device_opt)) docs = {} docs["shortdesc"] = "Fence agent for ePowerSwitch" docs["longdesc"] = "fence_eps is an I/O Fencing agent \ which can be used with the ePowerSwitch 8M+ power switch to fence \ connected machines. Fence agent works ONLY on 8M+ device, because \ this is only one, which has support for hidden page feature. \ \n.TP\n\ Agent basically works by connecting to hidden page and pass \ appropriate arguments to GET request. This means, that hidden \ page feature must be enabled and properly configured." docs["vendorurl"] = "http://www.epowerswitch.com" show_docs(options, docs) run_delay(options) #Run fence action. Conn is None, beacause we always need open new http connection result = fence_action(None, options, set_power_status, get_power_status, get_power_status) sys.exit(result) if __name__ == "__main__": main() diff --git a/fence/agents/hds_cb/fence_hds_cb.py b/fence/agents/hds_cb/fence_hds_cb.py index 5de8e2a5..51cf7176 100755 --- a/fence/agents/hds_cb/fence_hds_cb.py +++ b/fence/agents/hds_cb/fence_hds_cb.py @@ -1,138 +1,138 @@ -#!/usr/bin/python -tt +#!@PYTHON@ -tt ##### ## ## The Following Agent Has Been Tested On: ## ## Model Modle/Firmware ## +--------------------+---------------------------+ ## (1) Main application CB2000/A0300-E-6617 ## ##### import sys, re import atexit sys.path.append("@FENCEAGENTSLIBDIR@") from fencing import * #BEGIN_VERSION_GENERATION RELEASE_VERSION="New Compute Blade 2000 Agent - test release on steroids" REDHAT_COPYRIGHT="" BUILD_DATE="November, 2012" #END_VERSION_GENERATION RE_STATUS_LINE = r"^([0-9]+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+).*$" def get_power_status(conn, options): #### Maybe should put a conn.log_expect here to make sure #### we have properly entered into the main menu conn.sendline("S") # Enter System Command Mode conn.log_expect("SVP>", int(options["--shell-timeout"])) conn.sendline("PC") # Enter partition control conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) result = {} # Status can now be obtained from the output of the PC # command. Line looks like the following: # "P Power Condition LID lamp Mode Auto power on" # "0 On Normal Off Basic Synchronized" # "1 On Normal Off Basic Synchronized" for line in conn.before.splitlines(): # populate the relevant fields based on regex partition = re.search(RE_STATUS_LINE, line) if partition != None: # find the blade number defined in args if partition.group(1) == options["--plug"]: result = partition.group(2).lower() # We must make sure we go back to the main menu as the # status is checked before any fencing operations are # executed. We could in theory save some time by staying in # the partition control, but the logic is a little cleaner # this way. conn.sendline("Q") # Back to system command mode conn.log_expect("SVP>", int(options["--shell-timeout"])) conn.sendline("EX") # Back to system console main menu conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) return result def set_power_status(conn, options): action = { 'on' : "P", 'off': "F", 'reboot' : "H", }[options["--action"]] conn.sendline("S") # Enter System Command Mode conn.log_expect("SVP>", int(options["--shell-timeout"])) conn.sendline("PC") # Enter partition control conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) conn.sendline("P") # Enter power control menu conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) conn.sendline(action) # Execute action from array above conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) conn.sendline(options["--plug"]) # Select blade number from args conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) conn.sendline("Y") # Confirm action conn.log_expect("Hit enter key.", int(options["--shell-timeout"])) conn.sendline("") # Press the any key conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) conn.sendline("Q") # Quit back to partition control conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) conn.sendline("Q") # Quit back to system command mode conn.log_expect("SVP>", int(options["--shell-timeout"])) conn.sendline("EX") # Quit back to system console menu conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) def get_blades_list(conn, options): outlets = {} conn.sendline("S") # Enter System Command Mode conn.log_expect("SVP>", int(options["--shell-timeout"])) conn.sendline("PC") # Enter partition control conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) # Status can now be obtained from the output of the PC # command. Line looks like the following: # "P Power Condition LID lamp Mode Auto power on" # "0 On Normal Off Basic Synchronized" # "1 On Normal Off Basic Synchronized" for line in conn.before.splitlines(): partition = re.search(RE_STATUS_LINE, line) if partition != None: outlets[partition.group(1)] = (partition.group(2), "") conn.sendline("Q") # Quit back to system command mode conn.log_expect("SVP>", int(options["--shell-timeout"])) conn.sendline("EX") # Quit back to system console menu conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) return outlets def main(): device_opt = ["ipaddr", "login", "passwd", "cmd_prompt", "secure", \ "port", "missing_as_off", "telnet"] atexit.register(atexit_handler) all_opt["power_wait"]["default"] = "5" all_opt["cmd_prompt"]["default"] = [r"\) :"] options = check_input(device_opt, process_input(device_opt)) docs = {} docs["shortdesc"] = "Fence agent for Hitachi Compute Blade systems" docs["longdesc"] = "fence_hds_cb is an I/O Fencing agent \ which can be used with Hitachi Compute Blades with recent enough firmware that \ includes telnet support." docs["vendorurl"] = "http://www.hds.com" show_docs(options, docs) ## ## Operate the fencing device ###### conn = fence_login(options) result = fence_action(conn, options, set_power_status, get_power_status, get_blades_list) fence_logout(conn, "X") sys.exit(result) if __name__ == "__main__": main() diff --git a/fence/agents/hpblade/fence_hpblade.py b/fence/agents/hpblade/fence_hpblade.py index d527402c..a9e712cc 100644 --- a/fence/agents/hpblade/fence_hpblade.py +++ b/fence/agents/hpblade/fence_hpblade.py @@ -1,140 +1,140 @@ -#!/usr/bin/python -tt +#!@PYTHON@ -tt ##### ## ## The Following Agent Has Been Tested On: ## * HP BladeSystem c7000 Enclosure ## * HP Integrity Superdome X (BL920s) ##### import sys, re -import pexpect, exceptions +import pexpect import atexit sys.path.append("@FENCEAGENTSLIBDIR@") from fencing import * from fencing import fail, EC_STATUS #BEGIN_VERSION_GENERATION RELEASE_VERSION="4.0.11-HP" BUILD_DATE="(built Mon Mar 30 08:31:24 EDT 2015)" REDHAT_COPYRIGHT="Copyright (C) Red Hat, Inc. 2004-2010 All rights reserved." #END_VERSION_GENERATION def get_enclosure_type(conn, options): conn.send_eol("show enclosure info") conn.log_expect(options, options["--command-prompt"], int(options["--shell-timeout"])) type_re=re.compile(r"^\s*Enclosure Type: (\w+)(.*?)\s*$") enclosure="unknown" for line in conn.before.splitlines(): res = type_re.search(line) if res != None: enclosure=res.group(1) if enclosure == "unknown": fail(EC_GENERIC_ERROR) return enclosure.lower().strip() def get_power_status(conn, options): if options["enc_type"] == "superdome": cmd_send = "parstatus -M -p " + options["--plug"] powrestr = "^partition:\\d\\s+:\\w+\\s+/(\\w+)\\s.*$" else: cmd_send = "show server status " + options["--plug"] powrestr = "^\\s*Power: (.*?)\\s*$" conn.send_eol(cmd_send) conn.log_expect(options, options["--command-prompt"], int(options["--shell-timeout"])) power_re = re.compile(powrestr) status = "unknown" for line in conn.before.splitlines(): res = power_re.search(line) if res != None: if options["enc_type"] == "superdome": if res.group(1) == "DOWN": status = "off" else: status = "on" else: status = res.group(1) if status == "unknown": - if options.has_key("--missing-as-off"): + if "--missing-as-off" in options: return "off" else: fail(EC_STATUS) return status.lower().strip() def set_power_status(conn, options): if options["enc_type"] == "superdome": dev="partition " else: dev="server " if options["--action"] == "on": conn.send_eol("poweron " + dev + options["--plug"]) elif options["--action"] == "off": conn.send_eol("poweroff " + dev + options["--plug"] + " force") conn.log_expect(options, options["--command-prompt"], int(options["--shell-timeout"])) def get_instances_list(conn, options): outlets = {} if options["enc_type"] == "superdome": cmd_send = "parstatus -P -M" listrestr = "^partition:(\\d+)\\s+:\\w+\\s+/(\\w+)\\s+:OK.*?:(\\w+)\\s*$" else: cmd_send = "show server list" listrestr = "^\\s*(\\d+)\\s+(.*?)\\s+(.*?)\\s+OK\\s+(.*?)\\s+(.*?)\\s*$" conn.send_eol(cmd_send) conn.log_expect(options, options["--command-prompt"], int(options["--shell-timeout"])) list_re = re.compile(listrestr) for line in conn.before.splitlines(): res = list_re.search(line) if res != None: if options["enc_type"] == "superdome": outlets[res.group(1)] = (res.group(3), res.group(2).lower()) else: outlets[res.group(1)] = (res.group(2), res.group(4).lower()) return outlets def main(): device_opt = ["ipaddr", "login", "passwd", "cmd_prompt", "secure", \ "port", "missing_as_off", "telnet"] atexit.register(atexit_handler) all_opt["cmd_prompt"]["default"] = ["c7000oa>"] all_opt["login_timeout"]["default"] = "10" options = check_input(device_opt, process_input(device_opt)) docs = {} docs["shortdesc"] = "Fence agent for HP BladeSystem" docs["longdesc"] = "fence_hpblade is an I/O Fencing agent \ which can be used with HP BladeSystem and HP Integrity Superdome X. \ It logs into the onboard administrator of an enclosure via telnet or \ ssh and uses the command line interface to power blades or partitions \ on or off." docs["vendorurl"] = "http://www.hp.com" show_docs(options, docs) ## ## Operate the fencing device ###### options["eol"] = "\n" conn = fence_login(options) options["enc_type"] = get_enclosure_type(conn, options) result = fence_action(conn, options, set_power_status, get_power_status, get_instances_list) fence_logout(conn, "exit") sys.exit(result) if __name__ == "__main__": main() diff --git a/fence/agents/ibmblade/fence_ibmblade.py b/fence/agents/ibmblade/fence_ibmblade.py index b4810a5e..11ba1698 100644 --- a/fence/agents/ibmblade/fence_ibmblade.py +++ b/fence/agents/ibmblade/fence_ibmblade.py @@ -1,78 +1,78 @@ -#!/usr/bin/python -tt +#!@PYTHON@ -tt import sys import atexit sys.path.append("@FENCEAGENTSLIBDIR@") from fencing import * from fencing_snmp import FencingSnmp #BEGIN_VERSION_GENERATION RELEASE_VERSION="IBM Blade SNMP fence agent" REDHAT_COPYRIGHT="" BUILD_DATE="" #END_VERSION_GENERATION ### CONSTANTS ### # From fence_ibmblade.pl STATUSES_OID = ".1.3.6.1.4.1.2.3.51.2.22.1.5.1.1.4" # remoteControlBladePowerState CONTROL_OID = ".1.3.6.1.4.1.2.3.51.2.22.1.6.1.1.7" # powerOnOffBlade # Status constants returned as value from SNMP STATUS_DOWN = 0 STATUS_UP = 1 # Status constants to set as value to SNMP STATUS_SET_OFF = 0 STATUS_SET_ON = 1 ### FUNCTIONS ### def get_power_status(conn, options): (_, status) = conn.get("%s.%s"% (STATUSES_OID, options["--plug"])) return status == str(STATUS_UP) and "on" or "off" def set_power_status(conn, options): conn.set("%s.%s" % (CONTROL_OID, options["--plug"]), (options["--action"] == "on" and STATUS_SET_ON or STATUS_SET_OFF)) def get_outlets_status(conn, _): result = {} res_blades = conn.walk(STATUSES_OID, 30) for blade_info in res_blades: port_num = blade_info[0].split('.')[-1] port_alias = "" port_status = (blade_info[1] == str(STATUS_UP) and "on" or "off") result[port_num] = (port_alias, port_status) return result # Main agent method def main(): device_opt = ["ipaddr", "login", "passwd", "no_login", "no_password", \ "port", "snmp_version", "snmp"] atexit.register(atexit_handler) all_opt["snmp_version"]["default"] = "1" options = check_input(device_opt, process_input(device_opt)) docs = {} docs["shortdesc"] = "Fence agent for IBM BladeCenter over SNMP" docs["longdesc"] = "fence_ibmblade is an I/O Fencing agent \ which can be used with IBM BladeCenter chassis. It issues SNMP Set \ request to BladeCenter chassis, rebooting, powering up or down \ the specified Blade Server." docs["vendorurl"] = "http://www.ibm.com" show_docs(options, docs) # Operate the fencing device result = fence_action(FencingSnmp(options), options, set_power_status, get_power_status, get_outlets_status) sys.exit(result) if __name__ == "__main__": main() diff --git a/fence/agents/ifmib/fence_ifmib.py b/fence/agents/ifmib/fence_ifmib.py index 7df76837..963d3e93 100644 --- a/fence/agents/ifmib/fence_ifmib.py +++ b/fence/agents/ifmib/fence_ifmib.py @@ -1,122 +1,122 @@ -#!/usr/bin/python -tt +#!@PYTHON@ -tt # The Following agent has been tested on: # - Cisco MDS UROS 9134 FC (1 Slot) Chassis ("1/2/4 10 Gbps FC/Supervisor-2") Motorola, e500v2 # with BIOS 1.0.16, kickstart 4.1(1c), system 4.1(1c) # - Cisco MDS 9124 (1 Slot) Chassis ("1/2/4 Gbps FC/Supervisor-2") Motorola, e500 # with BIOS 1.0.16, kickstart 4.1(1c), system 4.1(1c) # - Partially with APC PDU (Network Management Card AOS v2.7.0, Rack PDU APP v2.7.3) # Only lance if is visible import sys import atexit sys.path.append("@FENCEAGENTSLIBDIR@") from fencing import * from fencing import fail_usage, array_to_dict from fencing_snmp import FencingSnmp #BEGIN_VERSION_GENERATION RELEASE_VERSION="IF:MIB SNMP fence agent" REDHAT_COPYRIGHT="" BUILD_DATE="" #END_VERSION_GENERATION ### CONSTANTS ### # IF-MIB trees for alias, status and port ALIASES_OID = ".1.3.6.1.2.1.31.1.1.1.18" PORTS_OID = ".1.3.6.1.2.1.2.2.1.2" STATUSES_OID = ".1.3.6.1.2.1.2.2.1.7" # Status constants returned as value from SNMP STATUS_UP = 1 STATUS_DOWN = 2 STATUS_TESTING = 3 ### GLOBAL VARIABLES ### # Port number converted from port name or index port_num = None ### FUNCTIONS ### # Convert port index or name to port index def port2index(conn, port): res = None if port.isdigit(): res = int(port) else: ports = conn.walk(PORTS_OID, 30) for x in ports: if x[1].strip('"') == port: res = int(x[0].split('.')[-1]) break if res == None: fail_usage("Can't find port with name %s!"%(port)) return res def get_power_status(conn, options): global port_num if port_num == None: port_num = port2index(conn, options["--plug"]) (_, status) = conn.get("%s.%d"%(STATUSES_OID, port_num)) return status == str(STATUS_UP) and "on" or "off" def set_power_status(conn, options): global port_num if port_num == None: port_num = port2index(conn, options["--plug"]) conn.set("%s.%d" % (STATUSES_OID, port_num), (options["--action"] == "on" and STATUS_UP or STATUS_DOWN)) def get_outlets_status(conn, options): result = {} res_fc = conn.walk(PORTS_OID, 30) res_aliases = array_to_dict(conn.walk(ALIASES_OID, 30)) for x in res_fc: port_number = x[0].split('.')[-1] port_name = x[1].strip('"') - port_alias = (res_aliases.has_key(port_number) and res_aliases[port_number].strip('"') or "") + port_alias = (port_number in res_aliases and res_aliases[port_number].strip('"') or "") port_status = "" result[port_name] = (port_alias, port_status) return result # Main agent method def main(): device_opt = ["fabric_fencing", "ipaddr", "login", "passwd", "no_login", "no_password", \ "port", "snmp_version", "snmp"] atexit.register(atexit_handler) all_opt["snmp_version"]["default"] = "2c" options = check_input(device_opt, process_input(device_opt)) docs = {} docs["shortdesc"] = "Fence agent for IF MIB" docs["longdesc"] = "fence_ifmib is an I/O Fencing agent \ which can be used with any SNMP IF-MIB capable device. \ \n.P\n\ It was written with managed ethernet switches in mind, in order to \ fence iSCSI SAN connections. However, there are many devices that \ support the IF-MIB interface. The agent uses IF-MIB::ifAdminStatus \ to control the state of an interface." docs["vendorurl"] = "http://www.ietf.org/wg/concluded/ifmib.html" show_docs(options, docs) # Operate the fencing device result = fence_action(FencingSnmp(options), options, set_power_status, get_power_status, get_outlets_status) sys.exit(result) if __name__ == "__main__": main() diff --git a/fence/agents/ilo/fence_ilo.py b/fence/agents/ilo/fence_ilo.py index 43f9c4c7..36e2ba14 100644 --- a/fence/agents/ilo/fence_ilo.py +++ b/fence/agents/ilo/fence_ilo.py @@ -1,149 +1,149 @@ -#!/usr/bin/python -tt +#!@PYTHON@ -tt ##### ## ## The Following Agent Has Been Tested On: ## ## iLO Version ## +---------------------------------------------+ ## iLO / firmware 1.91 / RIBCL 2.22 ## iLO2 / firmware 1.22 / RIBCL 2.22 ## iLO2 / firmware 1.50 / RIBCL 2.22 ##### import sys, re, pexpect import atexit from xml.sax.saxutils import quoteattr sys.path.append("@FENCEAGENTSLIBDIR@") from fencing import * from fencing import fail, EC_LOGIN_DENIED #BEGIN_VERSION_GENERATION RELEASE_VERSION="New ILO Agent - test release on steroids" REDHAT_COPYRIGHT="" BUILD_DATE="March, 2008" #END_VERSION_GENERATION def get_power_status(conn, options): conn.send("\r\n") conn.send("\r\n") conn.send("\r\n") conn.log_expect("HOST_POWER=\"(.*?)\"", int(options["--power-timeout"])) status = conn.match.group(1) return status.lower().strip() def set_power_status(conn, options): conn.send("\r\n") conn.send("") if options.get("fw_processor", None) == "iLO2": if options["fw_version"] > 1.29: conn.send("\r\n") else: conn.send("\r\n") elif options["--ribcl-version"] < 2.21: conn.send("\r\n") else: if options["--action"] == "off": conn.send("\r\n") else: conn.send("\r\n") conn.send("\r\n") return def define_new_opts(): all_opt["ribcl"] = { "getopt" : "r:", "longopt" : "ribcl-version", "help" : "-r, --ribcl-version=[version] Force ribcl version to use", "required" : "0", "shortdesc" : "Force ribcl version to use", "order" : 1} def main(): device_opt = ["ipaddr", "login", "passwd", "ssl", "notls", "tls1.0", "ribcl"] atexit.register(atexit_handler) define_new_opts() all_opt["login_timeout"]["default"] = "10" all_opt["retry_on"]["default"] = "3" all_opt["ssl"]["default"] = "1" options = check_input(device_opt, process_input(device_opt)) docs = {} docs["shortdesc"] = "Fence agent for HP iLO" docs["longdesc"] = "fence_ilo is an I/O Fencing agent \ used for HP servers with the Integrated Light Out (iLO) PCI card.\ The agent opens an SSL connection to the iLO card. Once the SSL \ connection is established, the agent is able to communicate with \ the iLO card through an XML stream." docs["vendorurl"] = "http://www.hp.com" docs["symlink"] = [("fence_ilo2", "Fence agent for HP iLO2")] show_docs(options, docs) ## ## Login and get version number #### conn = fence_login(options) try: conn.send("\r\n") conn.log_expect(["", ""], int(options["--login-timeout"])) except pexpect.TIMEOUT: fail(EC_LOGIN_DENIED) except pexpect.EOF: if "--tls1.0" in options: fail(EC_LOGIN_DENIED) options["--tls1.0"] = "1" conn.close() conn = fence_login(options) try: conn.send("\r\n") conn.log_expect(["", ""], int(options["--login-timeout"])) except pexpect.TIMEOUT: fail(EC_LOGIN_DENIED) except pexpect.EOF: fail(EC_LOGIN_DENIED) try: version = re.compile("= 2: conn.send("\r\n") else: conn.send("\r\n") conn.send("\r\n") if options["--ribcl-version"] >= 2: conn.send("\r\n") conn.send("\r\n") conn.log_expect(r"", int(options["--shell-timeout"])) options["fw_version"] = float(re.compile(r"FIRMWARE_VERSION\s*=\s*\"(.*?)\"", re.IGNORECASE).search(conn.before).group(1)) options["fw_processor"] = re.compile(r"MANAGEMENT_PROCESSOR\s*=\s*\"(.*?)\"", re.IGNORECASE).search(conn.before).group(1) conn.send("\r\n") except pexpect.TIMEOUT: fail(EC_LOGIN_DENIED) except pexpect.EOF: fail(EC_LOGIN_DENIED) ## ## Fence operations #### result = fence_action(conn, options, set_power_status, get_power_status, None) sys.exit(result) if __name__ == "__main__": main() diff --git a/fence/agents/ilo_moonshot/fence_ilo_moonshot.py b/fence/agents/ilo_moonshot/fence_ilo_moonshot.py index e161ac65..c534947c 100644 --- a/fence/agents/ilo_moonshot/fence_ilo_moonshot.py +++ b/fence/agents/ilo_moonshot/fence_ilo_moonshot.py @@ -1,69 +1,69 @@ -#!/usr/bin/python -tt +#!@PYTHON@ -tt import sys import atexit sys.path.append("@FENCEAGENTSLIBDIR@") from fencing import * from fencing import fail, EC_STATUS #BEGIN_VERSION_GENERATION RELEASE_VERSION="" REDHAT_COPYRIGHT="" BUILD_DATE="" #END_VERSION_GENERATION def get_power_status(conn, options): conn.send_eol("show node list") conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) nodes = {} for line in conn.before.splitlines(): if len(line.split()) == 10: nodes[line.split()[1]] = ("", line.split()[8].lower().strip()) if ["list", "monitor"].count(options["--action"]) == 1: return nodes else: try: (_, status) = nodes[options["--plug"]] return status.lower() except KeyError: fail(EC_STATUS) def set_power_status(conn, options): if options["--action"] == "on": conn.send_eol("set node power on %s" % (options["--plug"])) else: conn.send_eol("set node power off force %s" % (options["--plug"])) conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) return def main(): device_opt = ["ipaddr", "login", "passwd", "secure", "cmd_prompt", "port"] atexit.register(atexit_handler) all_opt["secure"]["default"] = "1" all_opt["cmd_prompt"]["default"] = ["MP>", "hpiLO->"] options = check_input(device_opt, process_input(device_opt)) docs = {} docs["shortdesc"] = "Fence agent for HP Moonshot iLO" docs["longdesc"] = "" docs["vendorurl"] = "http://www.hp.com" show_docs(options, docs) conn = fence_login(options) ## ## Fence operations #### result = fence_action(conn, options, set_power_status, get_power_status, get_power_status) fence_logout(conn, "exit") sys.exit(result) if __name__ == "__main__": main() diff --git a/fence/agents/ilo_mp/fence_ilo_mp.py b/fence/agents/ilo_mp/fence_ilo_mp.py index 396d1a9f..f878c5c4 100644 --- a/fence/agents/ilo_mp/fence_ilo_mp.py +++ b/fence/agents/ilo_mp/fence_ilo_mp.py @@ -1,64 +1,64 @@ -#!/usr/bin/python -tt +#!@PYTHON@ -tt import sys, re import atexit sys.path.append("@FENCEAGENTSLIBDIR@") from fencing import * #BEGIN_VERSION_GENERATION RELEASE_VERSION="" REDHAT_COPYRIGHT="" BUILD_DATE="" #END_VERSION_GENERATION def get_power_status(conn, options): conn.send_eol("show /system1") re_state = re.compile('EnabledState=(.*)', re.IGNORECASE) conn.log_expect(re_state, int(options["--shell-timeout"])) status = conn.match.group(1).lower() if status.startswith("enabled"): return "on" else: return "off" def set_power_status(conn, options): if options["--action"] == "on": conn.send_eol("start /system1") else: conn.send_eol("stop -f /system1") conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) return def main(): device_opt = ["ipaddr", "login", "passwd", "secure", "cmd_prompt", "telnet"] atexit.register(atexit_handler) all_opt["cmd_prompt"]["default"] = ["MP>", "hpiLO->"] all_opt["power_wait"]["default"] = 5 options = check_input(device_opt, process_input(device_opt)) docs = {} docs["shortdesc"] = "Fence agent for HP iLO MP" docs["longdesc"] = "" docs["vendorurl"] = "http://www.hp.com" show_docs(options, docs) conn = fence_login(options) conn.send_eol("SMCLP") ## ## Fence operations #### result = fence_action(conn, options, set_power_status, get_power_status) fence_logout(conn, "exit") sys.exit(result) if __name__ == "__main__": main() diff --git a/fence/agents/ilo_ssh/fence_ilo_ssh.py b/fence/agents/ilo_ssh/fence_ilo_ssh.py index a510b2e6..8caa6437 100644 --- a/fence/agents/ilo_ssh/fence_ilo_ssh.py +++ b/fence/agents/ilo_ssh/fence_ilo_ssh.py @@ -1,75 +1,75 @@ -#!/usr/bin/python -tt +#!@PYTHON@ -tt import sys, re import atexit sys.path.append("@FENCEAGENTSLIBDIR@") from fencing import * #BEGIN_VERSION_GENERATION RELEASE_VERSION="" REDHAT_COPYRIGHT="" BUILD_DATE="" #END_VERSION_GENERATION def get_power_status(conn, options): conn.send_eol("show /system1") re_state = re.compile('EnabledState=(.*)', re.IGNORECASE) conn.log_expect(re_state, int(options["--shell-timeout"])) status = conn.match.group(1).lower() if status.startswith("enabled"): return "on" else: return "off" def set_power_status(conn, options): if options["--action"] == "on": conn.send_eol("start /system1") else: conn.send_eol("power off hard") conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) return def reboot_cycle(conn, options): conn.send_eol("reset hard /system1") conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) return def main(): device_opt = ["ipaddr", "login", "passwd", "secure", "cmd_prompt", "method", "telnet"] atexit.register(atexit_handler) all_opt["cmd_prompt"]["default"] = ["MP>", "hpiLO->"] all_opt["power_wait"]["default"] = 5 all_opt["method"]["default"] = "onoff" options = check_input(device_opt, process_input(device_opt)) docs = {} docs["shortdesc"] = "Fence agent for HP iLO over SSH" docs["longdesc"] = "fence_ilo_ssh is a fence agent that connects to iLO device. It logs into \ device via ssh and reboot a specified outlet. " docs["vendorurl"] = "http://www.hp.com" docs["symlink"] = [("fence_ilo3_ssh", "Fence agent for HP iLO3 over SSH"), ("fence_ilo4_ssh", "Fence agent for HP iLO4 over SSH")] show_docs(options, docs) options["eol"] = "\r" conn = fence_login(options) conn.send_eol("SMCLP") ## ## Fence operations #### result = fence_action(conn, options, set_power_status, get_power_status, None, reboot_cycle) fence_logout(conn, "exit") sys.exit(result) if __name__ == "__main__": main() diff --git a/fence/agents/intelmodular/fence_intelmodular.py b/fence/agents/intelmodular/fence_intelmodular.py index e91ccc08..4e1301c9 100644 --- a/fence/agents/intelmodular/fence_intelmodular.py +++ b/fence/agents/intelmodular/fence_intelmodular.py @@ -1,92 +1,92 @@ -#!/usr/bin/python -tt +#!@PYTHON@ -tt # Tested with an Intel MFSYS25 using firmware package 2.6 Should work with an # MFSYS35 as well. # # Notes: # # The manual and firmware release notes says SNMP is read only. This is not # true, as per the MIBs that ship with the firmware you can write to # the bladePowerLed oid to control the servers. # # Thanks Matthew Kent for original agent and testing. import sys import atexit sys.path.append("@FENCEAGENTSLIBDIR@") from fencing import * from fencing_snmp import FencingSnmp #BEGIN_VERSION_GENERATION RELEASE_VERSION="Intel Modular SNMP fence agent" REDHAT_COPYRIGHT="" BUILD_DATE="" #END_VERSION_GENERATION ### CONSTANTS ### # From INTELCORPORATION-MULTI-FLEX-SERVER-BLADES-MIB.my that ships with # firmware updates STATUSES_OID = ".1.3.6.1.4.1.343.2.19.1.2.10.202.1.1.6" # Status constants returned as value from SNMP STATUS_UP = 2 STATUS_DOWN = 0 # Status constants to set as value to SNMP STATUS_SET_ON = 2 STATUS_SET_OFF = 3 ### FUNCTIONS ### def get_power_status(conn, options): (_, status) = conn.get("%s.%s"% (STATUSES_OID, options["--plug"])) return status == str(STATUS_UP) and "on" or "off" def set_power_status(conn, options): conn.set("%s.%s" % (STATUSES_OID, options["--plug"]), (options["--action"] == "on" and STATUS_SET_ON or STATUS_SET_OFF)) def get_outlets_status(conn, options): result = {} res_blades = conn.walk(STATUSES_OID, 30) for x in res_blades: port_num = x[0].split('.')[-1] port_alias = "" port_status = (x[1] == str(STATUS_UP) and "on" or "off") result[port_num] = (port_alias, port_status) return result # Main agent method def main(): device_opt = ["ipaddr", "login", "passwd", "no_login", "no_password", "port", "snmp_version", "snmp"] atexit.register(atexit_handler) options = check_input(device_opt, process_input(device_opt)) docs = {} docs["shortdesc"] = "Fence agent for Intel Modular" docs["longdesc"] = "fence_intelmodular is an I/O Fencing agent \ which can be used with Intel Modular device (tested on Intel MFSYS25, should \ work with MFSYS35 as well). \ \n.P\n\ Note: Since firmware update version 2.7, SNMP v2 write support is \ removed, and replaced by SNMP v3 support. So agent now has default \ SNMP version 3. If you are using older firmware, please supply -d \ for command line and snmp_version option for your cluster.conf." docs["vendorurl"] = "http://www.intel.com" show_docs(options, docs) # Operate the fencing device result = fence_action(FencingSnmp(options), options, set_power_status, get_power_status, get_outlets_status) sys.exit(result) if __name__ == "__main__": main() diff --git a/fence/agents/ipdu/fence_ipdu.py b/fence/agents/ipdu/fence_ipdu.py index 1b0589f7..7e648598 100644 --- a/fence/agents/ipdu/fence_ipdu.py +++ b/fence/agents/ipdu/fence_ipdu.py @@ -1,159 +1,159 @@ -#!/usr/bin/python -tt +#!@PYTHON@ -tt # The Following agent has been tested on: # IBM iPDU model 46M4002 # Firmware release OPDP_sIBM_v01.2_1 # import sys import atexit import logging sys.path.append("@FENCEAGENTSLIBDIR@") from fencing import * from fencing import fail_usage from fencing_snmp import FencingSnmp #BEGIN_VERSION_GENERATION RELEASE_VERSION="IBM iPDU SNMP fence agent" REDHAT_COPYRIGHT="" BUILD_DATE="" #END_VERSION_GENERATION ### CONSTANTS ### # oid defining fence device OID_SYS_OBJECT_ID = '.1.3.6.1.2.1.1.2.0' ### GLOBAL VARIABLES ### # Device - see IBM iPDU device = None # Port ID port_id = None # Switch ID switch_id = None # Classes describing Device params class IBMiPDU(object): # iPDU status_oid = '.1.3.6.1.4.1.2.6.223.8.2.2.1.11.%d' control_oid = '.1.3.6.1.4.1.2.6.223.8.2.2.1.11.%d' outlet_table_oid = '.1.3.6.1.4.1.2.6.223.8.2.2.1.2' ident_str = "IBM iPDU" state_on = 1 state_off = 0 turn_on = 1 turn_off = 0 has_switches = False ### FUNCTIONS ### def ipdu_set_device(conn, options): global device agents_dir = {'.1.3.6.1.4.1.2.6.223':IBMiPDU, None:IBMiPDU} # First resolve type of PDU device pdu_type = conn.walk(OID_SYS_OBJECT_ID) - if not ((len(pdu_type) == 1) and (agents_dir.has_key(pdu_type[0][1]))): + if not ((len(pdu_type) == 1) and (pdu_type[0][1] in agents_dir)): pdu_type = [[None, None]] device = agents_dir[pdu_type[0][1]] logging.debug("Trying %s"%(device.ident_str)) def ipdu_resolv_port_id(conn, options): global port_id, switch_id if device == None: ipdu_set_device(conn, options) # Now we resolv port_id/switch_id if options["--plug"].isdigit() and ((not device.has_switches) or (options["--switch"].isdigit())): port_id = int(options["--plug"]) if device.has_switches: switch_id = int(options["--switch"]) else: table = conn.walk(device.outlet_table_oid, 30) for x in table: if x[1].strip('"') == options["--plug"]: t = x[0].split('.') if device.has_switches: port_id = int(t[len(t)-1]) switch_id = int(t[len(t)-3]) else: port_id = int(t[len(t)-1]) if port_id == None: fail_usage("Can't find port with name %s!"%(options["--plug"])) def get_power_status(conn, options): if port_id == None: ipdu_resolv_port_id(conn, options) oid = ((device.has_switches) and device.status_oid%(switch_id, port_id) or device.status_oid%(port_id)) (oid, status) = conn.get(oid) return status == str(device.state_on) and "on" or "off" def set_power_status(conn, options): if port_id == None: ipdu_resolv_port_id(conn, options) oid = ((device.has_switches) and device.control_oid%(switch_id, port_id) or device.control_oid%(port_id)) conn.set(oid, (options["--action"] == "on" and device.turn_on or device.turn_off)) def get_outlets_status(conn, options): result = {} if device == None: ipdu_set_device(conn, options) res_ports = conn.walk(device.outlet_table_oid, 30) for x in res_ports: t = x[0].split('.') port_num = ((device.has_switches) and "%s:%s"%(t[len(t)-3], t[len(t)-1]) or "%s"%(t[len(t)-1])) port_name = x[1].strip('"') port_status = "" result[port_num] = (port_name, port_status) return result # Main agent method def main(): global device device_opt = ["ipaddr", "login", "passwd", "no_login", "no_password", \ "port", "snmp_version", "snmp"] atexit.register(atexit_handler) all_opt["snmp_version"]["default"] = "3" all_opt["community"]["default"] = "private" all_opt["switch"]["default"] = "1" device = IBMiPDU options = check_input(device_opt, process_input(device_opt)) docs = {} docs["shortdesc"] = "Fence agent for iPDU over SNMP" docs["longdesc"] = "fence_ipdu is an I/O Fencing agent \ which can be used with the IBM iPDU network power switch. It logs \ into a device via SNMP and reboots a specified outlet. It supports \ SNMP v3 with all combinations of authenticity/privacy settings." docs["vendorurl"] = "http://www.ibm.com" show_docs(options, docs) # Operate the fencing device result = fence_action(FencingSnmp(options), options, set_power_status, get_power_status, get_outlets_status) sys.exit(result) if __name__ == "__main__": main() diff --git a/fence/agents/ipmilan/fence_ipmilan.py b/fence/agents/ipmilan/fence_ipmilan.py index 66494ed1..ff679ec9 100644 --- a/fence/agents/ipmilan/fence_ipmilan.py +++ b/fence/agents/ipmilan/fence_ipmilan.py @@ -1,175 +1,175 @@ -#!/usr/bin/python -tt +#!@PYTHON@ -tt import sys, re, os import atexit from pipes import quote sys.path.append("@FENCEAGENTSLIBDIR@") from fencing import * from fencing import fail_usage, is_executable, run_command, run_delay #BEGIN_VERSION_GENERATION RELEASE_VERSION="" REDHAT_COPYRIGHT="" BUILD_DATE="" #END_VERSION_GENERATION def get_power_status(_, options): output = run_command(options, create_command(options, "status")) match = re.search('[Cc]hassis [Pp]ower is [\\s]*([a-zA-Z]{2,3})', str(output)) status = match.group(1) if match else None return status def set_power_status(_, options): run_command(options, create_command(options, options["--action"])) return def reboot_cycle(_, options): output = run_command(options, create_command(options, "cycle")) return bool(re.search('chassis power control: cycle', str(output).lower())) def reboot_diag(_, options): output = run_command(options, create_command(options, "diag")) return bool(re.search('chassis power control: diag', str(output).lower())) def create_command(options, action): cmd = options["--ipmitool-path"] # --lanplus / -L - if options.has_key("--lanplus") and options["--lanplus"] in ["", "1"]: + if "--lanplus" in options 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: + if "--username" in options and len(options["--username"]) != 0: cmd += " -U " + quote(options["--username"]) # --auth / -A - if options.has_key("--auth"): + if "--auth" in options: cmd += " -A " + options["--auth"] # --password / -p - if options.has_key("--password"): + if "--password" in options: cmd += " -P " + quote(options["--password"]) else: cmd += " -P ''" # --cipher / -C if "--cipher" in options: cmd += " -C " + options["--cipher"] # --port / -n - if options.has_key("--ipport"): + if "--ipport" in options: cmd += " -p " + options["--ipport"] - if options.has_key("--privlvl"): + if "--privlvl" in options: cmd += " -L " + options["--privlvl"] # --action / -o cmd += " chassis power " + action # --use-sudo / -d - if options.has_key("--use-sudo"): + if "--use-sudo" in options: cmd = options["--sudo-path"] + " " + cmd return cmd def define_new_opts(): all_opt["lanplus"] = { "getopt" : "P", "longopt" : "lanplus", "help" : "-P, --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.", "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)", "order": 1 } all_opt["privlvl"] = { "getopt" : "L:", "longopt" : "privlvl", "help" : "-L, --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" : ":", "longopt" : "ipmitool-path", "help" : "--ipmitool-path=[path] Path to ipmitool binary", "required" : "0", "shortdesc" : "Path to ipmitool binary", "default" : "@IPMITOOL_PATH@", "order": 200 } def main(): atexit.register(atexit_handler) device_opt = ["ipaddr", "login", "no_login", "no_password", "passwd", "diag", "lanplus", "auth", "cipher", "privlvl", "sudo", "ipmitool_path", "method"] define_new_opts() all_opt["power_wait"]["default"] = 2 if os.path.basename(sys.argv[0]) == "fence_ilo3": all_opt["power_wait"]["default"] = "4" all_opt["method"]["default"] = "cycle" all_opt["lanplus"]["default"] = "1" elif os.path.basename(sys.argv[0]) == "fence_ilo4": all_opt["lanplus"]["default"] = "1" all_opt["ipport"]["default"] = "623" options = check_input(device_opt, process_input(device_opt)) docs = {} docs["shortdesc"] = "Fence agent for IPMI" docs["longdesc"] = "fence_ipmilan is an I/O Fencing agent\ which can be used with machines controlled by IPMI.\ This agent calls support software ipmitool (http://ipmitool.sf.net/)." docs["vendorurl"] = "" docs["symlink"] = [("fence_ilo3", "Fence agent for HP iLO3"), ("fence_ilo4", "Fence agent for HP iLO4"), ("fence_imm", "Fence agent for IBM Integrated Management Module"), ("fence_idrac", "Fence agent for Dell iDRAC")] show_docs(options, docs) run_delay(options) if not is_executable(options["--ipmitool-path"]): fail_usage("Ipmitool not found or not accessible") reboot_fn = reboot_cycle if options["--action"] == "diag": # Diag is a special action that can't be verified so we will reuse reboot functionality # to minimize impact on generic library options["--action"] = "reboot" options["--method"] = "cycle" reboot_fn = reboot_diag result = fence_action(None, options, set_power_status, get_power_status, None, reboot_fn) sys.exit(result) if __name__ == "__main__": main() diff --git a/fence/agents/ldom/fence_ldom.py b/fence/agents/ldom/fence_ldom.py index 27a1a4aa..b4d87249 100644 --- a/fence/agents/ldom/fence_ldom.py +++ b/fence/agents/ldom/fence_ldom.py @@ -1,108 +1,108 @@ -#!/usr/bin/python -tt +#!@PYTHON@ -tt ## ## The Following Agent Has Been Tested On - LDOM 1.0.3 ## The interface is backward compatible so it will work ## with 1.0, 1.0.1 and .2 too. ## ##### -import sys, re, pexpect, exceptions +import sys, re, pexpect import atexit sys.path.append("@FENCEAGENTSLIBDIR@") from fencing import * from fencing import fail_usage #BEGIN_VERSION_GENERATION RELEASE_VERSION="Logical Domains (LDoms) fence Agent" REDHAT_COPYRIGHT="" BUILD_DATE="" #END_VERSION_GENERATION COMMAND_PROMPT_REG = r"\[PEXPECT\]$" COMMAND_PROMPT_NEW = "[PEXPECT]" # Start comunicating after login. Prepare good environment. def start_communication(conn, options): conn.send_eol("PS1='" + COMMAND_PROMPT_NEW + "'") res = conn.expect([pexpect.TIMEOUT, COMMAND_PROMPT_REG], int(options["--shell-timeout"])) if res == 0: #CSH stuff conn.send_eol("set prompt='" + COMMAND_PROMPT_NEW + "'") conn.log_expect(COMMAND_PROMPT_REG, int(options["--shell-timeout"])) def get_power_status(conn, options): start_communication(conn, options) conn.send_eol("ldm ls") conn.log_expect(COMMAND_PROMPT_REG, int(options["--shell-timeout"])) result = {} #This is status of mini finite automata. 0 = we didn't found NAME and STATE, 1 = we did fa_status = 0 for line in conn.before.splitlines(): domain = re.search(r"^(\S+)\s+(\S+)\s+.*$", line) if domain != None: if fa_status == 0 and domain.group(1) == "NAME" and domain.group(2) == "STATE": fa_status = 1 elif fa_status == 1: result[domain.group(1)] = ("", (domain.group(2).lower() == "bound" and "off" or "on")) if not options["--action"] in ['monitor', 'list']: if not options["--plug"] in result: fail_usage("Failed: You have to enter existing logical domain!") else: return result[options["--plug"]][1] else: return result def set_power_status(conn, options): start_communication(conn, options) cmd_line = "ldm "+ (options["--action"] == "on" and "start" or "stop -f") + " \"" + options["--plug"] + "\"" conn.send_eol(cmd_line) conn.log_expect(COMMAND_PROMPT_REG, int(options["--power-timeout"])) def main(): device_opt = ["ipaddr", "login", "passwd", "cmd_prompt", "secure", "port"] atexit.register(atexit_handler) all_opt["secure"]["default"] = "1" all_opt["cmd_prompt"]["default"] = [r"\ $"] options = check_input(device_opt, process_input(device_opt)) docs = {} docs["shortdesc"] = "Fence agent for Sun LDOM" docs["longdesc"] = "fence_ldom is an I/O Fencing agent \ which can be used with LDoms virtual machines. This agent works \ so, that run ldm command on host machine. So ldm must be directly \ runnable.\ \n.P\n\ Very useful parameter is -c (or cmd_prompt in stdin mode). This \ must be set to something, what is displayed after successful login \ to host machine. Default string is space on end of string (default \ for root in bash). But (for example) csh use ], so in that case you \ must use parameter -c with argument ]. Very similar situation is, \ if you use bash and login to host machine with other user than \ root. Than prompt is $, so again, you must use parameter -c." docs["vendorurl"] = "http://www.sun.com" show_docs(options, docs) ## ## Operate the fencing device #### conn = fence_login(options) result = fence_action(conn, options, set_power_status, get_power_status, get_power_status) fence_logout(conn, "logout") sys.exit(result) if __name__ == "__main__": main() diff --git a/fence/agents/lib/XenAPI.py.py b/fence/agents/lib/XenAPI.py.py index b91efdac..3f5456d5 100644 --- a/fence/agents/lib/XenAPI.py.py +++ b/fence/agents/lib/XenAPI.py.py @@ -1,209 +1,212 @@ #============================================================================ # This library is free software; you can redistribute it and/or # modify it under the terms of version 2.1 of the GNU Lesser General Public # License as published by the Free Software Foundation. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #============================================================================ # Copyright (C) 2006 XenSource Inc. #============================================================================ # # Parts of this file are based upon xmlrpclib.py, the XML-RPC client # interface included in the Python distribution. # # Copyright (c) 1999-2002 by Secret Labs AB # Copyright (c) 1999-2002 by Fredrik Lundh # # By obtaining, using, and/or copying this software and/or its # associated documentation, you agree that you have read, understood, # and will comply with the following terms and conditions: # # Permission to use, copy, modify, and distribute this software and # its associated documentation for any purpose and without fee is # hereby granted, provided that the above copyright notice appears in # all copies, and that both that copyright notice and this permission # notice appear in supporting documentation, and that the name of # Secret Labs AB or the author not be used in advertising or publicity # pertaining to distribution of the software without specific, written # prior permission. # # SECRET LABS AB AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD # TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT- # ABILITY AND FITNESS. IN NO EVENT SHALL SECRET LABS AB OR THE AUTHOR # BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY # DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, # WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS # ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE # OF THIS SOFTWARE. # -------------------------------------------------------------------- +import sys import gettext -import xmlrpclib -import httplib import socket import logging +if sys.version_info.major > 2: + import xmlrpc.client as xmlrpclib + import http.client as httplib +else: + import xmlrpclib + import httplib + translation = gettext.translation('xen-xm', fallback=True) class Failure(Exception): def __init__(self, details): try: # If this failure is MESSAGE_PARAMETER_COUNT_MISMATCH, then we # correct the return values here, to account for the fact that we # transparently add the session handle as the first argument. if details[0] == 'MESSAGE_PARAMETER_COUNT_MISMATCH': details[2] = str(int(details[2]) - 1) details[3] = str(int(details[3]) - 1) self.details = details - except Exception, exn: + except Exception as exn: self.details = ['INTERNAL_ERROR', 'Client-side: ' + str(exn)] def __str__(self): try: return translation.ugettext(self.details[0]) % self._details_map() - except TypeError, exn: + except TypeError as exn: return "Message database broken: %s.\nXen-API failure: %s" % \ (exn, str(self.details)) - except Exception, exn: + except Exception as exn: logging.error("%s\n", str(exn)) return "Xen-API failure: %s" % str(self.details) def _details_map(self): return dict([(str(i), self.details[i]) for i in range(len(self.details))]) _RECONNECT_AND_RETRY = (lambda _: ()) class UDSHTTPConnection(httplib.HTTPConnection): """ Stupid hacked up HTTPConnection subclass to allow HTTP over Unix domain sockets. """ def connect(self): path = self.host.replace("_", "/") self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) self.sock.connect(path) -class UDSHTTP(httplib.HTTP): - _connection_class = UDSHTTPConnection - class UDSTransport(xmlrpclib.Transport): def make_connection(self, host): - return UDSHTTP(host) + return httplib.HTTPConnection(host) class Session(xmlrpclib.ServerProxy): """A server proxy and session manager for communicating with Xend using the Xen-API. Example: session = Session('http://localhost:9363/') session.login_with_password('me', 'mypassword') session.xenapi.VM.start(vm_uuid) session.xenapi.session.logout() For now, this class also supports the legacy XML-RPC API, using session.xend.domain('Domain-0') and similar. This support will disappear once there is a working Xen-API replacement for every call in the legacy API. """ def __init__(self, uri, transport=None, encoding=None, verbose=0, allow_none=1): xmlrpclib.ServerProxy.__init__(self, uri, transport, encoding, verbose, allow_none) self._session = None self.last_login_method = None self.last_login_params = None def xenapi_request(self, methodname, params): if methodname.startswith('login'): self._login(methodname, params) return None else: retry_count = 0 while retry_count < 3: full_params = (self._session,) + params result = _parse_result(getattr(self, methodname)(*full_params)) if result == _RECONNECT_AND_RETRY: retry_count += 1 if self.last_login_method: self._login(self.last_login_method, self.last_login_params) else: raise xmlrpclib.Fault(401, 'You must log in') else: return result raise xmlrpclib.Fault( 500, 'Tried 3 times to get a valid session, but failed') def _login(self, method, params): result = _parse_result(getattr(self, 'session.%s' % method)(*params)) if result == _RECONNECT_AND_RETRY: raise xmlrpclib.Fault( 500, 'Received SESSION_INVALID when logging in') self._session = result self.last_login_method = method self.last_login_params = params def __getattr__(self, name): if name == 'xenapi': return _Dispatcher(self.xenapi_request, None) elif name.startswith('login'): return lambda *params: self._login(name, params) else: return xmlrpclib.ServerProxy.__getattr__(self, name) def xapi_local(): return Session("http://_var_xapi_xapi/", transport=UDSTransport()) def _parse_result(result): if type(result) != dict or 'Status' not in result: raise xmlrpclib.Fault(500, 'Missing Status in response from server' + result) if result['Status'] == 'Success': if 'Value' in result: return result['Value'] else: raise xmlrpclib.Fault(500, 'Missing Value in response from server') else: if 'ErrorDescription' in result: if result['ErrorDescription'][0] == 'SESSION_INVALID': return _RECONNECT_AND_RETRY else: raise Failure(result['ErrorDescription']) else: raise xmlrpclib.Fault( 500, 'Missing ErrorDescription in response from server') # Based upon _Method from xmlrpclib. class _Dispatcher: def __init__(self, send, name): self.__send = send self.__name = name def __repr__(self): if self.__name: return '' % self.__name else: return '' def __getattr__(self, name): if self.__name is None: return _Dispatcher(self.__send, name) else: return _Dispatcher(self.__send, "%s.%s" % (self.__name, name)) def __call__(self, *args): return self.__send(self.__name, args) diff --git a/fence/agents/lib/check_used_options.py b/fence/agents/lib/check_used_options.py index 0eb19e31..b90bc056 100755 --- a/fence/agents/lib/check_used_options.py +++ b/fence/agents/lib/check_used_options.py @@ -1,65 +1,65 @@ #!/usr/bin/python -tt ## Check if fence agent uses only options["--??"] which are defined in fencing library or ## fence agent itself ## ## Usage: ./check_used_options.py fence-agent (e.g. lpar/fence_lpar.py) ## import sys, re sys.path.append("@FENCEAGENTSLIBDIR@") from fencing import all_opt def main(): agent = sys.argv[1] available = {} ## all_opt from fencing library are imported - for k in all_opt.keys(): - if all_opt[k].has_key("longopt"): + for k in list(all_opt.keys()): + if "longopt" in all_opt[k]: available["--" + all_opt[k]["longopt"]] = True ## add UUID which is derived automatically from --plug if possible available["--uuid"] = True ## all_opt defined in fence agent are found agent_file = open(agent) opt_re = re.compile(r"\s*all_opt\[\"([^\"]*)\"\] = {") opt_longopt_re = re.compile(r"\s*\"longopt\" : \"([^\"]*)\"") in_opt = False for line in agent_file: if opt_re.search(line) != None: in_opt = True if in_opt and opt_longopt_re.search(line) != None: available["--" + opt_longopt_re.search(line).group(1)] = True in_opt = False ## check if all options are defined agent_file = open(agent) option_use_re = re.compile(r"options\[\"(-[^\"]*)\"\]") option_has_re = re.compile(r"options.has_key\(\"(-[^\"]*)\"\)") counter = 0 without_errors = True for line in agent_file: counter += 1 for option in option_use_re.findall(line): - if not available.has_key(option): - print "ERROR on line %d in %s: option %s is not defined" % (counter, agent, option_use_re.search(line).group(1)) + if option not in available: + print("ERROR on line %d in %s: option %s is not defined" % (counter, agent, option_use_re.search(line).group(1))) without_errors = False for option in option_has_re.findall(line): - if not available.has_key(option): - print "ERROR on line %d in %s: option %s is not defined" % (counter, agent, option_has_re.search(line).group(1)) + if option not in available: + print("ERROR on line %d in %s: option %s is not defined" % (counter, agent, option_has_re.search(line).group(1))) without_errors = False if without_errors: sys.exit(0) else: sys.exit(1) if __name__ == "__main__": main() diff --git a/fence/agents/lib/fencing.py.py b/fence/agents/lib/fencing.py.py index 0e57e39a..4e0b30af 100644 --- a/fence/agents/lib/fencing.py.py +++ b/fence/agents/lib/fencing.py.py @@ -1,1395 +1,1393 @@ -#!/usr/bin/python -tt +#!@PYTHON@ -tt import sys, getopt, time, os, uuid, pycurl, stat import pexpect, re, syslog import logging import subprocess import threading import shlex -import exceptions import socket import textwrap 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 __all__ = ['atexit_handler', 'check_input', 'process_input', 'all_opt', 'show_docs', 'fence_login', 'fence_action', 'fence_logout'] EC_OK = 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 EC_INVALID_PRIVILEGES = 11 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 Display 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", "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" : ":", "longopt" : "delay", "help" : "--delay=[seconds] Wait X seconds before fencing is started", "required" : "0", "default" : "0", "order" : 200}, "agent" : { "getopt" : "", "help" : "", "order" : 1}, "web" : { "getopt" : "", "help" : "", "order" : 1}, "force_on" : { "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", "order" : 1}, "ipport" : { "getopt" : "u:", "longopt" : "ipport", "help" : "-u, --ipport=[port] TCP/UDP port to use for connection", "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" : "?", "order" : 1}, "no_login" : { "getopt" : "", "help" : "", "order" : 1}, "no_password" : { "getopt" : "", "help" : "", "order" : 1}, "no_port" : { "getopt" : "", "help" : "", "order" : 1}, "no_status" : { "getopt" : "", "help" : "", "order" : 1}, "no_on" : { "getopt" : "", "help" : "", "order" : 1}, "no_off" : { "getopt" : "", "help" : "", "order" : 1}, "telnet" : { "getopt" : "", "help" : "", - "order" : ""}, + "order" : 1}, "diag" : { "getopt" : "", "help" : "", - "order" : ""}, + "order" : 1}, "passwd" : { "getopt" : "p:", "longopt" : "password", "help" : "-p, --password=[password] Login password or passphrase", "required" : "0", "order" : 1}, "passwd_script" : { "getopt" : "S:", "longopt" : "password-script", "help" : "-S, --password-script=[script] Script to run to retrieve password", "required" : "0", "order" : 1}, "identity_file" : { "getopt" : "k:", "longopt" : "identity-file", "help" : "-k, --identity-file=[filename] Identity file (private key) for SSH", "required" : "0", "order" : 1}, "cmd_prompt" : { "getopt" : "c:", "longopt" : "command-prompt", "help" : "-c, --command-prompt=[prompt] Force Python regex for command prompt", "required" : "0", "order" : 1}, "secure" : { "getopt" : "x", "longopt" : "ssh", "help" : "-x, --ssh Use SSH connection", "required" : "0", "order" : 1}, "ssh_options" : { "getopt" : ":", "longopt" : "ssh-options", "help" : "--ssh-options=[options] SSH options to use", "required" : "0", "order" : 1}, "ssl" : { "getopt" : "z", "longopt" : "ssl", "help" : "-z, --ssl Use SSL connection with verifying certificate", "required" : "0", "order" : 1}, "ssl_insecure" : { "getopt" : "", "longopt" : "ssl-insecure", "help" : "--ssl-insecure Use SSL connection without verifying certificate", "required" : "0", "order" : 1}, "ssl_secure" : { "getopt" : "", "longopt" : "ssl-secure", "help" : "--ssl-secure Use SSL connection with verifying certificate", "required" : "0", "order" : 1}, "notls" : { "getopt" : "t", "longopt" : "notls", "help" : "-t, --notls " "Disable TLS negotiation and force SSL3.0. " "This should only be used for devices that do not support TLS1.0 and up.", "required" : "0", "order" : 1}, "tls1.0" : { "getopt" : "", "longopt" : "tls1.0", "help" : "--tls1.0 " "Disable TLS negotiation and force TLS1.0. " "This should only be used for devices that do not support TLS1.1 and up.", "required" : "0", "order" : 1}, "port" : { "getopt" : "n:", "longopt" : "plug", "help" : "-n, --plug=[id] " "Physical plug number on device, UUID or identification of machine", "required" : "1", "order" : 1}, "switch" : { "getopt" : "s:", "longopt" : "switch", "help" : "-s, --switch=[id] Physical switch number on device", "required" : "0", "order" : 1}, "exec" : { "getopt" : "e:", "longopt" : "exec", "help" : "-e, --exec=[command] Command to execute", "required" : "0", "order" : 1}, "vmware_type" : { "getopt" : "d:", "longopt" : "vmware_type", "help" : "-d, --vmware_type=[type] Type of VMware to connect", "required" : "0", "order" : 1}, "vmware_datacenter" : { "getopt" : "s:", "longopt" : "vmware-datacenter", "help" : "-s, --vmware-datacenter=[dc] VMWare datacenter filter", "required" : "0", "order" : 2}, "snmp_version" : { "getopt" : "d:", "longopt" : "snmp-version", "help" : "-d, --snmp-version=[version] Specifies SNMP version to use (1|2c|3)", "required" : "0", "shortdesc" : "Specifies SNMP version to use", "choices" : ["1", "2c", "3"], "order" : 1}, "community" : { "getopt" : "c:", "longopt" : "community", "help" : "-c, --community=[community] Set the community string", "required" : "0", "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", "choices" : ["MD5", "SHA"], "order" : 1}, "snmp_sec_level" : { "getopt" : "E:", "longopt" : "snmp-sec-level", "help" : "-E, --snmp-sec-level=[level] " "Set security level (noAuthNoPriv|authNoPriv|authPriv)", "required" : "0", "shortdesc" : "Set security level", "choices" : ["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", "choices" : ["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", "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", "order" : 1}, "inet4_only" : { "getopt" : "4", "longopt" : "inet4-only", "help" : "-4, --inet4-only Forces agent to use IPv4 addresses only", "required" : "0", "order" : 1}, "inet6_only" : { "getopt" : "6", "longopt" : "inet6-only", "help" : "-6, --inet6-only Forces agent to use IPv6 addresses only", "required" : "0", "order" : 1}, "separator" : { "getopt" : "C:", "longopt" : "separator", "help" : "-C, --separator=[char] Separator for CSV created by 'list' operation", "default" : ",", "required" : "0", "order" : 100}, "login_timeout" : { "getopt" : ":", "longopt" : "login-timeout", "help" : "--login-timeout=[seconds] Wait X seconds for cmd prompt after login", "default" : "5", "required" : "0", "order" : 200}, "shell_timeout" : { "getopt" : ":", "longopt" : "shell-timeout", "help" : "--shell-timeout=[seconds] Wait X seconds for cmd prompt after issuing command", "default" : "3", "required" : "0", "order" : 200}, "power_timeout" : { "getopt" : ":", "longopt" : "power-timeout", "help" : "--power-timeout=[seconds] Test X seconds for status change after ON/OFF", "default" : "20", "required" : "0", "order" : 200}, "power_wait" : { "getopt" : ":", "longopt" : "power-wait", "help" : "--power-wait=[seconds] Wait X seconds after issuing ON/OFF", "default" : "0", "required" : "0", "order" : 200}, "missing_as_off" : { "getopt" : "", "longopt" : "missing-as-off", "help" : "--missing-as-off Missing port returns OFF instead of failure", "required" : "0", "order" : 200}, "retry_on" : { "getopt" : ":", "longopt" : "retry-on", "help" : "--retry-on=[attempts] Count of attempts to retry power on", "default" : "1", "required" : "0", "order" : 201}, "session_url" : { "getopt" : "s:", "longopt" : "session-url", "help" : "-s, --session-url URL to connect to XenServer on", "required" : "1", "order" : 1}, "sudo" : { "getopt" : "", "longopt" : "use-sudo", "help" : "--use-sudo Use sudo (without password) when calling 3rd party software", "required" : "0", "order" : 205}, "method" : { "getopt" : "m:", "longopt" : "method", "help" : "-m, --method=[method] Method to fence (onoff|cycle) (Default: onoff)", "required" : "0", "shortdesc" : "Method to fence", "default" : "onoff", "choices" : ["onoff", "cycle"], "order" : 1}, "telnet_path" : { "getopt" : ":", "longopt" : "telnet-path", "help" : "--telnet-path=[path] Path to telnet binary", "required" : "0", "default" : "@TELNET_PATH@", "order": 300}, "ssh_path" : { "getopt" : ":", "longopt" : "ssh-path", "help" : "--ssh-path=[path] Path to ssh binary", "required" : "0", "default" : "@SSH_PATH@", "order": 300}, "gnutlscli_path" : { "getopt" : ":", "longopt" : "gnutlscli-path", "help" : "--gnutlscli-path=[path] Path to gnutls-cli binary", "required" : "0", "default" : "@GNUTLSCLI_PATH@", "order": 300}, "sudo_path" : { "getopt" : ":", "longopt" : "sudo-path", "help" : "--sudo-path=[path] Path to sudo binary", "required" : "0", "default" : "@SUDO_PATH@", "order": 300}, "snmpwalk_path" : { "getopt" : ":", "longopt" : "snmpwalk-path", "help" : "--snmpwalk-path=[path] Path to snmpwalk binary", "required" : "0", "default" : "@SNMPWALK_PATH@", "order" : 300}, "snmpset_path" : { "getopt" : ":", "longopt" : "snmpset-path", "help" : "--snmpset-path=[path] Path to snmpset binary", "required" : "0", "default" : "@SNMPSET_PATH@", "order" : 300}, "snmpget_path" : { "getopt" : ":", "longopt" : "snmpget-path", "help" : "--snmpget-path=[path] Path to snmpget binary", "required" : "0", "default" : "@SNMPGET_PATH@", "order" : 300}, "snmp": { "getopt" : "", "help" : "", "order" : 1}, "port_as_ip": { "getopt" : "", "longopt" : "port-as-ip", "help" : "--port-as-ip Make \"port/plug\" to be an alias to IP address", "required" : "0", "order" : 200}, "on_target": { "getopt" : "", "help" : "", "order" : 1} } # 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"], "sudo" : ["sudo_path"], "secure" : ["identity_file", "ssh_options", "ssh_path"], "telnet" : ["telnet_path"], "ipaddr" : ["ipport", "inet4_only", "inet6_only"], "port" : ["separator"], "ssl" : ["ssl_secure", "ssl_insecure", "gnutlscli_path"], "snmp" : ["snmp_auth_prot", "snmp_sec_level", "snmp_priv_prot", \ "snmp_priv_passwd", "snmp_priv_passwd_script", "community", \ "snmpset_path", "snmpget_path", "snmpwalk_path"] } class fspawn(pexpect.spawn): def __init__(self, options, command): logging.info("Running command: %s", command) pexpect.spawn.__init__(self, command) self.opt = options def log_expect(self, pattern, timeout): result = self.expect(pattern, timeout) logging.debug("Received: %s", self.before + self.after) return result def send(self, message): logging.debug("Sent: %s", message) return pexpect.spawn.send(self, message) # send EOL according to what was detected in login process (telnet) def send_eol(self, message): return self.send(message + self.opt["eol"]) def atexit_handler(): try: sys.stdout.close() os.close(1) except IOError: logging.error("%s failed to close standard output\n", sys.argv[0]) sys.exit(EC_GENERIC_ERROR) def _add_dependency_options(options): ## Add also options which are available for every fence agent added_opt = [] for opt in options + ["default"]: - if DEPENDENCY_OPT.has_key(opt): + if opt in DEPENDENCY_OPT: added_opt.extend([y for y in DEPENDENCY_OPT[opt] if options.count(y) == 0]) if not "port" in (options + added_opt) and \ not "nodename" in (options + added_opt) and \ "ipaddr" in (options + added_opt): added_opt.append("port_as_ip") all_opt["port"]["help"] = "-n, --plug=[ip] IP address or hostname of fencing device " \ "(together with --port-as-ip)" return added_opt def fail_usage(message="", stop=True): if len(message) > 0: logging.error("%s\n", message) if stop: logging.error("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", EC_INVALID_PRIVILEGES : "Failed: The user does not have the correct privileges to do the requested action." }[error_code] + "\n" logging.error("%s\n", message) sys.exit(EC_GENERIC_ERROR) def usage(avail_opt): - print "Usage:" - print "\t" + os.path.basename(sys.argv[0]) + " [options]" - print "Options:" + 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"])) + sorted_list.sort(key=lambda x: x[1]["order"]) for key, value in sorted_list: if len(value["help"]) != 0: - print " " + _join_wrap([value["help"]], first_indent=3) + print(" " + _join_wrap([value["help"]], first_indent=3)) def metadata(avail_opt, docs): # avail_opt has to be unique, if there are duplicities then they should be removed sorted_list = [(key, all_opt[key]) for key in list(set(avail_opt))] - sorted_list.sort(lambda x, y: cmp(x[0], y[0])) - sorted_list.sort(lambda x, y: cmp(x[1]["order"], y[1]["order"])) + sorted_list.sort(key=lambda x: (x[1]["order"], x[0])) - print "" - print "" + print("") + print("") for (symlink, desc) in docs.get("symlink", []): - print "" - print "" + docs["longdesc"] + "" - print "" + docs["vendorurl"] + "" - print "" + print("") + print("" + docs["longdesc"] + "") + print("" + docs["vendorurl"] + "") + print("") for option, _ in sorted_list: - if all_opt[option].has_key("help") and len(all_opt[option]["help"]) > 0: - print "\t" + if "help" in all_opt[option] and len(all_opt[option]["help"]) > 0: + print("\t") default = "" - if all_opt[option].has_key("default"): + if "default" in all_opt[option]: default = "default=\"" + _encode_html_entities(str(all_opt[option]["default"])) + "\" " mixed = all_opt[option]["help"] ## split it between option and help text res = re.compile(r"^(.*?--\S+)\s+", re.IGNORECASE | re.S).search(mixed) if None != res: mixed = res.group(1) mixed = _encode_html_entities(mixed) if not "shortdesc" in all_opt[option]: shortdesc = re.sub("\s\s+", " ", all_opt[option]["help"][31:]) else: shortdesc = all_opt[option]["shortdesc"] - print "\t\t" - if all_opt[option].has_key("choices"): - print "\t\t" + print("\t\t") + if "choices" in all_opt[option]: + print("\t\t") for choice in all_opt[option]["choices"]: - print "\t\t\t" + print("\t\t\t") elif all_opt[option]["getopt"].count(":") > 0: - print "\t\t" + print("\t\t") else: - print "\t\t" - print "\t\t" + shortdesc + "" - print "\t" - print "" - print "" + print("\t\t") + print("\t\t" + shortdesc + "") + print("\t") + print("") + print("") (available_actions, _) = _get_available_actions(avail_opt) if "on" in available_actions: available_actions.remove("on") on_target = ' on_target="1"' if avail_opt.count("on_target") else '' - print "\t" % (on_target, avail_opt.count("fabric_fencing")) + print("\t" % (on_target, avail_opt.count("fabric_fencing"))) for action in available_actions: - print "\t" % (action) - print "" - print "" + print("\t" % (action)) + print("") + print("") def process_input(avail_opt): avail_opt.extend(_add_dependency_options(avail_opt)) # @todo: this should be put elsewhere? os.putenv("LANG", "C") os.putenv("LC_ALL", "C") if "port_as_ip" in avail_opt: avail_opt.append("port") if len(sys.argv) > 1: opt = _parse_input_cmdline(avail_opt) else: opt = _parse_input_stdin(avail_opt) if "--port-as-ip" in opt and "--plug" in opt: opt["--ip"] = opt["--plug"] 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, other_conditions = False): device_opt.extend(_add_dependency_options(device_opt)) options = dict(opt) options["device_opt"] = device_opt _update_metadata(options) options = _set_default_values(options) options["--action"] = options["--action"].lower() ## In special cases (show help, metadata or version) we don't need to check anything ##### # OCF compatibility if options["--action"] == "meta-data": options["--action"] = "metadata" - if options["--action"] == "metadata" or any(options.has_key(k) for k in ("--help", "--version")): + if options["--action"] == "metadata" or any(k in options for k in ("--help", "--version")): return options - if options.has_key("--verbose"): + if "--verbose" in options: logging.getLogger().setLevel(logging.DEBUG) ## add logging to syslog logging.getLogger().addHandler(SyslogLibHandler()) ## add logging to stderr logging.getLogger().addHandler(logging.StreamHandler(stream=sys.stderr)) (acceptable_actions, _) = _get_available_actions(device_opt) if 1 == device_opt.count("fabric_fencing"): acceptable_actions.extend(["enable", "disable"]) 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" if options["--action"] == "validate-all" and not other_conditions: _validate_input(options, False) sys.exit(EC_OK) else: _validate_input(options, True) - if options.has_key("--debug-file"): + if "--debug-file" in options: try: debug_file = logging.FileHandler(options["--debug-file"]) debug_file.setLevel(logging.DEBUG) logging.getLogger().addHandler(debug_file) except IOError: logging.error("Unable to create file %s", options["--debug-file"]) fail_usage("Failed: Unable to create file " + options["--debug-file"]) - if options.has_key("--snmp-priv-passwd-script"): + if "--snmp-priv-passwd-script" in options: options["--snmp-priv-passwd"] = os.popen(options["--snmp-priv-passwd-script"]).read().rstrip() - if options.has_key("--password-script"): + if "--password-script" in options: options["--password"] = os.popen(options["--password-script"]).read().rstrip() return options ## 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(connection, options, get_power_fn): status = "off" - plugs = options["--plugs"] if options.has_key("--plugs") else [""] + plugs = options["--plugs"] if "--plugs" in options else [""] for plug in plugs: try: options["--uuid"] = str(uuid.UUID(plug)) except ValueError: pass except KeyError: pass options["--plug"] = plug plug_status = get_power_fn(connection, options) if plug_status != "off": status = plug_status return status def set_multi_power_fn(connection, options, set_power_fn, get_power_fn, retry_attempts=1): - plugs = options["--plugs"] if options.has_key("--plugs") else [""] + plugs = options["--plugs"] if "--plugs" in options else [""] for _ in range(retry_attempts): for plug in plugs: try: options["--uuid"] = str(uuid.UUID(plug)) except ValueError: pass except KeyError: pass options["--plug"] = plug set_power_fn(connection, options) time.sleep(int(options["--power-wait"])) - for _ in xrange(int(options["--power-timeout"])): + for _ in range(int(options["--power-timeout"])): if get_multi_power_fn(connection, options, get_power_fn) != options["--action"]: time.sleep(1) else: return True return False def show_docs(options, docs=None): device_opt = options["device_opt"] if docs == None: docs = {} docs["shortdesc"] = "Fence agent" docs["longdesc"] = "" - if options.has_key("--help"): + if "--help" in options: usage(device_opt) sys.exit(0) if options.get("--action", "") == "metadata": if "port_as_ip" in device_opt: device_opt.remove("separator") metadata(device_opt, docs) sys.exit(0) - if options.has_key("--version"): - print __main__.RELEASE_VERSION, __main__.BUILD_DATE - print __main__.REDHAT_COPYRIGHT + if "--version" in options: + print(__main__.RELEASE_VERSION, __main__.BUILD_DATE) + print(__main__.REDHAT_COPYRIGHT) sys.exit(0) def fence_action(connection, options, set_power_fn, get_power_fn, get_outlet_list=None, reboot_cycle_fn=None): result = 0 try: - if options.has_key("--plug"): + if "--plug" in options: options["--plugs"] = options["--plug"].split(",") ## Process options that manipulate fencing device ##### if (options["--action"] in ["list", "list-status"]) or \ ((options["--action"] == "monitor") and 1 == options["device_opt"].count("port") and \ 0 == options["device_opt"].count("port_as_ip")): if 0 == options["device_opt"].count("port"): - print "N/A" + print("N/A") elif 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" + print("NOTICE: List option is not working on this device yet") else: options["--original-action"] = options["--action"] options["--action"] = "list" outlets = get_outlet_list(connection, options) options["--action"] = options["--original-action"] del options["--original-action"] ## keys can be numbers (port numbers) or strings (names of VM, UUID) - for outlet_id in outlets.keys(): + for outlet_id in list(outlets.keys()): (alias, status) = outlets[outlet_id] if status is None or (not status.upper() in ["ON", "OFF"]): status = "UNKNOWN" status = status.upper() if options["--action"] == "list": - print outlet_id + options["--separator"] + alias + print(outlet_id + options["--separator"] + alias) elif options["--action"] == "list-status": - print outlet_id + options["--separator"] + alias + options["--separator"] + status + print(outlet_id + options["--separator"] + alias + options["--separator"] + status) return if options["--action"] == "monitor" and not "port" in options["device_opt"] and "no_status" in options["device_opt"]: # Unable to do standard monitoring because 'status' action is not available return 0 status = None if not "no_status" in options["device_opt"]: status = get_multi_power_fn(connection, options, get_power_fn) if status != "on" and status != "off": fail(EC_STATUS) if options["--action"] == status: if not (status == "on" and "force_on" in options["device_opt"]): - print "Success: Already %s" % (status.upper()) + print("Success: Already %s" % (status.upper())) return 0 if options["--action"] == "on": if set_multi_power_fn(connection, options, set_power_fn, get_power_fn, 1 + int(options["--retry-on"])): - print "Success: Powered ON" + print("Success: Powered ON") else: fail(EC_WAITING_ON) elif options["--action"] == "off": if set_multi_power_fn(connection, options, set_power_fn, get_power_fn): - print "Success: Powered OFF" + print("Success: Powered OFF") else: fail(EC_WAITING_OFF) elif options["--action"] == "reboot": power_on = False if options.get("--method", "").lower() == "cycle" and reboot_cycle_fn is not None: for _ in range(1, 1 + int(options["--retry-on"])): if reboot_cycle_fn(connection, options): power_on = True break if not power_on: fail(EC_TIMED_OUT) else: if status != "off": options["--action"] = "off" if not set_multi_power_fn(connection, options, set_power_fn, get_power_fn): fail(EC_WAITING_OFF) options["--action"] = "on" try: power_on = set_multi_power_fn(connection, options, set_power_fn, get_power_fn, int(options["--retry-on"])) - except Exception, ex: + except Exception as ex: # an error occured during power ON phase in reboot # fence action was completed succesfully even in that case logging.warning("%s", str(ex)) if power_on == False: # this should not fail as node was fenced succesfully logging.error('Timed out waiting to power ON\n') - print "Success: Rebooted" + print("Success: Rebooted") elif options["--action"] == "status": - print "Status: " + status.upper() + 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: + except pycurl.error as ex: logging.error("%s\n", str(ex)) fail(EC_TIMED_OUT) - except socket.timeout, ex: + except socket.timeout as ex: logging.error("%s\n", str(ex)) fail(EC_TIMED_OUT) return result def fence_login(options, re_login_string=r"(login\s*: )|((?!Last )Login Name: )|(username: )|(User Name :)"): run_delay(options) - if not options.has_key("eol"): + if "eol" not in options: options["eol"] = "\r\n" - if options.has_key("--command-prompt") and type(options["--command-prompt"]) is not list: + if "--command-prompt" in options and type(options["--command-prompt"]) is not list: options["--command-prompt"] = [options["--command-prompt"]] try: - if options.has_key("--ssl"): + if "--ssl" in options: conn = _open_ssl_connection(options) - elif options.has_key("--ssh") and not options.has_key("--identity-file"): + elif "--ssh" in options and "--identity-file" not in options: conn = _login_ssh_with_password(options, re_login_string) - elif options.has_key("--ssh") and options.has_key("--identity-file"): + elif "--ssh" in options and "--identity-file" in options: conn = _login_ssh_with_identity_file(options) else: conn = _login_telnet(options, re_login_string) - except pexpect.EOF, exception: + except pexpect.EOF as exception: logging.debug("%s", str(exception)) fail(EC_LOGIN_DENIED) - except pexpect.TIMEOUT, exception: + except pexpect.TIMEOUT as exception: logging.debug("%s", str(exception)) 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 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) # For IPMI password occurs on command line, it should not be part of debug info log_command = command if "ipmitool" in log_command: log_command = re.sub("-P (.+?) -p", "-P [set] -p", log_command) logging.info("Executing: %s\n", log_command) try: process = subprocess.Popen(shlex.split(command), stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env) except OSError: 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)) return (status, pipe_stdout, pipe_stderr) def run_delay(options): ## Delay is important for two-node clusters fencing but we do not need to delay 'status' operations if options["--action"] in ["off", "reboot"]: logging.info("Delay %s second(s) before logging in to the fence device", options["--delay"]) time.sleep(int(options["--delay"])) def fence_logout(conn, logout_string, sleep=0): # Logout is not required part of fencing but we should attempt to do it properly # In some cases our 'exit' command is faster and we can not close connection as it # was already closed by fencing device try: conn.send_eol(logout_string) time.sleep(sleep) conn.close() - except exceptions.OSError: + except OSError: pass except pexpect.ExceptionPexpect: pass # Convert array of format [[key1, value1], [key2, value2], ... [keyN, valueN]] to dict, where key is # in format a.b.c.d...z and returned dict has key only z def array_to_dict(array): return dict([[x[0].split(".")[-1], x[1]] for x in array]) ## Own logger handler that uses old-style syslog handler as otherwise everything is sourced ## from /dev/syslog class SyslogLibHandler(logging.StreamHandler): """ A handler class that correctly push messages into syslog """ def emit(self, record): syslog_level = { logging.CRITICAL:syslog.LOG_CRIT, logging.ERROR:syslog.LOG_ERR, logging.WARNING:syslog.LOG_WARNING, logging.INFO:syslog.LOG_INFO, logging.DEBUG:syslog.LOG_DEBUG, logging.NOTSET:syslog.LOG_DEBUG, }[record.levelno] msg = self.format(record) # syslos.syslog can not have 0x00 character inside or exception is thrown syslog.syslog(syslog_level, msg.replace("\x00", "\n")) return def _open_ssl_connection(options): gnutls_opts = "" ssl_opts = "" - if options.has_key("--notls"): + if "--notls" in options: gnutls_opts = "--priority \"NORMAL:-VERS-TLS1.2:-VERS-TLS1.1:-VERS-TLS1.0:+VERS-SSL3.0\"" - elif options.has_key("--tls1.0"): + elif "--tls1.0" in options: gnutls_opts = "--priority \"NORMAL:-VERS-TLS1.2:-VERS-TLS1.1:+VERS-TLS1.0:%LATEST_RECORD_VERSION\"" # --ssl is same as the --ssl-secure; it means we want to verify certificate in these cases - if options.has_key("--ssl-insecure"): + if "--ssl-insecure" in options: ssl_opts = "--insecure" command = '%s %s %s --crlf -p %s %s' % \ (options["--gnutlscli-path"], gnutls_opts, ssl_opts, options["--ipport"], options["--ip"]) try: conn = fspawn(options, command) - except pexpect.ExceptionPexpect, ex: + except pexpect.ExceptionPexpect as ex: logging.error("%s\n", str(ex)) sys.exit(EC_GENERIC_ERROR) return conn def _login_ssh_with_identity_file(options): - if options.has_key("--inet6-only"): + if "--inet6-only" in options: force_ipvx = "-6 " - elif options.has_key("--inet4-only"): + elif "--inet4-only" in options: force_ipvx = "-4 " else: force_ipvx = "" command = '%s %s %s@%s -i %s -p %s' % \ (options["--ssh-path"], force_ipvx, options["--username"], options["--ip"], \ options["--identity-file"], options["--ipport"]) - if options.has_key("--ssh-options"): + if "--ssh-options" in options: command += ' ' + options["--ssh-options"] conn = fspawn(options, command) result = conn.log_expect(["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") result = conn.log_expect( ["Enter passphrase for key '" + options["--identity-file"]+"':"] + \ options["--command-prompt"], int(options["--login-timeout"])) if result == 0: - if options.has_key("--password"): + if "--password" in options: conn.sendline(options["--password"]) conn.log_expect(options["--command-prompt"], int(options["--login-timeout"])) else: fail_usage("Failed: You have to enter passphrase (-p) for identity file") return conn def _login_telnet(options, re_login_string): re_login = re.compile(re_login_string, re.IGNORECASE) re_pass = re.compile("(password)|(pass phrase)", re.IGNORECASE) conn = fspawn(options, options["--telnet-path"]) conn.send("set binary\n") conn.send("open %s -%s\n"%(options["--ip"], options["--ipport"])) conn.log_expect(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"]) conn.log_expect(re_pass, int(options["--login-timeout"])) elif re_pass.search(screen) == None: conn.log_expect(re_pass, int(options["--shell-timeout"])) try: conn.send_eol(options["--password"]) valid_password = conn.log_expect([re_login] + \ 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("") screen = conn.read_nonblocking(size=100, timeout=int(options["--shell-timeout"])) ## after sending EOL the fence device can either show 'Login' or 'Password' if re_login.search(conn.after + screen) != None: conn.send_eol("") conn.send_eol(options["--username"]) conn.log_expect(re_pass, int(options["--login-timeout"])) conn.send_eol(options["--password"]) conn.log_expect(options["--command-prompt"], int(options["--login-timeout"])) except KeyError: fail(EC_PASSWORD_MISSING) return conn def _login_ssh_with_password(options, re_login_string): re_login = re.compile(re_login_string, re.IGNORECASE) re_pass = re.compile("(password)|(pass phrase)", re.IGNORECASE) - if options.has_key("--inet6-only"): + if "--inet6-only" in options: force_ipvx = "-6 " - elif options.has_key("--inet4-only"): + elif "--inet4-only" in options: force_ipvx = "-4 " else: force_ipvx = "" command = '%s %s %s@%s -p %s -o PubkeyAuthentication=no' % \ (options["--ssh-path"], force_ipvx, options["--username"], options["--ip"], options["--ipport"]) - if options.has_key("--ssh-options"): + if "--ssh-options" in options: command += ' ' + options["--ssh-options"] conn = fspawn(options, command) - if options.has_key("telnet_over_ssh"): + if "telnet_over_ssh" in options: # This is for stupid ssh servers (like ALOM) which behave more like telnet # (ignore name and display login prompt) result = conn.log_expect( \ [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(re_login, int(options["--login-timeout"])) conn.sendline(options["--username"]) conn.log_expect(re_pass, int(options["--login-timeout"])) else: result = conn.log_expect( \ ["ssword:", "Are you sure you want to continue connecting (yes/no)?"], int(options["--login-timeout"])) if result == 1: conn.sendline("yes") conn.log_expect("ssword:", int(options["--login-timeout"])) conn.sendline(options["--password"]) conn.log_expect(options["--command-prompt"], int(options["--login-timeout"])) return conn # # To update metadata, we change values in all_opt def _update_metadata(options): device_opt = options["device_opt"] if device_opt.count("login") and device_opt.count("no_login") == 0: all_opt["login"]["required"] = "1" else: all_opt["login"]["required"] = "0" if device_opt.count("port_as_ip"): all_opt["ipaddr"]["required"] = "0" all_opt["port"]["required"] = "0" (available_actions, default_value) = _get_available_actions(device_opt) all_opt["action"]["default"] = default_value actions_with_default = \ [x if not x == all_opt["action"]["default"] else x + " (default)" for x in available_actions] all_opt["action"]["help"] = \ "-o, --action=[action] Action: %s" % (_join_wrap(actions_with_default, last_separator=" or ")) if device_opt.count("ipport"): default_value = None default_string = None - if all_opt["ipport"].has_key("default"): + if "default" in all_opt["ipport"]: default_value = all_opt["ipport"]["default"] elif device_opt.count("web") and device_opt.count("ssl"): default_value = "80" default_string = "(default 80, 443 if --ssl option is used)" elif device_opt.count("telnet") and device_opt.count("secure"): default_value = "23" default_string = "(default 23, 22 if --ssh option is used)" else: tcp_ports = {"community" : "161", "secure" : "22", "telnet" : "23", "web" : "80", "ssl" : "443"} # all cases where next command returns multiple results are covered by previous blocks protocol = [x for x in ["community", "secure", "ssl", "web", "telnet"] if device_opt.count(x)][0] default_value = tcp_ports[protocol] if default_string is None: all_opt["ipport"]["help"] = "-u, --ipport=[port] TCP/UDP port to use (default %s)" % \ (default_value) else: all_opt["ipport"]["help"] = "-u, --ipport=[port] TCP/UDP port to use\n" + " "*40 + default_string def _set_default_values(options): if "ipport" in options["device_opt"]: if not "--ipport" in options: if "default" in all_opt["ipport"]: options["--ipport"] = all_opt["ipport"]["default"] elif "community" in options["device_opt"]: options["--ipport"] = "161" elif "--ssh" in options or all_opt["secure"].get("default", "0") == "1": options["--ipport"] = "22" elif "--ssl" in options or all_opt["ssl"].get("default", "0") == "1": options["--ipport"] = "443" elif "--ssl-secure" in options or all_opt["ssl_secure"].get("default", "0") == "1": options["--ipport"] = "443" elif "--ssl-insecure" in options or all_opt["ssl_insecure"].get("default", "0") == "1": options["--ipport"] = "443" elif "web" in options["device_opt"]: options["--ipport"] = "80" elif "telnet" in options["device_opt"]: options["--ipport"] = "23" if "--ipport" in options: all_opt["ipport"]["default"] = options["--ipport"] for opt in options["device_opt"]: - if all_opt[opt].has_key("default") and not opt == "ipport": + if "default" in all_opt[opt] and not opt == "ipport": getopt_long = "--" + all_opt[opt]["longopt"] - if not options.has_key(getopt_long): + if getopt_long not in options: options[getopt_long] = all_opt[opt]["default"] return options # stop = True/False : exit fence agent when problem is encountered def _validate_input(options, stop = True): device_opt = options["device_opt"] valid_input = True - if not options.has_key("--username") and \ + if "--username" not in options and \ device_opt.count("login") and (device_opt.count("no_login") == 0): valid_input = False fail_usage("Failed: You have to set login name", stop) - if device_opt.count("ipaddr") and not options.has_key("--ip") and not options.has_key("--managed"): + if device_opt.count("ipaddr") and "--ip" not in options and "--managed" not in options: valid_input = False fail_usage("Failed: You have to enter fence address", stop) if device_opt.count("no_password") == 0: if 0 == device_opt.count("identity_file"): - if not (options.has_key("--password") or options.has_key("--password-script")): + if not ("--password" in options or "--password-script" in options): valid_input = False fail_usage("Failed: You have to enter password or password script", stop) else: - if not (options.has_key("--password") or \ - options.has_key("--password-script") or options.has_key("--identity-file")): + if not ("--password" in options or \ + "--password-script" in options or "--identity-file" in options): valid_input = False fail_usage("Failed: You have to enter password, password script or identity file", stop) - if not options.has_key("--ssh") and options.has_key("--identity-file"): + if "--ssh" not in options and "--identity-file" in options: valid_input = False fail_usage("Failed: You have to use identity file together with ssh connection (-x)", stop) - if options.has_key("--identity-file") and not os.path.isfile(options["--identity-file"]): + if "--identity-file" in options and not os.path.isfile(options["--identity-file"]): valid_input = False fail_usage("Failed: Identity file " + options["--identity-file"] + " does not exist", stop) if (0 == ["list", "list-status", "monitor"].count(options["--action"])) and \ - not options.has_key("--plug") and device_opt.count("port") and \ + "--plug" not in options and device_opt.count("port") and \ device_opt.count("no_port") == 0 and not device_opt.count("port_as_ip"): valid_input = False fail_usage("Failed: You have to enter plug number or machine identification", stop) - if options.has_key("--plug") and len(options["--plug"].split(",")) > 1 and \ - options.has_key("--method") and options["--method"] == "cycle": + if "--plug" in options and len(options["--plug"].split(",")) > 1 and \ + "--method" in options and options["--method"] == "cycle": valid_input = False fail_usage("Failed: Cannot use --method cycle for more than 1 plug", stop) for failed_opt in _get_opts_with_invalid_choices(options): valid_input = False fail_usage("Failed: You have to enter a valid choice for %s from the valid values: %s" % \ ("--" + all_opt[failed_opt]["longopt"], str(all_opt[failed_opt]["choices"])), stop) return valid_input def _encode_html_entities(text): return text.replace("&", "&").replace('"', """).replace('<', "<"). \ replace('>', ">").replace("'", "'") def _prepare_getopt_args(options): getopt_string = "" longopt_list = [] for k in options: - if all_opt.has_key(k) and all_opt[k]["getopt"] != ":": + if k in all_opt and all_opt[k]["getopt"] != ":": # getopt == ":" means that opt is without short getopt, but has value getopt_string += all_opt[k]["getopt"] - elif not all_opt.has_key(k): + elif k not in all_opt: fail_usage("Parse error: unknown option '"+k+"'") - if all_opt.has_key(k) and all_opt[k].has_key("longopt"): + if k in all_opt and "longopt" in all_opt[k]: if all_opt[k]["getopt"].endswith(":"): longopt_list.append(all_opt[k]["longopt"] + "=") else: longopt_list.append(all_opt[k]["longopt"]) return (getopt_string, longopt_list) def _parse_input_stdin(avail_opt): 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 and name in ["nodename"]: continue elif avail_opt.count(name) == 0: logging.warning("Parse error: Ignoring unknown option '%s'\n", 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" else: logging.warning("Parse error: Ignoring option '%s' because it does not have value\n", name) return opt def _parse_input_cmdline(avail_opt): filtered_opts = {} _verify_unique_getopt(avail_opt) (getopt_string, longopt_list) = _prepare_getopt_args(avail_opt) try: (entered_opt, left_arg) = getopt.gnu_getopt(sys.argv[1:], getopt_string, longopt_list) if len(left_arg) > 0: logging.warning("Unused arguments on command line: %s" % (str(left_arg))) - except getopt.GetoptError, error: + except getopt.GetoptError as error: fail_usage("Parse error: " + error.msg) for opt in avail_opt: filtered_opts.update({opt : all_opt[opt]}) # Short and long getopt names are changed to consistent "--" + long name (e.g. --username) long_opts = {} - for arg_name in dict(entered_opt).keys(): - all_key = [key for (key, value) in filtered_opts.items() \ + for arg_name in list(dict(entered_opt).keys()): + all_key = [key for (key, value) in list(filtered_opts.items()) \ if "--" + value.get("longopt", "") == arg_name or "-" + value.get("getopt", "").rstrip(":") == arg_name][0] long_opts["--" + filtered_opts[all_key]["longopt"]] = dict(entered_opt)[arg_name] # This test is specific because it does not apply to input on stdin if "port_as_ip" in avail_opt and not "--port-as-ip" in long_opts and "--plug" in long_opts: fail_usage("Parser error: option -n/--plug is not recognized") return long_opts # for ["John", "Mary", "Eli"] returns "John, Mary and Eli" def _join2(words, normal_separator=", ", last_separator=" and "): if len(words) <= 1: return "".join(words) else: return last_separator.join([normal_separator.join(words[:-1]), words[-1]]) def _join_wrap(words, normal_separator=", ", last_separator=" and ", first_indent=42): x = _join2(words, normal_separator, last_separator) wrapper = textwrap.TextWrapper() wrapper.initial_indent = " "*first_indent wrapper.subsequent_indent = " "*40 wrapper.width = 85 wrapper.break_on_hyphens = False wrapper.break_long_words = False wrapped_text = "" for line in wrapper.wrap(x): wrapped_text += line + "\n" return wrapped_text.lstrip().rstrip("\n") def _get_opts_with_invalid_choices(options): options_failed = [] device_opt = options["device_opt"] for opt in device_opt: - if all_opt[opt].has_key("choices"): + if "choices" in all_opt[opt]: longopt = "--" + all_opt[opt]["longopt"] possible_values_upper = [y.upper() for y in all_opt[opt]["choices"]] - if options.has_key(longopt): + if longopt in options: options[longopt] = options[longopt].upper() if not options["--" + all_opt[opt]["longopt"]] in possible_values_upper: options_failed.append(opt) return options_failed def _verify_unique_getopt(avail_opt): used_getopt = set() for opt in avail_opt: getopt_value = all_opt[opt].get("getopt", "").rstrip(":") if getopt_value and getopt_value in used_getopt: fail_usage("Short getopt for %s (-%s) is not unique" % (opt, getopt_value)) else: used_getopt.add(getopt_value) def _get_available_actions(device_opt): available_actions = ["on", "off", "reboot", "status", "list", "list-status", \ "monitor", "metadata", "validate-all"] default_value = "reboot" if device_opt.count("fabric_fencing"): available_actions.remove("reboot") default_value = "off" if device_opt.count("no_status"): available_actions.remove("status") if device_opt.count("no_on"): available_actions.remove("on") if device_opt.count("no_off"): available_actions.remove("off") if not device_opt.count("separator"): available_actions.remove("list") available_actions.remove("list-status") if device_opt.count("diag"): available_actions.append("diag") return (available_actions, default_value) diff --git a/fence/agents/lib/fencing_snmp.py.py b/fence/agents/lib/fencing_snmp.py.py index 88700c42..9aaf52be 100644 --- a/fence/agents/lib/fencing_snmp.py.py +++ b/fence/agents/lib/fencing_snmp.py.py @@ -1,134 +1,134 @@ -#!/usr/bin/python -tt +#!@PYTHON@ -tt # For example of use please see fence_cisco_mds import re, pexpect import logging from fencing import * from fencing import fail, fail_usage, EC_TIMED_OUT, run_delay __all__ = ['FencingSnmp'] ## do not add code here. #BEGIN_VERSION_GENERATION RELEASE_VERSION = "" REDHAT_COPYRIGHT = "" BUILD_DATE = "" #END_VERSION_GENERATION class FencingSnmp: def __init__(self, options): self.options = options run_delay(options) def quote_for_run(self, string): return string.replace(r"'", "'\\''") def complete_missed_params(self): mapping = [[ ['snmp-priv-passwd', 'password', '!snmp-sec-level'], 'self.options["--snmp-sec-level"]="authPriv"' ], [ ['!snmp-version', 'community', '!username', '!snmp-priv-passwd', '!password'], 'self.options["--snmp-version"]="2c"' ]] for val in mapping: e = val[0] res = True for item in e: - if item[0] == '!' and self.options.has_key("--" + item[1:]): + if item[0] == '!' and "--" + item[1:] in self.options: res = False break - if item[0] != '!' and not self.options.has_key("--" + item[0:]): + if item[0] != '!' and "--" + item[0:] not in self.options: res = False break if res: exec(val[1]) def prepare_cmd(self, command): cmd = "%s -m '' -Oeqn "% (command) self.complete_missed_params() #mapping from our option to snmpcmd option mapping = (('snmp-version', 'v'), ('community', 'c')) for item in mapping: - if self.options.has_key("--" + item[0]): + if "--" + item[0] in self.options: cmd += " -%s '%s'"% (item[1], self.quote_for_run(self.options["--" + item[0]])) # Some options make sense only for v3 (and for v1/2c can cause "problems") - if (self.options.has_key("--snmp-version")) and (self.options["--snmp-version"] == "3"): + if ("--snmp-version" in self.options) and (self.options["--snmp-version"] == "3"): # Mapping from our options to snmpcmd options for v3 mapping_v3 = (('snmp-auth-prot', 'a'), ('snmp-sec-level', 'l'), ('snmp-priv-prot', 'x'), \ ('snmp-priv-passwd', 'X'), ('password', 'A'), ('username', 'u')) for item in mapping_v3: - if self.options.has_key("--"+item[0]): + if "--"+item[0] in self.options: cmd += " -%s '%s'"% (item[1], self.quote_for_run(self.options["--" + item[0]])) force_ipvx = "" - if self.options.has_key("--inet6-only"): + if "--inet6-only" in self.options: force_ipvx = "udp6:" - if self.options.has_key("--inet4-only"): + if "--inet4-only" in self.options: force_ipvx = "udp:" cmd += " '%s%s%s'"% (force_ipvx, self.quote_for_run(self.options["--ip"]), - self.options.has_key("--ipport") and self.quote_for_run(":" + str(self.options["--ipport"])) or "") + "--ipport" in self.options and self.quote_for_run(":" + str(self.options["--ipport"])) or "") return cmd def run_command(self, command, additional_timemout=0): try: logging.debug("%s\n", command) (res_output, res_code) = pexpect.run(command, int(self.options["--shell-timeout"]) + int(self.options["--login-timeout"]) + additional_timemout, True) if res_code == None: fail(EC_TIMED_OUT) logging.debug("%s\n", res_output) if (res_code != 0) or (re.search("^Error ", res_output, re.MULTILINE) != None): fail_usage("Returned %d: %s"% (res_code, res_output)) except pexpect.ExceptionPexpect: fail_usage("Cannot run command %s"%(command)) return res_output def get(self, oid, additional_timemout=0): cmd = "%s '%s'"% (self.prepare_cmd(self.options["--snmpget-path"]), self.quote_for_run(oid)) output = self.run_command(cmd, additional_timemout).splitlines() return output[len(output)-1].split(None, 1) def set(self, oid, value, additional_timemout=0): mapping = ((int, 'i'), (str, 's')) type_of_value = '' for item in mapping: if isinstance(value, item[0]): type_of_value = item[1] break cmd = "%s '%s' %s '%s'" % (self.prepare_cmd(self.options["--snmpset-path"]), self.quote_for_run(oid), type_of_value, self.quote_for_run(str(value))) self.run_command(cmd, additional_timemout) def walk(self, oid, additional_timemout=0): cmd = "%s '%s'"% (self.prepare_cmd(self.options["--snmpwalk-path"]), self.quote_for_run(oid)) output = self.run_command(cmd, additional_timemout).splitlines() return [x.split(None, 1) for x in output if x.startswith(".")] diff --git a/fence/agents/lib/tests/test_fencing.py b/fence/agents/lib/tests/test_fencing.py index f8e421d8..6ee93858 100644 --- a/fence/agents/lib/tests/test_fencing.py +++ b/fence/agents/lib/tests/test_fencing.py @@ -1,123 +1,123 @@ #!/usr/bin/python import unittest import sys sys.path.append("..") import fencing import copy class Test_join2(unittest.TestCase): def test_single(self): words = ["Mike"] self.assertEqual(fencing._join2(words), "Mike") self.assertEqual(fencing._join2(words, last_separator=" xor "), "Mike") self.assertEqual(fencing._join2(words, normal_separator=" xor "), "Mike") def test_double(self): words = ["Mike", "John"] self.assertEqual(fencing._join2(words), "Mike and John") self.assertEqual(fencing._join2(words, last_separator=" xor "), "Mike xor John") self.assertEqual(fencing._join2(words, normal_separator=" xor "), "Mike and John") def test_triple(self): words = ["Mike", "John", "Adam"] self.assertEqual(fencing._join2(words), "Mike, John and Adam") self.assertEqual(fencing._join2(words, last_separator=" xor "), "Mike, John xor Adam") self.assertEqual(fencing._join2(words, normal_separator=" xor "), "Mike xor John and Adam") def test_quadruple(self): words = ["Eve", "Mike", "John", "Adam"] self.assertEqual(fencing._join2(words), "Eve, Mike, John and Adam") self.assertEqual(fencing._join2(words, last_separator=" xor "), "Eve, Mike, John xor Adam") self.assertEqual(fencing._join2(words, normal_separator=" xor "), "Eve xor Mike xor John and Adam") class Test_add_dependency_options(unittest.TestCase): basic_set = fencing.DEPENDENCY_OPT["default"] def test_add_nothing(self): self.assertEqual(set(fencing._add_dependency_options([])), set(self.basic_set)) self.assertEqual(set(fencing._add_dependency_options(["not-exist"])), set(self.basic_set)) def test_add_single(self): self.assertEqual(set(fencing._add_dependency_options(["passwd"])), set(self.basic_set + ["passwd_script"])) def test_add_tuple(self): self.assertEqual(set(fencing._add_dependency_options(["ssl", "passwd"])), \ set(self.basic_set + ["passwd_script", "ssl_secure", "ssl_insecure", "gnutlscli_path"])) class Test_set_default_values(unittest.TestCase): original_all_opt = None def setUp(self): # all_opt[*]["default"] can be changed during tests self.original_all_opt = copy.deepcopy(fencing.all_opt) def tearDown(self): fencing.all_opt = copy.deepcopy(self.original_all_opt) def _prepare_options(self, device_opts, args = {}): device_opts = fencing._add_dependency_options(device_opts) + device_opts arg_opts = args options = dict(arg_opts) options["device_opt"] = device_opts fencing._update_metadata(options) return fencing._set_default_values(options) def test_status_io(self): options = self._prepare_options([]) - self.assertEquals(options["--action"], "reboot") + self.assertEqual(options["--action"], "reboot") self.assertIsNone(options.get("--not-exist", None)) def test_status_fabric(self): options = self._prepare_options(["fabric_fencing"]) - self.assertEquals(options["--action"], "off") + self.assertEqual(options["--action"], "off") def test_ipport_nothing(self): # should fail because connection method (telnet/ssh/...) is not set at all self.assertRaises(IndexError, self._prepare_options, ["ipaddr"]) def test_ipport_set(self): options = self._prepare_options(["ipaddr", "telnet"], {"--ipport" : "999"}) - self.assertEquals(options["--ipport"], "999") + self.assertEqual(options["--ipport"], "999") def test_ipport_telnet(self): options = self._prepare_options(["ipaddr", "telnet"]) - self.assertEquals(options["--ipport"], "23") + self.assertEqual(options["--ipport"], "23") def test_ipport_ssh(self): options = self._prepare_options(["ipaddr", "secure"], {"--ssh" : "1"}) - self.assertEquals(options["--ipport"], "22") + self.assertEqual(options["--ipport"], "22") def test_ipport_sshtelnet_use_telnet(self): options = self._prepare_options(["ipaddr", "secure", "telnet"]) - self.assertEquals(options["--ipport"], "23") + self.assertEqual(options["--ipport"], "23") def test_ipport_sshtelnet_use_ssh(self): options = self._prepare_options(["ipaddr", "secure", "telnet"], {"--ssh" : "1"}) - self.assertEquals(options["--ipport"], "22") + self.assertEqual(options["--ipport"], "22") def test_ipport_ssl(self): options = self._prepare_options(["ipaddr", "ssl"], {"--ssl-secure" : "1"}) - self.assertEquals(options["--ipport"], "443") + self.assertEqual(options["--ipport"], "443") def test_ipport_ssl_insecure_as_default(self): fencing.all_opt["ssl_insecure"]["default"] = "1" options = self._prepare_options(["ipaddr", "ssl"]) - self.assertEquals(options["--ipport"], "443") + self.assertEqual(options["--ipport"], "443") def test_ipport_snmp(self): options = self._prepare_options(["ipaddr", "community"]) - self.assertEquals(options["--ipport"], "161") + self.assertEqual(options["--ipport"], "161") def test_ipport_web(self): options = self._prepare_options(["ipaddr", "web", "ssl"]) - self.assertEquals(options["--ipport"], "80") + self.assertEqual(options["--ipport"], "80") def test_path_telnet(self): options = self._prepare_options(["ipaddr", "telnet"]) self.assertTrue("--telnet-path" in options) if __name__ == '__main__': unittest.main() diff --git a/fence/agents/lpar/fence_lpar.py b/fence/agents/lpar/fence_lpar.py index 6676e1c6..26111ce9 100644 --- a/fence/agents/lpar/fence_lpar.py +++ b/fence/agents/lpar/fence_lpar.py @@ -1,159 +1,159 @@ -#!/usr/bin/python -tt +#!@PYTHON@ -tt ##### ## ## The Following Agent Has Been Tested On: ## ## Version ## +---------------------------------------------+ ## Tested on HMC ## ##### import sys, re import atexit sys.path.append("@FENCEAGENTSLIBDIR@") from fencing import * from fencing import fail, fail_usage, EC_STATUS_HMC #BEGIN_VERSION_GENERATION RELEASE_VERSION="" REDHAT_COPYRIGHT="" BUILD_DATE="" #END_VERSION_GENERATION def get_power_status(conn, options): if options["--hmc-version"] == "3": conn.send("lssyscfg -r lpar -m " + options["--managed"] + " -n " + options["--plug"] + " -F name,state\n") conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) try: status = re.compile("^" + options["--plug"] + ",(.*?),.*$", re.IGNORECASE | re.MULTILINE).search(conn.before).group(1) except AttributeError: fail(EC_STATUS_HMC) elif options["--hmc-version"] == "4": conn.send("lssyscfg -r lpar -m "+ options["--managed"] + " --filter 'lpar_names=" + options["--plug"] + "'\n") conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) try: status = re.compile(",state=(.*?),", re.IGNORECASE).search(conn.before).group(1) except AttributeError: fail(EC_STATUS_HMC) ## ## Transformation to standard ON/OFF status if possible if status in ["Running", "Open Firmware", "Shutting Down", "Starting"]: status = "on" else: status = "off" return status def set_power_status(conn, options): if options["--hmc-version"] == "3": conn.send("chsysstate -o " + options["--action"] + " -r lpar -m " + options["--managed"] + " -n " + options["--plug"] + "\n") conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) elif options["--hmc-version"] == "4": if options["--action"] == "on": conn.send("chsysstate -o on -r lpar -m " + options["--managed"] + " -n " + options["--plug"] + " -f `lssyscfg -r lpar -F curr_profile " + " -m " + options["--managed"] + " --filter \"lpar_names=" + options["--plug"] + "\"`\n") else: conn.send("chsysstate -o shutdown -r lpar --immed" + " -m " + options["--managed"] + " -n " + options["--plug"] + "\n") conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) def get_lpar_list(conn, options): outlets = {} if options["--hmc-version"] == "3": conn.send("query_partition_names -m " + options["--managed"] + "\n") conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) ## We have to remove first 3 lines (command + header) and last line (part of new prompt) #### res = re.search("^.+?\n(.+?\n){2}(.*)\n.*$", conn.before, re.S) if res == None: fail_usage("Unable to parse output of list command") lines = res.group(2).split("\n") for outlet_line in lines: outlets[outlet_line.rstrip()] = ("", "") elif options["--hmc-version"] == "4": conn.send("lssyscfg -r lpar -m " + options["--managed"] + " -F name:state\n") conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) ## We have to remove first line (command) and last line (part of new prompt) #### res = re.search("^.+?\n(.*)\n.*$", conn.before, re.S) if res == None: fail_usage("Unable to parse output of list command") lines = res.group(1).split("\n") for outlet_line in lines: (port, status) = outlet_line.split(":") outlets[port] = ("", status) return outlets def define_new_opts(): all_opt["managed"] = { "getopt" : "s:", "longopt" : "managed", "help" : "-s, --managed=[id] Name of the managed system", "required" : "0", "shortdesc" : "Managed system name", "order" : 1} all_opt["hmc_version"] = { "getopt" : "H:", "longopt" : "hmc-version", "help" : "-H, --hmc-version=[version] Force HMC version to use: (3|4) (default: 4)", "required" : "0", "shortdesc" : "Force HMC version to use", "default" : "4", "choices" : ["3", "4"], "order" : 1} def main(): device_opt = ["ipaddr", "login", "passwd", "secure", "cmd_prompt", \ "port", "managed", "hmc_version"] atexit.register(atexit_handler) define_new_opts() all_opt["login_timeout"]["default"] = "15" all_opt["secure"]["default"] = "1" all_opt["cmd_prompt"]["default"] = [r":~>", r"]\$", r"\$ "] options = check_input(device_opt, process_input(device_opt), other_conditions = True) docs = {} docs["shortdesc"] = "Fence agent for IBM LPAR" docs["longdesc"] = "" docs["vendorurl"] = "http://www.ibm.com" show_docs(options, docs) - if not options.has_key("--managed"): + if "--managed" not in options: fail_usage("Failed: You have to enter name of managed system") if options["--action"] == "validate-all": sys.exit(0) ## ## Operate the fencing device #### conn = fence_login(options) result = fence_action(conn, options, set_power_status, get_power_status, get_lpar_list) fence_logout(conn, "quit\r\n") sys.exit(result) if __name__ == "__main__": main() diff --git a/fence/agents/mpath/fence_mpath.py b/fence/agents/mpath/fence_mpath.py index f990d7eb..65648f92 100644 --- a/fence/agents/mpath/fence_mpath.py +++ b/fence/agents/mpath/fence_mpath.py @@ -1,251 +1,251 @@ -#!/usr/bin/python -tt +#!@PYTHON@ -tt import sys import stat import re import os import logging import atexit sys.path.append("@FENCEAGENTSLIBDIR@") from fencing import fail_usage, run_command, atexit_handler, check_input, process_input, show_docs from fencing import fence_action, all_opt, run_delay #BEGIN_VERSION_GENERATION RELEASE_VERSION="" REDHAT_COPYRIGHT="" BUILD_DATE="" #END_VERSION_GENERATION def get_status(conn, options): del conn status = "off" for dev in options["devices"]: is_block_device(dev) if options["--key"] in get_registration_keys(options, dev): status = "on" else: logging.debug("No registration for key "\ + options["--key"] + " on device " + dev + "\n") if options["--action"] == "monitor": dev_read(options) return status def set_status(conn, options): del conn count = 0 if options["--action"] == "on": for dev in options["devices"]: is_block_device(dev) register_dev(options, dev) if options["--key"] not in get_registration_keys(options, dev): count += 1 logging.debug("Failed to register key "\ + options["--key"] + "on device " + dev + "\n") continue dev_write(options, dev) if get_reservation_key(options, dev) is None \ and not reserve_dev(options, dev) \ and get_reservation_key(options, dev) is None: count += 1 logging.debug("Failed to create reservation (key="\ + options["--key"] + ", device=" + dev + ")\n") else: dev_keys = dev_read(options) for dev in options["devices"]: is_block_device(dev) if options["--key"] in get_registration_keys(options, dev): preempt_abort(options, dev_keys[dev], dev) for dev in options["devices"]: if options["--key"] in get_registration_keys(options, dev): count += 1 logging.debug("Failed to remove key "\ + options["--key"] + " on device " + dev + "\n") continue if not get_reservation_key(options, dev): count += 1 logging.debug("No reservation exists on device " + dev + "\n") if count: logging.error("Failed to verify " + str(count) + " device(s)") sys.exit(1) #run command, returns dict, ret["err"] = exit code; ret["out"] = output def run_cmd(options, cmd): ret = {} - if options.has_key("--use-sudo"): + if "--use-sudo" in options: prefix = options["--sudo-path"] + " " else: prefix = "" (ret["err"], ret["out"], _) = run_command(options, prefix + cmd) ret["out"] = "".join([i for i in ret["out"] if i is not None]) 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_abort(options, host, dev): cmd = options["--mpathpersist-path"] + " -o --preempt-abort --prout-type=5 --param-rk=" + host +" --param-sark=" + options["--key"] +"-d " + dev return not bool(run_cmd(options, cmd)["err"]) def register_dev(options, dev): cmd = options["--mpathpersist-path"] + " -o --register --param-sark=" + options["--key"] + " -d " + dev #cmd return code != 0 but registration can be successful return not bool(run_cmd(options, cmd)["err"]) def reserve_dev(options, dev): cmd = options["--mpathpersist-path"] + " -o --reserv --prout-type=5 --param-rk=" + options["--key"] + " -d " + dev return not bool(run_cmd(options, cmd)["err"]) def get_reservation_key(options, dev): cmd = options["--mpathpersist-path"] + " -i -r -d " + dev out = run_cmd(options, cmd) if out["err"]: fail_usage("Cannot get reservation key") match = re.search(r"\s+key\s*=\s*0x(\S+)\s+", out["out"], re.IGNORECASE) return match.group(1) if match else None def get_registration_keys(options, dev): keys = [] cmd = options["--mpathpersist-path"] + " -i -k -d " + dev out = run_cmd(options, cmd) if out["err"]: fail_usage("Cannot get registration keys") for line in out["out"].split("\n"): match = re.search(r"\s+0x(\S+)\s*", line) if match: keys.append(match.group(1)) return keys def dev_write(options, dev): file_path = options["--store-path"] + "/mpath.devices" if not os.path.isdir(options["--store-path"]): os.makedirs(options["--store-path"]) try: store_fh = open(file_path, "a+") except IOError: fail_usage("Failed: Cannot open file \""+ file_path + "\"") out = store_fh.read() if not re.search(r"^" + dev + r"\s+", out): store_fh.write(dev + "\t" + options["--key"] + "\n") store_fh.close() def dev_read(options): dev_key = {} file_path = options["--store-path"] + "/mpath.devices" try: store_fh = open(file_path, "r") except IOError: fail_usage("Failed: Cannot open file \"" + file_path + "\"") # get not empty lines from file for (device, key) in [line.strip().split() for line in store_fh if line.strip()]: dev_key[device] = key store_fh.close() return dev_key def define_new_opts(): all_opt["devices"] = { "getopt" : "d:", "longopt" : "devices", "help" : "-d, --devices=[devices] List of devices to use for current operation", "required" : "1", "shortdesc" : "List of devices to use for current operation. Devices can \ be comma-separated list of device-mapper multipath devices (eg. /dev/dm-3). \ Each device must support SCSI-3 persistent reservations.", "order": 1 } all_opt["key"] = { "getopt" : "k:", "longopt" : "key", "help" : "-k, --key=[key] Key to use for the current operation", "required" : "1", "shortdesc" : "Key to use for the current operation. This key should be \ unique to a node and have to be written in /etc/multipath.conf. For the \"on\" action, the key specifies the key use to \ register the local node. For the \"off\" action, this key specifies the key to \ be removed from the device(s).", "order": 1 } all_opt["mpathpersist_path"] = { "getopt" : ":", "longopt" : "mpathpersist-path", "help" : "--mpathpersist-path=[path] Path to mpathpersist binary", "required" : "0", "shortdesc" : "Path to mpathpersist binary", "default" : "@MPATH_PATH@", "order": 200 } all_opt["store_path"] = { "getopt" : ":", "longopt" : "store-path", "help" : "--store-path=[path] Path to directory containing cached keys", "required" : "0", "shortdesc" : "Path to directory where fence agent can store information", "default" : "@STORE_PATH@", "order": 200 } def main(): atexit.register(atexit_handler) device_opt = ["no_login", "no_password", "devices", "key", "sudo", \ "fabric_fencing", "on_target", "store_path", "mpathpersist_path", "force_on"] define_new_opts() options = check_input(device_opt, process_input(device_opt), other_conditions=True) docs = {} docs["shortdesc"] = "Fence agent for multipath persistent reservation" docs["longdesc"] = "fence_mpath is an I/O fencing agent that uses SCSI-3 \ persistent reservations to control access multipath devices. Underlying \ devices must support SCSI-3 persistent reservations (SPC-3 or greater) as \ well as the \"preempt-and-abort\" subcommand.\nThe fence_mpath agent works by \ having an unique key for each pair of node and device that has to be set also \ in /etc/multipath.conf. 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_mpath 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." docs["vendorurl"] = "https://www.sourceware.org/dm/" show_docs(options, docs) run_delay(options) # Input control BEGIN if not "--key" in options: fail_usage("Failed: key is required") if options["--action"] == "validate-all": sys.exit(0) options["devices"] = options["--devices"].split(",") if not options["devices"]: fail_usage("Failed: No devices found") # Input control END result = fence_action(None, options, set_status, get_status) sys.exit(result) if __name__ == "__main__": main() diff --git a/fence/agents/netio/fence_netio.py b/fence/agents/netio/fence_netio.py index 7b67e150..6dc6a1ad 100755 --- a/fence/agents/netio/fence_netio.py +++ b/fence/agents/netio/fence_netio.py @@ -1,100 +1,100 @@ -#!/usr/bin/python -tt +#!@PYTHON@ -tt import sys, re, pexpect import atexit sys.path.append("@FENCEAGENTSLIBDIR@") from fencing import * from fencing import fspawn, fail, EC_LOGIN_DENIED, run_delay #BEGIN_VERSION_GENERATION RELEASE_VERSION="" REDHAT_COPYRIGHT="" BUILD_DATE="" #END_VERSION_GENERATION def get_power_status(conn, options): conn.send_eol("port %s" % options["--plug"]) re_status = re.compile("250 [01imt]") conn.log_expect(re_status, int(options["--shell-timeout"])) status = { "0" : "off", "1" : "on", "i" : "reboot", "m" : "manual", "t" : "timer" }[conn.after.split()[1]] return status def set_power_status(conn, options): action = { "on" : "1", "off" : "0", "reboot" : "i" }[options["--action"]] conn.send_eol("port %s %s" % (options["--plug"], action)) conn.log_expect("250 OK", int(options["--shell-timeout"])) def get_outlet_list(conn, options): result = {} try: # the NETIO-230B has 4 ports, counting start at 1 for plug in ["1", "2", "3", "4"]: conn.send_eol("port setup %s" % plug) conn.log_expect("250 .+", int(options["--shell-timeout"])) # the name is enclosed in "", drop those with [1:-1] name = conn.after.split()[1][1:-1] result[plug] = (name, "unknown") - except Exception, exn: - print str(exn) + except Exception as exn: + print(str(exn)) return result def main(): device_opt = ["ipaddr", "login", "passwd", "port", "telnet"] atexit.register(atexit_handler) all_opt["ipport"]["default"] = "1234" opt = process_input(device_opt) opt["eol"] = "\r\n" options = check_input(device_opt, opt) docs = {} docs["shortdesc"] = "I/O Fencing agent for Koukaam NETIO-230B" docs["longdesc"] = "fence_netio is an I/O Fencing agent which can be \ used with the Koukaam NETIO-230B Power Distribution Unit. It logs into \ device via telnet and reboots a specified outlet. Lengthy telnet connections \ should be avoided while a GFS cluster is running because the connection will \ block any necessary fencing actions." docs["vendorurl"] = "http://www.koukaam.se/" show_docs(options, docs) ## ## Operate the fencing device ## We can not use fence_login(), username and passwd are sent on one line #### run_delay(options) try: conn = fspawn(options, options["--telnet-path"]) conn.send("set binary\n") conn.send("open %s -%s\n"%(options["--ip"], options["--ipport"])) conn.read_nonblocking(size=100, timeout=int(options["--shell-timeout"])) conn.log_expect("100 HELLO .*", int(options["--shell-timeout"])) conn.send_eol("login %s %s" % (options["--username"], options["--password"])) conn.log_expect("250 OK", int(options["--shell-timeout"])) except pexpect.EOF: fail(EC_LOGIN_DENIED) except pexpect.TIMEOUT: fail(EC_LOGIN_DENIED) result = fence_action(conn, options, set_power_status, get_power_status, get_outlet_list) fence_logout(conn, "quit\n") sys.exit(result) if __name__ == "__main__": main() diff --git a/fence/agents/ovh/fence_ovh.py b/fence/agents/ovh/fence_ovh.py index de5333ca..f5403c54 100644 --- a/fence/agents/ovh/fence_ovh.py +++ b/fence/agents/ovh/fence_ovh.py @@ -1,163 +1,163 @@ -#!/usr/bin/python -tt +#!@PYTHON@ -tt # Copyright 2013 Adrian Gibanel Lopez (bTactic) # Adrian Gibanel improved this script at 2013 to add verification of success and to output metadata # Based on: # This is a fence agent for use at OVH # As there are no other fence devices available, we must use OVH's SOAP API #Quick-and-dirty # assemled by Dennis Busch, secofor GmbH, Germany # This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License. import sys, time import shutil, tempfile import logging import atexit from datetime import datetime from suds.client import Client from suds.xsd.doctor import ImportDoctor, Import sys.path.append("@FENCEAGENTSLIBDIR@") from fencing import * from fencing import fail, fail_usage, EC_LOGIN_DENIED, run_delay OVH_RESCUE_PRO_NETBOOT_ID = '28' OVH_HARD_DISK_NETBOOT_ID = '1' STATUS_HARD_DISK_SLEEP = 240 # Wait 4 minutes to SO to boot STATUS_RESCUE_PRO_SLEEP = 150 # Wait 2 minutes 30 seconds to Rescue-Pro to run def define_new_opts(): all_opt["email"] = { "getopt" : "Z:", "longopt" : "email", "help" : "-Z, --email=[email] email for reboot message: admin@domain.com", "required" : "1", "shortdesc" : "Reboot email", "order" : 1} def netboot_reboot(conn, options, mode): # dedicatedNetbootModifyById changes the mode of the next reboot conn.service.dedicatedNetbootModifyById(options["session"], options["--plug"], mode, '', options["--email"]) # dedicatedHardRebootDo initiates a hard reboot on the given node conn.service.dedicatedHardRebootDo(options["session"], options["--plug"], 'Fencing initiated by cluster', '', 'en') conn.logout(options["session"]) def reboot_time(conn, options): result = conn.service.dedicatedHardRebootStatus(options["session"], options["--plug"]) tmpstart = datetime.strptime(result.start, '%Y-%m-%d %H:%M:%S') tmpend = datetime.strptime(result.end, '%Y-%m-%d %H:%M:%S') result.start = tmpstart result.end = tmpend return result def soap_login(options): imp = Import('http://schemas.xmlsoap.org/soap/encoding/') url = 'https://www.ovh.com/soapi/soapi-re-1.59.wsdl' imp.filter.add('http://soapi.ovh.com/manager') d = ImportDoctor(imp) tmp_dir = tempfile.mkdtemp() tempfile.tempdir = tmp_dir atexit.register(remove_tmp_dir, tmp_dir) try: soap = Client(url, doctor=d) session = soap.service.login(options["--username"], options["--password"], 'en', 0) except Exception: fail(EC_LOGIN_DENIED) options["session"] = session return soap def remove_tmp_dir(tmp_dir): shutil.rmtree(tmp_dir) def main(): device_opt = ["login", "passwd", "port", "email", "no_status", "web"] atexit.register(atexit_handler) define_new_opts() options = check_input(device_opt, process_input(device_opt), other_conditions=True) docs = {} docs["shortdesc"] = "Fence agent for OVH" docs["longdesc"] = "fence_ovh is an Power Fencing agent \ which can be used within OVH datecentre. \ Poweroff is simulated with a reboot into rescue-pro mode." docs["vendorurl"] = "http://www.ovh.net" show_docs(options, docs) if options["--action"] == "list": fail_usage("Action 'list' is not supported in this fence agent") if options["--action"] == "list-status": fail_usage("Action 'list-status' is not supported in this fence agent") - if not options.has_key("--email"): + if "--email" not in options: fail_usage("You have to enter e-mail address which is notified by fence agent") if options["--action"] == "validate-all": sys.exit(0) if options["--action"] != "monitor" and not options["--plug"].endswith(".ovh.net"): options["--plug"] += ".ovh.net" run_delay(options) conn = soap_login(options) if options["--action"] == 'monitor': try: conn.service.logout(options["session"]) except Exception: pass sys.exit(0) # Save datetime just before changing netboot before_netboot_reboot = datetime.now() if options["--action"] == 'off': # Reboot in Rescue-pro netboot_reboot(conn, options, OVH_RESCUE_PRO_NETBOOT_ID) time.sleep(STATUS_RESCUE_PRO_SLEEP) elif options["--action"] in ['on', 'reboot']: # Reboot from HD netboot_reboot(conn, options, OVH_HARD_DISK_NETBOOT_ID) time.sleep(STATUS_HARD_DISK_SLEEP) # Save datetime just after reboot after_netboot_reboot = datetime.now() # Verify that action was completed sucesfully reboot_t = reboot_time(conn, options) logging.debug("reboot_start_end.start: %s\n", reboot_t.start.strftime('%Y-%m-%d %H:%M:%S')) logging.debug("before_netboot_reboot: %s\n", before_netboot_reboot.strftime('%Y-%m-%d %H:%M:%S')) logging.debug("reboot_start_end.end: %s\n", reboot_t.end.strftime('%Y-%m-%d %H:%M:%S')) logging.debug("after_netboot_reboot: %s\n", after_netboot_reboot.strftime('%Y-%m-%d %H:%M:%S')) if reboot_t.start < after_netboot_reboot < reboot_t.end: result = 0 logging.debug("Netboot reboot went OK.\n") else: result = 1 logging.debug("ERROR: Netboot reboot wasn't OK.\n") try: conn.service.logout(options["session"]) except Exception: pass sys.exit(result) if __name__ == "__main__": main() diff --git a/fence/agents/pve/fence_pve.py b/fence/agents/pve/fence_pve.py index 39d0e863..474cfa26 100755 --- a/fence/agents/pve/fence_pve.py +++ b/fence/agents/pve/fence_pve.py @@ -1,182 +1,184 @@ -#!/usr/bin/python -tt +#!@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 io 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 +if sys.version_info.major > 2: import urllib.parse as urllib +else: import urllib + #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 dict or "data" not in vms or type(vms["data"]) is not list: return None for vm in vms["data"]: outlets[vm["vmid"]] = [vm["name"], vm["status"]] return outlets def get_ticket(options): post = {'username': options["--username"], 'password': options["--password"]} result = send_cmd(options, "access/ticket", post=post) if type(result) is dict and "data" in result: if type(result["data"]) is dict and "ticket" in result["data"] and "CSRFPreventionToken" in result["data"]: return { "ticket" : str("PVEAuthCookie=" + result["data"]["ticket"] + "; " + \ "version=0; path=/; domain=" + options["--ip"] + \ "; port=" + str(options["--ipport"]) + "; path_spec=0; secure=1; " + \ "expires=7200; discard=0"), "CSRF_token" : str("CSRFPreventionToken: " + result["data"]["CSRFPreventionToken"]) } return None def send_cmd(options, cmd, post=None): url = options["url"] + cmd conn = pycurl.Curl() - output_buffer = StringIO.StringIO() + output_buffer = io.StringIO() if logging.getLogger().getEffectiveLevel() < logging.WARNING: conn.setopt(pycurl.VERBOSE, True) conn.setopt(pycurl.HTTPGET, 1) conn.setopt(pycurl.URL, str(url)) if "auth" in options and options["auth"] is not None: conn.setopt(pycurl.COOKIE, options["auth"]["ticket"]) conn.setopt(pycurl.HTTPHEADER, [options["auth"]["CSRF_token"]]) if post is not None: conn.setopt(pycurl.POSTFIELDS, urllib.urlencode(post)) conn.setopt(pycurl.WRITEFUNCTION, output_buffer.write) conn.setopt(pycurl.TIMEOUT, int(options["--shell-timeout"])) - if options.has_key("--ssl") or options.has_key("--ssl-secure"): + if "--ssl" in options or "--ssl-secure" in options: conn.setopt(pycurl.SSL_VERIFYPEER, 1) conn.setopt(pycurl.SSL_VERIFYHOST, 2) else: conn.setopt(pycurl.SSL_VERIFYPEER, 0) conn.setopt(pycurl.SSL_VERIFYHOST, 0) logging.debug("URL: " + url) try: conn.perform() result = output_buffer.getvalue() logging.debug("RESULT [" + str(conn.getinfo(pycurl.RESPONSE_CODE)) + \ "]: " + result) conn.close() return json.loads(result) except pycurl.error: logging.error("Connection failed") except: logging.error("Cannot parse json") return None def main(): atexit.register(atexit_handler) all_opt["node_name"] = { "getopt" : "N:", "longopt" : "nodename", "help" : "-N, --nodename " "Node on which machine is located", "required" : "0", "shortdesc" : "Node on which machine is located. " "(Optional, will be automatically determined)", "order": 2 } device_opt = ["ipaddr", "login", "passwd", "web", "port", "node_name"] all_opt["login"]["required"] = "0" all_opt["login"]["default"] = "root@pam" all_opt["ipport"]["default"] = "8006" all_opt["port"]["shortdesc"] = "Id of the virtual machine." all_opt["ipaddr"]["shortdesc"] = "IP Address or Hostname of a node " +\ "within the Proxmox cluster." options = check_input(device_opt, process_input(device_opt)) docs = {} docs["shortdesc"] = "Fencing agent for the Proxmox Virtual Environment" docs["longdesc"] = "The fence_pve agent can be used to fence virtual \ machines acting as nodes in a virtualized cluster." docs["vendorurl"] = "http://www.proxmox.com/" show_docs(options, docs) run_delay(options) if "--nodename" not in options or not options["--nodename"]: options["--nodename"] = None options["url"] = "https://" + options["--ip"] + ":" + str(options["--ipport"]) + "/api2/json/" options["auth"] = get_ticket(options) if options["auth"] is None: fail(EC_LOGIN_DENIED) result = fence_action(None, options, set_power_status, get_power_status, get_outlet_list) sys.exit(result) if __name__ == "__main__": main() diff --git a/fence/agents/raritan/fence_raritan.py b/fence/agents/raritan/fence_raritan.py index 502742e0..36f2beaa 100644 --- a/fence/agents/raritan/fence_raritan.py +++ b/fence/agents/raritan/fence_raritan.py @@ -1,90 +1,90 @@ -#!/usr/bin/python -tt +#!@PYTHON@ -tt import sys, re, pexpect import atexit sys.path.append("@FENCEAGENTSLIBDIR@") from fencing import * from fencing import fspawn, fail, EC_LOGIN_DENIED, run_delay #BEGIN_VERSION_GENERATION RELEASE_VERSION="" REDHAT_COPYRIGHT="" BUILD_DATE="" #END_VERSION_GENERATION # --plug should include path to the outlet # such as port 1: # /system1/outlet1 def get_power_status(conn, options): conn.send_eol("show -d properties=powerState %s" % options["--plug"]) re_status = re.compile(".*powerState is [12].*") conn.log_expect(re_status, int(options["--shell-timeout"])) status = { #"0" : "off", "1" : "on", "2" : "off", }[conn.after.split()[2]] return status def set_power_status(conn, options): action = { "on" : "on", "off" : "off", }[options["--action"]] conn.send_eol("set %s powerState=%s" % (options["--plug"], action)) def main(): device_opt = ["ipaddr", "login", "passwd", "port", "telnet"] atexit.register(atexit_handler) opt = process_input(device_opt) all_opt["ipport"]["default"] = "23" opt["eol"] = "\r\n" options = check_input(device_opt, opt) docs = {} docs["shortdesc"] = "I/O Fencing agent for Raritan Dominion PX" docs["longdesc"] = "fence_raritan is an I/O Fencing agent which can be \ used with the Raritan DPXS12-20 Power Distribution Unit. It logs into \ device via telnet and reboots a specified outlet. Lengthy telnet connections \ should be avoided while a GFS cluster is running because the connection will \ block any necessary fencing actions." docs["vendorurl"] = "http://www.raritan.com/" show_docs(options, docs) # add support also for delay before login which is very useful for 2-node clusters run_delay(options) ## ## Operate the fencing device ## We can not use fence_login(), username and passwd are sent on one line #### try: conn = fspawn(options, options["--telnet-path"]) conn.send("set binary\n") conn.send("open %s -%s\n"%(options["--ip"], options["--ipport"])) conn.read_nonblocking(size=100, timeout=int(options["--shell-timeout"])) conn.log_expect("Login.*", int(options["--shell-timeout"])) conn.send_eol("%s" % (options["--username"])) conn.log_expect("Password.*", int(options["--shell-timeout"])) conn.send_eol("%s" % (options["--password"])) conn.log_expect("clp.*", int(options["--shell-timeout"])) except pexpect.EOF: fail(EC_LOGIN_DENIED) except pexpect.TIMEOUT: fail(EC_LOGIN_DENIED) result = 0 if options["--action"] != "monitor": result = fence_action(conn, options, set_power_status, get_power_status) fence_logout(conn, "exit\n") sys.exit(result) if __name__ == "__main__": main() diff --git a/fence/agents/rcd_serial/fence_rcd_serial.py b/fence/agents/rcd_serial/fence_rcd_serial.py index 104efb9b..b1cbc5be 100644 --- a/fence/agents/rcd_serial/fence_rcd_serial.py +++ b/fence/agents/rcd_serial/fence_rcd_serial.py @@ -1,106 +1,106 @@ -#!/usr/bin/python -tt +#!@PYTHON@ -tt # Copyright 2015 Infoxchange, Danielle Madeley, Sam McLeod-Jones # Controls an RCD serial device # Ported from stonith/rcd_serial.c # The Following Agent Has Been Tested On: # CentOS Linux release 7.1.1503 # Resource example: # primitive stonith_node_1 ocf:rcd_serial_py params port="/dev/ttyS0" time=1000 hostlist=stonith_node_1 stonith-timeout=5s import sys import atexit import os import struct import logging import time from fcntl import ioctl from termios import TIOCMBIC, TIOCMBIS, TIOCM_RTS, TIOCM_DTR from time import sleep sys.path.append("@FENCEAGENTSLIBDIR@") from fencing import * #BEGIN_VERSION_GENERATION RELEASE_VERSION="rcd_serial (serial reset) fence agent" REDHAT_COPYRIGHT="" BUILD_DATE="22 Jul 2015" #END_VERSION_GENERATION class RCDSerial(object): """Control class for serial device""" def __init__(self, port='/dev/ttyS0'): self.fd = fd = os.open(port, os.O_RDONLY | os.O_NDELAY) logging.debug("Opened %s on fd %i", port, fd) ioctl(fd, TIOCMBIC, struct.pack('I', TIOCM_RTS | TIOCM_DTR)) def close(self): """Close the serial device""" logging.debug("Closing serial device") ret = os.close(self.fd) return ret def toggle_pin(self, pin=TIOCM_DTR, time=1000): """Toggle the pin high for the time specified""" logging.debug("Set pin high") ioctl(self.fd, TIOCMBIS, struct.pack('I', pin)) sleep(float(time) / 1000.) logging.debug("Set pin low") ioctl(self.fd, TIOCMBIC, struct.pack('I', pin)) def reboot_device(conn, options): conn.toggle_pin(time=options["--power-wait"]) return True def main(): device_opt = ["serial_port", "no_status", "no_password", "no_login", "method", "no_on", "no_off"] atexit.register(atexit_handler) all_opt["serial_port"] = { "getopt" : ":", "longopt" : "serial-port", "help":"--serial-port=[port] Port of the serial device (e.g. /dev/ttyS0)", "required" : "1", "shortdesc" : "Port of the serial device", "default" : "/dev/ttyS0", "order": 1 } all_opt["method"]["default"] = "cycle" all_opt["power_wait"]["default"] = "2" options = check_input(device_opt, process_input(device_opt)) docs = {} docs["shortdesc"] = "rcd_serial fence agent" docs["longdesc"] = "fence_rcd_serial operates a serial cable that toggles a \ reset of an opposing server using the reset switch on its motherboard. The \ cable itself is simple with no power, network or moving parts. An example of \ the cable is available here: https://smcleod.net/rcd-stonith/ and the circuit \ design is available in the fence-agents src as SVG" docs["vendorurl"] = "http://www.scl.co.uk/rcd_serial/" show_docs(options, docs) if options["--action"] in ["off", "reboot"]: time.sleep(int(options["--delay"])) ## Operate the fencing device conn = RCDSerial(port=options["--serial-port"]) result = fence_action(conn, options, None, None, reboot_cycle_fn=reboot_device) conn.close() sys.exit(result) if __name__ == "__main__": main() diff --git a/fence/agents/rhevm/fence_rhevm.py b/fence/agents/rhevm/fence_rhevm.py index 3926f3b3..ee005b73 100644 --- a/fence/agents/rhevm/fence_rhevm.py +++ b/fence/agents/rhevm/fence_rhevm.py @@ -1,166 +1,166 @@ -#!/usr/bin/python -tt +#!@PYTHON@ -tt import sys, re -import pycurl, StringIO +import pycurl, io import logging import atexit sys.path.append("@FENCEAGENTSLIBDIR@") from fencing import * from fencing import fail, EC_STATUS, run_delay #BEGIN_VERSION_GENERATION RELEASE_VERSION="New RHEV-M Agent - test release on steroids" REDHAT_COPYRIGHT="" BUILD_DATE="March, 2008" #END_VERSION_GENERATION RE_GET_ID = re.compile("(.*?)", re.IGNORECASE) RE_GET_NAME = re.compile("(.*?)", re.IGNORECASE) def get_power_status(conn, options): del conn ### Obtain real ID from name res = send_command(options, "vms/?search=name%3D" + options["--plug"]) result = RE_GET_ID.search(res) if result == None: # Unable to obtain ID needed to access virtual machine fail(EC_STATUS) options["id"] = result.group(2) result = RE_STATUS.search(res) if result == None: # We were able to parse ID so output is correct # in some cases it is possible that RHEV-M output does not # contain line. We can assume machine is OFF then return "off" else: status = result.group(1) if status.lower() == "down": return "off" else: return "on" def set_power_status(conn, options): del conn action = { 'on' : "start", 'off' : "stop" }[options["--action"]] url = "vms/" + options["id"] + "/" + action send_command(options, url, "POST") def get_list(conn, options): del conn outlets = {} try: res = send_command(options, "vms") lines = res.split("") conn.setopt(pycurl.WRITEFUNCTION, web_buffer.write) conn.perform() - if not opt.has_key("cookie") and opt.has_key("--use-cookies"): + if "cookie" not in opt and "--use-cookies" in opt: cookie = "" for c in conn.getinfo(pycurl.INFO_COOKIELIST): tokens = c.split("\t",7) cookie = cookie + tokens[5] + "=" + tokens[6] + ";" opt["cookie"] = cookie result = web_buffer.getvalue() logging.debug("%s\n", command) logging.debug("%s\n", result) return result def define_new_opts(): all_opt["use_cookies"] = { "getopt" : "", "longopt" : "use-cookies", "help" : "--use-cookies Reuse cookies for authentication", "required" : "0", "shortdesc" : "Reuse cookies for authentication", "order" : 1} def main(): device_opt = ["ipaddr", "login", "passwd", "ssl", "notls", "web", "port", "use_cookies" ] atexit.register(atexit_handler) define_new_opts() all_opt["power_wait"]["default"] = "1" options = check_input(device_opt, process_input(device_opt)) docs = {} docs["shortdesc"] = "Fence agent for RHEV-M REST API" docs["longdesc"] = "fence_rhevm is an I/O Fencing agent which can be \ used with RHEV-M REST API to fence virtual machines." docs["vendorurl"] = "http://www.redhat.com" show_docs(options, docs) ## ## Fence operations #### run_delay(options) result = fence_action(None, options, set_power_status, get_power_status, get_list) sys.exit(result) if __name__ == "__main__": main() diff --git a/fence/agents/rsa/fence_rsa.py b/fence/agents/rsa/fence_rsa.py index 46f4bb96..7b24ea64 100644 --- a/fence/agents/rsa/fence_rsa.py +++ b/fence/agents/rsa/fence_rsa.py @@ -1,69 +1,69 @@ -#!/usr/bin/python -tt +#!@PYTHON@ -tt ##### ## ## The Following Agent Has Been Tested On: ## Main GFEP25A & Boot GFBP25A ## ##### import sys, re import atexit sys.path.append("@FENCEAGENTSLIBDIR@") from fencing import * #BEGIN_VERSION_GENERATION RELEASE_VERSION="New RSA2 Agent - test release on steroids" REDHAT_COPYRIGHT="" BUILD_DATE="" #END_VERSION_GENERATION def get_power_status(conn, options): conn.send_eol("power state") conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) match = re.compile("Power: (.*)", re.IGNORECASE).search(conn.before) if match != None: status = match.group(1) else: status = "undefined" return status.lower().strip() def set_power_status(conn, options): conn.send_eol("power " + options["--action"]) conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) def main(): device_opt = ["ipaddr", "login", "passwd", "cmd_prompt", "secure", "telnet"] atexit.register(atexit_handler) all_opt["login_timeout"]["default"] = 10 all_opt["cmd_prompt"]["default"] = [">"] # This device will not allow us to login even with LANG=C all_opt["ssh_options"]["default"] = "-F /dev/null" options = check_input(device_opt, process_input(device_opt)) docs = {} docs["shortdesc"] = "Fence agent for IBM RSA" docs["longdesc"] = "fence_rsa is an I/O Fencing agent \ which can be used with the IBM RSA II management interface. It \ logs into an RSA II device via telnet and reboots the associated \ machine. Lengthy telnet connections to the RSA II device should \ be avoided while a GFS cluster is running because the connection \ will block any necessary fencing actions." docs["vendorurl"] = "http://www.ibm.com" show_docs(options, docs) ## ## Operate the fencing device ###### conn = fence_login(options) result = fence_action(conn, options, set_power_status, get_power_status, None) fence_logout(conn, "exit") sys.exit(result) if __name__ == "__main__": main() diff --git a/fence/agents/rsb/fence_rsb.py b/fence/agents/rsb/fence_rsb.py index 2ee85fe6..725398d2 100755 --- a/fence/agents/rsb/fence_rsb.py +++ b/fence/agents/rsb/fence_rsb.py @@ -1,76 +1,76 @@ -#!/usr/bin/python -tt +#!@PYTHON@ -tt import sys, re import atexit sys.path.append("@FENCEAGENTSLIBDIR@") from fencing import * #BEGIN_VERSION_GENERATION RELEASE_VERSION="" REDHAT_COPYRIGHT="" BUILD_DATE="" #END_VERSION_GENERATION def get_power_status(conn, options): conn.send("2") conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) status = re.compile(r"Power Status[\s]*: (on|off)", re.IGNORECASE).search(conn.before).group(1) conn.send("0") conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) return status.lower().strip() def set_power_status(conn, options): action = { 'on' : "4", 'off': "1" }[options["--action"]] conn.send("2") conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) conn.send_eol(action) conn.log_expect(["want to power " + options["--action"], "yes/no", "'yes' or 'no'"], int(options["--shell-timeout"])) conn.send_eol("yes") conn.log_expect("any key to continue", int(options["--power-timeout"])) conn.send_eol("") conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) conn.send_eol("0") conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) def main(): device_opt = ["ipaddr", "login", "passwd", "secure", "cmd_prompt", "telnet"] atexit.register(atexit_handler) all_opt["cmd_prompt"]["default"] = ["to quit:"] opt = process_input(device_opt) - if not opt.has_key("--ssh") and not opt.has_key("--ipport"): + if "--ssh" not in opt and "--ipport" not in opt: # set default value like it should be set as usually all_opt["ipport"]["default"] = "3172" opt["--ipport"] = all_opt["ipport"]["default"] options = check_input(device_opt, opt) docs = {} docs["shortdesc"] = "I/O Fencing agent for Fujitsu-Siemens RSB" docs["longdesc"] = "fence_rsb is an I/O Fencing agent \ which can be used with the Fujitsu-Siemens RSB management interface. It logs \ into device via telnet/ssh and reboots a specified outlet. Lengthy telnet/ssh \ connections should be avoided while a GFS cluster is running because the connection \ will block any necessary fencing actions." docs["vendorurl"] = "http://www.fujitsu.com" show_docs(options, docs) ## ## Operate the fencing device #### conn = fence_login(options) result = fence_action(conn, options, set_power_status, get_power_status, None) fence_logout(conn, "0") sys.exit(result) if __name__ == "__main__": main() diff --git a/fence/agents/sanbox2/fence_sanbox2.py b/fence/agents/sanbox2/fence_sanbox2.py index efa7dc8d..e298a3e7 100644 --- a/fence/agents/sanbox2/fence_sanbox2.py +++ b/fence/agents/sanbox2/fence_sanbox2.py @@ -1,157 +1,157 @@ -#!/usr/bin/python -tt +#!@PYTHON@ -tt ##### ## ## The Following Agent Has Been Tested On: ## ## Version Firmware ## +-----------------+---------------------------+ ##### -import sys, re, pexpect, exceptions +import sys, re, pexpect import logging import atexit sys.path.append("@FENCEAGENTSLIBDIR@") from fencing import * from fencing import fail, EC_TIMED_OUT, EC_GENERIC_ERROR #BEGIN_VERSION_GENERATION RELEASE_VERSION="New Sanbox2 Agent - test release on steroids" REDHAT_COPYRIGHT="" BUILD_DATE="March, 2008" #END_VERSION_GENERATION def get_power_status(conn, options): status_trans = { 'online' : "on", 'offline' : "off" } try: conn.send_eol("show port " + options["--plug"]) conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) except pexpect.TIMEOUT: try: conn.send_eol("admin end") conn.send_eol("exit") conn.close() except Exception: pass fail(EC_TIMED_OUT) status = re.compile(r".*AdminState\s+(online|offline)\s+", re.IGNORECASE | re.MULTILINE).search(conn.before).group(1) try: return status_trans[status.lower().strip()] except KeyError: return "PROBLEM" def set_power_status(conn, options): action = { 'on' : "online", 'off' : "offline" }[options["--action"]] try: conn.send_eol("set port " + options["--plug"] + " state " + action) conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) except pexpect.TIMEOUT: try: conn.send_eol("admin end") conn.send_eol("exit") conn.close() except Exception: pass fail(EC_TIMED_OUT) try: conn.send_eol("set port " + options["--plug"] + " state " + action) conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) except pexpect.TIMEOUT: try: conn.send_eol("admin end") conn.send_eol("exit") conn.close() except Exception: pass fail(EC_TIMED_OUT) def get_list_devices(conn, options): outlets = {} try: conn.send_eol("show port") conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) list_re = re.compile(r"^\s+(\d+?)\s+(Online|Offline)\s+", re.IGNORECASE) for line in conn.before.splitlines(): if list_re.search(line): status = { 'online' : "ON", 'offline' : "OFF" }[list_re.search(line).group(2).lower()] outlets[list_re.search(line).group(1)] = ("", status) except pexpect.TIMEOUT: try: conn.send_eol("admin end") conn.send_eol("exit") conn.close() except Exception: pass fail(EC_TIMED_OUT) return outlets def main(): device_opt = ["fabric_fencing", "ipaddr", "login", "passwd", "cmd_prompt", \ "port", "telnet"] atexit.register(atexit_handler) all_opt["cmd_prompt"]["default"] = [" #> "] options = check_input(device_opt, process_input(device_opt)) docs = {} docs["shortdesc"] = "Fence agent for QLogic SANBox2 FC switches" docs["longdesc"] = "fence_sanbox2 is an I/O Fencing agent which can be used with \ QLogic SANBox2 FC switches. It logs into a SANBox2 switch via telnet and disables a specified \ port. Disabling the port which a machine is connected to effectively fences that machine. \ Lengthy telnet connections to the switch should be avoided while a GFS cluster is running \ because the connection will block any necessary fencing actions." docs["vendorurl"] = "http://www.qlogic.com" show_docs(options, docs) ## ## Operate the fencing device ## conn = fence_login(options) conn.send_eol("admin start") conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) if re.search(r"\(admin\)", conn.before, re.MULTILINE) == None: ## Someone else is in admin section, we can't enable/disable ## ports so we will rather exit logging.error("Failed: Unable to switch to admin section\n") sys.exit(EC_GENERIC_ERROR) result = fence_action(conn, options, set_power_status, get_power_status, get_list_devices) ## ## Logout from system ###### try: conn.send_eol("admin end") conn.send_eol("exit\n") conn.close() - except exceptions.OSError: + except OSError: pass except pexpect.ExceptionPexpect: pass sys.exit(result) if __name__ == "__main__": main() diff --git a/fence/agents/sbd/fence_sbd.py b/fence/agents/sbd/fence_sbd.py index 7120c4db..44327e85 100644 --- a/fence/agents/sbd/fence_sbd.py +++ b/fence/agents/sbd/fence_sbd.py @@ -1,421 +1,421 @@ -#!/usr/bin/python -tt +#!@PYTHON@ -tt import sys, stat import logging import os import atexit sys.path.append("@FENCEAGENTSLIBDIR@") from fencing import fail_usage, run_command, fence_action, all_opt from fencing import atexit_handler, check_input, process_input, show_docs from fencing import run_delay #BEGIN_VERSION_GENERATION RELEASE_VERSION="" REDHAT_COPYRIGHT="" BUILD_DATE="" #END_VERSION_GENERATION DEVICE_INIT = 1 DEVICE_NOT_INIT = -3 PATH_NOT_EXISTS = -1 PATH_NOT_BLOCK = -2 def is_block_device(filename): """Checks if a given path is a valid block device Key arguments: filename -- the file to check Return codes: True if it's a valid block device False, otherwise """ try: mode = os.lstat(filename).st_mode except OSError: return False else: return stat.S_ISBLK(mode) def is_link(filename): """Checks if a given path is a link. Key arguments: filename -- the file to check Return codes: True if it's a link False, otherwise """ try: mode = os.lstat(filename).st_mode except OSError: return False else: return stat.S_ISLNK(mode) def check_sbd_device(options, device_path): """checks that a given sbd device exists and is initialized Key arguments: options -- options dictionary device_path -- device path to check Return Codes: 1 / DEVICE_INIT if the device exists and is initialized -1 / PATH_NOT_EXISTS if the path does not exists -2 / PATH_NOT_BLOCK if the path exists but is not a valid block device -3 / DEVICE_NOT_INIT if the sbd device is not initialized """ # First of all we need to check if the device is valid if not os.path.exists(device_path): return PATH_NOT_EXISTS # We need to check if device path is a symbolic link. If so we resolve that # link. if is_link(device_path): link_target = os.readlink(device_path) device_path = os.path.join(os.path.dirname(device_path), link_target) # As second step we make sure it's a valid block device if not is_block_device(device_path): return PATH_NOT_BLOCK cmd = "%s -d %s dump" % (options["--sbd-path"], device_path) (return_code, out, err) = run_command(options, cmd) for line in out.split("\n"): if len(line) == 0: continue # If we read "NOT dumped" something went wrong, e.g. the device is not # initialized. if "NOT dumped" in line: return DEVICE_NOT_INIT return DEVICE_INIT def generate_sbd_command(options, command, arguments=None): """Generates a sbd command based on given arguments. Return Value: generated sbd command (string) """ cmd = options["--sbd-path"] # add "-d" for each sbd device for device in parse_sbd_devices(options): cmd += " -d %s" % device cmd += " %s %s" % (command, arguments) return cmd def send_sbd_message(conn, options, plug, message): """Sends a message to all sbd devices. Key arguments: conn -- connection structure options -- options dictionary plug -- plug to sent the message to message -- message to send Return Value: (return_code, out, err) Tuple containing the error code, """ del conn arguments = "%s %s" % (plug, message) cmd = generate_sbd_command(options, "message", arguments) (return_code, out, err) = run_command(options, cmd) return (return_code, out, err) def get_msg_timeout(options): """Reads the configured sbd message timeout from each device. Key arguments: options -- options dictionary Return Value: msg_timeout (integer, seconds) """ # get the defined msg_timeout msg_timeout = -1 # default sbd msg timeout cmd = generate_sbd_command(options, "dump") (return_code, out, err) = run_command(options, cmd) for line in out.split("\n"): if len(line) == 0: continue if "msgwait" in line: tmp_msg_timeout = int(line.split(':')[1]) if -1 != msg_timeout and tmp_msg_timeout != msg_timeout: logging.warn(\ "sbd message timeouts differ in different devices") # we only save the highest timeout if tmp_msg_timeout > msg_timeout: msg_timeout = tmp_msg_timeout return msg_timeout def set_power_status(conn, options): """send status to sbd device (poison pill) Key arguments: conn -- connection structure options -- options dictionary Return Value: return_code -- return code (integer) """ target_status = options["--action"] plug = options["--plug"] return_code = 99 out = "" err = "" # Map fencing actions to sbd messages if "on" == target_status: (return_code, out, err) = send_sbd_message(conn, options, plug, "clear") elif "off" == target_status: (return_code, out, err) = send_sbd_message(conn, options, plug, "off") elif "reboot" == target_status: (return_code, out, err) = send_sbd_message(conn, options, plug, "reset") if 0 != return_code: logging.error("sending message to sbd device(s) \ failed with return code %d", return_code) logging.error("DETAIL: output on stdout was \"%s\"", out) logging.error("DETAIL: output on stderr was \"%s\"", err) return return_code def reboot_cycle(conn, options): """" trigger reboot by sbd messages Key arguments: conn -- connection structure options -- options dictionary Return Value: return_code -- return code (integer) """ plug = options["--plug"] return_code = 99 out = "" err = "" (return_code, out, err) = send_sbd_message(conn, options, plug, "reset") return return_code def get_power_status(conn, options): """Returns the status of a specific node. Key arguments: conn -- connection structure options -- option dictionary Return Value: status -- status code (string) """ status = "UNKWNOWN" plug = options["--plug"] nodelist = get_node_list(conn, options) # We need to check if the specified plug / node a already a allocated slot # on the device. - if not nodelist.has_key(plug): + if plug not in nodelist: logging.error("node \"%s\" not found in node list", plug) else: status = nodelist[plug][1] return status def translate_status(sbd_status): """Translates the sbd status to fencing status. Key arguments: sbd_status -- status to translate (string) Return Value: status -- fencing status (string) """ status = "UNKNOWN" # Currently we only accept "clear" to be marked as online. Eventually we # should also check against "test" online_status = ["clear"] offline_status = ["reset", "off"] if any(online_status_element in sbd_status \ for online_status_element in online_status): status = "on" if any(offline_status_element in sbd_status \ for offline_status_element in offline_status): status = "off" return status def get_node_list(conn, options): """Returns a list of hostnames, registerd on the sbd device. Key arguments: conn -- connection options options -- options Return Value: nodelist -- dictionary wich contains all node names and there status """ del conn nodelist = {} cmd = generate_sbd_command(options, "list") (return_code, out, err) = run_command(options, cmd) for line in out.split("\n"): if len(line) == 0: continue # if we read "unreadable" something went wrong if "NOT dumped" in line: return nodelist words = line.split() port = words[1] sbd_status = words[2] nodelist[port] = (port, translate_status(sbd_status)) return nodelist def parse_sbd_devices(options): """Returns an array of all sbd devices. Key arguments: options -- options dictionary Return Value: devices -- array of device paths """ devices = [str.strip(dev) \ for dev in str.split(options["--devices"], ",")] return devices def define_new_opts(): """Defines the all opt list """ all_opt["devices"] = { "getopt" : ":", "longopt" : "devices", "help":"--devices=[device_a,device_b] \ Comma separated list of sbd devices", "required" : "1", "shortdesc" : "SBD Device", "order": 1 } all_opt["sbd_path"] = { "getopt" : ":", "longopt" : "sbd-path", "help" : "--sbd-path=[path] Path to SBD binary", "required" : "0", "default" : "@SBD_PATH@", "order": 200 } def main(): """Main function """ # We need to define "no_password" otherwise we will be ask about it if # we don't provide any password. device_opt = ["no_password", "devices", "port", "method", "sbd_path"] # close stdout if we get interrupted atexit.register(atexit_handler) define_new_opts() all_opt["method"]["default"] = "cycle" all_opt["method"]["help"] = "-m, --method=[method] Method to fence (onoff|cycle) (Default: cycle)" options = check_input(device_opt, process_input(device_opt)) # fill the needed variables to generate metadata and help text output docs = {} docs["shortdesc"] = "Fence agent for sbd" docs["longdesc"] = "fence_sbd is I/O Fencing agent \ which can be used in environments where sbd can be used (shared storage)." docs["vendorurl"] = "" show_docs(options, docs) # We need to check if --devices is given and not empty. - if not options.has_key("--devices"): + if "--devices" not in options: fail_usage("No SBD devices specified. \ At least one SBD device is required.") run_delay(options) # We need to check if the provided sbd_devices exists. We need to do # that for every given device. for device_path in parse_sbd_devices(options): logging.debug("check device \"%s\"", device_path) return_code = check_sbd_device(options, device_path) if PATH_NOT_EXISTS == return_code: logging.error("\"%s\" does not exist", device_path) elif PATH_NOT_BLOCK == return_code: logging.error("\"%s\" is not a valid block device", device_path) elif DEVICE_NOT_INIT == return_code: logging.error("\"%s\" is not initialized", device_path) elif DEVICE_INIT != return_code: logging.error("UNKNOWN error while checking \"%s\"", device_path) # If we get any error while checking the device we need to exit at this # point. if DEVICE_INIT != return_code: exit(return_code) # we check against the defined timeouts. If the pacemaker timeout is smaller # then that defined within sbd we should report this. power_timeout = int(options["--power-timeout"]) sbd_msg_timeout = get_msg_timeout(options) if power_timeout <= sbd_msg_timeout: logging.warn("power timeout needs to be \ greater then sbd message timeout") result = fence_action(\ None, \ options, \ set_power_status, \ get_power_status, \ get_node_list, \ reboot_cycle) sys.exit(result) if __name__ == "__main__": main() diff --git a/fence/agents/scsi/fence_scsi.py b/fence/agents/scsi/fence_scsi.py index 3988339e..54cf9c80 100644 --- a/fence/agents/scsi/fence_scsi.py +++ b/fence/agents/scsi/fence_scsi.py @@ -1,498 +1,498 @@ -#!/usr/bin/python -tt +#!@PYTHON@ -tt import sys import stat import re import os import time import logging import atexit import hashlib import ctypes sys.path.append("@FENCEAGENTSLIBDIR@") from fencing import fail_usage, run_command, atexit_handler, check_input, process_input, show_docs, fence_action, all_opt from fencing import run_delay #BEGIN_VERSION_GENERATION RELEASE_VERSION="" REDHAT_COPYRIGHT="" BUILD_DATE="" #END_VERSION_GENERATION STORE_PATH = "/var/run/cluster/fence_scsi" def get_status(conn, options): del conn status = "off" for dev in options["devices"]: is_block_device(dev) reset_dev(options, dev) if options["--key"] in get_registration_keys(options, dev): status = "on" else: logging.debug("No registration for key "\ + options["--key"] + " on device " + dev + "\n") if options["--action"] == "on": status = "off" break return status def set_status(conn, options): del conn count = 0 if options["--action"] == "on": set_key(options) for dev in options["devices"]: is_block_device(dev) register_dev(options, dev) if options["--key"] not in get_registration_keys(options, dev): count += 1 logging.debug("Failed to register key "\ + options["--key"] + "on device " + dev + "\n") continue dev_write(dev, options) if get_reservation_key(options, dev) is None \ and not reserve_dev(options, dev) \ and get_reservation_key(options, dev) is None: count += 1 logging.debug("Failed to create reservation (key="\ + options["--key"] + ", device=" + dev + ")\n") else: host_key = get_key() if host_key == options["--key"].lower(): fail_usage("Failed: keys cannot be same. You can not fence yourself.") for dev in options["devices"]: is_block_device(dev) if options["--key"] in get_registration_keys(options, dev): preempt_abort(options, host_key, dev) for dev in options["devices"]: if options["--key"] in get_registration_keys(options, dev): count += 1 logging.debug("Failed to remove key "\ + options["--key"] + " on device " + dev + "\n") continue if not get_reservation_key(options, dev): count += 1 logging.debug("No reservation exists on device " + dev + "\n") if count: logging.error("Failed to verify " + str(count) + " device(s)") sys.exit(1) # check if host is ready to execute actions def do_action_monitor(options): # Check if required binaries are installed if bool(run_cmd(options, options["--sg_persist-path"] + " -V")["err"]): logging.error("Unable to run " + options["--sg_persist-path"]) return 1 elif bool(run_cmd(options, options["--sg_turs-path"] + " -V")["err"]): logging.error("Unable to run " + options["--sg_turs-path"]) return 1 elif ("--devices" not in options and bool(run_cmd(options, options["--vgs-path"] + " --version")["err"])): logging.error("Unable to run " + options["--vgs-path"]) return 1 # Keys have to be present in order to fence/unfence get_key() dev_read() return 0 #run command, returns dict, ret["err"] = exit code; ret["out"] = output def run_cmd(options, cmd): ret = {} (ret["err"], ret["out"], _) = run_command(options, cmd) ret["out"] = "".join([i for i in ret["out"] if i is not None]) 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_abort(options, host, dev): reset_dev(options,dev) cmd = options["--sg_persist-path"] + " -n -o -A -T 5 -K " + host + " -S " + options["--key"] + " -d " + dev return not bool(run_cmd(options, cmd)["err"]) def reset_dev(options, dev): return run_cmd(options, options["--sg_turs-path"] + " " + dev)["err"] def register_dev(options, dev): dev = os.path.realpath(dev) if re.search(r"^dm", dev[5:]): for slave in get_mpath_slaves(dev): register_dev(options, slave) return True reset_dev(options, dev) cmd = options["--sg_persist-path"] + " -n -o -I -S " + options["--key"] + " -d " + dev cmd += " -Z" if "--aptpl" in options else "" #cmd return code != 0 but registration can be successful return not bool(run_cmd(options, cmd)["err"]) def reserve_dev(options, dev): reset_dev(options,dev) cmd = options["--sg_persist-path"] + " -n -o -R -T 5 -K " + options["--key"] + " -d " + dev return not bool(run_cmd(options, cmd)["err"]) def get_reservation_key(options, dev): reset_dev(options,dev) cmd = options["--sg_persist-path"] + " -n -i -r -d " + dev out = run_cmd(options, cmd) if out["err"]: fail_usage("Cannot get reservation key") match = re.search(r"\s+key=0x(\S+)\s+", out["out"], re.IGNORECASE) return match.group(1) if match else None def get_registration_keys(options, dev): reset_dev(options,dev) keys = [] cmd = options["--sg_persist-path"] + " -n -i -k -d " + dev out = run_cmd(options, cmd) if out["err"]: fail_usage("Cannot get registration keys") for line in out["out"].split("\n"): match = re.search(r"\s+0x(\S+)\s*", line) if match: keys.append(match.group(1)) return keys def get_cluster_id(options): cmd = options["--corosync-cmap-path"] + " totem.cluster_name" match = re.search(r"\(str\) = (\S+)\n", run_cmd(options, cmd)["out"]) return hashlib.md5(match.group(1)).hexdigest() if match else fail_usage("Failed: cannot get cluster name") def get_node_id(options): cmd = options["--corosync-cmap-path"] + " nodelist." match = re.search(r".(\d).ring._addr \(str\) = " + options["--nodename"] + "\n", run_cmd(options, cmd)["out"]) return match.group(1) if match else fail_usage("Failed: unable to parse output of corosync-cmapctl or node does not exist") def generate_key(options): return "%.4s%.4d" % (get_cluster_id(options), int(get_node_id(options))) # save node key to file def set_key(options): file_path = options["store_path"] + ".key" if not os.path.isdir(os.path.dirname(options["store_path"])): os.makedirs(os.path.dirname(options["store_path"])) try: f = open(file_path, "w") except IOError: fail_usage("Failed: Cannot open file \""+ file_path + "\"") f.write(options["--key"].lower() + "\n") f.close() # read node key from file def get_key(fail=True): file_path = STORE_PATH + ".key" try: f = open(file_path, "r") except IOError: if fail: fail_usage("Failed: Cannot open file \""+ file_path + "\"") else: return None return f.readline().strip().lower() def dev_write(dev, options): file_path = options["store_path"] + ".dev" if not os.path.isdir(os.path.dirname(options["store_path"])): os.makedirs(os.path.dirname(options["store_path"])) try: f = open(file_path, "a+") except IOError: fail_usage("Failed: Cannot open file \""+ file_path + "\"") out = f.read() if not re.search(r"^" + dev + "\s+", out): f.write(dev + "\n") f.close() def dev_read(fail=True): file_path = STORE_PATH + ".dev" try: f = open(file_path, "r") except IOError: if fail: fail_usage("Failed: Cannot open file \"" + file_path + "\"") else: return None # get not empty lines from file devs = [line.strip() for line in f if line.strip()] f.close() return devs def dev_delete(options): file_path = options["store_path"] + ".dev" os.remove(file_path) if os.path.exists(file_path) else None def get_clvm_devices(options): devs = [] cmd = options["--vgs-path"] + " " +\ "--noheadings " +\ "--separator : " +\ "--sort pv_uuid " +\ "--options vg_attr,pv_name "+\ "--config 'global { locking_type = 0 } devices { preferred_names = [ \"^/dev/dm\" ] }'" out = run_cmd(options, cmd) if out["err"]: fail_usage("Failed: Cannot get clvm devices") for line in out["out"].split("\n"): if 'c' in line.split(":")[0]: devs.append(line.split(":")[1]) return devs def get_mpath_slaves(dev): if dev[:5] == "/dev/": dev = dev[5:] slaves = [i for i in os.listdir("/sys/block/" + dev + "/slaves/") if i[:1] != "."] if slaves[0][:2] == "dm": slaves = get_mpath_slaves(slaves[0]) else: slaves = ["/dev/" + x for x in slaves] return slaves def define_new_opts(): all_opt["devices"] = { "getopt" : "d:", "longopt" : "devices", "help" : "-d, --devices=[devices] List of devices to use for current operation", "required" : "0", "shortdesc" : "List of devices to use for current operation. Devices can \ be comma-separated list of raw device (eg. /dev/sdc) or device-mapper multipath \ devices (eg. /dev/dm-3). Each device must support SCSI-3 persistent reservations.", "order": 1 } all_opt["nodename"] = { "getopt" : "n:", "longopt" : "nodename", "help" : "-n, --nodename=[nodename] Name of the node to be fenced", "required" : "0", "shortdesc" : "Name of the node to be fenced. The node name is used to \ generate the key value used for the current operation. This option will be \ ignored when used with the -k option.", "order": 1 } all_opt["key"] = { "getopt" : "k:", "longopt" : "key", "help" : "-k, --key=[key] Key to use for the current operation", "required" : "0", "shortdesc" : "Key to use for the current operation. This key should be \ unique to a node. For the \"on\" action, the key specifies the key use to \ register the local node. For the \"off\" action, this key specifies the key to \ be removed from the device(s).", "order": 1 } all_opt["aptpl"] = { "getopt" : "a", "longopt" : "aptpl", "help" : "-a, --aptpl Use the APTPL flag for registrations", "required" : "0", "shortdesc" : "Use the APTPL flag for registrations. This option is only used for the 'on' action.", "order": 1 } all_opt["logfile"] = { "getopt" : ":", "longopt" : "logfile", "help" : "-f, --logfile Log output (stdout and stderr) to file", "required" : "0", "shortdesc" : "Log output (stdout and stderr) to file", "order": 5 } all_opt["corosync-cmap_path"] = { "getopt" : ":", "longopt" : "corosync-cmap-path", "help" : "--corosync-cmap-path=[path] Path to corosync-cmapctl binary", "required" : "0", "shortdesc" : "Path to corosync-cmapctl binary", "default" : "@COROSYNC_CMAPCTL_PATH@", "order": 300 } all_opt["sg_persist_path"] = { "getopt" : ":", "longopt" : "sg_persist-path", "help" : "--sg_persist-path=[path] Path to sg_persist binary", "required" : "0", "shortdesc" : "Path to sg_persist binary", "default" : "@SG_PERSIST_PATH@", "order": 300 } all_opt["sg_turs_path"] = { "getopt" : ":", "longopt" : "sg_turs-path", "help" : "--sg_turs-path=[path] Path to sg_turs binary", "required" : "0", "shortdesc" : "Path to sg_turs binary", "default" : "@SG_TURS_PATH@", "order": 300 } all_opt["vgs_path"] = { "getopt" : ":", "longopt" : "vgs-path", "help" : "--vgs-path=[path] Path to vgs binary", "required" : "0", "shortdesc" : "Path to vgs binary", "default" : "@VGS_PATH@", "order": 300 } def scsi_check_get_verbose(): try: f = open("/etc/sysconfig/watchdog", "r") except IOError: return False match = re.search(r"^\s*verbose=yes", "".join(f.readlines()), re.MULTILINE) f.close() return bool(match) def scsi_check(hardreboot=False): if len(sys.argv) >= 3 and sys.argv[1] == "repair": return int(sys.argv[2]) options = {} options["--sg_turs-path"] = "@SG_TURS_PATH@" options["--sg_persist-path"] = "@SG_PERSIST_PATH@" options["--power-timeout"] = "5" if scsi_check_get_verbose(): logging.getLogger().setLevel(logging.DEBUG) devs = dev_read(fail=False) if not devs: logging.error("No devices found") return 0 key = get_key(fail=False) if not key: logging.error("Key not found") return 0 for dev in devs: if key in get_registration_keys(options, dev): logging.debug("key " + key + " registered with device " + dev) return 0 else: logging.debug("key " + key + " not registered with device " + dev) logging.debug("key " + key + " registered with any devices") if hardreboot == True: libc = ctypes.cdll['libc.so.6'] libc.reboot(0x1234567) return 2 def main(): atexit.register(atexit_handler) device_opt = ["no_login", "no_password", "devices", "nodename", "key",\ "aptpl", "fabric_fencing", "on_target", "corosync-cmap_path",\ "sg_persist_path", "sg_turs_path", "logfile", "vgs_path", "force_on"] define_new_opts() all_opt["delay"]["getopt"] = "H:" #fence_scsi_check if os.path.basename(sys.argv[0]) == "fence_scsi_check": sys.exit(scsi_check()) elif os.path.basename(sys.argv[0]) == "fence_scsi_check_hardreboot": sys.exit(scsi_check(True)) options = check_input(device_opt, process_input(device_opt), other_conditions=True) docs = {} docs["shortdesc"] = "Fence agent for SCSI persistent reservation" docs["longdesc"] = "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.\nThe 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." docs["vendorurl"] = "" show_docs(options, docs) run_delay(options) # backward compatibility layer BEGIN if "--logfile" in options: try: logfile = open(options["--logfile"], 'w') sys.stderr = logfile sys.stdout = logfile except IOError: fail_usage("Failed: Unable to create file " + options["--logfile"]) # backward compatibility layer END options["store_path"] = STORE_PATH # Input control BEGIN stop_after_error = False if options["--action"] == "validate-all" else True if options["--action"] == "monitor": sys.exit(do_action_monitor(options)) if not (("--nodename" in options and options["--nodename"])\ or ("--key" in options and options["--key"])): fail_usage("Failed: nodename or key is required", stop_after_error) if not ("--key" in options and options["--key"]): options["--key"] = generate_key(options) if options["--key"] == "0" or not options["--key"]: fail_usage("Failed: key cannot be 0", stop_after_error) if options["--action"] == "validate-all": sys.exit(0) options["--key"] = options["--key"].lstrip('0') if not ("--devices" in options and options["--devices"].split(",")): options["devices"] = get_clvm_devices(options) else: options["devices"] = options["--devices"].split(",") if not options["devices"]: fail_usage("Failed: No devices found") # Input control END result = fence_action(None, options, set_status, get_status) sys.exit(result) if __name__ == "__main__": main() diff --git a/fence/agents/vbox/fence_vbox.py b/fence/agents/vbox/fence_vbox.py index bed95ef0..43473522 100644 --- a/fence/agents/vbox/fence_vbox.py +++ b/fence/agents/vbox/fence_vbox.py @@ -1,113 +1,113 @@ -#!/usr/bin/python -tt +#!@PYTHON@ -tt # The Following Agent Has Been Tested On: # # VirtualBox 5.0.4 x64 on openSUSE 13.2 # import sys import re import time import atexit sys.path.append("@FENCEAGENTSLIBDIR@") from fencing import * from fencing import fail_usage #BEGIN_VERSION_GENERATION RELEASE_VERSION = "VirtualBox fence agent" REDHAT_COPYRIGHT = "" BUILD_DATE = "" #END_VERSION_GENERATION def get_name_or_uuid(options): return options.get("--uuid") or options.get("--plug") _domain_re = re.compile(r'^\"(.*)\" \{(.*)\}$') def _invoke(conn, options, *cmd): prefix = options["--sudo-path"] + " " if "--use-sudo" in options else "" conn.sendline(prefix + "VBoxManage " + " ".join(cmd)) conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) def get_outlets_status(conn, options): result = {} _invoke(conn, options, "list", "vms") for line in conn.before.splitlines(): # format: "" {} domain = _domain_re.search(line.strip()) if domain is not None: result[domain.group(1)] = ("", "off") _invoke(conn, options, "list", "runningvms") for line in conn.before.splitlines(): # format: "" {} domain = _domain_re.search(line.strip()) if domain is not None: result[domain.group(1)] = ("", "on") return result def get_power_status(conn, options): name = get_name_or_uuid(options) _invoke(conn, options, "list", "runningvms") for line in conn.before.splitlines(): domain = _domain_re.search(line.strip()) if domain is not None and name in domain.groups(): return "on" if "--missing-as-off" in options: return "off" _invoke(conn, options, "list", "vms") for line in conn.before.splitlines(): domain = _domain_re.search(line.strip()) if domain is not None and name in domain.groups(): return "off" fail_usage("Failed: You have to enter existing name/UUID of virtual machine!") def set_power_status(conn, options): name = get_name_or_uuid(options) if options["--action"] == "on": _invoke(conn, options, "startvm", '"%s"' % name, "--type", "headless") else: _invoke(conn, options, "controlvm", '"%s"' % name, "poweroff") def main(): device_opt = ["ipaddr", "login", "passwd", "cmd_prompt", "secure", "port", "sudo", "missing_as_off"] atexit.register(atexit_handler) all_opt["secure"]["default"] = "1" all_opt["cmd_prompt"]["default"] = [r"\[EXPECT\]#\ "] all_opt["ssh_options"]["default"] = "-t '/bin/bash -c \"" + r"PS1=\\[EXPECT\\]#\ " + "/bin/bash --noprofile --norc\"'" options = check_input(device_opt, process_input(device_opt)) docs = {} docs["shortdesc"] = "Fence agent for VirtualBox" docs["longdesc"] = "fence_vbox is an I/O Fencing agent \ which can be used with the virtual machines managed by VirtualBox. \ It logs via ssh to a dom0 where it runs VBoxManage to do all of \ the work. \ \n.P\n\ By default, vbox needs to log in as a user that is a member of the \ vboxusers group. Also, you must allow ssh login in your sshd_config." docs["vendorurl"] = "https://www.virtualbox.org/" show_docs(options, docs) # Operate the fencing device conn = fence_login(options) result = fence_action(conn, options, set_power_status, get_power_status, get_outlets_status) fence_logout(conn, "quit") sys.exit(result) if __name__ == "__main__": main() diff --git a/fence/agents/virsh/fence_virsh.py b/fence/agents/virsh/fence_virsh.py index 643f31fc..baa5ee09 100644 --- a/fence/agents/virsh/fence_virsh.py +++ b/fence/agents/virsh/fence_virsh.py @@ -1,102 +1,102 @@ -#!/usr/bin/python -tt +#!@PYTHON@ -tt # The Following Agent Has Been Tested On: # # Virsh 0.3.3 on RHEL 5.2 with xen-3.0.3-51 # import sys, re import time import atexit sys.path.append("@FENCEAGENTSLIBDIR@") from fencing import * from fencing import fail_usage #BEGIN_VERSION_GENERATION RELEASE_VERSION="Virsh fence agent" REDHAT_COPYRIGHT="" BUILD_DATE="" #END_VERSION_GENERATION def get_name_or_uuid(options): - return options["--uuid"] if options.has_key("--uuid") else options["--plug"] + return options["--uuid"] if "--uuid" in options else options["--plug"] def get_outlets_status(conn, options): - if options.has_key("--use-sudo"): + if "--use-sudo" in options: prefix = options["--sudo-path"] + " " else: prefix = "" conn.sendline(prefix + "virsh list --all") conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) 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(r"^\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 def get_power_status(conn, options): - prefix = options["--sudo-path"] + " " if options.has_key("--use-sudo") else "" + prefix = options["--sudo-path"] + " " if "--use-sudo" in options else "" conn.sendline(prefix + "virsh domstate %s" % (get_name_or_uuid(options))) conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) for line in conn.before.splitlines(): if line.strip() in ["running", "blocked", "idle", "no state", "paused"]: return "on" - if "error: failed to get domain" in line.strip() and options.has_key("--missing-as-off"): + if "error: failed to get domain" in line.strip() and "--missing-as-off" in options: return "off" if "error:" in line.strip(): fail_usage("Failed: You have to enter existing name/UUID of virtual machine!") return "off" def set_power_status(conn, options): - prefix = options["--sudo-path"] + " " if options.has_key("--use-sudo") else "" + prefix = options["--sudo-path"] + " " if "--use-sudo" in options else "" conn.sendline(prefix + "virsh %s " % (options["--action"] == "on" and "start" or "destroy") + get_name_or_uuid(options)) conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) time.sleep(int(options["--power-wait"])) def main(): device_opt = ["ipaddr", "login", "passwd", "cmd_prompt", "secure", "port", "sudo", "missing_as_off"] atexit.register(atexit_handler) all_opt["secure"]["default"] = "1" all_opt["cmd_prompt"]["default"] = [r"\[EXPECT\]#\ "] all_opt["ssh_options"]["default"] = "-t '/bin/bash -c \"" + r"PS1=\\[EXPECT\\]#\ " + "/bin/bash --noprofile --norc\"'" options = check_input(device_opt, process_input(device_opt)) docs = {} docs["shortdesc"] = "Fence agent for virsh" docs["longdesc"] = "fence_virsh is an I/O Fencing agent \ which can be used with the virtual machines managed by libvirt. \ It logs via ssh to a dom0 and there run virsh command, which does \ all work. \ \n.P\n\ By default, virsh needs root account to do properly work. So you \ must allow ssh login in your sshd_config." docs["vendorurl"] = "http://libvirt.org" show_docs(options, docs) ## Operate the fencing device conn = fence_login(options) result = fence_action(conn, options, set_power_status, get_power_status, get_outlets_status) fence_logout(conn, "quit") sys.exit(result) if __name__ == "__main__": main() diff --git a/fence/agents/vmware/fence_vmware.py b/fence/agents/vmware/fence_vmware.py index e252fe3f..8bb061e4 100644 --- a/fence/agents/vmware/fence_vmware.py +++ b/fence/agents/vmware/fence_vmware.py @@ -1,342 +1,342 @@ -#!/usr/bin/python -tt +#!@PYTHON@ -tt # # The Following agent has been tested on: # vmrun 2.0.0 build-116503 (from VMware Server 2.0) against: # VMware ESX 4.0.0 # VMware vCenter 4.0.0 # VMware ESX 3.5 # VMware Server 2.0.0 # VMware ESXi 3.5 update 2 # VMware Server 1.0.7 (works but list/status show only running VMs) # # VI Perl API 1.6 against: # VMware ESX 4.0.0 # VMware vCenter 4.0.0 # VMware ESX 3.5 # VMware ESXi 3.5 update 2 # VMware Virtual Center 2.5 # # VMware vSphere SDK for Perl 4.0.0 against: # VMware ESX 4.0.0 # VMware vCenter 4.0.0 # import sys, re, pexpect import logging import atexit sys.path.append("@FENCEAGENTSLIBDIR@") from fencing import * from fencing import fail, fail_usage, EC_TIMED_OUT, run_delay #BEGIN_VERSION_GENERATION RELEASE_VERSION="VMware Agent using VI Perl API and/or VIX vmrun command" REDHAT_COPYRIGHT="" BUILD_DATE="" #END_VERSION_GENERATION ### CONSTANTS #### # VMware type is ESX/ESXi/VC VMWARE_TYPE_ESX = 0 # VMware type is Server 1.x VMWARE_TYPE_SERVER1 = 1 # VMware type is Server 2.x and/or ESX 3.5 up2, ESXi 3.5 up2, VC 2.5 up2 VMWARE_TYPE_SERVER2 = 2 # Minimum required version of vmrun command VMRUN_MINIMUM_REQUIRED_VERSION = 2 # Default path to vmhelper command VMHELPER_COMMAND = "fence_vmware_helper" # Default path to vmrun command VMRUN_COMMAND = "/usr/bin/vmrun" # Default type of vmware VMWARE_DEFAULT_TYPE = "esx" #### GLOBAL VARIABLES #### # Internal type. One of VMWARE_TYPE_, set by #vmware_check_vmware_type vmware_internal_type = VMWARE_TYPE_ESX # If ESX is disconnected, say, that VM is off (don't return previous state) vmware_disconnected_hack = False ### FUNCTIONS #### #Split string in simplified DSV format to array of items def dsv_split(dsv_str): delimiter_c = ':' escape_c = '\\' res = [] status = 0 tmp_str = "" for x in dsv_str: if status == 0: if x == delimiter_c: res.append(tmp_str) tmp_str = "" elif x == escape_c: status = 1 else: tmp_str += x elif status == 1: if x == delimiter_c: tmp_str += delimiter_c elif x == escape_c: tmp_str += escape_c else: tmp_str += escape_c+x status = 0 if tmp_str != "": res.append(tmp_str) return res # Quote string for proper existence in quoted string used for pexpect.run function # Ex. test'this will return test'\''this. So pexpect run will really pass ' to argument def quote_for_run(text): dstr = '' for c in text: if c == r"'": dstr += "'\\''" else: dstr += c return dstr # Return string with command and additional parameters (something like vmrun -h 'host' def vmware_prepare_command(options, add_login_params, additional_params): res = options["--exec"] if add_login_params: if vmware_internal_type == VMWARE_TYPE_ESX: res += " --server '%s' --username '%s' --password '%s' "% (quote_for_run(options["--ip"]), quote_for_run(options["--username"]), quote_for_run(options["--password"])) elif vmware_internal_type == VMWARE_TYPE_SERVER2: res += " -h 'https://%s/sdk' -u '%s' -p '%s' -T server "% (quote_for_run(options["--ip"]), quote_for_run(options["--username"]), quote_for_run(options["--password"])) elif vmware_internal_type == VMWARE_TYPE_SERVER1: host_name_array = options["--ip"].split(':') res += " -h '%s' -u '%s' -p '%s' -T server1 "% (quote_for_run(host_name_array[0]), quote_for_run(options["--username"]), quote_for_run(options["--password"])) if len(host_name_array) > 1: res += "-P '%s' "% (quote_for_run(host_name_array[1])) - if options.has_key("--vmware-datacenter") and vmware_internal_type == VMWARE_TYPE_ESX: + if "--vmware-datacenter" in options and vmware_internal_type == VMWARE_TYPE_ESX: res += "--datacenter '%s' "% (quote_for_run(options["--vmware-datacenter"])) if additional_params != "": res += additional_params return res # Run command with timeout and parameters. Internaly uses vmware_prepare_command. Returns string # with output from vmrun command. If something fails (command not found, exit code is not 0), fail_usage # function is called (and never return). def vmware_run_command(options, add_login_params, additional_params, additional_timeout): command = vmware_prepare_command(options, add_login_params, additional_params) try: logging.debug("%s\n", command) (res_output, res_code) = pexpect.run(command, int(options["--shell-timeout"]) + int(options["--login-timeout"]) + additional_timeout, True) if res_code == None: fail(EC_TIMED_OUT) if res_code != 0 and add_login_params: logging.debug("%s\n", res_output) fail_usage("%s returned %s"% (options["--exec"], res_output)) else: logging.debug("%s\n", res_output) except pexpect.ExceptionPexpect: fail_usage("Cannot run command %s"% (options["--exec"])) return res_output # Get outlet list with status as hash table. If you will use add_vm_name, only VM with vmname is # returned. This is used in get_status function def vmware_get_outlets_vi(options, add_vm_name): outlets = {} if add_vm_name: all_machines = vmware_run_command(options, True, ("--operation status --vmname '%s'"% (quote_for_run(options["--plug"]))), 0) else: all_machines = vmware_run_command(options, True, "--operation list", int(options["--power-timeout"])) all_machines_array = all_machines.splitlines() for machine in all_machines_array: machine_array = dsv_split(machine) if len(machine_array) == 4: if machine_array[0] in outlets: fail_usage("Failed. More machines with same name %s found!"%(machine_array[0])) if vmware_disconnected_hack: outlets[machine_array[0]] = ("", ( ((machine_array[2].lower() in ["poweredon"]) and (machine_array[3].lower() == "connected")) and "on" or "off")) else: outlets[machine_array[0]] = ("", ((machine_array[2].lower() in ["poweredon"]) and "on" or "off")) return outlets # Get outlet list with status as hash table. def vmware_get_outlets_vix(options): outlets = {} running_machines = vmware_run_command(options, True, "list", 0) running_machines_array = running_machines.splitlines()[1:] if vmware_internal_type == VMWARE_TYPE_SERVER2: all_machines = vmware_run_command(options, True, "listRegisteredVM", 0) all_machines_array = all_machines.splitlines()[1:] elif vmware_internal_type == VMWARE_TYPE_SERVER1: all_machines_array = running_machines_array for machine in all_machines_array: if machine != "": outlets[machine] = ("", ((machine in running_machines_array) and "on" or "off")) return outlets def get_outlets_status(conn, options): del conn if vmware_internal_type == VMWARE_TYPE_ESX: return vmware_get_outlets_vi(options, False) if vmware_internal_type == VMWARE_TYPE_SERVER1 or vmware_internal_type == VMWARE_TYPE_SERVER2: return vmware_get_outlets_vix(options) def get_power_status(conn, options): if vmware_internal_type == VMWARE_TYPE_ESX: outlets = vmware_get_outlets_vi(options, True) else: outlets = get_outlets_status(conn, options) if vmware_internal_type == VMWARE_TYPE_SERVER2 or vmware_internal_type == VMWARE_TYPE_ESX: if not options["--plug"] in outlets: fail_usage("Failed: You have to enter existing name of virtual machine!") else: return outlets[options["--plug"]][1] elif vmware_internal_type == VMWARE_TYPE_SERVER1: return (options["--plug"] in outlets) and "on" or "off" def set_power_status(conn, options): del conn if vmware_internal_type == VMWARE_TYPE_ESX: additional_params = "--operation %s --vmname '%s'" % \ ((options["--action"] == "on" and "on" or "off"), quote_for_run(options["--plug"])) elif vmware_internal_type == VMWARE_TYPE_SERVER1 or vmware_internal_type == VMWARE_TYPE_SERVER2: additional_params = "%s '%s'" % \ ((options["--action"] == "on" and "start" or "stop"), quote_for_run(options["--plug"])) if options["--action"] == "off": additional_params += " hard" vmware_run_command(options, True, additional_params, int(options["--power-timeout"])) # Returns True, if user uses supported vmrun version (currently >=2.0.0) otherwise False. def vmware_is_supported_vmrun_version(options): vmware_help_str = vmware_run_command(options, False, "", 0) version_re = re.search(r"vmrun version (\d\.(\d[\.]*)*)", vmware_help_str.lower()) if version_re == None: return False # Looks like this "vmrun" is not real vmrun version_array = version_re.group(1).split(".") try: if int(version_array[0]) < VMRUN_MINIMUM_REQUIRED_VERSION: return False except Exception: return False return True # Check vmware type, set vmware_internal_type to one of VMWARE_TYPE_ value and # options["--exec"] to path (if not specified) def vmware_check_vmware_type(options): global vmware_internal_type options["--vmware_type"] = options["--vmware_type"].lower() if options["--vmware_type"] == "esx": vmware_internal_type = VMWARE_TYPE_ESX - if not options.has_key("--exec"): + if "--exec" not in options: options["--exec"] = VMHELPER_COMMAND elif options["--vmware_type"] == "server2": vmware_internal_type = VMWARE_TYPE_SERVER2 - if not options.has_key("--exec"): + if "--exec" not in options: options["--exec"] = VMRUN_COMMAND elif options["--vmware_type"] == "server1": vmware_internal_type = VMWARE_TYPE_SERVER1 - if not options.has_key("--exec"): + if "--exec" not in options: options["--exec"] = VMRUN_COMMAND else: fail_usage("vmware_type can be esx,server2 or server1!") # Main agent method def main(): device_opt = ["ipaddr", "login", "passwd", "secure", "exec", "vmware_type", "vmware_datacenter"] atexit.register(atexit_handler) all_opt["secure"]["default"] = "1" all_opt["vmware_type"]["default"] = VMWARE_DEFAULT_TYPE options = check_input(device_opt, process_input(device_opt)) docs = {} docs["shortdesc"] = "Fence agent for VMWare" docs["longdesc"] = "fence_vmware is an I/O Fencing agent \ which can be used with the VMware ESX, VMware ESXi or VMware Server \ to fence virtual machines.\ \n.P\n\ Before you can use this agent, it must be installed VI Perl Toolkit or \ vmrun command on every node you want to make fencing.\ \n.P\n\ VI Perl Toolkit is preferred for VMware ESX/ESXi and Virtual Center. Vmrun \ command is only solution for VMware Server 1/2 (this command will works against \ ESX/ESXi 3.5 up2 and VC up2 too, but not cluster aware!) and is available as part \ of VMware VIX API SDK package. VI Perl and VIX API SDK are both available from \ VMware web pages (not int RHEL repository!). \ \n.P\n\ You can specify type of VMware you are connecting to with \\fB-d\\fP switch \ (or \\fIvmware_type\\fR for stdin). Possible values are esx, server2 and server1.\ Default value is esx, which will use VI Perl. With server1 and server2, vmrun \ command is used.\ \n.P\n\ After you have successfully installed VI Perl Toolkit or VIX API, you should \ be able to run fence_vmware_helper (part of this agent) or vmrun command. \ This agent supports only vmrun from version 2.0.0 (VIX API 1.6.0)." docs["vendorurl"] = "http://www.vmware.com" show_docs(options, docs) run_delay(options) # Check vmware type and set path vmware_check_vmware_type(options) # Test user vmrun command version if vmware_internal_type == VMWARE_TYPE_SERVER1 or vmware_internal_type == VMWARE_TYPE_SERVER2: if not vmware_is_supported_vmrun_version(options): fail_usage("Unsupported version of vmrun command! You must use at least version %d!" % (VMRUN_MINIMUM_REQUIRED_VERSION)) # Operate the fencing device result = fence_action(None, options, set_power_status, get_power_status, get_outlets_status) sys.exit(result) if __name__ == "__main__": main() diff --git a/fence/agents/vmware_soap/fence_vmware_soap.py b/fence/agents/vmware_soap/fence_vmware_soap.py index e47f11e5..df84ae55 100644 --- a/fence/agents/vmware_soap/fence_vmware_soap.py +++ b/fence/agents/vmware_soap/fence_vmware_soap.py @@ -1,257 +1,257 @@ -#!/usr/bin/python -tt +#!@PYTHON@ -tt import sys import shutil, tempfile, suds import logging, requests import atexit sys.path.append("@FENCEAGENTSLIBDIR@") from suds.client import Client from suds.sudsobject import Property from suds.transport.http import HttpAuthenticated from suds.transport import Reply, TransportError from fencing import * from fencing import fail, fail_usage, EC_STATUS, EC_LOGIN_DENIED, EC_INVALID_PRIVILEGES, EC_WAITING_ON, EC_WAITING_OFF from fencing import run_delay #BEGIN_VERSION_GENERATION RELEASE_VERSION="New VMWare Agent - test release on steroids" REDHAT_COPYRIGHT="" BUILD_DATE="April, 2011" #END_VERSION_GENERATION options_global = None conn_global = None class RequestsTransport(HttpAuthenticated): def __init__(self, **kwargs): self.cert = kwargs.pop('cert', None) self.verify = kwargs.pop('verify', True) self.session = requests.Session() # super won't work because not using new style class HttpAuthenticated.__init__(self, **kwargs) def send(self, request): self.addcredentials(request) resp = self.session.post(request.url, data=request.message, headers=request.headers, cert=self.cert, verify=self.verify) result = Reply(resp.status_code, resp.headers, resp.content) return result def soap_login(options): run_delay(options) - if options.has_key("--ssl") or options.has_key("--ssl-secure") or options.has_key("--ssl-insecure"): - if options.has_key("--ssl-insecure"): + if "--ssl" in options or "--ssl-secure" in options or "--ssl-insecure" in options: + if "--ssl-insecure" in options: verify = False else: verify = True url = "https://" else: verify = False url = "http://" url += options["--ip"] + ":" + str(options["--ipport"]) + "/sdk" tmp_dir = tempfile.mkdtemp() tempfile.tempdir = tmp_dir atexit.register(remove_tmp_dir, tmp_dir) try: headers = {"Content-Type" : "text/xml;charset=UTF-8", "SOAPAction" : ""} conn = Client(url + "/vimService.wsdl", location=url, transport=RequestsTransport(verify=verify), headers=headers) mo_ServiceInstance = Property('ServiceInstance') mo_ServiceInstance._type = 'ServiceInstance' ServiceContent = conn.service.RetrieveServiceContent(mo_ServiceInstance) mo_SessionManager = Property(ServiceContent.sessionManager.value) mo_SessionManager._type = 'SessionManager' conn.service.Login(mo_SessionManager, options["--username"], options["--password"]) - except requests.exceptions.SSLError, ex: + except requests.exceptions.SSLError as ex: fail_usage("Server side certificate verification failed") except Exception: fail(EC_LOGIN_DENIED) options["ServiceContent"] = ServiceContent options["mo_SessionManager"] = mo_SessionManager return conn def process_results(results, machines, uuid, mappingToUUID): for m in results.objects: info = {} for i in m.propSet: info[i.name] = i.val # Prevent error KeyError: 'config.uuid' when reaching systems which P2V failed, # since these systems don't have a valid UUID - if info.has_key("config.uuid"): + if "config.uuid" in info: machines[info["name"]] = (info["config.uuid"], info["summary.runtime.powerState"]) uuid[info["config.uuid"]] = info["summary.runtime.powerState"] mappingToUUID[m.obj.value] = info["config.uuid"] return (machines, uuid, mappingToUUID) def get_power_status(conn, options): mo_ViewManager = Property(options["ServiceContent"].viewManager.value) mo_ViewManager._type = "ViewManager" mo_RootFolder = Property(options["ServiceContent"].rootFolder.value) mo_RootFolder._type = "Folder" mo_PropertyCollector = Property(options["ServiceContent"].propertyCollector.value) mo_PropertyCollector._type = 'PropertyCollector' ContainerView = conn.service.CreateContainerView(mo_ViewManager, recursive=1, container=mo_RootFolder, type=['VirtualMachine']) mo_ContainerView = Property(ContainerView.value) mo_ContainerView._type = "ContainerView" FolderTraversalSpec = conn.factory.create('ns0:TraversalSpec') FolderTraversalSpec.name = "traverseEntities" FolderTraversalSpec.path = "view" FolderTraversalSpec.skip = False FolderTraversalSpec.type = "ContainerView" objSpec = conn.factory.create('ns0:ObjectSpec') objSpec.obj = mo_ContainerView objSpec.selectSet = [FolderTraversalSpec] objSpec.skip = True propSpec = conn.factory.create('ns0:PropertySpec') propSpec.all = False propSpec.pathSet = ["name", "summary.runtime.powerState", "config.uuid"] propSpec.type = "VirtualMachine" propFilterSpec = conn.factory.create('ns0:PropertyFilterSpec') propFilterSpec.propSet = [propSpec] propFilterSpec.objectSet = [objSpec] try: raw_machines = conn.service.RetrievePropertiesEx(mo_PropertyCollector, propFilterSpec) except Exception: fail(EC_STATUS) (machines, uuid, mappingToUUID) = process_results(raw_machines, {}, {}, {}) # Probably need to loop over the ContinueRetreive if there are more results after 1 iteration. while hasattr(raw_machines, 'token'): try: raw_machines = conn.service.ContinueRetrievePropertiesEx(mo_PropertyCollector, raw_machines.token) except Exception: fail(EC_STATUS) (more_machines, more_uuid, more_mappingToUUID) = process_results(raw_machines, {}, {}, {}) machines.update(more_machines) uuid.update(more_uuid) mappingToUUID.update(more_mappingToUUID) # Do not run unnecessary SOAP requests - if options.has_key("--uuid") and options["--uuid"] in uuid: + if "--uuid" in options and options["--uuid"] in uuid: break if ["list", "monitor"].count(options["--action"]) == 1: return machines else: - if not options.has_key("--uuid"): + if "--uuid" not in options: if options["--plug"].startswith('/'): ## Transform InventoryPath to UUID mo_SearchIndex = Property(options["ServiceContent"].searchIndex.value) mo_SearchIndex._type = "SearchIndex" vm = conn.service.FindByInventoryPath(mo_SearchIndex, options["--plug"]) try: options["--uuid"] = mappingToUUID[vm.value] except KeyError: fail(EC_STATUS) except AttributeError: fail(EC_STATUS) else: ## Name of virtual machine instead of path ## warning: if you have same names of machines this won't work correctly try: (options["--uuid"], _) = machines[options["--plug"]] except KeyError: fail(EC_STATUS) except AttributeError: fail(EC_STATUS) try: if uuid[options["--uuid"]] == "poweredOn": return "on" else: return "off" except KeyError: fail(EC_STATUS) def set_power_status(conn, options): mo_SearchIndex = Property(options["ServiceContent"].searchIndex.value) mo_SearchIndex._type = "SearchIndex" vm = conn.service.FindByUuid(mo_SearchIndex, vmSearch=1, uuid=options["--uuid"]) mo_machine = Property(vm.value) mo_machine._type = "VirtualMachine" try: if options["--action"] == "on": conn.service.PowerOnVM_Task(mo_machine) else: conn.service.PowerOffVM_Task(mo_machine) - except suds.WebFault, ex: + except suds.WebFault as ex: if (str(ex).find("Permission to perform this operation was denied")) >= 0: fail(EC_INVALID_PRIVILEGES) else: if options["--action"] == "on": fail(EC_WAITING_ON) else: fail(EC_WAITING_OFF) def remove_tmp_dir(tmp_dir): shutil.rmtree(tmp_dir) def logout(): try: conn_global.service.Logout(options_global["mo_SessionManager"]) except Exception: pass def main(): global options_global global conn_global device_opt = ["ipaddr", "login", "passwd", "web", "ssl", "notls", "port"] atexit.register(atexit_handler) atexit.register(logout) options_global = check_input(device_opt, process_input(device_opt)) ## ## Fence agent specific defaults ##### docs = {} docs["shortdesc"] = "Fence agent for VMWare over SOAP API" docs["longdesc"] = "fence_vmware_soap is an I/O Fencing agent \ which can be used with the virtual machines managed by VMWare products \ that have SOAP API v4.1+. \ \n.P\n\ Name of virtual machine (-n / port) has to be used in inventory path \ format (e.g. /datacenter/vm/Discovered virtual machine/myMachine). \ In the cases when name of yours VM is unique you can use it instead. \ Alternatively you can always use UUID to access virtual machine." docs["vendorurl"] = "http://www.vmware.com" show_docs(options_global, docs) logging.basicConfig(level=logging.INFO) logging.getLogger('suds.client').setLevel(logging.CRITICAL) logging.getLogger("requests").setLevel(logging.CRITICAL) logging.getLogger("urllib3").setLevel(logging.CRITICAL) ## ## Operate the fencing device #### conn_global = soap_login(options_global) result = fence_action(conn_global, options_global, set_power_status, get_power_status, get_power_status) ## Logout from system is done automatically via atexit() sys.exit(result) if __name__ == "__main__": main() diff --git a/fence/agents/wti/fence_wti.py b/fence/agents/wti/fence_wti.py index f4ab51b7..a7b2f0de 100644 --- a/fence/agents/wti/fence_wti.py +++ b/fence/agents/wti/fence_wti.py @@ -1,245 +1,245 @@ -#!/usr/bin/python -tt +#!@PYTHON@ -tt ##### ## ## The Following Agent Has Been Tested On: ## ## Version Firmware ## +-----------------+---------------------------+ ## WTI RSM-8R4 ?? unable to find out ?? ## WTI MPC-??? ?? unable to find out ?? ## WTI IPS-800-CE v1.40h (no username) ('list' tested) ##### import sys, re, pexpect import atexit import time sys.path.append("@FENCEAGENTSLIBDIR@") from fencing import * from fencing import fspawn, fail, fail_usage, EC_LOGIN_DENIED #BEGIN_VERSION_GENERATION RELEASE_VERSION="New WTI Agent - test release on steroids" REDHAT_COPYRIGHT="" BUILD_DATE="March, 2008" #END_VERSION_GENERATION def get_listing(conn, options, listing_command): listing = "" conn.send_eol(listing_command) if isinstance(options["--command-prompt"], list): re_all = list(options["--command-prompt"]) else: re_all = [options["--command-prompt"]] re_next = re.compile("Enter: ", re.IGNORECASE) re_all.append(re_next) result = conn.log_expect(re_all, int(options["--shell-timeout"])) listing = conn.before if result == (len(re_all) - 1): conn.send_eol("") conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) listing += conn.before return listing def get_plug_status(conn, options): listing = get_listing(conn, options, "/S") plug_section = 0 plug_index = -1 name_index = -1 status_index = -1 plug_header = list() outlets = {} for line in listing.splitlines(): if (plug_section == 2) and line.find("|") >= 0 and line.startswith("PLUG") == False: plug_line = [x.strip().lower() for x in line.split("|")] if len(plug_line) < len(plug_header): plug_section = -1 if ["list", "monitor"].count(options["--action"]) == 0 and \ options["--plug"].lower() == plug_line[plug_index]: return plug_line[status_index] else: ## We already believe that first column contains plug number if len(plug_line[0]) != 0: outlets[plug_line[0]] = (plug_line[name_index], plug_line[status_index]) elif plug_section == 1: plug_section = 2 elif line.upper().startswith("PLUG"): plug_section = 1 plug_header = [x.strip().lower() for x in line.split("|")] plug_index = plug_header.index("plug") name_index = plug_header.index("name") status_index = plug_header.index("status") if ["list", "monitor"].count(options["--action"]) == 1: return outlets else: return "PROBLEM" def get_plug_group_status_from_list(status_list): for status in status_list: if status == "on": return status return "off" def get_plug_group_status(conn, options): listing = get_listing(conn, options, "/SG") outlets = {} line_index = 0 status_index = -1 plug_index = -1 name_index = -1 lines = listing.splitlines() while line_index < len(lines) and line_index >= 0: line = lines[line_index] if line.find("|") >= 0 and line.lstrip().startswith("GROUP NAME") == False: plug_line = [x.strip().lower() for x in line.split("|")] if ["list", "monitor"].count(options["--action"]) == 0 and \ options["--plug"].lower() == plug_line[name_index]: plug_status = [] while line_index < len(lines) and line_index >= 0: plug_line = [x.strip().lower() for x in lines[line_index].split("|")] if len(plug_line) >= max(name_index, status_index) and \ len(plug_line[plug_index]) > 0 and \ (len(plug_line[name_index]) == 0 or options["--plug"].lower() == plug_line[name_index]): ## Firmware 1.43 does not have a valid value of plug on first line as only name is defined on that line if not "---" in plug_line[status_index]: plug_status.append(plug_line[status_index]) line_index += 1 else: line_index = -1 return get_plug_group_status_from_list(plug_status) else: ## We already believe that first column contains plug number if len(plug_line[0]) != 0: group_name = plug_line[0] plug_line_index = line_index + 1 plug_status = [] while plug_line_index < len(lines) and plug_line_index >= 0: plug_line = [x.strip().lower() for x in lines[plug_line_index].split("|")] if len(plug_line[name_index]) > 0: plug_line_index = -1 break if len(plug_line[plug_index]) > 0: plug_status.append(plug_line[status_index]) plug_line_index += 1 else: plug_line_index = -1 outlets[group_name] = (group_name, get_plug_group_status_from_list(plug_status)) line_index += 1 elif line.upper().lstrip().startswith("GROUP NAME"): plug_header = [x.strip().lower() for x in line.split("|")] name_index = plug_header.index("group name") plug_index = plug_header.index("plug") status_index = plug_header.index("status") line_index += 2 else: line_index += 1 if ["list", "monitor"].count(options["--action"]) == 1: results = {} - for group, status in outlets.items(): + for group, status in list(outlets.items()): results[group] = (group, status[0]) return results else: return "PROBLEM" def get_power_status(conn, options): if ["list"].count(options["--action"]) == 0: ret = get_plug_status(conn, options) if ret == "PROBLEM": ret = get_plug_group_status(conn, options) else: - ret = dict(get_plug_status(conn, options).items() + \ - get_plug_group_status(conn, options).items()) + ret = dict(list(get_plug_status(conn, options).items()) + \ + list(get_plug_group_status(conn, options).items())) return ret def set_power_status(conn, options): action = { 'on' : "/on", 'off': "/off" }[options["--action"]] conn.send_eol(action + " " + options["--plug"] + ",y") conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) def main(): device_opt = ["ipaddr", "login", "passwd", "no_login", "no_password", \ "cmd_prompt", "secure", "port", "telnet"] atexit.register(atexit_handler) all_opt["cmd_prompt"]["default"] = ["RSM>", "MPC>", "IPS>", "TPS>", "NBB>", "NPS>", "VMR>"] options = check_input(device_opt, process_input(device_opt)) docs = {} docs["shortdesc"] = "Fence agent for WTI" docs["longdesc"] = "fence_wti is an I/O Fencing agent \ which can be used with the WTI Network Power Switch (NPS). It logs \ into an NPS via telnet or ssh and boots a specified plug. \ Lengthy telnet connections to the NPS should be avoided while a GFS cluster \ is running because the connection will block any necessary fencing actions." docs["vendorurl"] = "http://www.wti.com" show_docs(options, docs) ## ## Operate the fencing device ## ## @note: if it possible that this device does not need either login, password or both of them ##### - if not options.has_key("--ssh"): + if "--ssh" not in options: try: if options["--action"] in ["off", "reboot"]: time.sleep(int(options["--delay"])) options["eol"] = "\r\n" conn = fspawn(options, options["--telnet-path"]) conn.send("set binary\n") conn.send("open %s -%s\n"%(options["--ip"], options["--ipport"])) re_login = re.compile("(login: )|(Login Name: )|(username: )|(User Name :)", re.IGNORECASE) re_prompt = re.compile("|".join(["(" + x + ")" for x in options["--command-prompt"]]), re.IGNORECASE) result = conn.log_expect([re_login, "Password: ", re_prompt], int(options["--shell-timeout"])) if result == 0: - if options.has_key("--username"): + if "--username" in options: conn.send_eol(options["--username"]) result = conn.log_expect([re_login, "Password: ", re_prompt], int(options["--shell-timeout"])) else: fail_usage("Failed: You have to set login name") if result == 1: - if options.has_key("--password"): + if "--password" in options: conn.send_eol(options["--password"]) conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) else: fail_usage("Failed: You have to enter password or password script") except pexpect.EOF: fail(EC_LOGIN_DENIED) except pexpect.TIMEOUT: fail(EC_LOGIN_DENIED) else: conn = fence_login(options) result = fence_action(conn, options, set_power_status, get_power_status, get_power_status) fence_logout(conn, "/X") sys.exit(result) if __name__ == "__main__": main() diff --git a/fence/agents/xenapi/fence_xenapi.py b/fence/agents/xenapi/fence_xenapi.py index 5fe7646b..ccddf2d9 100644 --- a/fence/agents/xenapi/fence_xenapi.py +++ b/fence/agents/xenapi/fence_xenapi.py @@ -1,227 +1,227 @@ -#!/usr/bin/python -tt +#!@PYTHON@ -tt # ############################################################################# # Copyright 2011 Matthew Clark # This file is part of fence-xenserver # # fence-xenserver is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # fence-xenserver is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # Please let me know if you are using this script so that I can work out # whether I should continue support for it. mattjclark0407 at hotmail dot com ############################################################################# ############################################################################# # It's only just begun... # Current status: completely usable. This script is now working well and, # has a lot of functionality as a result of the fencing.py library and the # XenAPI libary. ############################################################################# # Please let me know if you are using this script so that I can work out # whether I should continue support for it. mattjclark0407 at hotmail dot com import sys import atexit sys.path.append("@FENCEAGENTSLIBDIR@") from fencing import * from fencing import run_delay import XenAPI #BEGIN_VERSION_GENERATION RELEASE_VERSION="" REDHAT_COPYRIGHT="" BUILD_DATE="" #END_VERSION_GENERATION EC_BAD_SESSION = 1 # Find the status of the port given in the -U flag of options. def get_power_fn(session, options): - if options.has_key("--verbose"): + if "--verbose" in options: verbose = True else: verbose = False try: # Get a reference to the vm specified in the UUID or vm_name/port parameter vm = return_vm_reference(session, options) # Query the VM for its' associated parameters record = session.xenapi.VM.get_record(vm) # Check that we are not trying to manipulate a template or a control # domain as they show up as VM's with specific properties. if not record["is_a_template"] and not record["is_control_domain"]: status = record["power_state"] if verbose: - print "UUID:", record["uuid"], "NAME:", record["name_label"], "POWER STATUS:", record["power_state"] + print("UUID:", record["uuid"], "NAME:", record["name_label"], "POWER STATUS:", record["power_state"]) # Note that the VM can be in the following states (from the XenAPI document) # Halted: VM is offline and not using any resources. # Paused: All resources have been allocated but the VM itself is paused and its vCPUs are not running # Running: Running # Paused: VM state has been saved to disk and it is nolonger running. Note that disks remain in-Use while # We want to make sure that we only return the status "off" if the machine is actually halted as the status # is checked before a fencing action. Only when the machine is Halted is it not consuming resources which # may include whatever you are trying to protect with this fencing action. return status == "Halted" and "off" or "on" - except Exception, exn: - print str(exn) + except Exception as exn: + print(str(exn)) return "Error" # Set the state of the port given in the -U flag of options. def set_power_fn(session, options): try: # Get a reference to the vm specified in the UUID or vm_name/port parameter vm = return_vm_reference(session, options) # Query the VM for its' associated parameters record = session.xenapi.VM.get_record(vm) # Check that we are not trying to manipulate a template or a control # domain as they show up as VM's with specific properties. if not record["is_a_template"] and not record["is_control_domain"]: if options["--action"] == "on": # Start the VM session.xenapi.VM.start(vm, False, True) elif options["--action"] == "off": # Force shutdown the VM session.xenapi.VM.hard_shutdown(vm) elif options["--action"] == "reboot": # Force reboot the VM session.xenapi.VM.hard_reboot(vm) - except Exception, exn: - print str(exn) + except Exception as exn: + print(str(exn)) # Function to populate an array of virtual machines and their status def get_outlet_list(session, options): result = {} - if options.has_key("--verbose"): + if "--verbose" in options: verbose = True else: verbose = False try: # Return an array of all the VM's on the host vms = session.xenapi.VM.get_all() for vm in vms: # Query the VM for its' associated parameters record = session.xenapi.VM.get_record(vm) # Check that we are not trying to manipulate a template or a control # domain as they show up as VM's with specific properties. if not record["is_a_template"] and not record["is_control_domain"]: name = record["name_label"] uuid = record["uuid"] status = record["power_state"] result[uuid] = (name, status) if verbose: - print "UUID:", record["uuid"], "NAME:", name, "POWER STATUS:", record["power_state"] - except Exception, exn: - print str(exn) + print("UUID:", record["uuid"], "NAME:", name, "POWER STATUS:", record["power_state"]) + except Exception as exn: + print(str(exn)) return result # Function to initiate the XenServer session via the XenAPI library. def connect_and_login(options): url = options["--session-url"] username = options["--username"] password = options["--password"] try: # Create the XML RPC session to the specified URL. session = XenAPI.Session(url) # Login using the supplied credentials. session.xenapi.login_with_password(username, password) - except Exception, exn: - print str(exn) + except Exception as exn: + print(str(exn)) # http://sources.redhat.com/cluster/wiki/FenceAgentAPI says that for no connectivity # the exit value should be 1. It doesn't say anything about failed logins, so # until I hear otherwise it is best to keep this exit the same to make sure that # anything calling this script (that uses the same information in the web page # above) knows that this is an error condition, not a msg signifying a down port. sys.exit(EC_BAD_SESSION) return session # return a reference to the VM by either using the UUID or the vm_name/port. If the UUID is set then # this is tried first as this is the only properly unique identifier. # Exceptions are not handled in this function, code that calls this must be ready to handle them. def return_vm_reference(session, options): - if options.has_key("--verbose"): + if "--verbose" in options: verbose = True else: verbose = False # Case where the UUID has been specified - if options.has_key("--uuid"): + if "--uuid" in options: uuid = options["--uuid"].lower() # When using the -n parameter for name, we get an error message (in verbose # mode) that tells us that we didn't find a VM. To immitate that here we # need to catch and re-raise the exception produced by get_by_uuid. try: return session.xenapi.VM.get_by_uuid(uuid) except Exception: if verbose: - print "No VM's found with a UUID of \"%s\"" % uuid + print("No VM's found with a UUID of \"%s\"" % uuid) raise # Case where the vm_name/port has been specified - if options.has_key("--plug"): + if "--plug" in options: vm_name = options["--plug"] vm_arr = session.xenapi.VM.get_by_name_label(vm_name) # Need to make sure that we only have one result as the vm_name may # not be unique. Average case, so do it first. if len(vm_arr) == 1: return vm_arr[0] else: if len(vm_arr) == 0: if verbose: - print "No VM's found with a name of \"%s\"" % vm_name + print("No VM's found with a name of \"%s\"" % vm_name) # NAME_INVALID used as the XenAPI throws a UUID_INVALID if it can't find # a VM with the specified UUID. This should make the output look fairly # consistent. raise Exception("NAME_INVALID") else: if verbose: - print "Multiple VM's have the name \"%s\", use UUID instead" % vm_name + print("Multiple VM's have the name \"%s\", use UUID instead" % vm_name) raise Exception("MULTIPLE_VMS_FOUND") # We should never get to this case as the input processing checks that either the UUID or # the name parameter is set. Regardless of whether or not a VM is found the above if # statements will return to the calling function (either by exception or by a reference # to the VM). raise Exception("VM_LOGIC_ERROR") def main(): device_opt = ["login", "passwd", "port", "no_login", "no_password", "session_url", "web"] atexit.register(atexit_handler) options = check_input(device_opt, process_input(device_opt)) docs = {} docs["shortdesc"] = "Fence agent for Citrix XenServer over XenAPI" docs["longdesc"] = "\ fence_cxs is an I/O Fencing agent used on Citrix XenServer hosts. \ It uses the XenAPI, supplied by Citrix, to establish an XML-RPC sesssion \ to a XenServer host. Once the session is established, further XML-RPC \ commands are issued in order to switch on, switch off, restart and query \ the status of virtual machines running on the host." docs["vendorurl"] = "http://www.xenproject.org" show_docs(options, docs) run_delay(options) xen_session = connect_and_login(options) result = fence_action(xen_session, options, set_power_fn, get_power_fn, get_outlet_list) sys.exit(result) if __name__ == "__main__": main() diff --git a/fence/agents/zvm/fence_zvmip.py b/fence/agents/zvm/fence_zvmip.py index 08c7ae7c..f4214fc3 100644 --- a/fence/agents/zvm/fence_zvmip.py +++ b/fence/agents/zvm/fence_zvmip.py @@ -1,195 +1,195 @@ -#!/usr/bin/python -tt +#!@PYTHON@ -tt import sys import atexit import socket import struct import logging sys.path.append("@FENCEAGENTSLIBDIR@") from fencing import * from fencing import fail, fail_usage, run_delay, EC_LOGIN_DENIED, EC_TIMED_OUT #BEGIN_VERSION_GENERATION RELEASE_VERSION="" REDHAT_COPYRIGHT="" BUILD_DATE="" #END_VERSION_GENERATION INT4 = 4 def open_socket(options): try: if "--inet6-only" in options: protocol = socket.AF_INET6 elif "--inet4-only" in options: protocol = socket.AF_INET else: protocol = 0 (_, _, _, _, addr) = socket.getaddrinfo( \ options["--ip"], options["--ipport"], protocol, 0, socket.IPPROTO_TCP, socket.AI_PASSIVE )[0] except socket.gaierror: fail(EC_LOGIN_DENIED) conn = socket.socket() conn.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) conn.settimeout(float(options["--shell-timeout"])) try: conn.connect(addr) except socket.error: fail(EC_LOGIN_DENIED) return conn def smapi_pack_string(string): return struct.pack("!i%ds" % (len(string)), len(string), string) def prepare_smapi_command(options, smapi_function, additional_args): packet_size = 3*INT4 + len(smapi_function) + len(options["--username"]) + len(options["--password"]) for arg in additional_args: packet_size += INT4 + len(arg) command = struct.pack("!i", packet_size) command += smapi_pack_string(smapi_function) command += smapi_pack_string(options["--username"]) command += smapi_pack_string(options["--password"]) for arg in additional_args: command += smapi_pack_string(arg) return command def get_power_status(conn, options): del conn if options.get("--original-action", None) == "monitor": (return_code, reason_code, images_active) = \ get_list_of_images(options, "Check_Authentication", None) logging.debug("Check_Authenticate (%d,%d)", return_code, reason_code) if return_code == 0: return {} else: fail(EC_LOGIN_DENIED) if options["--action"] == "list": # '*' = list all active images options["--plug"] = "*" (return_code, reason_code, images_active) = \ get_list_of_images(options, "Image_Status_Query", options["--plug"]) logging.debug("Image_Status_Query results are (%d,%d)", return_code, reason_code) if not options["--action"] == "list": if (return_code == 0) and (reason_code == 0): return "on" elif (return_code == 0) and (reason_code == 12): # We are running always with --missing-as-off because we can not check if image # is defined or not (look at rhbz#1188750) return "off" else: return "unknown" else: (return_code, reason_code, images_defined) = \ get_list_of_images(options, "Image_Name_Query_DM", options["--username"]) logging.debug("Image_Name_Query_DM results are (%d,%d)", return_code, reason_code) return dict([(i, ("", "on" if i in images_active else "off")) for i in images_defined]) def set_power_status(conn, options): conn = open_socket(options) packet = None if options["--action"] == "on": packet = prepare_smapi_command(options, "Image_Activate", [options["--plug"]]) elif options["--action"] == "off": packet = prepare_smapi_command(options, "Image_Deactivate", [options["--plug"], "IMMED"]) conn.send(packet) request_id = struct.unpack("!i", conn.recv(INT4))[0] (output_len, request_id, return_code, reason_code) = struct.unpack("!iiii", conn.recv(INT4 * 4)) logging.debug("Image_(De)Activate results are (%d,%d)", return_code, reason_code) conn.close() return def get_list_of_images(options, command, data_as_plug): conn = open_socket(options) if data_as_plug is None: packet = prepare_smapi_command(options, command, []) else: packet = prepare_smapi_command(options, command, [data_as_plug]) conn.send(packet) request_id = struct.unpack("!i", conn.recv(INT4))[0] (output_len, request_id, return_code, reason_code) = struct.unpack("!iiii", conn.recv(INT4 * 4)) images = set() if output_len > 3*INT4: array_len = struct.unpack("!i", conn.recv(INT4))[0] data = "" while True: read_data = conn.recv(1024, socket.MSG_WAITALL) data += read_data if array_len == len(data): break elif not read_data: logging.error("Failed: Not enough data read from socket") fail(EC_TIMED_OUT) parsed_len = 0 while parsed_len < array_len: string_len = struct.unpack("!i", data[parsed_len:parsed_len+INT4])[0] parsed_len += INT4 image_name = struct.unpack("!%ds" % (string_len), data[parsed_len:parsed_len+string_len])[0] parsed_len += string_len images.add(image_name) conn.close() return (return_code, reason_code, images) def main(): device_opt = ["ipaddr", "login", "passwd", "port", "method", "missing_as_off"] atexit.register(atexit_handler) all_opt["ipport"]["default"] = "44444" all_opt["shell_timeout"]["default"] = "5.0" all_opt["missing_as_off"]["default"] = "1" options = check_input(device_opt, process_input(device_opt), other_conditions=True) if len(options.get("--plug", "")) > 8: fail_usage("Failed: Name of image can not be longer than 8 characters") if options["--action"] == "validate-all": sys.exit(0) docs = {} docs["shortdesc"] = "Fence agent for use with z/VM Virtual Machines" docs["longdesc"] = """The fence_zvm agent is intended to be used with with z/VM SMAPI service via TCP/IP To use this agent the z/VM SMAPI service needs to be configured to allow the virtual machine running this agent to connect to it and issue the image_recycle operation. This involves updating the VSMWORK1 AUTHLIST VMSYS:VSMWORK1. file. The entry should look something similar to this: Column 1 Column 66 Column 131 | | | V V V XXXXXXXX ALL IMAGE_OPERATIONS Where XXXXXXX is the name of the virtual machine used in the authuser field of the request. """ docs["vendorurl"] = "http://www.ibm.com" show_docs(options, docs) run_delay(options) result = fence_action(None, options, set_power_status, get_power_status, get_power_status) sys.exit(result) if __name__ == "__main__": main() diff --git a/make/ac_python_module.m4 b/make/ac_python_module.m4 index 32b9d727..d1c81f66 100644 --- a/make/ac_python_module.m4 +++ b/make/ac_python_module.m4 @@ -1,30 +1,30 @@ dnl @synopsis AC_PYTHON_MODULE(modname[, fatal]) dnl dnl Checks for Python module. dnl dnl If fatal is non-empty then absence of a module will trigger an dnl error. dnl dnl @category InstalledPackages dnl @author Andrew Collier . dnl @version 2004-07-14 dnl @license AllPermissive AC_DEFUN([AC_PYTHON_MODULE],[ AC_MSG_CHECKING(python module: $1) - python -c "import $1" 2>/dev/null + $PYTHON -c "import $1" 2>/dev/null if test $? -eq 0; then AC_MSG_RESULT(yes) eval AS_TR_CPP(HAVE_PYMOD_$1)=yes else AC_MSG_RESULT(no) eval AS_TR_CPP(HAVE_PYMOD_$1)=no # if test -n "$2" then AC_MSG_ERROR(failed to find required module $1) exit 1 fi fi ]) diff --git a/make/agentpycheck.mk b/make/agentpycheck.mk index 45dcefbc..e1434cf3 100644 --- a/make/agentpycheck.mk +++ b/make/agentpycheck.mk @@ -1,30 +1,30 @@ DATADIR:=$(abs_top_srcdir)/tests/data/metadata AWK_VAL='BEGIN {store=-1} /name=\"store_path\"/ {store=2} {if (store!=0) {print}; store--}' check: $(TARGET:%=xml-check.%) $(SYMTARGET:%=xml-check.%) $(TARGET:%=delay-check.%) $(TARGET:%=rng-check.%) xml-check.%: % $(eval INPUT=$(subst xml-check.,,$@)) $(eval TEMPFILE = $(shell mktemp)) - PYTHONPATH=$(abs_srcdir)/../lib:$(abs_builddir)/../lib python ./$(INPUT) -o metadata | $(AWK) $(AWK_VAL) > $(TEMPFILE) + PYTHONPATH=$(abs_srcdir)/../lib:$(abs_builddir)/../lib $(PYTHON) ./$(INPUT) -o metadata | $(AWK) $(AWK_VAL) > $(TEMPFILE) diff $(TEMPFILE) $(DATADIR)/$(INPUT).xml rm $(TEMPFILE) xml-upload.%: % $(eval INPUT=$(subst xml-upload.,,$@)) - PYTHONPATH=$(abs_srcdir)/../lib:$(abs_builddir)/../lib python ./$(INPUT) -o metadata | $(AWK) $(AWK_VAL) > $(DATADIR)/$(INPUT).xml + PYTHONPATH=$(abs_srcdir)/../lib:$(abs_builddir)/../lib $(PYTHON) ./$(INPUT) -o metadata | $(AWK) $(AWK_VAL) > $(DATADIR)/$(INPUT).xml # If test will fail, rerun fence agents to show problems delay-check.%: % $(eval INPUT=$(subst delay-check.,,$@)) test `PYTHONPATH=$(abs_srcdir)/../lib:$(abs_builddir)/../lib /usr/bin/time -f "%e" \ - python ./$(INPUT) --delay 10 $(FENCE_TEST_ARGS) -- 2>&1 |\ + $(PYTHON) ./$(INPUT) --delay 10 $(FENCE_TEST_ARGS) -- 2>&1 |\ sed 's/\.//' | tail -n 1` -ge 1000 || ( \ PYTHONPATH=$(abs_srcdir)/../lib:$(abs_builddir)/../lib /usr/bin/time -f "%e" \ - python ./$(INPUT) --delay 0 $(FENCE_TEST_ARGS) --; false ) + $(PYTHON) ./$(INPUT) --delay 0 $(FENCE_TEST_ARGS) --; false ) rng-check.%: % - PYTHONPATH=$(abs_srcdir)/../lib:$(abs_builddir)/../lib python ./$(INPUT) -o metadata | \ + PYTHONPATH=$(abs_srcdir)/../lib:$(abs_builddir)/../lib $(PYTHON) ./$(INPUT) -o metadata | \ /usr/bin/xsltproc ${abs_top_srcdir}/fence/agents/lib/fence2rng.xsl - | \ sed -e 's/ rha:description=/ description=/g' -e 's/ rha:name=/ name=/g' | \ xmllint --nsclean --noout - diff --git a/make/fencebuild.mk b/make/fencebuild.mk index 2e9330cb..8be199bd 100644 --- a/make/fencebuild.mk +++ b/make/fencebuild.mk @@ -1,38 +1,39 @@ $(TARGET): $(SRC) bash $(top_srcdir)/scripts/fenceparse \ $(top_srcdir)/make/copyright.cf REDHAT_COPYRIGHT \ $(VERSION) \ $(abs_srcdir) $@ | \ sed \ + -e 's#@''PYTHON@#${PYTHON}#g' \ -e 's#@''FENCEAGENTSLIBDIR@#${FENCEAGENTSLIBDIR}#g' \ -e 's#@''LOGDIR@#${LOGDIR}#g' \ -e 's#@''SBINDIR@#${sbindir}#g' \ -e 's#@''LIBEXECDIR@#${libexecdir}#g' \ -e 's#@''IPMITOOL_PATH@#${IPMITOOL_PATH}#g' \ -e 's#@''AMTTOOL_PATH@#${AMTTOOL_PATH}#g' \ -e 's#@''GNUTLSCLI_PATH@#${GNUTLSCLI_PATH}#g' \ -e 's#@''COROSYNC_CMAPCTL_PATH@#${COROSYNC_CMAPCTL_PATH}#g' \ -e 's#@''SG_PERSIST_PATH@#${SG_PERSIST_PATH}#g' \ -e 's#@''SG_TURS_PATH@#${SG_TURS_PATH}#g' \ -e 's#@''VGS_PATH@#${VGS_PATH}#g' \ -e 's#@''SUDO_PATH@#${SUDO_PATH}#g' \ -e 's#@''SSH_PATH@#${SSH_PATH}#g' \ -e 's#@''TELNET_PATH@#${TELNET_PATH}#g' \ -e 's#@''MPATH_PATH@#${MPATH_PATH}#g' \ -e 's#@''SBD_PATH@#${SBD_PATH}#g' \ -e 's#@''STORE_PATH@#${CLUSTERVARRUN}#g' \ -e 's#@''SUDO_PATH@#${SUDO_PATH}#g' \ -e 's#@''SNMPWALK_PATH@#${SNMPWALK_PATH}#g' \ -e 's#@''SNMPSET_PATH@#${SNMPSET_PATH}#g' \ -e 's#@''SNMPGET_PATH@#${SNMPGET_PATH}#g' \ -e 's#@''NOVA_PATH@#${NOVA_PATH}#g' \ > $@ if [ 0 -eq `echo "$(SRC)" | grep fence_ &> /dev/null; echo $$?` ]; then \ PYTHONPATH=$(abs_srcdir)/../lib:$(abs_builddir)/../lib $(top_srcdir)/fence/agents/lib/check_used_options.py $@; \ else true ; fi clean: clean-man rm -f $(TARGET) $(SYMTARGET) *.pyc *.wiki -clean-local: clean \ No newline at end of file +clean-local: clean diff --git a/make/fenceman.mk b/make/fenceman.mk index c3360b78..e5e18f65 100644 --- a/make/fenceman.mk +++ b/make/fenceman.mk @@ -1,10 +1,10 @@ %.8: $(TARGET) $(top_srcdir)/fence/agents/lib/fence2man.xsl set -e && \ PYTHONPATH=$(abs_srcdir)/../lib:$(abs_builddir)/../lib \ - python $(@:%.8=%) -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 > $@ xsltproc $(top_srcdir)/fence/agents/lib/fence2wiki.xsl .$@.tmp | grep -v ' $(@:%.8=%.wiki) clean-man: rm -f *.8 .*.8.tmp *.wiki diff --git a/tests/data/metadata/fence_docker.xml b/tests/data/metadata/fence_docker.xml index 8aeded67..6ef60190 100644 --- a/tests/data/metadata/fence_docker.xml +++ b/tests/data/metadata/fence_docker.xml @@ -1,151 +1,151 @@ fence_docker is I/O fencing agent which can be used with the Docker Engine containers. You can use this fence-agent without any authentication, or you can use TLS authentication (use --ssl option, more info about TLS authentication in docker: http://docs.docker.com/examples/https/). www.docker.io Fencing action Forces agent to use IPv4 addresses only Forces agent to use IPv6 addresses only IP address or hostname of fencing device TCP/UDP port to use for connection with device Method to fence Physical plug number on device, UUID or identification of machine Use SSL connection with verifying certificate Use SSL connection without verifying certificate Use SSL connection with verifying certificate + + + + Version of Docker Remote API (default: 1.11) + Path to CA certificate (PEM format) for TLS authentication. Required if --ssl option is used. Path to client certificate (PEM format) for TLS authentication. Required if --ssl option is used. Path to client key (PEM format) for TLS authentication. Required if --ssl option is used. Verbose mode Write debug information to given file Display version information and exit Display help and exit Separator for CSV created by 'list' operation Wait X seconds before fencing is started Wait X seconds for cmd prompt after login Test X seconds for status change after ON/OFF Wait X seconds after issuing ON/OFF Wait X seconds for cmd prompt after issuing command Count of attempts to retry power on Path to gnutls-cli binary - - - - Version of Docker Remote API (default: 1.11) - diff --git a/tests/fence_testing.py b/tests/fence_testing.py index 166eaf81..524a56a6 100755 --- a/tests/fence_testing.py +++ b/tests/fence_testing.py @@ -1,126 +1,126 @@ """ Library for fence agents testing via predefined scenarios """ from configobj import ConfigObj import re, sys, os EC_CONFIG_FAIL = 1 def _prepare_command(agent_file, method): """ Parse configuration of fence device and prepare (command + STDIN values) to execute. Fence device configuration is used to generate a command which can be executed. Because fence agents supports several options how to enter data, we can select from three different methods ("stdin", "getopt" - short options, "longopt"). When method "stdin" is used then this function will generate also text which should be entered on STDIN instead of command itself. Example of agent definition: name = "Dummy fence device configuration" agent = "/bin/true" [options] login = [ "foo", "--username", "-l" ] passwd = [ "bar", "--password", "-p" ] ipaddr = [ "fence.example.com", "--ip", "-a" ] port = [ "1", "--plug" ] """ assert (method in ["stdin", "getopt", "longopt"]), "Invalid method entered" config = ConfigObj(agent_file, unrepr = True) - assert (config.has_key("agent")), "Fence agent has to be defined" + assert ("agent" in config), "Fence agent has to be defined" final_command = config["agent"] stdin_values = None - for opt in config["options"].keys(): + for opt in list(config["options"].keys()): assert isinstance(config["options"][opt], list), "Option %s have to have at least value and longopt"% (opt) assert len(config["options"][opt]) >= 2, "Option %s have to have at least value and longopt"% (opt) value = config["options"][opt][0] if opt == "action": ## ignore action as it is not part of fence device definition continue if method == "stdin": option = opt if stdin_values == None: stdin_values = "" stdin_values += option + "=" + value + "\n" elif method == "longopt": option = config["options"][opt][1] final_command += " " + option + " " + value elif method == "getopt": if len(config["options"][opt]) == (2 + 1): option = config["options"][opt][2] else: option = config["options"][opt][1] final_command += " " + option + " " + value return (final_command, stdin_values) def test_action(agent, action_file, method, verbose = False): """ Run defined sequence of actions on a given fence agent. This function will run one set of test on a fence agent. Test itself consists of sequence of action and expected return codes. User can select from actions supported by fence agent (on, off, reboot, list, status, monitor) and sleep(X) command where X is in seconds and determine the length of pause between commands. Each action has to have defined regular expression which define acceptable return codes from fence agent or sleep. Example of action configuration file: name = "Simple Status" actions = [ { "command" : "status", "return_code" : "^[02]$" }, { "command" : "sleep(1)", "return_code" : "^0$" } ] """ re_sleep_command = re.compile('sleep\(([0-9]+)\)', re.IGNORECASE) config = ConfigObj(action_file, unrepr = True) (command, stdin_options) = _prepare_command(agent, method) for action in config["actions"]: - assert action.has_key("command"), "Action %s need to have defined 'command'"% (action_file) - assert action.has_key("return_code"), "Command %s (in %s) need to have 'return_code' defined"% (action_file, action["command"]) + assert "command" in action, "Action %s need to have defined 'command'"% (action_file) + assert "return_code" in action, "Command %s (in %s) need to have 'return_code' defined"% (action_file, action["command"]) sleep_wait = None current_command = None current_stdin_options = None if not (action["command"] in [ "status", "reboot", "on", "off", "list", "monitor" ]): is_sleep = re.search(re_sleep_command, action["command"]) if is_sleep != None: sleep_wait = is_sleep.group(1) else: sys.stderr.write("ERROR: %s contains unsupported action \"%s\"\n"% (action_file, action["command"])) sys.exit(1) if sleep_wait != None: current_command = "/bin/sleep " + sleep_wait current_stdin_options = None else: current_command = command current_stdin_options = stdin_options if method == "stdin": if current_stdin_options == None: current_stdin_options = "" current_stdin_options += "action=%s"% (action["command"]) elif method == "longopt": current_command += " --action=%s"% (action["command"]) elif method == "getopt": current_command += " -o %s"% (action["command"]) # @note: Broken pipe can occur here and I'm not sure why - non-deterministic if method == "stdin" and sleep_wait == None: current_command = "/bin/echo -e \"" + current_stdin_options + "\" | " + current_command if verbose == False: result = os.system(current_command + " &> /dev/null") else: - print current_command + print(current_command) result = os.system(current_command) exitcode = (result >> 8) & 0xFF is_valid_result_code = re.search(action["return_code"], str(exitcode), re.IGNORECASE) if is_valid_result_code == None: - print "TEST FAILED: %s failed on %s when using (%s)\n"% (agent, action_file, method) - print "TEST INFO: %s returns %s\n"% (action["command"], str(exitcode)) + print(("TEST FAILED: %s failed on %s when using (%s)\n"% (agent, action_file, method))) + print(("TEST INFO: %s returns %s\n"% (action["command"], str(exitcode)))) return - print "TEST PASSED: %s worked on %s (%s)\n"% (agent, action_file, method) + print(("TEST PASSED: %s worked on %s (%s)\n"% (agent, action_file, method))) diff --git a/tests/fence_testing_test.py b/tests/fence_testing_test.py index 368ff70e..36b2a5e0 100755 --- a/tests/fence_testing_test.py +++ b/tests/fence_testing_test.py @@ -1,70 +1,70 @@ #!/usr/bin/python import unittest import fence_testing class TestPrepareCommand(unittest.TestCase): DEVICE_MISSING_OPTION = "devices.d/invalid-missing_option.cfg" DEVICE_CORRECT = "devices.d/true.cfg" DEVICE_CORRECT_WITH_ACTION = "devices.d/true-with_action.cfg" def test_missing_device(self): self.assertRaises(fence_testing._prepare_command, None, "getopt") def test_missing_option(self): self.assertRaises(AssertionError, fence_testing._prepare_command, self.DEVICE_MISSING_OPTION, "stdin") def test_valid_methods(self): fence_testing._prepare_command(self.DEVICE_CORRECT, "getopt") fence_testing._prepare_command(self.DEVICE_CORRECT, "longopt") fence_testing._prepare_command(self.DEVICE_CORRECT, "stdin") def test_invalid_method(self): self.assertRaises(AssertionError, fence_testing._prepare_command, self.DEVICE_CORRECT, "invalid") def test_is_action_ignored(self): (command1, _) = fence_testing._prepare_command(self.DEVICE_CORRECT, "getopt") (command2, _) = fence_testing._prepare_command(self.DEVICE_CORRECT_WITH_ACTION, "getopt") - self.assertEquals(command1, command2) + self.assertEqual(command1, command2) def test_is_stdin_empty(self): (_, stdin) = fence_testing._prepare_command(self.DEVICE_CORRECT, "getopt") - self.assertEquals(None, stdin) + self.assertEqual(None, stdin) (_, stdin) = fence_testing._prepare_command(self.DEVICE_CORRECT, "longopt") - self.assertEquals(None, stdin) + self.assertEqual(None, stdin) def test_prepared_command_getopt(self): ## Test also fallback to longopt if short is not present (command, _) = fence_testing._prepare_command(self.DEVICE_CORRECT, "getopt") - self.assertEquals("/bin/true -l foo -p bar -a fence.example.com --plug 1", command) + self.assertEqual("/bin/true -l foo -p bar -a fence.example.com --plug 1", command) def test_prepared_command_longopt(self): (command, _) = fence_testing._prepare_command(self.DEVICE_CORRECT, "longopt") - self.assertEquals("/bin/true --username foo --password bar --ip fence.example.com --plug 1", command) + self.assertEqual("/bin/true --username foo --password bar --ip fence.example.com --plug 1", command) def test_prepared_command_stdin(self): (command, stdin) = fence_testing._prepare_command(self.DEVICE_CORRECT, "stdin") - self.assertEquals("/bin/true", command) - self.assertEquals("login=foo\npasswd=bar\nipaddr=fence.example.com\nport=1\n", stdin) + self.assertEqual("/bin/true", command) + self.assertEqual("login=foo\npasswd=bar\nipaddr=fence.example.com\nport=1\n", stdin) class TestTestAction(unittest.TestCase): def test_valid_actions(self): pass def test_invalid_actions(self): pass def test_valid_return_code(self): pass def test_invalid_return_code(self): pass def test_valid_re_contains(self): pass def test_invalid_re_contains(self): pass if __name__ == '__main__': unittest.main()