diff --git a/.travis.yml b/.travis.yml index b4ef8819..f11a2083 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,43 +1,43 @@ language: python sudo: required dist: trusty python: - "2.7" addons: apt: packages: - python-pexpect - xsltproc - time - libpam0g-dev - libxml2-utils - libcimcclient0-dev - swig before_install: - pip install suds - pip install pycurl - pip install requests - pip install pexpect before_script: - wget https://github.com/Openwsman/openwsman/archive/v2.6.2.tar.gz -O /tmp/openwsman-2.6.2.tar.gz - tar zxvf /tmp/openwsman-2.6.2.tar.gz - cd openwsman-2.6.2 - perl -p -i -e "s/(\\$\{CURL_LIBRARIES\})/\1 ssl crypto/g" src/lib/CMakeLists.txt - mkdir build && cd build - cmake .. -DPYTHON_EXECUTABLE:FILEPATH=~/virtualenv/python2.7.10/bin/python -DLIB=/lib/x86_64-linux-gnu -DCMAKE_LIBRARY_ARCHITECTURE=x86_64-linux-gnu -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_VERBOSE_MAKEFILE=TRUE - make - sudo make install - cd ../.. - sudo rm -rf ~/virtualenv/python2.7.10/lib/python2.7/site-packages/{_,}pywsman* - pip install pywsman script: - ./autogen.sh - ./configure - - make - - make check + - make -j4 + - make -j4 check - PYTHONPATH=fence/agents/lib python fence/agents/lib/tests/test_fencing.py diff --git a/configure.ac b/configure.ac index 33939b99..940b6e66 100644 --- a/configure.ac +++ b/configure.ac @@ -1,331 +1,280 @@ # 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]) +AM_INIT_AUTOMAKE([-Wno-portability dist-bzip2 dist-xz subdir-objects]) 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'` + AGENTS_LIST=`find $srcdir/fence/agents -mindepth 2 -maxdepth 2 -name '*.py' -printf '%P ' | sed -e 's#lib/[A-Za-z_.]* ##g' -e 's#nss_wrapper/[A-Za-z_.]* ##g' -e 's#autodetect/[A-Za-z_.]* ##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/Makefile.am b/fence/agents/Makefile.am index 3b76b9a8..4d21e97a 100644 --- a/fence/agents/Makefile.am +++ b/fence/agents/Makefile.am @@ -1,3 +1,84 @@ -MAINTAINERCLEANFILES = Makefile.in +MAINTAINERCLEANFILES = Makefile.in -SUBDIRS = $(AGENTS_LIST) +TARGET = $(AGENTS_LIST:%.py=%) + +SRC = $(TARGET:=.py) + +CLEAN_TARGET_ADDITIONAL = kdump/fence_kdump_send + +EXTRA_DIST = $(SRC) + +sbin_SCRIPTS = $(TARGET) manual/fence_ack_manual + +EXTRA_SCRIPTS = + +man_MANS = $(sbin_SCRIPTS:=.8) + +sbin_PROGRAMS = kdump/fence_kdump zvm/fence_zvm +libexec_PROGRAMS = kdump/fence_kdump_send + +noinst_HEADERS = kdump/list.h kdump/message.h kdump/options.h kdump/version.h + +kdump_fence_kdump_SOURCES = kdump/fence_kdump.c +kdump_fence_kdump_CFLAGS = -D_GNU_SOURCE -Ikdump + +kdump_fence_kdump_send_SOURCES = kdump/fence_kdump_send.c +kdump_fence_kdump_send_CFLAGS = -D_GNU_SOURCE -Ikdump + +dist_man_MANS = kdump/fence_kdump.8 kdump/fence_kdump_send.8 + +scsidatadir = $(CLUSTERDATA) +scsidata_SCRIPTS = scsi/fence_scsi_check scsi/fence_scsi_check_hardreboot + +zvm_fence_zvm_SOURCES = zvm/fence_zvm.c +zvm_fence_zvm_CFLAGS = -D_GNU_SOURCE + +FENCE_TEST_ARGS = \ +login=test\n\ +passwd=test\n\ +ipaddr=test\n\ +port=1\n\ +managed=1\n\ +devices=test\n\ +session_url=http://test\n\ +email=test@test.te + +manual/fence_ack_manual: manual/fence_ack_manual.in + cat $^ | sed \ + -e 's#@clustervarrun@#${CLUSTERVARRUN}#g' \ + > $@ + +scsi/fence_scsi_check: scsi/fence_scsi + cp $^ $@ + +scsi/fence_scsi_check_hardreboot: scsi/fence_scsi + cp $^ $@ + +kdump/fence_kdump.8: kdump/fence_kdump $(top_srcdir)/fence/agents/lib/fence2man.xsl + set -e && \ + ./$(@:%.8=%) -o metadata > $(@D)/.$(@F).tmp && \ + xmllint --noout --relaxng $(top_srcdir)/fence/agents/lib/metadata.rng $(@D)/.$(@F).tmp && \ + xsltproc $(top_srcdir)/fence/agents/lib/fence2man.xsl $(@D)/.$(@F).tmp > $@ + xsltproc $(top_srcdir)/fence/agents/lib/fence2wiki.xsl $(@D)/.$(@F).tmp | grep -v ' $(@D)/$(@F:%.8=%.wiki) + +kdump/fence_kdump_send.8: + true + +manual/fence_ack_manual.8: + true + +zvm/fence_zvm.8: zvm/fence_zvm + cp $(top_srcdir)/fence/agents/zvm/fence_zvm_man_page $(@D)/fence_zvm.8 + +cisco_mds/fence_cisco_mds.delay-check: cisco_mds/fence_cisco_mds + $(eval INPUT=$(subst .delay-check,,$@)) + FENCE_TEST_ARGS_CISCO_MDS=$$(/bin/echo -e '$(FENCE_TEST_ARGS)' | sed 's#port=1#port=fc1/1#'); \ + test `PYTHONPATH=$(abs_srcdir)/lib:$(abs_builddir)/lib /usr/bin/time -f "%e" \ + sh -c "/bin/echo -e 'delay=10\n $$FENCE_TEST_ARGS_CISCO_MDS' | $(PYTHON) ./$(INPUT)" 2>&1 |\ + sed 's/\.//' | tail -n 1` -ge 1000 || ( \ + PYTHONPATH=$(abs_srcdir)/lib:$(abs_builddir)/lib /usr/bin/time -f "%e" \ + sh -c "/bin/echo -e "delay=0\n $$FENCE_TEST_ARGS_CISCO_MDS" | $(PYTHON) ./$(INPUT)"; false ) + +include $(top_srcdir)/make/fencebuild.mk +include $(top_srcdir)/make/fenceman.mk +include $(top_srcdir)/make/agentpycheck.mk diff --git a/fence/agents/apc_snmp/fence_apc_snmp.py b/fence/agents/apc_snmp/fence_apc_snmp.py index 6a6698f0..f93cfa84 100644 --- a/fence/agents/apc_snmp/fence_apc_snmp.py +++ b/fence/agents/apc_snmp/fence_apc_snmp.py @@ -1,223 +1,224 @@ #!@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 (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 ("--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 "--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" + docs["symlink"] = [("fence_tripplite_snmp", "Fence agent for Tripplife over SNMP")] 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/dummy/fence_dummy.py b/fence/agents/dummy/fence_dummy.py index 77d7d348..e4f1589c 100644 --- a/fence/agents/dummy/fence_dummy.py +++ b/fence/agents/dummy/fence_dummy.py @@ -1,145 +1,139 @@ #!@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 "--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 "--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"] + device_opt = ["no_password", "status_file", "random_sleep_range", "type", "no_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 ("--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 "--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/kdump/fence_kdump.8 b/fence/agents/kdump/fence_kdump.8 deleted file mode 100644 index 768f2d35..00000000 --- a/fence/agents/kdump/fence_kdump.8 +++ /dev/null @@ -1,85 +0,0 @@ -.TH fence_kdump 8 -.SH NAME -fence_kdump - fencing agent for use with kdump crash recovery service -.SH SYNOPSIS -.B -fence_kdump -[\fIOPTIONS\fR]... -.SH DESCRIPTION -\fIfence_kdump\fP is an I/O fencing agent to be used with the kdump -crash recovery service. When the \fIfence_kdump\fP agent is invoked, -it will listen for a message from the failed node that acknowledges -that the failed node it executing the kdump crash kernel. -Note that \fIfence_kdump\fP is not a replacement for traditional -fencing methods. The \fIfence_kdump\fP agent can only detect that a -node has entered the kdump crash recovery service. This allows the -kdump crash recovery service complete without being preempted by -traditional power fencing methods. -.SH OPTIONS -.TP -.B -n, --nodename=\fINODE\fP -Name or IP address of node to be fenced. This option is required for -the "off" action. (default: none) -.TP -.B -p, --ipport=\fIPORT\fP -IP port number that the \fIfence_kdump\fP agent will use to listen for -messages. (default: 7410) -.TP -.B -f, --family=\fIFAMILY\fP -IP network family. Force the \fIfence_kdump\fP agent to use a specific -family. The value for \fIFAMILY\fP can be "auto", "ipv4", or -"ipv6". (default: auto) -.TP -.B -o, --action=\fIACTION\fP -Fencing action to perform. The value for \fIACTION\fP can be either -"off" or "metadata". (default: off) -.TP -.B -t, --timeout=\fITIMEOUT\fP -Numer of seconds to wait for message from failed node. If no message -is received within \fITIMEOUT\fP seconds, the \fIfence_kdump\fP agent -returns failure. (default: 60) -.TP -.B -v, --verbose -Print verbose output. -.TP -.B -V, --version -Print version and exit. -.TP -.B -h, --help -Print usage and exit. -.SH STDIN PARAMETERS -.PP -These parameters are passed to \fIfence_kdump\fP via standard input if -no command-line options are present. -.TP -.B nodename=\fINODE\fP -Name or IP address of node to be fenced. This option is required for -the "off" action. (default: none) -.TP -.B ipport=\fIPORT\fP -IP port number that the \fIfence_kdump\fP agent will use to listen for -messages. (default: 7410) -.TP -.B action=\fIACTION\fP -Fencing action to perform. The value for \fIACTION\fP can be either -"off" or "metadata". (default: off) -.TP -.B timeout=\fITIMEOUT\fP -Numer of seconds to wait for message from failed node. If no message -is received within \fITIMEOUT\fP seconds, the \fIfence_kdump\fP agent -returns failure. (default: 60) -.SH ACTIONS -.TP -.B off -Listen for message from failed node that acknowledges node has entered -kdump crash recovery service. If a valid message is received from the -failed node, the node is considered to be fenced and the agent returns -success. Failure to receive a valid message from the failed node in -the given timeout period results in fencing failure. -.TP -.B metadata -Print XML metadata to standard output. -.SH AUTHOR -Ryan O'Hara -.SH SEE ALSO -fence_kdump_send(8), fenced(8), fence_node(8) diff --git a/fence/agents/kdump/fence_kdump.c b/fence/agents/kdump/fence_kdump.c index 781df64d..c3bcf084 100644 --- a/fence/agents/kdump/fence_kdump.c +++ b/fence/agents/kdump/fence_kdump.c @@ -1,544 +1,565 @@ /* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- * * Copyright (c) Ryan O'Hara (rohara@redhat.com) * Copyright (c) Red Hat, Inc. * * This program 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. * * This program 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, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "options.h" #include "message.h" #include "version.h" static int verbose = 0; #define log_debug(lvl, fmt, args...) \ do { \ if (lvl <= verbose) { \ fprintf (stdout, "[debug]: " fmt, ##args); \ syslog (LOG_INFO, fmt, ##args); \ } \ } while (0); #define log_error(lvl, fmt, args...) \ do { \ if (lvl <= verbose) { \ fprintf (stderr, "[error]: " fmt, ##args); \ syslog (LOG_ERR, fmt, ##args); \ } \ } while (0); static int trim (char *str) { char *p; int len; if (!str) return (0); len = strlen (str); while (len--) { if (isspace (str[len])) { str[len] = 0; } else { break; } } for (p = str; *p && isspace (*p); p++); memmove (str, p, strlen (p) + 1); return (strlen (str)); } static int read_message (const fence_kdump_node_t *node, void *msg, int len) { int error; char addr[NI_MAXHOST]; char port[NI_MAXSERV]; struct sockaddr_storage ss; socklen_t size = sizeof (ss); error = recvfrom (node->socket, msg, len, 0, (struct sockaddr *) &ss, &size); if (error < 0) { log_error (2, "recvfrom (%s)\n", strerror (errno)); goto out; } error = getnameinfo ((struct sockaddr *) &ss, size, addr, sizeof (addr), port, sizeof (port), NI_NUMERICHOST | NI_NUMERICSERV); if (error != 0) { log_error (2, "getnameinfo (%s)\n", gai_strerror (error)); goto out; } error = strcasecmp (node->addr, addr); if (error != 0) { log_debug (1, "discard message from '%s'\n", addr); } out: return (error); } static int do_action_monitor (void) { const char cmdline_path[] = "/proc/cmdline"; FILE *procFile; size_t sz = 0; char *lines = NULL; int result = 1; procFile = fopen(cmdline_path, "r"); if (procFile == NULL) { log_error (0, "Unable to open file %s (%s)\n", cmdline_path, strerror (errno)); return 1; } while (!feof (procFile)) { ssize_t rv = getline (&lines, &sz, procFile); if ((rv != -1) && (strstr(lines, "crashkernel=") != NULL)) { result = 0; } } free (lines); fclose (procFile); return result; } static int do_action_off (const fence_kdump_opts_t *opts) { int error; fd_set rfds; fence_kdump_msg_t msg; fence_kdump_node_t *node; struct timeval timeout; if (list_empty (&opts->nodes)) { return (1); } else { node = list_first_entry (&opts->nodes, fence_kdump_node_t, list); } timeout.tv_sec = opts->timeout; timeout.tv_usec = 0; FD_ZERO (&rfds); FD_SET (node->socket, &rfds); log_debug (0, "waiting for message from '%s'\n", node->addr); for (;;) { error = select (node->socket + 1, &rfds, NULL, NULL, &timeout); if (error < 0) { log_error (2, "select (%s)\n", strerror (errno)); break; } if (error == 0) { log_debug (0, "timeout after %d seconds\n", opts->timeout); break; } if (read_message (node, &msg, sizeof (msg)) != 0) { continue; } if (msg.magic != FENCE_KDUMP_MAGIC) { log_debug (1, "invalid magic number '0x%X'\n", msg.magic); continue; } switch (msg.version) { case FENCE_KDUMP_MSGV1: log_debug (0, "received valid message from '%s'\n", node->addr); return (0); default: log_debug (1, "invalid message version '0x%X'\n", msg.version); continue; } } return (1); } static int do_action_metadata (const char *self) { fprintf (stdout, "\n"); fprintf (stdout, "\n"); + fprintf (stdout, " shortdesc=\"fencing agent for use with kdump crash recovery service\">\n"); fprintf (stdout, ""); - fprintf (stdout, "The fence_kdump agent is intended to be used with with kdump service."); + fprintf (stdout, "\\fIfence_kdump\\fP is an I/O fencing agent to be used with the kdump\n" + "crash recovery service. When the \\fIfence_kdump\\fP agent is invoked,\n" + "it will listen for a message from the failed node that acknowledges\n" + "that the failed node it executing the kdump crash kernel.\n" + "Note that \\fIfence_kdump\\fP is not a replacement for traditional\n" + "fencing methods. The \\fIfence_kdump\\fP agent can only detect that a\n" + "node has entered the kdump crash recovery service. This allows the\n" + "kdump crash recovery service complete without being preempted by\n" + "traditional power fencing methods.\n\n" + "Note: the \"off\" action listen for message from failed node that\n" + "acknowledges node has entered kdump crash recovery service. If a valid\n" + "message is received from the failed node, the node is considered to be\n" + "fenced and the agent returns success. Failure to receive a valid\n" + "message from the failed node in the given timeout period results in\n" + "fencing failure."); fprintf (stdout, "\n"); fprintf (stdout, "http://www.kernel.org/pub/linux/utils/kernel/kexec/\n"); fprintf (stdout, "\n"); fprintf (stdout, "\t\n"); - fprintf (stdout, "\t\t\n"); + fprintf (stdout, "\t\t\n"); fprintf (stdout, "\t\t\n"); fprintf (stdout, "\t\t%s\n", - "Name or IP address of node to be fenced"); + "Name or IP address of node to be fenced. This option is required for\n" + "the \"off\" action."); fprintf (stdout, "\t\n"); fprintf (stdout, "\t\n"); - fprintf (stdout, "\t\t\n"); + fprintf (stdout, "\t\t\n"); fprintf (stdout, "\t\t\n"); fprintf (stdout, "\t\t%s\n", - "Port number"); + "IP port number that the \\fIfence_kdump\\fP agent will use to listen for\n" + "messages."); fprintf (stdout, "\t\n"); fprintf (stdout, "\t\n"); - fprintf (stdout, "\t\t\n"); + fprintf (stdout, "\t\t\n"); fprintf (stdout, "\t\t\n"); fprintf (stdout, "\t\t%s\n", - "Network family"); + "IP network family. Force the \\fIfence_kdump\\fP agent to use a specific\n" + "family. The value for \\fIFAMILY\\fP can be \"auto\", \"ipv4\", or\n" + "\"ipv6\"."); fprintf (stdout, "\t\n"); fprintf (stdout, "\t\n"); - fprintf (stdout, "\t\t\n"); + fprintf (stdout, "\t\t\n"); fprintf (stdout, "\t\t\n"); fprintf (stdout, "\t\t%s\n", - "Fencing action"); + "Fencing action to perform. The value for \\fIACTION\\fP can be either\n" + "\"off\" or \"metadata\"."); fprintf (stdout, "\t\n"); fprintf (stdout, "\t\n"); - fprintf (stdout, "\t\t\n"); + fprintf (stdout, "\t\t\n"); fprintf (stdout, "\t\t\n"); fprintf (stdout, "\t\t%s\n", - "Timeout in seconds"); + "Number of seconds to wait for message from failed node. If no message\n" + "is received within \\fITIMEOUT\\fP seconds, the \\fIfence_kdump\\fP agent\n" + "returns failure."); fprintf (stdout, "\t\n"); fprintf (stdout, "\t\n"); fprintf (stdout, "\t\t\n"); fprintf (stdout, "\t\t\n"); fprintf (stdout, "\t\t%s\n", "Print verbose output"); fprintf (stdout, "\t\n"); fprintf (stdout, "\t\n"); fprintf (stdout, "\t\t\n"); fprintf (stdout, "\t\t\n"); fprintf (stdout, "\t\t%s\n", "Print version"); fprintf (stdout, "\t\n"); fprintf (stdout, "\t\n"); fprintf (stdout, "\t\t\n"); fprintf (stdout, "\t\t\n"); fprintf (stdout, "\t\t%s\n", "Print usage"); fprintf (stdout, "\t\n"); fprintf (stdout, "\n"); fprintf (stdout, "\n"); fprintf (stdout, "\t\n"); fprintf (stdout, "\t\n"); fprintf (stdout, "\t\n"); fprintf (stdout, "\n"); fprintf (stdout, "\n"); return (0); } static void print_usage (const char *self) { fprintf (stdout, "Usage: %s [options]\n", basename (self)); fprintf (stdout, "\n"); fprintf (stdout, "Options:\n"); fprintf (stdout, "\n"); fprintf (stdout, "%s\n", " -n, --nodename=NODE Name or IP address of node to be fenced"); fprintf (stdout, "%s\n", " -p, --ipport=PORT IP port number (default: 7410)"); fprintf (stdout, "%s\n", " -f, --family=FAMILY Network family: ([auto], ipv4, ipv6)"); fprintf (stdout, "%s\n", " -o, --action=ACTION Fencing action: ([off], monitor, metadata)"); fprintf (stdout, "%s\n", " -t, --timeout=TIMEOUT Timeout in seconds (default: 60)"); fprintf (stdout, "%s\n", " -v, --verbose Print verbose output"); fprintf (stdout, "%s\n", " -V, --version Print version"); fprintf (stdout, "%s\n", " -h, --help Print usage"); fprintf (stdout, "\n"); return; } static int get_options_node (fence_kdump_opts_t *opts) { int error; struct addrinfo hints; fence_kdump_node_t *node; node = malloc (sizeof (fence_kdump_node_t)); if (!node) { log_error (2, "malloc (%s)\n", strerror (errno)); return (1); } memset (node, 0, sizeof (fence_kdump_node_t)); memset (&hints, 0, sizeof (hints)); hints.ai_family = opts->family; hints.ai_socktype = SOCK_DGRAM; hints.ai_protocol = IPPROTO_UDP; hints.ai_flags = AI_NUMERICSERV; strncpy (node->name, opts->nodename, sizeof (node->name)); snprintf (node->port, sizeof (node->port), "%d", opts->ipport); node->info = NULL; error = getaddrinfo (node->name, node->port, &hints, &node->info); if (error != 0) { log_error (2, "getaddrinfo (%s)\n", gai_strerror (error)); free_node (node); return (1); } error = getnameinfo (node->info->ai_addr, node->info->ai_addrlen, node->addr, sizeof (node->addr), node->port, sizeof (node->port), NI_NUMERICHOST | NI_NUMERICSERV); if (error != 0) { log_error (2, "getnameinfo (%s)\n", gai_strerror (error)); free_node (node); return (1); } hints.ai_family = node->info->ai_family; hints.ai_flags |= AI_PASSIVE; freeaddrinfo (node->info); node->info = NULL; error = getaddrinfo (NULL, node->port, &hints, &node->info); if (error != 0) { log_error (2, "getaddrinfo (%s)\n", gai_strerror (error)); free_node (node); return (1); } node->socket = socket (node->info->ai_family, node->info->ai_socktype, node->info->ai_protocol); if (node->socket < 0) { log_error (2, "socket (%s)\n", strerror (errno)); free_node (node); return (1); } error = bind (node->socket, node->info->ai_addr, node->info->ai_addrlen); if (error != 0) { log_error (2, "bind (%s)\n", strerror (errno)); free_node (node); return (1); } list_add_tail (&node->list, &opts->nodes); return (0); } static void get_options (int argc, char **argv, fence_kdump_opts_t *opts) { int opt; struct option options[] = { { "nodename", required_argument, NULL, 'n' }, { "ipport", required_argument, NULL, 'p' }, { "family", required_argument, NULL, 'f' }, { "action", required_argument, NULL, 'o' }, { "timeout", required_argument, NULL, 't' }, { "verbose", optional_argument, NULL, 'v' }, { "version", no_argument, NULL, 'V' }, { "help", no_argument, NULL, 'h' }, { 0, 0, 0, 0 } }; while ((opt = getopt_long (argc, argv, "n:p:f:o:t:v::Vh", options, NULL)) != EOF) { switch (opt) { case 'n': set_option_nodename (opts, optarg); break; case 'p': set_option_ipport (opts, optarg); break; case 'f': set_option_family (opts, optarg); break; case 'o': set_option_action (opts, optarg); break; case 't': set_option_timeout (opts, optarg); break; case 'v': set_option_verbose (opts, optarg); break; case 'V': print_version (argv[0]); exit (0); case 'h': print_usage (argv[0]); exit (0); default: print_usage (argv[0]); exit (1); } } verbose = opts->verbose; return; } static void get_options_stdin (fence_kdump_opts_t *opts) { char buf[1024]; char *opt; char *arg; while (fgets (buf, sizeof (buf), stdin) != 0) { if (trim (buf) == 0) { continue; } if (buf[0] == '#') { continue; } opt = buf; if ((arg = strchr (opt, '=')) != 0) { *arg = 0; arg += 1; } else { continue; } if (!strcasecmp (opt, "nodename")) { set_option_nodename (opts, arg); continue; } if (!strcasecmp (opt, "ipport")) { set_option_ipport (opts, arg); continue; } if (!strcasecmp (opt, "family")) { set_option_family (opts, arg); continue; } if (!strcasecmp (opt, "action")) { set_option_action (opts, arg); continue; } if (!strcasecmp (opt, "timeout")) { set_option_timeout (opts, arg); continue; } if (!strcasecmp (opt, "verbose")) { set_option_verbose (opts, arg); continue; } } verbose = opts->verbose; return; } int main (int argc, char **argv) { int error = 1; fence_kdump_opts_t opts; init_options (&opts); if (argc > 1) { get_options (argc, argv, &opts); } else { get_options_stdin (&opts); } openlog ("fence_kdump", LOG_CONS|LOG_PID, LOG_DAEMON); if (opts.action == FENCE_KDUMP_ACTION_OFF) { if (opts.nodename == NULL) { log_error (0, "action 'off' requires nodename\n"); exit (1); } if (get_options_node (&opts) != 0) { log_error (0, "failed to get node '%s'\n", opts.nodename); exit (1); } } if (verbose != 0) { print_options (&opts); } switch (opts.action) { case FENCE_KDUMP_ACTION_OFF: error = do_action_off (&opts); break; case FENCE_KDUMP_ACTION_METADATA: error = do_action_metadata (argv[0]); break; case FENCE_KDUMP_ACTION_MONITOR: error = do_action_monitor (); break; default: break; } free_options (&opts); return (error); } diff --git a/fence/agents/pve/fence_pve.py b/fence/agents/pve/fence_pve.py index 9f6390ae..3867047d 100755 --- a/fence/agents/pve/fence_pve.py +++ b/fence/agents/pve/fence_pve.py @@ -1,187 +1,187 @@ #!@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 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 = 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: - if "skiplock" in post: - conn.setopt(conn.CUSTOMREQUEST, 'POST') - else: - conn.setopt(pycurl.POSTFIELDS, urllib.urlencode(post)) + if "skiplock" in post: + conn.setopt(conn.CUSTOMREQUEST, 'POST') + else: + conn.setopt(pycurl.POSTFIELDS, urllib.urlencode(post)) conn.setopt(pycurl.WRITEFUNCTION, output_buffer.write) conn.setopt(pycurl.TIMEOUT, int(options["--shell-timeout"])) 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/make/agentpycheck.mk b/make/agentpycheck.mk index e1434cf3..181fd174 100644 --- a/make/agentpycheck.mk +++ b/make/agentpycheck.mk @@ -1,30 +1,41 @@ 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.%) +TEST_TARGET=$(filter-out $(TEST_TARGET_SKIP),$(TARGET)) -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) - diff $(TEMPFILE) $(DATADIR)/$(INPUT).xml - rm $(TEMPFILE) +check: $(TEST_TARGET:%=%.xml-check) $(SYMTARGET:%=%.xml-check) $(TEST_TARGET:%=%.delay-check) $(TEST_TARGET:%=%.rng-check) -xml-upload.%: % - $(eval INPUT=$(subst xml-upload.,,$@)) - PYTHONPATH=$(abs_srcdir)/../lib:$(abs_builddir)/../lib $(PYTHON) ./$(INPUT) -o metadata | $(AWK) $(AWK_VAL) > $(DATADIR)/$(INPUT).xml +%.xml-check: % + $(eval INPUT=$(subst .xml-check,,$(@F))) + for x in $(INPUT) `PYTHONPATH=$(abs_srcdir)/lib:$(abs_builddir)/lib $(PYTHON) $(@D)/$(INPUT) -o metadata | grep symlink | sed -e "s/.*\(fence.*\)\" .*/\1/g"`; do \ + TEMPFILE=$$(mktemp); \ + PYTHONPATH=$(abs_srcdir)/lib:$(abs_builddir)/lib $(PYTHON) $(@D)/$$x -o metadata | $(AWK) $(AWK_VAL) > $$TEMPFILE && \ + diff $$TEMPFILE $(DATADIR)/$$x.xml && \ + rm $$TEMPFILE; \ + done + +%.xml-upload: % + $(eval INPUT=$(subst .xml-upload,,$(@F))) + for x in $(INPUT) `PYTHONPATH=$(abs_srcdir)/lib:$(abs_builddir)/lib $(PYTHON) $(@D)/$(INPUT) -o metadata | grep symlink | sed -e "s/.*\(fence.*\)\" .*/\1/g"`; do \ + PYTHONPATH=$(abs_srcdir)/lib:$(abs_builddir)/lib $(PYTHON) $(@D)/$$x -o metadata | $(AWK) $(AWK_VAL) > $(DATADIR)/$$x.xml; \ + done # 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 |\ - 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 ) +%.delay-check: % + $(eval INPUT=$(subst .delay-check,,$(@F))) + for x in $(INPUT) `PYTHONPATH=$(abs_srcdir)/lib:$(abs_builddir)/lib $(PYTHON) $(@D)/$(INPUT) -o metadata | grep symlink | sed -e "s/.*\(fence.*\)\" .*/\1/g"`; do \ + test `PYTHONPATH=$(abs_srcdir)/lib:$(abs_builddir)/lib /usr/bin/time -f "%e" \ + sh -c "/bin/echo -e 'delay=10\n $(FENCE_TEST_ARGS)' | $(PYTHON) $(@D)/$$x" 2>&1 |\ + sed 's/\.//' | tail -n 1` -ge 1000 || ( \ + PYTHONPATH=$(abs_srcdir)/lib:$(abs_builddir)/lib /usr/bin/time -f "%e" \ + sh -c "/bin/echo -e 'delay=0\n $(FENCE_TEST_ARGS)' | $(PYTHON) $(@D)/$$x"; false ); \ + done -rng-check.%: % - 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 - +%.rng-check: % + $(eval INPUT=$(subst .rng-check,,$(@F))) + for x in $(INPUT) `PYTHONPATH=$(abs_srcdir)/lib:$(abs_builddir)/lib $(PYTHON) $(@D)/$(INPUT) -o metadata | grep symlink | sed -e "s/.*\(fence.*\)\" .*/\1/g"`; do \ + PYTHONPATH=$(abs_srcdir)/lib:$(abs_builddir)/lib $(PYTHON) $(@D)/$$x -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 -; \ + done diff --git a/make/fencebuild.mk b/make/fencebuild.mk index 8be199bd..ef6113c2 100644 --- a/make/fencebuild.mk +++ b/make/fencebuild.mk @@ -1,39 +1,48 @@ $(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 $@; \ + if [ 0 -eq `echo "$(@)" | 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 + for x in `PYTHONPATH=$(abs_srcdir)/lib:$(abs_builddir)/lib $(PYTHON) $(@) -o metadata | grep symlink | sed -e "s/.*\(fence.*\)\" .*/\1/g"`; do \ + cp $(@) $(@D)/$$x; \ + $(MAKE) $(@D)/$$x.8; \ + done + clean: clean-man - rm -f $(TARGET) $(SYMTARGET) *.pyc *.wiki + rm -f $(CLEAN_TARGET:%.8=%) $(CLEAN_TARGET_ADDITIONAL) $(scsidata_SCRIPTS) kdump/fence_kdump_send */*.pyc */*.wiki + + if [ "$(abs_builddir)" = "$(abs_top_builddir)/fence/agents/lib" ]; then \ + rm -f $(TARGET); \ + fi clean-local: clean diff --git a/make/fenceman.mk b/make/fenceman.mk index e5e18f65..29e05d7a 100644 --- a/make/fenceman.mk +++ b/make/fenceman.mk @@ -1,10 +1,11 @@ %.8: $(TARGET) $(top_srcdir)/fence/agents/lib/fence2man.xsl set -e && \ - PYTHONPATH=$(abs_srcdir)/../lib:$(abs_builddir)/../lib \ - $(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) + PYTHONPATH=$(abs_srcdir)/lib:$(abs_builddir)/../lib \ + $(PYTHON) $(@:%.8=%) -o metadata > $(@D)/.$(@F).tmp && \ + xmllint --noout --relaxng $(abs_srcdir)/lib/metadata.rng $(@D)/.$(@F).tmp && \ + xsltproc $(top_srcdir)/fence/agents/lib/fence2man.xsl $(@D)/.$(@F).tmp > $@ + xsltproc $(top_srcdir)/fence/agents/lib/fence2wiki.xsl $(@D)/.$(@F).tmp | grep -v ' $(@D)/$(@F:%.8=%.wiki) clean-man: - rm -f *.8 .*.8.tmp *.wiki + $(eval CLEAN_TARGET=$(shell find -name "*.8" | grep -Pv "kdump/fence_kdump_send.8|manual/fence_ack_manual.8")) + rm -f $(CLEAN_TARGET) */.*.8.tmp */*.wiki diff --git a/make/fencemanc.mk b/make/fencemanc.mk index 53156c54..ddeb2717 100644 --- a/make/fencemanc.mk +++ b/make/fencemanc.mk @@ -1,9 +1,10 @@ %.8: $(TARGET) $(top_srcdir)/fence/agents/lib/fence2man.xsl set -e && \ - ./$^ -o metadata > .$@.tmp && \ - xmllint --noout --relaxng $(top_srcdir)/fence/agents/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) + ./$(@:%.8=%) -o metadata > $(@D)/.$(@F).tmp && \ + xmllint --noout --relaxng $(top_srcdir)/fence/agents/lib/metadata.rng $(@D)/.$(@F).tmp && \ + xsltproc $(top_srcdir)/fence/agents/lib/fence2man.xsl $(@D)/.$(@F).tmp > $@ + xsltproc $(top_srcdir)/fence/agents/lib/fence2wiki.xsl $(@D)/.$(@F).tmp | grep -v ' $(@D)/$(@F:%.8=%.wiki) clean-man: - rm -f *.8 .*.8.tmp *.wiki + $(eval CLEAN_TARGET=$(shell find -name "*.8" | grep -Pv "kdump/fence_kdump_send.8|manual/fence_ack_manual.8")) + rm -f $(CLEAN_TARGET) */.*.8.tmp */*.wiki diff --git a/tests/data/metadata/fence_apc_snmp.xml b/tests/data/metadata/fence_apc_snmp.xml index 8f2bb4df..608f2714 100644 --- a/tests/data/metadata/fence_apc_snmp.xml +++ b/tests/data/metadata/fence_apc_snmp.xml @@ -1,182 +1,183 @@ + 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. http://www.apc.com Fencing action Set the community string 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 Login name Login password or passphrase Script to run to retrieve password Physical plug number on device, UUID or identification of machine Set authentication protocol Set privacy protocol password Script to run to retrieve privacy password Set privacy protocol Set security level Specifies SNMP version to use 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 snmpget binary Path to snmpset binary Path to snmpwalk binary diff --git a/tests/data/metadata/fence_tripplite_snmp.xml b/tests/data/metadata/fence_tripplite_snmp.xml index 64d332c3..4ce4ec46 100644 --- a/tests/data/metadata/fence_tripplite_snmp.xml +++ b/tests/data/metadata/fence_tripplite_snmp.xml @@ -1,182 +1,183 @@ + 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. http://www.apc.com Fencing action Set the community string 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 Login name Login password or passphrase Script to run to retrieve password Physical plug number on device, UUID or identification of machine Set authentication protocol Set privacy protocol password Script to run to retrieve privacy password Set privacy protocol Set security level Specifies SNMP version to use 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 snmpget binary Path to snmpset binary Path to snmpwalk binary diff --git a/tests/data/metadata/fence_apc_snmp.xml b/tests/data/metadata/fence_vmware.xml similarity index 55% copy from tests/data/metadata/fence_apc_snmp.xml copy to tests/data/metadata/fence_vmware.xml index 8f2bb4df..fbe0323e 100644 --- a/tests/data/metadata/fence_apc_snmp.xml +++ b/tests/data/metadata/fence_vmware.xml @@ -1,182 +1,159 @@ - -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. -http://www.apc.com + +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. +.P +Before you can use this agent, it must be installed VI Perl Toolkit or vmrun command on every node you want to make fencing. +.P +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!). +.P +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. +.P +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). +http://www.vmware.com Fencing action - - - - Set the community string + + + + Command to execute + + + + + Identity file (private key) for SSH 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 - + Login name Login password or passphrase Script to run to retrieve password - - + + - Physical plug number on device, UUID or identification of machine - - - - - - Set authentication protocol - - - + IP address or hostname of fencing device (together with --port-as-ip) + + + + + Use SSH connection + + + - Set privacy protocol password + SSH options to use + + + + + Type of VMware to connect - - + + - Script to run to retrieve privacy password - - - - - - Set privacy protocol - - - - - - Set security level - - - - - - Specifies SNMP version to use + VMWare datacenter filter 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 + + + + Make "port/plug" to be an alias to IP address + 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 snmpget binary - - - - - Path to snmpset binary - - - - - Path to snmpwalk binary + + + + Path to ssh binary - -