├── .gitignore ├── Makefile.am ├── README.md ├── agents ├── Makefile.am ├── aliyun │ └── fence_aliyun.py ├── alom │ └── fence_alom.py ├── amt │ └── fence_amt.py ├── amt_ws │ └── fence_amt_ws.py ├── apc │ └── fence_apc.py ├── apc_snmp │ ├── README │ ├── fence_apc_snmp.py │ └── powernet369.mib ├── autodetect │ ├── a.py │ ├── autodetect.py │ ├── autodetect_test.py │ ├── b.py │ ├── fence_apc.py │ ├── fence_bladecenter.py │ ├── fence_brocade.py │ ├── fence_ilo_moonshot.py │ ├── fence_lpar.py │ └── fencing.py ├── aws │ └── fence_aws.py ├── aws_vpc_net │ ├── fence_aws_vpc_net.py │ └── readme.md ├── azure_arm │ └── fence_azure_arm.py ├── bladecenter │ └── fence_bladecenter.py ├── brocade │ └── fence_brocade.py ├── cdu │ └── fence_cdu.py ├── cisco_mds │ └── fence_cisco_mds.py ├── cisco_ucs │ └── fence_cisco_ucs.py ├── compute │ └── fence_compute.py ├── crosslink │ ├── README.md │ └── fence_crosslink.py ├── cyberpower_ssh │ └── fence_cyberpower_ssh.py ├── docker │ └── fence_docker.py ├── drac │ └── fence_drac.py ├── drac5 │ └── fence_drac5.py ├── dummy │ └── fence_dummy.py ├── eaton_snmp │ ├── README │ └── fence_eaton_snmp.py ├── eaton_ssh │ └── fence_eaton_ssh.py ├── ecloud │ └── fence_ecloud.py ├── emerson │ └── fence_emerson.py ├── eps │ └── fence_eps.py ├── evacuate │ └── fence_evacuate.py ├── gce │ └── fence_gce.py ├── hds_cb │ └── fence_hds_cb.py ├── heuristics_ping │ └── fence_heuristics_ping.py ├── hpblade │ └── fence_hpblade.py ├── ibm_powervs │ └── fence_ibm_powervs.py ├── ibm_vpc │ └── fence_ibm_vpc.py ├── ibmblade │ └── fence_ibmblade.py ├── ibmz │ └── fence_ibmz.py ├── ifmib │ ├── README │ └── fence_ifmib.py ├── ilo │ └── fence_ilo.py ├── ilo_moonshot │ └── fence_ilo_moonshot.py ├── ilo_mp │ └── fence_ilo_mp.py ├── ilo_ssh │ └── fence_ilo_ssh.py ├── intelmodular │ └── fence_intelmodular.py ├── ipdu │ └── fence_ipdu.py ├── ipmilan │ └── fence_ipmilan.py ├── ironic │ └── fence_ironic.py ├── kdump │ ├── fence_kdump.c │ ├── fence_kdump_send.8 │ ├── fence_kdump_send.c │ ├── list.h │ ├── message.h │ ├── options.h │ └── version.h ├── kubevirt │ └── fence_kubevirt.py ├── ldom │ └── fence_ldom.py ├── lindy_pdu │ └── fence_lindypdu.py ├── lpar │ └── fence_lpar.py ├── manual │ ├── fence_ack_manual.8 │ └── fence_ack_manual.in ├── mpath │ └── fence_mpath.py ├── netio │ └── fence_netio.py ├── nutanix_ahv │ └── fence_nutanix_ahv.py ├── openstack │ └── fence_openstack.py ├── ovh │ └── fence_ovh.py ├── ovm │ └── fence_ovm.py ├── powerman │ └── fence_powerman.py ├── pve │ └── fence_pve.py ├── raritan │ └── fence_raritan.py ├── raritan_px3 │ └── fence_raritan_px3.py ├── rcd_serial │ ├── fence_rcd_serial.py │ └── rcd_serial_cable_diagram.svg ├── redfish │ └── fence_redfish.py ├── rhevm │ └── fence_rhevm.py ├── rsa │ └── fence_rsa.py ├── rsb │ └── fence_rsb.py ├── sanbox2 │ └── fence_sanbox2.py ├── sbd │ └── fence_sbd.py ├── scsi │ └── fence_scsi.py ├── skalar │ └── fence_skalar.py ├── vbox │ └── fence_vbox.py ├── virsh │ └── fence_virsh.py ├── virt │ ├── Makefile.am │ ├── client │ │ ├── Makefile.am │ │ ├── main.c │ │ ├── mcast.c │ │ ├── options.c │ │ ├── serial.c │ │ ├── tcp.c │ │ └── vsock.c │ ├── common │ │ ├── Makefile.am │ │ ├── bcast.c │ │ ├── debug.c │ │ ├── fdops.c │ │ ├── ip_lookup.c │ │ ├── log.c │ │ ├── mcast.c │ │ ├── simple_auth.c │ │ └── tcp.c │ ├── config │ │ ├── Makefile.am │ │ ├── config-stack.h │ │ ├── config.l │ │ ├── config.y │ │ ├── fence_virt.conf │ │ └── simpleconfig.c │ ├── docs │ │ ├── README │ │ ├── TODO │ │ ├── architecture.txt │ │ └── fence_virt.txt │ ├── fence_virtd.service.in │ ├── include │ │ ├── bcast.h │ │ ├── client.h │ │ ├── debug.h │ │ ├── fdops.h │ │ ├── history.h │ │ ├── ip_lookup.h │ │ ├── list.h │ │ ├── mcast.h │ │ ├── options.h │ │ ├── server_plugin.h │ │ ├── simple_auth.h │ │ ├── simpleconfig.h │ │ ├── static_map.h │ │ ├── tcp.h │ │ ├── tcp_listener.h │ │ └── xvm.h │ ├── man │ │ ├── .gitignore │ │ ├── Makefile.am │ │ ├── fence_virt.conf.5 │ │ ├── fence_virtd.8 │ │ └── fence_xvm.8 │ └── server │ │ ├── Makefile.am │ │ ├── config.c │ │ ├── cpg-virt.c │ │ ├── cpg.c │ │ ├── cpg.h │ │ ├── daemon_init.c │ │ ├── history.c │ │ ├── libvirt.c │ │ ├── main.c │ │ ├── mcast.c │ │ ├── plugin.c │ │ ├── serial.c │ │ ├── serial.h │ │ ├── static_map.c │ │ ├── tcp.c │ │ ├── uuid-test.c │ │ ├── uuid-test.h │ │ ├── virt-serial.c │ │ ├── virt-sockets.c │ │ ├── virt.c │ │ ├── virt.h │ │ └── vsock.c ├── vmware │ ├── fence_vmware.py │ └── fence_vmware_helper.pl ├── vmware_rest │ └── fence_vmware_rest.py ├── vmware_soap │ └── fence_vmware_soap.py ├── vmware_vcloud │ └── fence_vmware_vcloud.py ├── wti │ └── fence_wti.py ├── xenapi │ └── fence_xenapi.py └── zvm │ ├── fence_zvm.c │ ├── fence_zvm.h │ ├── fence_zvm_man_page │ ├── fence_zvmip.c │ └── fence_zvmip.py ├── autogen.sh ├── configure.ac ├── doc ├── COPYING.applications ├── COPYING.libraries ├── COPYRIGHT ├── FenceAgentAPI.md ├── Makefile.am ├── README.licence └── fa-dev-guide.md ├── docker ├── Dockerfile ├── README.md └── entrypoint.sh ├── fence-agents.pc.in ├── fence-agents.spec.in ├── lib ├── Makefile.am ├── XenAPI.py.py ├── azure_fence.py.py ├── check_used_options.py ├── fence.rng.head ├── fence.rng.tail ├── fence2man.xsl ├── fence2rng.xsl ├── fence2wiki.xsl ├── fencing.py.py ├── fencing_snmp.py.py ├── metadata.rng └── tests │ ├── Makefile.am │ └── test_fencing.py ├── m4 ├── PKG_CHECK_VAR.m4 ├── ac_python_module.m4 ├── ax_check_link_flag.m4 ├── ax_prog_date.m4 └── ax_pthread.m4 ├── make ├── agentccheck.mk ├── agentpycheck.mk ├── fencebuild.mk ├── fenceman.mk ├── git-version-gen ├── gitlog-to-changelog └── release.mk ├── systemd ├── Makefile.am └── fence-agents.conf.in └── tests ├── actions.d ├── list.cfg ├── power-on-off.cfg ├── sleep.cfg └── status.cfg ├── data └── metadata │ ├── fence_aliyun.xml │ ├── fence_alom.xml │ ├── fence_amt.xml │ ├── fence_amt_ws.xml │ ├── fence_apc.xml │ ├── fence_apc_snmp.xml │ ├── fence_aws.xml │ ├── fence_aws_vpc_net.xml │ ├── fence_azure_arm.xml │ ├── fence_bladecenter.xml │ ├── fence_brocade.xml │ ├── fence_cdu.xml │ ├── fence_cisco_mds.xml │ ├── fence_cisco_ucs.xml │ ├── fence_compute.xml │ ├── fence_crosslink.xml │ ├── fence_cyberpower_ssh.xml │ ├── fence_docker.xml │ ├── fence_drac.xml │ ├── fence_drac5.xml │ ├── fence_dummy.xml │ ├── fence_eaton_snmp.xml │ ├── fence_eaton_ssh.xml │ ├── fence_ecloud.xml │ ├── fence_emerson.xml │ ├── fence_eps.xml │ ├── fence_epsr2.xml │ ├── fence_evacuate.xml │ ├── fence_gce.xml │ ├── fence_hds_cb.xml │ ├── fence_heuristics_ping.xml │ ├── fence_hpblade.xml │ ├── fence_ibm_powervs.xml │ ├── fence_ibm_vpc.xml │ ├── fence_ibmblade.xml │ ├── fence_ibmz.xml │ ├── fence_idrac.xml │ ├── fence_ifmib.xml │ ├── fence_ilo.xml │ ├── fence_ilo2.xml │ ├── fence_ilo3.xml │ ├── fence_ilo3_ssh.xml │ ├── fence_ilo4.xml │ ├── fence_ilo4_ssh.xml │ ├── fence_ilo5.xml │ ├── fence_ilo5_ssh.xml │ ├── fence_ilo_moonshot.xml │ ├── fence_ilo_mp.xml │ ├── fence_ilo_ssh.xml │ ├── fence_imm.xml │ ├── fence_intelmodular.xml │ ├── fence_ipdu.xml │ ├── fence_ipmilan.xml │ ├── fence_ipmilanplus.xml │ ├── fence_ironic.xml │ ├── fence_kdump.xml │ ├── fence_kubevirt.xml │ ├── fence_ldom.xml │ ├── fence_lindypdu.xml │ ├── fence_lpar.xml │ ├── fence_mpath.xml │ ├── fence_netio.xml │ ├── fence_nutanix_ahv.xml │ ├── fence_openstack.xml │ ├── fence_ovh.xml │ ├── fence_ovm.xml │ ├── fence_powerman.xml │ ├── fence_pve.xml │ ├── fence_raritan.xml │ ├── fence_raritan_px3.xml │ ├── fence_rcd_serial.xml │ ├── fence_redfish.xml │ ├── fence_rhevm.xml │ ├── fence_rsa.xml │ ├── fence_rsb.xml │ ├── fence_sanbox2.xml │ ├── fence_sbd.xml │ ├── fence_scsi.xml │ ├── fence_skalar.xml │ ├── fence_tripplite_snmp.xml │ ├── fence_vbox.xml │ ├── fence_virsh.xml │ ├── fence_virt.xml │ ├── fence_vmware.xml │ ├── fence_vmware_rest.xml │ ├── fence_vmware_soap.xml │ ├── fence_vmware_vcloud.xml │ ├── fence_wti.xml │ ├── fence_xenapi.xml │ └── fence_zvmip.xml ├── devices.d ├── dummy-with_action.cfg ├── dummy.cfg ├── invalid-missing_option.cfg ├── true-with_action.cfg └── true.cfg ├── fence_testing.py ├── fence_testing_test.py ├── test-apc2.py ├── test-apc5.py ├── test-drac4.py ├── test-multi-apc2.py └── test.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.orig 2 | *.rej 3 | *.swp 4 | Makefile.in 5 | aclocal.m4 6 | autoconf 7 | autoheader 8 | autom4te.cache 9 | automake 10 | autoscan.log 11 | compile 12 | configure 13 | configure.scan 14 | config.guess 15 | config.log 16 | config.sub 17 | config.status 18 | Makefile 19 | depcomp 20 | install-sh 21 | libtoolize 22 | ltmain.sh 23 | libtool 24 | make/stamp-h1 25 | 26 | # ignore "libtoolized" m4 files, but keep our (enumerated) ones 27 | /m4/* 28 | !/m4/ac_python_module.m4 29 | !/m4/ax*.m4 30 | 31 | # make/release.mk related litter 32 | /.tarball-version 33 | /tag-* 34 | 35 | make/config.h* 36 | missing 37 | *.pc 38 | .deps 39 | .libs 40 | *.o 41 | *.la 42 | *.lo 43 | lib/*.py* 44 | lib/__pycache__ 45 | !lib/*.py.py 46 | !lib/check_used_options.py 47 | agents/*/fence_* 48 | agents/*/.dirstamp 49 | !agents/*/fence_*.py 50 | !agents/*/fence_*.c 51 | !agents/*/fence_*.h 52 | !agents/kdump/fence_kdump_send.8 53 | !agents/manual/fence_ack_manual.8 54 | !agents/zvm/fence_zvm_man_page 55 | .fence*.tmp 56 | fence-agents* 57 | .version 58 | tests/devices.d/* 59 | 60 | y.tab.* 61 | *.o 62 | *.lo 63 | *.la 64 | .deps 65 | .libs 66 | .*version 67 | *.swp 68 | agents/virt/client/fence_virt 69 | agents/virt/client/fence_xvm 70 | agents/virt/common/libfence_virt.a 71 | agents/virt/config/config.c 72 | agents/virt/config/libsimpleconfig.a 73 | agents/virt/fence_virtd.service 74 | agents/virt/server/fence_virtd 75 | fence-virt-* 76 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Fence agents 2 | 3 | Fence agents were developed as device "drivers" which are able to prevent computers from destroying data on shared 4 | storage. Their aim is to isolate a corrupted computer, using one of three methods: 5 | 6 | * Power - A computer that is switched off cannot corrupt data, but it is important to not do a "soft-reboot" as we 7 | won't know if this is possible. This also works for virtual machines when the fence device is a hypervisor. 8 | * Network - Switches can prevent routing to a given computer, so even if a computer is powered on it won't be able to 9 | harm the data. 10 | * Configuration - Fibre-channel switches or SCSI devices allow us to limit who can write to managed disks. 11 | 12 | Fence agents do not use configuration files, as configuration management is outside of their scope. All of the 13 | configuration has to be specified either as command-line arguments or lines of standard input (see the complete list 14 | for more info). 15 | 16 | Because many fence agents are quite similar to each other, a fencing library (in Python) was developed. Please use it 17 | for further development. Creating or modifying a new fence agent should be quite simple using this library. 18 | 19 | ## Where can I find more information? 20 | 21 | * [ClusterLabs website](http://www.clusterlabs.org/) 22 | * [Fence Agent Developer's Guide](https://github.com/ClusterLabs/fence-agents/tree/main/doc/fa-dev-guide.md) 23 | * [User and developer documentation](https://github.com/ClusterLabs/fence-agents/tree/main/doc/FenceAgentAPI.md) 24 | * Mailing lists for [users](http://oss.clusterlabs.org/mailman/listinfo/users) and 25 | [developers](http://oss.clusterlabs.org/mailman/listinfo/developers) 26 | * [ClusterLabs IRC channel](https://wiki.clusterlabs.org/wiki/ClusterLabs_IRC_channel) 27 | -------------------------------------------------------------------------------- /agents/Makefile.am: -------------------------------------------------------------------------------- 1 | MAINTAINERCLEANFILES = Makefile.in 2 | 3 | TARGET = $(AGENTS_LIST:%.py=%) 4 | 5 | SRC = $(TARGET:=.py) 6 | 7 | CLEAN_TARGET_ADDITIONAL = kdump/fence_kdump_send manual/fence_ack_manual */*.o 8 | 9 | EXTRA_DIST = $(SRC) 10 | 11 | sbin_PROGRAMS = 12 | sbin_SCRIPTS = $(TARGET) 13 | libexec_PROGRAMS = 14 | 15 | noinst_HEADERS = kdump/list.h kdump/message.h kdump/options.h kdump/version.h zvm/fence_zvm.h 16 | 17 | man_MANS = $(sbin_SCRIPTS:=.8) 18 | dist_man_MANS = 19 | 20 | EXTRA_SCRIPTS = 21 | 22 | if BUILD_FENCE_VIRT 23 | SUBDIRS = virt 24 | endif 25 | 26 | if BUILD_FENCE_KDUMP 27 | sbin_PROGRAMS += kdump/fence_kdump 28 | libexec_PROGRAMS += kdump/fence_kdump_send 29 | 30 | man_MANS += kdump/fence_kdump.8 31 | dist_man_MANS += kdump/fence_kdump_send.8 32 | 33 | kdump_fence_kdump_SOURCES = kdump/fence_kdump.c 34 | kdump_fence_kdump_CFLAGS = -D_GNU_SOURCE -Ikdump $(AM_CFLAGS) -Wno-cast-align 35 | 36 | kdump_fence_kdump_send_SOURCES = kdump/fence_kdump_send.c 37 | kdump_fence_kdump_send_CFLAGS = -D_GNU_SOURCE -Ikdump $(AM_CFLAGS) -Wno-cast-align 38 | endif 39 | 40 | if BUILD_FENCE_MANUAL 41 | EXTRA_DIST += manual/fence_ack_manual.in manual/fence_ack_manual.8 42 | 43 | sbin_SCRIPTS += manual/fence_ack_manual 44 | endif 45 | 46 | if BUILD_FENCE_ZVM 47 | EXTRA_DIST += zvm/fence_zvm_man_page 48 | 49 | sbin_PROGRAMS += zvm/fence_zvm 50 | 51 | man_MANS += zvm/fence_zvm.8 52 | 53 | zvm_fence_zvm_SOURCES = zvm/fence_zvm.c 54 | zvm_fence_zvm_CFLAGS = -D_GNU_SOURCE -Izvm $(AM_CFLAGS) 55 | endif 56 | 57 | if BUILD_FENCE_MPATH 58 | mpathdatadir = $(CLUSTERDATA) 59 | mpathdata_SCRIPTS = mpath/fence_mpath_check mpath/fence_mpath_check_hardreboot 60 | endif 61 | 62 | if BUILD_FENCE_SCSI 63 | scsidatadir = $(CLUSTERDATA) 64 | scsidata_SCRIPTS = scsi/fence_scsi_check scsi/fence_scsi_check_hardreboot 65 | endif 66 | 67 | FENCE_TEST_ARGS = \ 68 | login=test\n\ 69 | passwd=test\n\ 70 | ipaddr=test\n\ 71 | port=1\n\ 72 | managed=1\n\ 73 | devices=test\n\ 74 | session_url=http://test\n\ 75 | email=test@test.te\n\ 76 | ping_targets=localhost 77 | 78 | manual/fence_ack_manual: manual/fence_ack_manual.in 79 | mkdir -p $(@D) 80 | cat $^ | sed \ 81 | -e 's#@clustervarrun@#${CLUSTERVARRUN}#g' \ 82 | > $@ 83 | 84 | mpath/fence_mpath_check: mpath/fence_mpath 85 | cp $^ $@ 86 | 87 | mpath/fence_mpath_check_hardreboot: mpath/fence_mpath 88 | cp $^ $@ 89 | 90 | scsi/fence_scsi_check: scsi/fence_scsi 91 | cp $^ $@ 92 | 93 | scsi/fence_scsi_check_hardreboot: scsi/fence_scsi 94 | cp $^ $@ 95 | 96 | kdump/fence_kdump.8: kdump/fence_kdump $(top_srcdir)/lib/fence2man.xsl 97 | set -e && \ 98 | ./$(@:%.8=%) -o metadata > $(@D)/.$(@F).tmp && \ 99 | xmllint --noout --relaxng $(top_srcdir)/lib/metadata.rng $(@D)/.$(@F).tmp && \ 100 | xsltproc $(top_srcdir)/lib/fence2man.xsl $(@D)/.$(@F).tmp > $@ 101 | xsltproc $(top_srcdir)/lib/fence2wiki.xsl $(@D)/.$(@F).tmp | grep -v ' $(@D)/$(@F:%.8=%.wiki) 102 | 103 | kdump/fence_kdump_send.8: 104 | true 105 | 106 | manual/fence_ack_manual.8: 107 | true 108 | 109 | zvm/fence_zvm.8: zvm/fence_zvm 110 | cp $(top_srcdir)/agents/zvm/fence_zvm_man_page $(@D)/fence_zvm.8 111 | 112 | cisco_mds/fence_cisco_mds.delay-check: cisco_mds/fence_cisco_mds 113 | $(eval INPUT=$(subst .delay-check,,$@)) 114 | FENCE_TEST_ARGS_CISCO_MDS=$$(printf '$(FENCE_TEST_ARGS)' | sed 's#port=1#port=fc1/1#'); \ 115 | test `PYTHONPATH=$(abs_top_srcdir)/lib:$(abs_top_builddir)/lib /usr/bin/time -p \ 116 | sh -c "printf 'delay=10\n $$FENCE_TEST_ARGS_CISCO_MDS' | $(PYTHON) ./$(INPUT)" 2>&1 |\ 117 | awk -F"[. ]" -vOFS= '/real/ {print $$2,$$3}'` -ge 1000 || ( \ 118 | PYTHONPATH=$(abs_top_srcdir)/lib:$(abs_top_builddir)/lib /usr/bin/time -p \ 119 | sh -c "printf "delay=0\n $$FENCE_TEST_ARGS_CISCO_MDS" | $(PYTHON) ./$(INPUT)"; false ) 120 | 121 | include $(top_srcdir)/make/fencebuild.mk 122 | include $(top_srcdir)/make/fenceman.mk 123 | include $(top_srcdir)/make/agentpycheck.mk 124 | -------------------------------------------------------------------------------- /agents/alom/fence_alom.py: -------------------------------------------------------------------------------- 1 | #!@PYTHON@ -tt 2 | 3 | # The Following Agent Has Been Tested On: 4 | # 5 | # Sun(tm) Advanced Lights Out Manager CMT v1.6.1 6 | # as found on SUN T2000 Niagara 7 | 8 | import sys, re, time 9 | import atexit 10 | sys.path.append("@FENCEAGENTSLIBDIR@") 11 | from fencing import * 12 | 13 | def get_power_status(conn, options): 14 | conn.send_eol("showplatform") 15 | conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) 16 | status = re.search(r"standby", conn.before.lower()) 17 | result = (status != None and "off" or "on") 18 | 19 | return result 20 | 21 | def set_power_status(conn, options): 22 | cmd_line = (options["--action"] == "on" and "poweron" or "poweroff -f -y") 23 | conn.send_eol(cmd_line) 24 | conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) 25 | # Get the machine some time between poweron and poweroff 26 | time.sleep(int(options["--power-timeout"])) 27 | 28 | def main(): 29 | device_opt = ["ipaddr", "login", "passwd", "cmd_prompt", "secure"] 30 | 31 | atexit.register(atexit_handler) 32 | 33 | all_opt["secure"]["default"] = "1" 34 | all_opt["cmd_prompt"]["default"] = [r"sc\>\ "] 35 | 36 | options = check_input(device_opt, process_input(device_opt)) 37 | options["telnet_over_ssh"] = 1 38 | 39 | docs = {} 40 | docs["shortdesc"] = "Fence agent for Sun ALOM" 41 | docs["longdesc"] = "fence_alom is a Power Fencing agent \ 42 | which can be used with ALOM connected machines." 43 | docs["vendorurl"] = "http://www.sun.com" 44 | show_docs(options, docs) 45 | 46 | # Operate the fencing device 47 | conn = fence_login(options) 48 | result = fence_action(conn, options, set_power_status, get_power_status, None) 49 | fence_logout(conn, "logout") 50 | sys.exit(result) 51 | 52 | if __name__ == "__main__": 53 | main() 54 | -------------------------------------------------------------------------------- /agents/amt/fence_amt.py: -------------------------------------------------------------------------------- 1 | #!@PYTHON@ -tt 2 | 3 | import sys, re, os 4 | import atexit 5 | sys.path.append("@FENCEAGENTSLIBDIR@") 6 | from fencing import * 7 | from fencing import fail_usage, is_executable, run_command, run_delay 8 | 9 | try: 10 | from shlex import quote 11 | except ImportError: 12 | from pipes import quote 13 | 14 | def get_power_status(_, options): 15 | output = amt_run_command(options, create_command(options, "status")) 16 | match = re.search(r'Powerstate:[\s]*(..)', str(output)) 17 | status = match.group(1) if match else None 18 | 19 | if status == None: 20 | return "fail" 21 | elif status == "S0": # SO = on; S3 = sleep; S5 = off 22 | return "on" 23 | else: 24 | return "off" 25 | 26 | def set_power_status(_, options): 27 | amt_run_command(options, create_command(options, options["--action"])) 28 | return 29 | 30 | def reboot_cycle(_, options): 31 | (status, _, _) = run_command(options, create_command(options, "cycle")) 32 | return not bool(status) 33 | 34 | def amt_run_command(options, command, timeout=None): 35 | env = os.environ.copy() 36 | 37 | x = quote(options["--password"]) 38 | x = x[:-1] if x.endswith("'") else x 39 | x = x[1:] if x.startswith("'") else x 40 | env["AMT_PASSWORD"] = x 41 | 42 | # This is needed because setting the AMT_PASSWORD env 43 | # variable only works when no pipe is involved. E.g.: 44 | # - Broken: 45 | # $ AMT_PASSWORD='foobar' echo 'y' | /usr/bin/amttool nuc2 powerdown 46 | # 401 Unauthorized at /usr/bin/amttool line 129. 47 | # - Working: 48 | # $ AMT_PASSWORD='foobar' sh -c "(echo 'y' | /usr/bin/amttool nuc2 powerdown)" 49 | # execute: powerdown 50 | # result: pt_status: success 51 | newcommand = "sh -c \"(%s)\"" % command 52 | return run_command(options, newcommand, timeout, env) 53 | 54 | def create_command(options, action): 55 | cmd = options["--amttool-path"] 56 | 57 | # --ip / -a 58 | cmd += " " + options["--ip"] 59 | 60 | # --action / -o 61 | if action == "status": 62 | cmd += " info" 63 | elif action == "on": 64 | cmd = "echo \"y\"|" + cmd 65 | cmd += " powerup" 66 | elif action == "off": 67 | cmd = "echo \"y\"|" + cmd 68 | cmd += " powerdown" 69 | elif action == "cycle": 70 | cmd = "echo \"y\"|" + cmd 71 | cmd += " powercycle" 72 | if action in ["on", "off", "cycle"] and "--boot-option" in options: 73 | cmd += options["--boot-option"] 74 | 75 | # --use-sudo / -d 76 | if "--use-sudo" in options: 77 | cmd = options["--sudo-path"] + " " + cmd 78 | 79 | return cmd 80 | 81 | def define_new_opts(): 82 | all_opt["boot_option"] = { 83 | "getopt" : "b:", 84 | "longopt" : "boot-option", 85 | "help" : "-b, --boot-option=[option] " 86 | "Change the default boot behavior of the machine. (pxe|hd|hdsafe|cd|diag)", 87 | "required" : "0", 88 | "shortdesc" : "Change the default boot behavior of the machine.", 89 | "choices" : ["pxe", "hd", "hdsafe", "cd", "diag"], 90 | "order" : 1 91 | } 92 | all_opt["amttool_path"] = { 93 | "getopt" : ":", 94 | "longopt" : "amttool-path", 95 | "help" : "--amttool-path=[path] Path to amttool binary", 96 | "required" : "0", 97 | "shortdesc" : "Path to amttool binary", 98 | "default" : "@AMTTOOL_PATH@", 99 | "order": 200 100 | } 101 | 102 | def main(): 103 | atexit.register(atexit_handler) 104 | 105 | device_opt = ["ipaddr", "no_login", "passwd", "boot_option", "no_port", 106 | "sudo", "amttool_path", "method"] 107 | 108 | define_new_opts() 109 | 110 | all_opt["ipport"]["default"] = "16994" 111 | 112 | options = check_input(device_opt, process_input(device_opt)) 113 | 114 | docs = {} 115 | docs["shortdesc"] = "Fence agent for AMT" 116 | docs["longdesc"] = "fence_amt is a Power Fencing agent \ 117 | which can be used with Intel AMT. This agent calls support software amttool\ 118 | (http://www.kraxel.org/cgit/amtterm/)." 119 | docs["vendorurl"] = "http://www.intel.com/" 120 | show_docs(options, docs) 121 | 122 | run_delay(options) 123 | 124 | if not is_executable(options["--amttool-path"]): 125 | fail_usage("Amttool not found or not accessible") 126 | 127 | result = fence_action(None, options, set_power_status, get_power_status, None, reboot_cycle) 128 | 129 | sys.exit(result) 130 | 131 | if __name__ == "__main__": 132 | main() 133 | -------------------------------------------------------------------------------- /agents/apc_snmp/README: -------------------------------------------------------------------------------- 1 | This is an snmp based fence agent for APC power switches to be used 2 | with RHEL4 Red Hat Cluster Suite. 3 | 4 | The reasons to use this agent rather than the current fence_apc agent are: 5 | 1) This script has been tested with EVERY powerswitch that APC currently 6 | makes. 7 | 2) It will work on many older models that are no longer supported by APC. 8 | I have been told that it even works with the AP9200 switch. Older switches 9 | usually don't do well with the fence_apc script. 10 | 3) This agent works with large power switches that have more than 8 outlets. 11 | The fence_apc script will also, in the next update -- this script will work for you now. 12 | 13 | If feedback on this beta version of the agent is good, and if ganged switches 14 | can be supported, then this agent may replace fence_apc. 15 | 16 | In order to use this agent, you will need to have net-snmp-utils installed 17 | on every node in your cluster. net-snmp-utils is scheduled for inclusion 18 | in the base RHEL distribution for Update 4, and is yummable in FC5. 19 | 20 | After net-snmp-utils is installed, there will be a directory named: 21 | /usr/share/snmp/mibs/ 22 | 23 | Place the accompanying powernet369.mib file in this directory. 24 | 25 | To use the agent, cp the agent to the /sbin directory on every 26 | cluster node. The interface for the fence_apc_snmp agent is identical to 27 | the existing fence_apc agent, so if you are using APC for fencing in 28 | your cluster, you *could* backup your current fence_apc agent, and 29 | rename this agent from fence_apc_snmp to fence_apc, and it should just work. 30 | 31 | NOTE: The fence_apc_snmp agent does not yet support ganged or 'daisy-chained' 32 | APC switches. 33 | 34 | If you would rather not copy over your fence_apc agent, you can still use 35 | the fence_apc_snmp agent by dropping it into /sbin on every node, and then 36 | defining a in the cluster.conf file with agent="fence_apc_snmp" 37 | as an attribute, and use it that way. Note, please, that the GUI does 38 | not support this agent yet, and you will have to edit your cluster.conf 39 | by hand and then propagate it yourself. If you need help with this, email 40 | me on linux-cluster or at the address below. 41 | 42 | Big thanks to Nate Straz who laid the foundation for this agent. 43 | 44 | Please let me know how this agent works. 45 | --Jim Parsons - jparsons@redhat.com 46 | -------------------------------------------------------------------------------- /agents/apc_snmp/powernet369.mib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ClusterLabs/fence-agents/c95f3413ad06f77a56a9b11f234c0b8752f790df/agents/apc_snmp/powernet369.mib -------------------------------------------------------------------------------- /agents/autodetect/a.py: -------------------------------------------------------------------------------- 1 | from b import myf 2 | 3 | def maf(): 4 | return 5 5 | 6 | def maf2(): 7 | return myf() 8 | -------------------------------------------------------------------------------- /agents/autodetect/autodetect_test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import unittest 4 | import autodetect as detect 5 | 6 | class TestDetectDevice(unittest.TestCase): 7 | options = {} 8 | 9 | def setUp(self): 10 | self.options = {} 11 | self.options["--ssh-path"] = "/usr/bin/ssh" 12 | self.options["--telnet-path"] = "/usr/bin/telnet" 13 | self.options["--login-timeout"] = "10" 14 | self.options["--shell-timeout"] = "5" 15 | self.options["--power-timeout"] = "10" 16 | self.options["eol"] = "\r\n" 17 | 18 | def test_bladecenter(self): 19 | self.options["--username"] = "rhts" 20 | self.options["--password"] = "100yard-" 21 | self.options["--ip"] = "blade-mm.englab.brq.redhat.com" 22 | 23 | (found_cmd_prompt, conn) = detect.detect_login_telnet(self.options) 24 | res = detect.detect_device(conn, self.options, found_cmd_prompt) 25 | self.assertEqual('fence_bladecenter', res) 26 | 27 | def test_apc5(self): 28 | self.assertEqual('foo', 'foo') 29 | self.options["c"] = "c" 30 | print self.options 31 | 32 | if __name__ == "__main__": 33 | unittest.main() 34 | -------------------------------------------------------------------------------- /agents/autodetect/b.py: -------------------------------------------------------------------------------- 1 | def myf(): 2 | return 3 3 | -------------------------------------------------------------------------------- /agents/autodetect/fence_bladecenter.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python -tt 2 | 3 | ##### 4 | ## 5 | ## The Following Agent Has Been Tested On: 6 | ## 7 | ## Model Firmware 8 | ## +--------------------+---------------------------+ 9 | ## (1) Main application BRET85K, rev 16 10 | ## Boot ROM BRBR67D, rev 16 11 | ## Remote Control BRRG67D, rev 16 12 | ## 13 | ##### 14 | 15 | import sys, re 16 | import atexit 17 | sys.path.append("@FENCEAGENTSLIBDIR@") 18 | from fencing import * 19 | from fencing import fail, EC_STATUS, EC_GENERIC_ERROR 20 | 21 | #BEGIN_VERSION_GENERATION 22 | RELEASE_VERSION="New Bladecenter Agent - test release on steroids" 23 | REDHAT_COPYRIGHT="" 24 | BUILD_DATE="March, 2008" 25 | #END_VERSION_GENERATION 26 | 27 | def get_power_status(conn, options): 28 | node_cmd = r"system:blade\[" + options["--plug"] + r"\]>" 29 | 30 | conn.send_eol("env -T system:blade[" + options["--plug"] + "]") 31 | i = conn.log_expect([node_cmd, "system>"], int(options["--shell-timeout"])) 32 | if i == 1: 33 | ## Given blade number does not exist 34 | if options.has_key("--missing-as-off"): 35 | return "off" 36 | else: 37 | fail(EC_STATUS) 38 | conn.send_eol("power -state") 39 | conn.log_expect(node_cmd, int(options["--shell-timeout"])) 40 | status = conn.before.splitlines()[-1] 41 | conn.send_eol("env -T system") 42 | conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) 43 | 44 | return status.lower().strip() 45 | 46 | def set_power_status(conn, options): 47 | node_cmd = r"system:blade\[" + options["--plug"] + r"\]>" 48 | 49 | conn.send_eol("env -T system:blade[" + options["--plug"] + "]") 50 | i = conn.log_expect([node_cmd, "system>"], int(options["--shell-timeout"])) 51 | if i == 1: 52 | ## Given blade number does not exist 53 | if options.has_key("--missing-as-off"): 54 | return 55 | else: 56 | fail(EC_GENERIC_ERROR) 57 | 58 | conn.send_eol("power -"+options["--action"]) 59 | conn.log_expect(node_cmd, int(options["--shell-timeout"])) 60 | conn.send_eol("env -T system") 61 | conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) 62 | 63 | def get_blades_list(conn, options): 64 | outlets = {} 65 | 66 | node_cmd = "system>" 67 | 68 | conn.send_eol("env -T system") 69 | conn.log_expect(node_cmd, int(options["--shell-timeout"])) 70 | conn.send_eol("list -l 2") 71 | conn.log_expect(node_cmd, int(options["--shell-timeout"])) 72 | 73 | lines = conn.before.split("\r\n") 74 | filter_re = re.compile(r"^\s*blade\[(\d+)\]\s+(.*?)\s*$") 75 | for blade_line in lines: 76 | res = filter_re.search(blade_line) 77 | if res != None: 78 | outlets[res.group(1)] = (res.group(2), "") 79 | 80 | return outlets 81 | 82 | def main(): 83 | device_opt = ["ipaddr", "login", "passwd", "cmd_prompt", "secure", \ 84 | "port", "missing_as_off", "telnet"] 85 | 86 | atexit.register(atexit_handler) 87 | 88 | all_opt["power_wait"]["default"] = "10" 89 | all_opt["cmd_prompt"]["default"] = ["system>"] 90 | 91 | options = check_input(device_opt, process_input(device_opt)) 92 | 93 | docs = {} 94 | docs["shortdesc"] = "Fence agent for IBM BladeCenter" 95 | docs["longdesc"] = "fence_bladecenter is an I/O Fencing agent \ 96 | which can be used with IBM Bladecenters with recent enough firmware that \ 97 | includes telnet support. It logs into a Brocade chasis via telnet or ssh \ 98 | and uses the command line interface to power on and off blades." 99 | docs["vendorurl"] = "http://www.ibm.com" 100 | show_docs(options, docs) 101 | 102 | ## 103 | ## Operate the fencing device 104 | ###### 105 | conn = fence_login(options, "(username\s*:\s*)") 106 | result = fence_action(conn, options, set_power_status, get_power_status, get_blades_list) 107 | fence_logout(conn, "exit") 108 | sys.exit(result) 109 | 110 | if __name__ == "__main__": 111 | main() 112 | -------------------------------------------------------------------------------- /agents/autodetect/fence_brocade.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python -tt 2 | 3 | import sys, re 4 | import atexit 5 | sys.path.append("@FENCEAGENTSLIBDIR@") 6 | from fencing import * 7 | from fencing import fail, EC_STATUS 8 | 9 | #BEGIN_VERSION_GENERATION 10 | RELEASE_VERSION="New Brocade Agent - test release on steroids" 11 | REDHAT_COPYRIGHT="" 12 | BUILD_DATE="March, 20013" 13 | #END_VERSION_GENERATION 14 | 15 | def set_power_status(conn, options): 16 | action = { 17 | 'on' : "portCfgPersistentEnable", 18 | 'off': "portCfgPersistentDisable" 19 | }[options["--action"]] 20 | 21 | conn.send_eol(action + " " + options["--plug"]) 22 | conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) 23 | 24 | def get_power_status(conn, options): 25 | line_re = re.compile(r'=========', re.IGNORECASE) 26 | outlets = {} 27 | in_index = False 28 | 29 | conn.send_eol("switchshow") 30 | conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) 31 | for line in str(conn.before).split("\n"): 32 | if line_re.search(line): 33 | in_index = True 34 | elif in_index and line.lstrip()[0].isdigit(): 35 | tokens = line.lstrip().split() 36 | status = "off" if len(tokens) > 7 and tokens[7] == "Disabled" else "on" 37 | outlets[tokens[0]] = ("", status) 38 | 39 | if ["list", "monitor"].count(options["--action"]) == 0: 40 | (_, status) = outlets[options["--plug"]] 41 | return status 42 | else: 43 | return outlets 44 | 45 | def main(): 46 | device_opt = ["ipaddr", "login", "passwd", "cmd_prompt", "secure", \ 47 | "port", "fabric_fencing", "telnet"] 48 | 49 | atexit.register(atexit_handler) 50 | 51 | all_opt["cmd_prompt"]["default"] = ["> "] 52 | 53 | options = check_input(device_opt, process_input(device_opt)) 54 | options["eol"] = "\n" 55 | 56 | docs = {} 57 | docs["shortdesc"] = "Fence agent for HP Brocade over telnet/ssh" 58 | docs["longdesc"] = "fence_brocade is an I/O Fencing agent which can be used with Brocade FC switches. \ 59 | It logs into a Brocade switch via telnet and disables a specified port. Disabling the port which a machine is \ 60 | connected to effectively fences that machine. Lengthy telnet connections to the switch should be avoided while \ 61 | a GFS cluster is running because the connection will block any necessary fencing actions. \ 62 | \ 63 | After a fence operation has taken place the fenced machine can no longer connect to the Brocade FC switch. \ 64 | When the fenced machine is ready to be brought back into the GFS cluster (after reboot) the port on the Brocade \ 65 | FC switch needs to be enabled. This can be done by running fence_brocade and specifying the enable action" 66 | docs["vendorurl"] = "http://www.brocade.com" 67 | show_docs(options, docs) 68 | 69 | ## 70 | ## Operate the fencing device 71 | #### 72 | conn = fence_login(options) 73 | result = fence_action(conn, options, set_power_status, get_power_status, get_power_status) 74 | fence_logout(conn, "exit") 75 | sys.exit(result) 76 | 77 | if __name__ == "__main__": 78 | main() 79 | -------------------------------------------------------------------------------- /agents/autodetect/fence_ilo_moonshot.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python -tt 2 | 3 | import sys 4 | import atexit 5 | sys.path.append("@FENCEAGENTSLIBDIR@") 6 | from fencing import * 7 | from fencing import fail, EC_STATUS 8 | 9 | #BEGIN_VERSION_GENERATION 10 | RELEASE_VERSION="" 11 | REDHAT_COPYRIGHT="" 12 | BUILD_DATE="" 13 | #END_VERSION_GENERATION 14 | 15 | def get_power_status(conn, options): 16 | conn.send_eol("show node list") 17 | conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) 18 | 19 | nodes = {} 20 | for line in conn.before.splitlines(): 21 | if len(line.split()) == 10: 22 | nodes[line.split()[1]] = ("", line.split()[8].lower().strip()) 23 | 24 | if ["list", "monitor"].count(options["--action"]) == 1: 25 | return nodes 26 | else: 27 | try: 28 | (_, status) = nodes[options["--plug"]] 29 | return status.lower() 30 | except KeyError: 31 | fail(EC_STATUS) 32 | 33 | def set_power_status(conn, options): 34 | if options["--action"] == "on": 35 | conn.send_eol("set node power on %s" % (options["--plug"])) 36 | else: 37 | conn.send_eol("set node power off force %s" % (options["--plug"])) 38 | 39 | conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) 40 | 41 | return 42 | 43 | def main(): 44 | device_opt = ["ipaddr", "login", "passwd", "secure", "cmd_prompt", "port"] 45 | 46 | atexit.register(atexit_handler) 47 | 48 | all_opt["secure"]["default"] = "1" 49 | all_opt["cmd_prompt"]["default"] = ["MP>", "hpiLO->"] 50 | 51 | options = check_input(device_opt, process_input(device_opt)) 52 | 53 | docs = {} 54 | docs["shortdesc"] = "Fence agent for HP Moonshot iLO" 55 | docs["longdesc"] = "" 56 | docs["vendorurl"] = "http://www.hp.com" 57 | show_docs(options, docs) 58 | 59 | conn = fence_login(options) 60 | 61 | ## 62 | ## Fence operations 63 | #### 64 | result = fence_action(conn, options, set_power_status, get_power_status, get_power_status) 65 | fence_logout(conn, "exit") 66 | sys.exit(result) 67 | 68 | if __name__ == "__main__": 69 | main() 70 | -------------------------------------------------------------------------------- /agents/bladecenter/fence_bladecenter.py: -------------------------------------------------------------------------------- 1 | #!@PYTHON@ -tt 2 | 3 | ##### 4 | ## 5 | ## The Following Agent Has Been Tested On: 6 | ## 7 | ## Model Firmware 8 | ## +--------------------+---------------------------+ 9 | ## (1) Main application BRET85K, rev 16 10 | ## Boot ROM BRBR67D, rev 16 11 | ## Remote Control BRRG67D, rev 16 12 | ## 13 | ##### 14 | 15 | import sys, re 16 | import atexit 17 | sys.path.append("@FENCEAGENTSLIBDIR@") 18 | from fencing import * 19 | from fencing import fail, EC_STATUS, EC_GENERIC_ERROR 20 | 21 | def get_power_status(conn, options): 22 | node_cmd = r"system:blade\[" + options["--plug"] + r"\]>" 23 | 24 | conn.send_eol("env -T system:blade[" + options["--plug"] + "]") 25 | i = conn.log_expect([node_cmd, "system>"], int(options["--shell-timeout"])) 26 | if i == 1: 27 | ## Given blade number does not exist 28 | if "--missing-as-off" in options: 29 | return "off" 30 | else: 31 | fail(EC_STATUS) 32 | conn.send_eol("power -state") 33 | conn.log_expect(node_cmd, int(options["--shell-timeout"])) 34 | status = conn.before.splitlines()[-1] 35 | conn.send_eol("env -T system") 36 | conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) 37 | 38 | return status.lower().strip() 39 | 40 | def set_power_status(conn, options): 41 | node_cmd = r"system:blade\[" + options["--plug"] + r"\]>" 42 | 43 | conn.send_eol("env -T system:blade[" + options["--plug"] + "]") 44 | i = conn.log_expect([node_cmd, "system>"], int(options["--shell-timeout"])) 45 | if i == 1: 46 | ## Given blade number does not exist 47 | if "--missing-as-off" in options: 48 | return 49 | else: 50 | fail(EC_GENERIC_ERROR) 51 | 52 | conn.send_eol("power -"+options["--action"]) 53 | conn.log_expect(node_cmd, int(options["--shell-timeout"])) 54 | conn.send_eol("env -T system") 55 | conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) 56 | 57 | def get_blades_list(conn, options): 58 | outlets = {} 59 | 60 | node_cmd = "system>" 61 | 62 | conn.send_eol("env -T system") 63 | conn.log_expect(node_cmd, int(options["--shell-timeout"])) 64 | conn.send_eol("list -l 2") 65 | conn.log_expect(node_cmd, int(options["--shell-timeout"])) 66 | 67 | lines = conn.before.split("\r\n") 68 | filter_re = re.compile(r"^\s*blade\[(\d+)\]\s+(.*?)\s*$") 69 | for blade_line in lines: 70 | res = filter_re.search(blade_line) 71 | if res != None: 72 | outlets[res.group(1)] = (res.group(2), "") 73 | 74 | return outlets 75 | 76 | def main(): 77 | device_opt = ["ipaddr", "login", "passwd", "cmd_prompt", "secure", \ 78 | "port", "missing_as_off", "telnet"] 79 | 80 | atexit.register(atexit_handler) 81 | 82 | all_opt["power_wait"]["default"] = "10" 83 | all_opt["cmd_prompt"]["default"] = ["system>"] 84 | 85 | options = check_input(device_opt, process_input(device_opt)) 86 | 87 | docs = {} 88 | docs["shortdesc"] = "Fence agent for IBM BladeCenter" 89 | docs["longdesc"] = "fence_bladecenter is a Power Fencing agent \ 90 | which can be used with IBM Bladecenters with recent enough firmware that \ 91 | includes telnet support. It logs into a Brocade chasis via telnet or ssh \ 92 | and uses the command line interface to power on and off blades." 93 | docs["vendorurl"] = "http://www.ibm.com" 94 | show_docs(options, docs) 95 | 96 | ## 97 | ## Operate the fencing device 98 | ###### 99 | conn = fence_login(options, r"(username\s*:\s*)") 100 | result = fence_action(conn, options, set_power_status, get_power_status, get_blades_list) 101 | fence_logout(conn, "exit") 102 | sys.exit(result) 103 | 104 | if __name__ == "__main__": 105 | main() 106 | -------------------------------------------------------------------------------- /agents/brocade/fence_brocade.py: -------------------------------------------------------------------------------- 1 | #!@PYTHON@ -tt 2 | 3 | import sys, re 4 | import atexit 5 | sys.path.append("@FENCEAGENTSLIBDIR@") 6 | from fencing import * 7 | from fencing import fail, EC_STATUS 8 | 9 | def set_power_status(conn, options): 10 | action = { 11 | 'on' : "portCfgPersistentEnable", 12 | 'off': "portCfgPersistentDisable" 13 | }[options["--action"]] 14 | 15 | conn.send_eol(action + " " + options["--plug"]) 16 | conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) 17 | 18 | def get_power_status(conn, options): 19 | line_re = re.compile(r'=========', re.IGNORECASE) 20 | outlets = {} 21 | in_index = False 22 | 23 | conn.send_eol("switchshow") 24 | conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) 25 | for line in str(conn.before).split("\n"): 26 | if line_re.search(line): 27 | in_index = True 28 | elif in_index and line.lstrip()[0].isdigit(): 29 | tokens = line.lstrip().split() 30 | status = "off" if len(tokens) > 7 and tokens[7] == "Disabled" else "on" 31 | outlets[tokens[0]] = ("", status) 32 | 33 | if ["list", "monitor"].count(options["--action"]) == 0: 34 | (_, status) = outlets[options["--plug"]] 35 | return status 36 | else: 37 | return outlets 38 | 39 | def main(): 40 | device_opt = ["ipaddr", "login", "passwd", "cmd_prompt", "secure", \ 41 | "port", "fabric_fencing", "telnet"] 42 | 43 | atexit.register(atexit_handler) 44 | 45 | all_opt["cmd_prompt"]["default"] = ["> "] 46 | 47 | options = check_input(device_opt, process_input(device_opt)) 48 | options["eol"] = "\n" 49 | 50 | docs = {} 51 | docs["shortdesc"] = "Fence agent for HP Brocade over telnet/ssh" 52 | docs["longdesc"] = "fence_brocade is an I/O Fencing agent which can be used with Brocade FC switches. \ 53 | It logs into a Brocade switch via telnet and disables a specified port. Disabling the port which a machine is \ 54 | connected to effectively fences that machine. Lengthy telnet connections to the switch should be avoided while \ 55 | a GFS cluster is running because the connection will block any necessary fencing actions. \ 56 | \ 57 | After a fence operation has taken place the fenced machine can no longer connect to the Brocade FC switch. \ 58 | When the fenced machine is ready to be brought back into the GFS cluster (after reboot) the port on the Brocade \ 59 | FC switch needs to be enabled. This can be done by running fence_brocade and specifying the enable action" 60 | docs["vendorurl"] = "http://www.brocade.com" 61 | show_docs(options, docs) 62 | 63 | ## 64 | ## Operate the fencing device 65 | #### 66 | conn = fence_login(options) 67 | result = fence_action(conn, options, set_power_status, get_power_status, get_power_status) 68 | fence_logout(conn, "exit") 69 | sys.exit(result) 70 | 71 | if __name__ == "__main__": 72 | main() 73 | -------------------------------------------------------------------------------- /agents/cisco_mds/fence_cisco_mds.py: -------------------------------------------------------------------------------- 1 | #!@PYTHON@ -tt 2 | 3 | # The Following agent has been tested on: 4 | # - Cisco MDS UROS 9134 FC (1 Slot) Chassis ("1/2/4 10 Gbps FC/Supervisor-2") Motorola, e500v2 5 | # with BIOS 1.0.16, kickstart 4.1(1c), system 4.1(1c) 6 | # - Cisco MDS 9124 (1 Slot) Chassis ("1/2/4 Gbps FC/Supervisor-2") Motorola, e500 7 | # with BIOS 1.0.16, kickstart 4.1(1c), system 4.1(1c) 8 | 9 | import sys, re 10 | import atexit 11 | sys.path.append("@FENCEAGENTSLIBDIR@") 12 | from fencing import * 13 | from fencing import fail_usage, array_to_dict 14 | from fencing_snmp import FencingSnmp 15 | 16 | ### CONSTANTS ### 17 | # Cisco admin status 18 | PORT_ADMIN_STATUS_OID = ".1.3.6.1.2.1.75.1.2.2.1.1" 19 | 20 | # IF-MIB trees for alias, status and port 21 | ALIASES_OID = ".1.3.6.1.2.1.31.1.1.1.18" 22 | PORTS_OID = ".1.3.6.1.2.1.2.2.1.2" 23 | 24 | ### GLOBAL VARIABLES ### 25 | # OID converted from fc port name (fc(x)/(y)) 26 | PORT_OID = "" 27 | 28 | ### FUNCTIONS ### 29 | 30 | # Convert cisco port name (fc(x)/(y)) to OID 31 | def cisco_port2oid(port): 32 | port = port.lower() 33 | 34 | nums = re.match(r'^fc(\d+)/(\d+)$', port) 35 | 36 | if nums and len(nums.groups()) == 2: 37 | return "%s.%d.%d"% (PORT_ADMIN_STATUS_OID, int(nums.group(1))+21, int(nums.group(2))-1) 38 | else: 39 | fail_usage("Mangled port number: %s"%(port)) 40 | 41 | def get_power_status(conn, options): 42 | (_, status) = conn.get(PORT_OID) 43 | return status == "1" and "on" or "off" 44 | 45 | def set_power_status(conn, options): 46 | conn.set(PORT_OID, (options["--action"] == "on" and 1 or 2)) 47 | 48 | def get_outlets_status(conn, options): 49 | result = {} 50 | 51 | res_fc = conn.walk(PORTS_OID, 30) 52 | res_aliases = array_to_dict(conn.walk(ALIASES_OID, 30)) 53 | 54 | fc_re = re.compile(r'^"fc\d+/\d+"$') 55 | 56 | for x in res_fc: 57 | if fc_re.match(x[1]): 58 | port_num = x[0].split('.')[-1] 59 | 60 | port_name = x[1].strip('"') 61 | port_alias = (port_num in res_aliases and res_aliases[port_num].strip('"') or "") 62 | port_status = "" 63 | result[port_name] = (port_alias, port_status) 64 | 65 | return result 66 | 67 | # Main agent method 68 | def main(): 69 | global PORT_OID 70 | 71 | device_opt = ["fabric_fencing", "ipaddr", "login", "passwd", "no_login", "no_password", \ 72 | "port", "snmp_version", "snmp"] 73 | 74 | atexit.register(atexit_handler) 75 | 76 | options = check_input(device_opt, process_input(device_opt)) 77 | 78 | docs = {} 79 | docs["shortdesc"] = "Fence agent for Cisco MDS" 80 | docs["longdesc"] = "fence_cisco_mds is an I/O Fencing agent \ 81 | which can be used with any Cisco MDS 9000 series with SNMP enabled device." 82 | docs["vendorurl"] = "http://www.cisco.com" 83 | show_docs(options, docs) 84 | 85 | if not options["--action"] in ["list", "monitor"]: 86 | PORT_OID = cisco_port2oid(options["--plug"]) 87 | 88 | # Operate the fencing device 89 | result = fence_action(FencingSnmp(options), options, set_power_status, get_power_status, get_outlets_status) 90 | 91 | sys.exit(result) 92 | 93 | if __name__ == "__main__": 94 | main() 95 | -------------------------------------------------------------------------------- /agents/crosslink/README.md: -------------------------------------------------------------------------------- 1 | # Two node cross-link fence agent 2 | 3 | The problem that this fence agents tries to solve is the following: 4 | 5 | Given a two-node cluster with a direct crosslink ethernet cable 6 | between the two nodes (in addition to the normal networking setup), we want to 7 | be able to maintain quorum on node (A) when node (B) lost power. 8 | The loss of power on node (B) in this case implies its BMC/IPMI is also 9 | not available which would be normally used in fencing in this case. 10 | 11 | Note: An external PDU would be preferrable and would solve this 12 | situation more elegantly. The assumption here is that something 13 | like that won't be available in this environment. 14 | 15 | This works by creating a stonith level composed of a BMC/IPMI 16 | fencing at level 1 and then the fence_crosslink agent at level 2. 17 | 18 | In case node (A) has lost power, then node (B) will do the following: 19 | 1. Try to fence node (B) via IPMI, which will fail since the node has no 20 | power and the BMC is unavailable 21 | 2. Check via fence_crosslink the cross-cable interconnect. If the cross cable 22 | IP is not reachable, then we know for "sure" (this is a potentially broad 23 | assumption) that the node is really down and fence_crosslink tells pacemaker 24 | that the fencing was successful, so pacemaker can work with that new 25 | information. 26 | 27 | Here are some example configuration commands: 28 | ~~~ 29 | pcs stonith create crosslink-controller-1 fence_crosslink crosscableip=1.1.1.2 pcmk_host_list=controller-1 pcmk_reboot_action=off 30 | pcs stonith create crosslink-controller-0 fence_crosslink crosscableip=1.1.1.1 pcmk_host_list=controller-0 pcmk_reboot_action=off 31 | # We make sure the stonith resource do not run on the same node as the fencing target 32 | pcs constraint location crosslink-controller-1 avoids controller-1 33 | pcs constraint location crosslink-controller-0 avoids controller-0 34 | pcs stonith level add 2 controller-0 crosslink-controller-0 35 | pcs stonith level add 2 controller-1 crosslink-controller-1 36 | ~~~ 37 | 38 | Testing done: 39 | - Simulate power outage by turning off the controller-1 VM and its IPMI interface and leaving the crosslink intact. 40 | 41 | * Expected Outcome: 42 | We should retain quorum on controller-0 and all services should be running on controller-0. No UNCLEAN resources should be observed on controller-0. 43 | * Actual Outcome: 44 | Matched the expected outcome. 45 | -------------------------------------------------------------------------------- /agents/crosslink/fence_crosslink.py: -------------------------------------------------------------------------------- 1 | #!@PYTHON@ -tt 2 | 3 | # Copyright (c) 2020 Red Hat 4 | # 5 | # This library is free software; you can redistribute it and/or 6 | # modify it under the terms of the GNU Lesser General Public 7 | # License as published by the Free Software Foundation; either 8 | # version 2.1 of the License, or (at your option) any later version. 9 | # 10 | # This library is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | # Lesser General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU Lesser General Public 16 | # License along with this library. If not, see 17 | # . 18 | 19 | import atexit 20 | import logging 21 | import sys 22 | sys.path.append("@FENCEAGENTSLIBDIR@") 23 | from fencing import (all_opt, atexit_handler, check_input, # noqa: E402 24 | fence_action, process_input, run_command, run_delay, 25 | show_docs) 26 | 27 | logger = logging.getLogger(__name__) 28 | logger.setLevel("WARNING") 29 | 30 | 31 | def get_power_status(conn, options): 32 | logger.debug("get_power_status(): %s" % options) 33 | ip = options['--crosscableip'] 34 | timeout = options['--timeout'] 35 | # This returns 'off' if not a single ICMP packet gets answered during the 36 | # whole timeout window. (the ping executable will return 1 in such case and 37 | # 0 if even a single packet gets replied to) 38 | (status, stdout, stderr) = run_command(options, "ping -w%s -n %s" % 39 | (timeout, ip)) 40 | logger.debug("get_power_status(): %s - Stdout: %s - Stderr: %s" % 41 | (status, stdout, stderr)) 42 | if status == 0: 43 | return "on" 44 | else: 45 | return "off" 46 | 47 | 48 | def set_power_status(conn, options): 49 | logger.debug("set_power_status(): %s" % options) 50 | # If we got here it means the previous call to get_power_status() returned 51 | # on At this point we've been invoked but the node is still reachable over 52 | # the cross connect, so we can just error out. 53 | ip = options['--crosscableip'] 54 | if options['--action'] == 'off': 55 | logger.error("We've been asked to turn off the node at %s but the " 56 | "cross-cable link is up so erroring out" % ip) 57 | sys.exit(1) 58 | elif options['--action'] == 'on': 59 | logger.error("We've been asked to turn on the node at %s but the " 60 | "cross-cable link is off so erroring out" % ip) 61 | sys.exit(1) 62 | else: 63 | logger.error("set_power_status() was called with action %s which " 64 | "is not supported" % options['--action']) 65 | sys.exit(1) 66 | 67 | 68 | def define_new_opts(): 69 | all_opt["crosscableip"] = { 70 | "getopt": "a:", 71 | "longopt": "crosscableip", 72 | "help": "-a, --crosscableip=[IP] IP over the cross-cable link", 73 | "required": "1", 74 | "shortdesc": "Cross-cable IP", 75 | "order": 1 76 | } 77 | all_opt["timeout"] = { 78 | "getopt": "T:", 79 | "longopt": "timeout", 80 | "help": "-T, --timeout=[seconds] timeout in seconds", 81 | "required": "0", 82 | "shortdesc": "No ICMP reply in 5 seconds -> Node is considered dead", 83 | "default": "5", 84 | "order": 1 85 | } 86 | 87 | 88 | def main(): 89 | atexit.register(atexit_handler) 90 | 91 | device_opt = ["crosscableip", "timeout", "no_password", "no_login", "port"] 92 | define_new_opts() 93 | 94 | options = check_input(device_opt, process_input(device_opt)) 95 | 96 | docs = {} 97 | docs["shortdesc"] = "Fence agent for cross-link two-node clusters" 98 | docs["longdesc"] = "This agent helps two-node clusters to tackle the " \ 99 | "situation where one node lost power, cannot be " \ 100 | "fenced by telling pacemaker that if the node is not " \ 101 | "reachable over the crosslink cable, we can assume " \ 102 | "it is dead" 103 | docs["vendorurl"] = "" 104 | show_docs(options, docs) 105 | 106 | run_delay(options) 107 | 108 | result = fence_action(None, options, set_power_status, get_power_status) 109 | sys.exit(result) 110 | 111 | 112 | if __name__ == "__main__": 113 | main() 114 | -------------------------------------------------------------------------------- /agents/cyberpower_ssh/fence_cyberpower_ssh.py: -------------------------------------------------------------------------------- 1 | #!@PYTHON@ -tt 2 | 3 | ##### 4 | ## 5 | ## Fence agent for CyberPower based SSH-capable power strip 6 | ## Tested with CyberPower model PDU41001, ePDU Firmware version 1.2.0 7 | ## 8 | ##### 9 | 10 | import sys, re, time 11 | import atexit 12 | sys.path.append("@FENCEAGENTSLIBDIR@") 13 | from fencing import * 14 | from fencing import fail, EC_STATUS 15 | 16 | def set_power_status(conn, options): 17 | conn.send_eol("oltctrl index " + options["--plug"] + " act delay" + options["--action"]) 18 | conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) 19 | 20 | def get_power_status(conn, options): 21 | outlets = {} 22 | conn.send_eol("oltsta show") 23 | conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) 24 | lines = conn.before.split("\n") 25 | show_re = re.compile(r'(\s*)(\d)\s*(.*)\s*(On|Off)\s*') 26 | for line in lines: 27 | res = show_re.search(line) 28 | if res != None: 29 | outlets[res.group(2)] = (res.group(3), res.group(4)) 30 | if ["list", "monitor"].count(options["--action"]) == 1: 31 | return outlets 32 | else: 33 | try: 34 | (_,status) = outlets[options["--plug"]] 35 | return status.lower().strip() 36 | except KeyError: 37 | fail(EC_STATUS) 38 | 39 | def main(): 40 | device_opt = ["ipaddr", "login", "passwd", "cmd_prompt", "secure", \ 41 | "port"] 42 | 43 | atexit.register(atexit_handler) 44 | 45 | all_opt["cmd_prompt"]["default"] = ["\n>", "\nCyberPower >"] 46 | 47 | options = check_input(device_opt, process_input(device_opt)) 48 | 49 | docs = {} 50 | docs["shortdesc"] = "Fence agent for CyberPower over ssh" 51 | docs["longdesc"] = "fence_cyberpower_ssh is a Power Fencing agent \ 52 | which can be used with the CyberPower network power switch. It logs into \ 53 | device via ssh and reboots a specified outlet. Lengthy ssh connections \ 54 | should be avoided while a GFS cluster is running because the connection \ 55 | will block any necessary fencing actions." 56 | docs["vendorurl"] = "http://www.cyberpower.com" 57 | show_docs(options, docs) 58 | 59 | ## 60 | ## Operate the fencing device 61 | #### 62 | conn = fence_login(options) 63 | 64 | result = fence_action(conn, options, set_power_status, get_power_status, get_power_status) 65 | 66 | fence_logout(conn, "exit") 67 | sys.exit(result) 68 | 69 | if __name__ == "__main__": 70 | main() 71 | -------------------------------------------------------------------------------- /agents/drac/fence_drac.py: -------------------------------------------------------------------------------- 1 | #!@PYTHON@ -tt 2 | 3 | import sys, re 4 | import atexit 5 | sys.path.append("@FENCEAGENTSLIBDIR@") 6 | from fencing import * 7 | 8 | def get_power_status(conn, options): 9 | conn.send_eol("getmodinfo") 10 | conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) 11 | status = re.compile(r"\s+(on|off)\s+", re.IGNORECASE).search(conn.before).group(1) 12 | return status.lower().strip() 13 | 14 | def set_power_status(conn, options): 15 | action = { 16 | 'on' : "powerup", 17 | 'off': "powerdown" 18 | }[options["--action"]] 19 | 20 | conn.send_eol("serveraction -d 0 " + action) 21 | conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) 22 | 23 | def main(): 24 | device_opt = ["ipaddr", "login", "passwd", "cmd_prompt", "telnet"] 25 | 26 | atexit.register(atexit_handler) 27 | 28 | opt = process_input(device_opt) 29 | if "--username" in opt: 30 | all_opt["cmd_prompt"]["default"] = ["\\[" + opt["--username"] + "\\]# "] 31 | else: 32 | all_opt["cmd_prompt"]["default"] = ["\\[" "username" + "\\]# "] 33 | 34 | options = check_input(device_opt, opt) 35 | 36 | docs = {} 37 | docs["shortdesc"] = "Power Fencing agent for Dell DRAC IV" 38 | docs["longdesc"] = "fence_drac is a Power Fencing agent which can be used with \ 39 | the Dell Remote Access Card (DRAC). This card provides remote access to controlling \ 40 | power to a server. It logs into the DRAC through the telnet interface of the card. By \ 41 | default, the telnet interface is not enabled. To enable the interface, you will need \ 42 | to use the racadm command in the racser-devel rpm available from Dell. \ 43 | \ 44 | To enable telnet on the DRAC: \ 45 | \ 46 | [root]# racadm config -g cfgSerial -o cfgSerialTelnetEnable 1 \ 47 | \ 48 | [root]# racadm racreset \ 49 | " 50 | docs["vendorurl"] = "http://www.dell.com" 51 | show_docs(options, docs) 52 | 53 | ## 54 | ## Operate the fencing device 55 | #### 56 | conn = fence_login(options) 57 | result = fence_action(conn, options, set_power_status, get_power_status, None) 58 | fence_logout(conn, "exit") 59 | sys.exit(result) 60 | 61 | if __name__ == "__main__": 62 | main() 63 | -------------------------------------------------------------------------------- /agents/dummy/fence_dummy.py: -------------------------------------------------------------------------------- 1 | #!@PYTHON@ -tt 2 | 3 | import sys, random 4 | import logging 5 | import time 6 | import atexit 7 | sys.path.append("@FENCEAGENTSLIBDIR@") 8 | from fencing import * 9 | from fencing import fail_usage, run_delay 10 | 11 | plug_status = "on" 12 | 13 | def get_power_status_file(conn, options): 14 | del conn 15 | 16 | try: 17 | status_file = open(options["--status-file"], 'r') 18 | except Exception: 19 | return "off" 20 | 21 | status = status_file.read() 22 | status_file.close() 23 | 24 | return status.lower() 25 | 26 | def set_power_status_file(conn, options): 27 | del conn 28 | 29 | if not (options["--action"] in ["on", "off"]): 30 | return 31 | 32 | status_file = open(options["--status-file"], 'w') 33 | status_file.write(options["--action"]) 34 | status_file.close() 35 | 36 | def get_power_status_fail(conn, options): 37 | outlets = get_outlets_fail(conn, options) 38 | 39 | if len(outlets) == 0 or "--plug" not in options: 40 | fail_usage("Failed: You have to enter existing machine!") 41 | else: 42 | return outlets[options["--plug"]][0] 43 | 44 | def set_power_status_fail(conn, options): 45 | global plug_status 46 | del conn 47 | 48 | plug_status = "unknown" 49 | if options["--action"] == "on": 50 | plug_status = "off" 51 | 52 | def get_outlets_fail(conn, options): 53 | del conn 54 | 55 | result = {} 56 | global plug_status 57 | 58 | if options["--action"] == "on": 59 | plug_status = "off" 60 | 61 | # This fake agent has no port data to list, so we have to make 62 | # something up for the list action. 63 | if options.get("--action", None) == "list": 64 | result["fake_port_1"] = [plug_status, "fake"] 65 | result["fake_port_2"] = [plug_status, "fake"] 66 | elif "--plug" not in options: 67 | fail_usage("Failed: You have to enter existing machine!") 68 | else: 69 | port = options["--plug"] 70 | result[port] = [plug_status, "fake"] 71 | 72 | return result 73 | 74 | def main(): 75 | device_opt = ["no_password", "status_file", "random_sleep_range", "type", "no_port"] 76 | 77 | atexit.register(atexit_handler) 78 | 79 | all_opt["status_file"] = { 80 | "getopt" : ":", 81 | "longopt" : "status-file", 82 | "help":"--status-file=[file] Name of file that holds current status", 83 | "required" : "0", 84 | "shortdesc" : "File with status", 85 | "default" : "/tmp/fence_dummy.status", 86 | "order": 1 87 | } 88 | 89 | all_opt["random_sleep_range"] = { 90 | "getopt" : ":", 91 | "longopt" : "random_sleep_range", 92 | "help":"--random_sleep_range=[seconds] Issue a sleep between 1 and [seconds]", 93 | "required" : "0", 94 | "shortdesc" : "Issue a sleep between 1 and X seconds. Used for testing.", 95 | "order": 1 96 | } 97 | 98 | all_opt["type"] = { 99 | "getopt" : ":", 100 | "longopt" : "type", 101 | "help":"--type=[type] Possible types are: file and fail", 102 | "required" : "0", 103 | "shortdesc" : "Type of the dummy fence agent", 104 | "default" : "file", 105 | "order": 1 106 | } 107 | 108 | options = check_input(device_opt, process_input(device_opt)) 109 | 110 | docs = {} 111 | docs["shortdesc"] = "Dummy fence agent" 112 | docs["longdesc"] = "fence_dummy" 113 | docs["vendorurl"] = "http://www.example.com" 114 | show_docs(options, docs) 115 | 116 | run_delay(options) 117 | 118 | # random sleep for testing 119 | if "--random_sleep_range" in options: 120 | val = int(options["--random_sleep_range"]) 121 | ran = random.randint(1, val) 122 | logging.info("Random sleep for %d seconds\n", ran) 123 | time.sleep(ran) 124 | 125 | if options["--type"] == "fail": 126 | result = fence_action(None, options, set_power_status_fail, get_power_status_fail, get_outlets_fail) 127 | else: 128 | result = fence_action(None, options, set_power_status_file, get_power_status_file, None) 129 | 130 | sys.exit(result) 131 | 132 | if __name__ == "__main__": 133 | main() 134 | -------------------------------------------------------------------------------- /agents/eaton_snmp/README: -------------------------------------------------------------------------------- 1 | This is an snmp based fence agent for Eaton power distribution units to be used 2 | with RHEL4 Red Hat Cluster Suite. 3 | 4 | In order to use this agent, you will need to have net-snmp-utils installed 5 | on every node in your cluster. net-snmp-utils is scheduled for inclusion 6 | in the base RHEL distribution for Update 4, and is yummable in FC5. 7 | 8 | To use the agent, cp the agent to the /sbin directory on every 9 | cluster node. 10 | 11 | Then define a in the cluster.conf file with 12 | agent="fence_eaton_snmp" as an attribute, and use it that way. 13 | Note, please, that the GUI does not support this agent yet, and you will have 14 | to edit your cluster.conf by hand and then propagate it yourself. If you need 15 | help with this, email me at the address below. 16 | 17 | The interface for the fence_eaton_snmp agent is identical to the existing 18 | fence_apc_snmp agent, upon which it has been derived. 19 | 20 | --Arnaud Quette - ArnaudQuette@Eaton.com 21 | -------------------------------------------------------------------------------- /agents/emerson/fence_emerson.py: -------------------------------------------------------------------------------- 1 | #!@PYTHON@ -tt 2 | 3 | import sys 4 | import atexit 5 | sys.path.append("@FENCEAGENTSLIBDIR@") 6 | from fencing import * 7 | from fencing_snmp import FencingSnmp 8 | 9 | ### CONSTANTS ### 10 | STATUSES_OID = ".1.3.6.1.4.1.476.1.42.3.8.50.20.1.95" 11 | CONTROL_OID = ".1.3.6.1.4.1.476.1.42.3.8.50.20.1.100" 12 | NAMES_OID = ".1.3.6.1.4.1.476.1.42.3.8.50.20.1.10" 13 | 14 | # Status constants returned as value from SNMP 15 | STATUS_DOWN = 1 16 | STATUS_UP = 2 17 | 18 | # Status constants to set as value to SNMP 19 | STATUS_SET_OFF = 0 20 | STATUS_SET_ON = 1 21 | 22 | def get_power_status(conn, options): 23 | (_, status) = conn.get("%s.%s"% (STATUSES_OID, options["--plug"])) 24 | return status == str(STATUS_UP) and "on" or "off" 25 | 26 | def set_power_status(conn, options): 27 | conn.set("%s.%s" % (CONTROL_OID, options["--plug"]), 28 | (options["--action"] == "on" and STATUS_SET_ON or STATUS_SET_OFF)) 29 | 30 | def get_outlets_status(conn, _): 31 | result = {} 32 | res_outlet = conn.walk(STATUSES_OID, 30) 33 | 34 | for outlet_info in res_outlet: 35 | port_num = ".".join(outlet_info[0].split('.')[-3:]) 36 | port_alias = conn.get("%s.%s"% (NAMES_OID, port_num))[1] 37 | port_status = (outlet_info[1] == str(STATUS_UP) and "on" or "off") 38 | result[port_num] = (port_alias, port_status) 39 | return result 40 | 41 | def main(): 42 | device_opt = ["ipaddr", "login", "passwd", "no_login", "no_password", \ 43 | "port", "snmp_version", "snmp"] 44 | 45 | atexit.register(atexit_handler) 46 | 47 | all_opt["power_wait"]["default"] = "5" 48 | options = check_input(device_opt, process_input(device_opt)) 49 | 50 | docs = {} 51 | docs["shortdesc"] = "Fence agent for Emerson over SNMP" 52 | docs["longdesc"] = "fence_emerson is a Power Fencing agent \ 53 | which can be used with MPX and MPH2 managed rack PDU." 54 | docs["vendorurl"] = "http://www.emersonnetworkpower.com" 55 | show_docs(options, docs) 56 | 57 | # Operate the fencing device 58 | result = fence_action(FencingSnmp(options), options, set_power_status, get_power_status, get_outlets_status) 59 | 60 | sys.exit(result) 61 | if __name__ == "__main__": 62 | main() 63 | -------------------------------------------------------------------------------- /agents/hpblade/fence_hpblade.py: -------------------------------------------------------------------------------- 1 | #!@PYTHON@ -tt 2 | 3 | ##### 4 | ## 5 | ## The Following Agent Has Been Tested On: 6 | ## * HP BladeSystem c7000 Enclosure 7 | ## * HP Integrity Superdome X (BL920s) 8 | ##### 9 | 10 | import sys, re 11 | import pexpect 12 | import atexit 13 | sys.path.append("@FENCEAGENTSLIBDIR@") 14 | from fencing import * 15 | from fencing import fail, EC_STATUS 16 | 17 | def get_enclosure_type(conn, options): 18 | conn.send_eol("show enclosure info") 19 | conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) 20 | 21 | type_re=re.compile(r"^\s*Enclosure Type: (\w+)(.*?)\s*$") 22 | enclosure="unknown" 23 | for line in conn.before.splitlines(): 24 | res = type_re.search(line) 25 | if res != None: 26 | enclosure=res.group(1) 27 | 28 | if enclosure == "unknown": 29 | fail(EC_GENERIC_ERROR) 30 | 31 | return enclosure.lower().strip() 32 | 33 | def get_power_status(conn, options): 34 | if options["enc_type"] == "superdome": 35 | cmd_send = "parstatus -M -p " + options["--plug"] 36 | powrestr = r"^partition:\d\s+:\w+\s+/(\w+)\s.*$" 37 | else: 38 | cmd_send = "show server status " + options["--plug"] 39 | powrestr = r"^\s*Power: (.*?)\s*$" 40 | 41 | conn.send_eol(cmd_send) 42 | conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) 43 | 44 | power_re = re.compile(powrestr) 45 | status = "unknown" 46 | for line in conn.before.splitlines(): 47 | res = power_re.search(line) 48 | if res != None: 49 | if options["enc_type"] == "superdome": 50 | if res.group(1) == "DOWN": 51 | status = "off" 52 | else: 53 | status = "on" 54 | else: 55 | status = res.group(1) 56 | 57 | if status == "unknown": 58 | if "--missing-as-off" in options: 59 | return "off" 60 | else: 61 | fail(EC_STATUS) 62 | 63 | return status.lower().strip() 64 | 65 | def set_power_status(conn, options): 66 | if options["enc_type"] == "superdome": 67 | dev="partition " 68 | else: 69 | dev="server " 70 | 71 | if options["--action"] == "on": 72 | conn.send_eol("poweron " + dev + options["--plug"]) 73 | elif options["--action"] == "off": 74 | conn.send_eol("poweroff " + dev + options["--plug"] + " force") 75 | conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) 76 | 77 | def get_instances_list(conn, options): 78 | outlets = {} 79 | if options["enc_type"] == "superdome": 80 | cmd_send = "parstatus -P -M" 81 | listrestr = r"^partition:(\d+)\s+:\w+\s+/(\w+)\s+:OK.*?:(\w+)\s*$" 82 | else: 83 | cmd_send = "show server list" 84 | listrestr = r"^\s*(\d+)\s+(.*?)\s+(.*?)\s+OK\s+(.*?)\s+(.*?)\s*$" 85 | 86 | conn.send_eol(cmd_send) 87 | conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) 88 | 89 | list_re = re.compile(listrestr) 90 | for line in conn.before.splitlines(): 91 | res = list_re.search(line) 92 | if res != None: 93 | if options["enc_type"] == "superdome": 94 | outlets[res.group(1)] = (res.group(3), res.group(2).lower()) 95 | else: 96 | outlets[res.group(1)] = (res.group(2), res.group(4).lower()) 97 | 98 | return outlets 99 | 100 | def main(): 101 | device_opt = ["ipaddr", "login", "passwd", "cmd_prompt", "secure", \ 102 | "port", "missing_as_off", "telnet"] 103 | 104 | atexit.register(atexit_handler) 105 | 106 | all_opt["cmd_prompt"]["default"] = ["c7000oa>"] 107 | all_opt["login_timeout"]["default"] = "10" 108 | 109 | options = check_input(device_opt, process_input(device_opt)) 110 | 111 | docs = {} 112 | docs["shortdesc"] = "Fence agent for HP BladeSystem" 113 | docs["longdesc"] = "fence_hpblade is a Power Fencing agent \ 114 | which can be used with HP BladeSystem and HP Integrity Superdome X. \ 115 | It logs into the onboard administrator of an enclosure via telnet or \ 116 | ssh and uses the command line interface to power blades or partitions \ 117 | on or off." 118 | docs["vendorurl"] = "http://www.hp.com" 119 | show_docs(options, docs) 120 | 121 | ## 122 | ## Operate the fencing device 123 | ###### 124 | options["eol"] = "\n" 125 | conn = fence_login(options) 126 | 127 | options["enc_type"] = get_enclosure_type(conn, options) 128 | 129 | result = fence_action(conn, options, set_power_status, get_power_status, get_instances_list) 130 | fence_logout(conn, "exit") 131 | sys.exit(result) 132 | 133 | if __name__ == "__main__": 134 | main() 135 | -------------------------------------------------------------------------------- /agents/ibmblade/fence_ibmblade.py: -------------------------------------------------------------------------------- 1 | #!@PYTHON@ -tt 2 | 3 | import sys 4 | import atexit 5 | sys.path.append("@FENCEAGENTSLIBDIR@") 6 | from fencing import * 7 | from fencing_snmp import FencingSnmp 8 | 9 | ### CONSTANTS ### 10 | # From fence_ibmblade.pl 11 | STATUSES_OID = ".1.3.6.1.4.1.2.3.51.2.22.1.5.1.1.4" # remoteControlBladePowerState 12 | CONTROL_OID = ".1.3.6.1.4.1.2.3.51.2.22.1.6.1.1.7" # powerOnOffBlade 13 | 14 | # Status constants returned as value from SNMP 15 | STATUS_DOWN = 0 16 | STATUS_UP = 1 17 | 18 | # Status constants to set as value to SNMP 19 | STATUS_SET_OFF = 0 20 | STATUS_SET_ON = 1 21 | 22 | ### FUNCTIONS ### 23 | 24 | def get_power_status(conn, options): 25 | (_, status) = conn.get("%s.%s"% (STATUSES_OID, options["--plug"])) 26 | return status == str(STATUS_UP) and "on" or "off" 27 | 28 | def set_power_status(conn, options): 29 | conn.set("%s.%s" % (CONTROL_OID, options["--plug"]), 30 | (options["--action"] == "on" and STATUS_SET_ON or STATUS_SET_OFF)) 31 | 32 | def get_outlets_status(conn, _): 33 | result = {} 34 | 35 | res_blades = conn.walk(STATUSES_OID, 30) 36 | 37 | for blade_info in res_blades: 38 | port_num = blade_info[0].split('.')[-1] 39 | 40 | port_alias = "" 41 | port_status = (blade_info[1] == str(STATUS_UP) and "on" or "off") 42 | 43 | result[port_num] = (port_alias, port_status) 44 | 45 | return result 46 | 47 | # Main agent method 48 | def main(): 49 | device_opt = ["ipaddr", "login", "passwd", "no_login", "no_password", \ 50 | "port", "snmp_version", "snmp"] 51 | 52 | atexit.register(atexit_handler) 53 | 54 | all_opt["snmp_version"]["default"] = "1" 55 | 56 | options = check_input(device_opt, process_input(device_opt)) 57 | 58 | docs = {} 59 | docs["shortdesc"] = "Fence agent for IBM BladeCenter over SNMP" 60 | docs["longdesc"] = "fence_ibmblade is a Power Fencing agent \ 61 | which can be used with IBM BladeCenter chassis. It issues SNMP Set \ 62 | request to BladeCenter chassis, rebooting, powering up or down \ 63 | the specified Blade Server." 64 | docs["vendorurl"] = "http://www.ibm.com" 65 | show_docs(options, docs) 66 | 67 | # Operate the fencing device 68 | result = fence_action(FencingSnmp(options), options, set_power_status, get_power_status, get_outlets_status) 69 | 70 | sys.exit(result) 71 | if __name__ == "__main__": 72 | main() 73 | -------------------------------------------------------------------------------- /agents/ifmib/README: -------------------------------------------------------------------------------- 1 | Intro: 2 | ------ 3 | This is an SNMP-based fencing agent for RHCS. It was designed with the use-case 4 | of disabling ethernet ports on an iSCSI SAN, but could be used to disable any 5 | port on any SNMP v1/2c/3 device that implementes the IF-MIB. 6 | 7 | The script requires NetSNMP to be installed and working on all nodes 8 | in the cluster. There are no requirements for any MIBs to be setup --- all of 9 | the required OIDs are hard-coded into the script. Since the IF-MIB is an IETF 10 | standard, these identifiers are very widely supported and will not change. 11 | 12 | 13 | Typical usage: 14 | -------------- 15 | To use this agent with the switch used on the iSCSI network, you'll need: 16 | 1) A managed switch running SNMP. 17 | 2) An SNMP community with write privileges. 18 | 3) Permission to send SNMP through any ACLs or firewalls from the nodes. 19 | 4) The ifIndex or ifPort associated with the ports being used by the cluster nodes. 20 | 21 | Consider a three-node cluster composed of A, B, and C. Each node has two 22 | network interfaces - one used for network and cluster communication, the second 23 | used for iSCSI traffic. If A needs to be fenced, B and C will run this script 24 | to administratively disable the switchport for A's connection to the iSCSI 25 | storage. 26 | 27 | If you are using a single interface for cluster and iSCSI traffic, this will 28 | still work, but you will lose network connectivity to the fenced host. 29 | 30 | 31 | cluster.conf: 32 | ------------- 33 | There is no GUI support for this fence agent at this time. To use it, you will 34 | need something like this cluster.conf 35 | 36 | 37 | 38 | In a node's fencing methods, you'll include a line like this: 39 | 40 | 41 | 42 | This node will be fenced by disabling the port with ifIndex 43 on the host sw1. 43 | In SNMP speak, we set IF-MIB::ifAdminStatus.43 = down(2). 44 | 45 | If you will use port name (like fc1/1), script will try to find ifIndex. 46 | -------------------------------------------------------------------------------- /agents/ifmib/fence_ifmib.py: -------------------------------------------------------------------------------- 1 | #!@PYTHON@ -tt 2 | 3 | # The Following agent has been tested on: 4 | # - Cisco MDS UROS 9134 FC (1 Slot) Chassis ("1/2/4 10 Gbps FC/Supervisor-2") Motorola, e500v2 5 | # with BIOS 1.0.16, kickstart 4.1(1c), system 4.1(1c) 6 | # - Cisco MDS 9124 (1 Slot) Chassis ("1/2/4 Gbps FC/Supervisor-2") Motorola, e500 7 | # with BIOS 1.0.16, kickstart 4.1(1c), system 4.1(1c) 8 | # - Partially with APC PDU (Network Management Card AOS v2.7.0, Rack PDU APP v2.7.3) 9 | # Only lance if is visible 10 | 11 | import sys 12 | import atexit 13 | sys.path.append("@FENCEAGENTSLIBDIR@") 14 | from fencing import * 15 | from fencing import fail_usage, array_to_dict 16 | from fencing_snmp import FencingSnmp 17 | 18 | ### CONSTANTS ### 19 | # IF-MIB trees for alias, status and port 20 | ALIASES_OID = ".1.3.6.1.2.1.31.1.1.1.18" 21 | PORTS_OID = ".1.3.6.1.2.1.2.2.1.2" 22 | STATUSES_OID = ".1.3.6.1.2.1.2.2.1.7" 23 | 24 | # Status constants returned as value from SNMP 25 | STATUS_UP = 1 26 | STATUS_DOWN = 2 27 | STATUS_TESTING = 3 28 | 29 | ### GLOBAL VARIABLES ### 30 | # Port number converted from port name or index 31 | port_num = None 32 | 33 | ### FUNCTIONS ### 34 | 35 | # Convert port index or name to port index 36 | def port2index(conn, port): 37 | res = None 38 | 39 | if port.isdigit(): 40 | res = int(port) 41 | else: 42 | ports = conn.walk(PORTS_OID, 30) 43 | 44 | for x in ports: 45 | if x[1].strip('"') == port: 46 | res = int(x[0].split('.')[-1]) 47 | break 48 | 49 | if res == None: 50 | fail_usage("Can't find port with name %s!"%(port)) 51 | 52 | return res 53 | 54 | def get_power_status(conn, options): 55 | global port_num 56 | 57 | if port_num == None: 58 | port_num = port2index(conn, options["--plug"]) 59 | 60 | (_, status) = conn.get("%s.%d"%(STATUSES_OID, port_num)) 61 | return status == str(STATUS_UP) and "on" or "off" 62 | 63 | def set_power_status(conn, options): 64 | global port_num 65 | 66 | if port_num == None: 67 | port_num = port2index(conn, options["--plug"]) 68 | 69 | conn.set("%s.%d" % (STATUSES_OID, port_num), (options["--action"] == "on" and STATUS_UP or STATUS_DOWN)) 70 | 71 | def get_outlets_status(conn, options): 72 | result = {} 73 | 74 | res_fc = conn.walk(PORTS_OID, 30) 75 | res_aliases = array_to_dict(conn.walk(ALIASES_OID, 30)) 76 | 77 | for x in res_fc: 78 | port_number = x[0].split('.')[-1] 79 | 80 | port_name = x[1].strip('"') 81 | port_alias = (port_number in res_aliases and res_aliases[port_number].strip('"') or "") 82 | port_status = "" 83 | result[port_name] = (port_alias, port_status) 84 | 85 | return result 86 | 87 | # Main agent method 88 | def main(): 89 | device_opt = ["fabric_fencing", "ipaddr", "login", "passwd", "no_login", "no_password", \ 90 | "port", "snmp_version", "snmp"] 91 | 92 | atexit.register(atexit_handler) 93 | 94 | all_opt["snmp_version"]["default"] = "2c" 95 | 96 | options = check_input(device_opt, process_input(device_opt)) 97 | 98 | docs = {} 99 | docs["shortdesc"] = "Fence agent for IF MIB" 100 | docs["longdesc"] = "fence_ifmib is an I/O Fencing agent \ 101 | which can be used with any SNMP IF-MIB capable device. \ 102 | \n.P\n\ 103 | It was written with managed ethernet switches in mind, in order to \ 104 | fence iSCSI SAN connections. However, there are many devices that \ 105 | support the IF-MIB interface. The agent uses IF-MIB::ifAdminStatus \ 106 | to control the state of an interface." 107 | docs["vendorurl"] = "http://www.ietf.org/wg/concluded/ifmib.html" 108 | show_docs(options, docs) 109 | 110 | # Operate the fencing device 111 | result = fence_action(FencingSnmp(options), options, set_power_status, get_power_status, get_outlets_status) 112 | 113 | sys.exit(result) 114 | 115 | if __name__ == "__main__": 116 | main() 117 | -------------------------------------------------------------------------------- /agents/ilo_moonshot/fence_ilo_moonshot.py: -------------------------------------------------------------------------------- 1 | #!@PYTHON@ -tt 2 | 3 | import sys 4 | import logging 5 | import atexit 6 | sys.path.append("@FENCEAGENTSLIBDIR@") 7 | from fencing import * 8 | from fencing import fail, EC_STATUS 9 | 10 | def get_power_status(conn, options): 11 | conn.send_eol("show node list") 12 | conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) 13 | 14 | nodes = {} 15 | for line in conn.before.splitlines(): 16 | if len(line.split()) == 10: 17 | nodes[line.split()[1]] = ("", line.split()[8].lower().strip()) 18 | 19 | if ["list", "monitor"].count(options["--action"]) == 1: 20 | return nodes 21 | else: 22 | try: 23 | (_, status) = nodes[options["--plug"]] 24 | return status.lower() 25 | except KeyError as e: 26 | logging.error("Failed: {}".format(str(e))) 27 | fail(EC_STATUS) 28 | 29 | def set_power_status(conn, options): 30 | if options["--action"] == "on": 31 | conn.send_eol("set node power on %s" % (options["--plug"])) 32 | else: 33 | conn.send_eol("set node power off force %s" % (options["--plug"])) 34 | 35 | conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) 36 | 37 | return 38 | 39 | def main(): 40 | device_opt = ["ipaddr", "login", "passwd", "secure", "cmd_prompt", "port"] 41 | 42 | atexit.register(atexit_handler) 43 | 44 | all_opt["secure"]["default"] = "1" 45 | all_opt["cmd_prompt"]["default"] = ["MP>", "hpiLO->"] 46 | 47 | options = check_input(device_opt, process_input(device_opt)) 48 | 49 | docs = {} 50 | docs["shortdesc"] = "Fence agent for HP Moonshot iLO" 51 | docs["longdesc"] = "fence_ilo_moonshot is a Power Fencing agent \ 52 | for HP Moonshot iLO." 53 | docs["longdesc"] = "" 54 | docs["vendorurl"] = "http://www.hp.com" 55 | show_docs(options, docs) 56 | 57 | conn = fence_login(options) 58 | 59 | ## 60 | ## Fence operations 61 | #### 62 | result = fence_action(conn, options, set_power_status, get_power_status, get_power_status) 63 | fence_logout(conn, "exit") 64 | sys.exit(result) 65 | 66 | if __name__ == "__main__": 67 | main() 68 | -------------------------------------------------------------------------------- /agents/ilo_mp/fence_ilo_mp.py: -------------------------------------------------------------------------------- 1 | #!@PYTHON@ -tt 2 | 3 | import sys, re 4 | import atexit 5 | sys.path.append("@FENCEAGENTSLIBDIR@") 6 | from fencing import * 7 | 8 | def get_power_status(conn, options): 9 | conn.send_eol("show /system1") 10 | 11 | re_state = re.compile(r'EnabledState=(.*)', re.IGNORECASE) 12 | conn.log_expect(re_state, int(options["--shell-timeout"])) 13 | 14 | status = conn.match.group(1).lower() 15 | 16 | if status.startswith("enabled"): 17 | return "on" 18 | else: 19 | return "off" 20 | 21 | def set_power_status(conn, options): 22 | if options["--action"] == "on": 23 | conn.send_eol("start /system1") 24 | else: 25 | conn.send_eol("stop -f /system1") 26 | 27 | conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) 28 | 29 | return 30 | 31 | def main(): 32 | device_opt = ["ipaddr", "login", "passwd", "secure", "cmd_prompt", "telnet"] 33 | 34 | atexit.register(atexit_handler) 35 | 36 | all_opt["cmd_prompt"]["default"] = ["MP>", "hpiLO->"] 37 | all_opt["power_wait"]["default"] = 5 38 | 39 | options = check_input(device_opt, process_input(device_opt)) 40 | 41 | docs = {} 42 | docs["shortdesc"] = "Fence agent for HP iLO MP" 43 | docs["longdesc"] = "fence_ilo_mp is a Power Fencing agent \ 44 | for HP iLO MP." 45 | docs["vendorurl"] = "http://www.hp.com" 46 | show_docs(options, docs) 47 | 48 | conn = fence_login(options) 49 | conn.send_eol("SMCLP") 50 | 51 | ## 52 | ## Fence operations 53 | #### 54 | result = fence_action(conn, options, set_power_status, get_power_status) 55 | fence_logout(conn, "exit") 56 | sys.exit(result) 57 | 58 | if __name__ == "__main__": 59 | main() 60 | -------------------------------------------------------------------------------- /agents/ilo_ssh/fence_ilo_ssh.py: -------------------------------------------------------------------------------- 1 | #!@PYTHON@ -tt 2 | 3 | import sys, os, re 4 | import atexit 5 | import logging 6 | sys.path.append("@FENCEAGENTSLIBDIR@") 7 | from fencing import * 8 | 9 | def get_power_status(conn, options): 10 | conn.send_eol("show /system1") 11 | 12 | re_state = re.compile(r'EnabledState=(.*)', re.IGNORECASE) 13 | conn.log_expect(re_state, int(options["--shell-timeout"])) 14 | 15 | status = conn.match.group(1).lower() 16 | 17 | if status.startswith("enabled"): 18 | return "on" 19 | else: 20 | return "off" 21 | 22 | def set_power_status(conn, options): 23 | if options["--action"] == "on": 24 | conn.send_eol("start /system1") 25 | else: 26 | conn.send_eol("power off hard") 27 | 28 | conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) 29 | 30 | return 31 | 32 | def reboot_cycle(conn, options): 33 | conn.send_eol("reset /system1 hard") 34 | conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) 35 | 36 | if get_power_status(conn, options) == "off": 37 | logging.error("Timed out waiting to power ON\n") 38 | 39 | return True 40 | 41 | def main(): 42 | device_opt = ["ipaddr", "login", "passwd", "secure", "cmd_prompt", "method", "telnet"] 43 | 44 | atexit.register(atexit_handler) 45 | 46 | all_opt["cmd_prompt"]["default"] = ["MP>", "hpiLO->"] 47 | all_opt["power_wait"]["default"] = 5 48 | 49 | options = check_input(device_opt, process_input(device_opt)) 50 | 51 | docs = {} 52 | docs["agent_name"] = "fence_ilo_ssh" 53 | docs["shortdesc"] = "Fence agent for HP iLO over SSH" 54 | docs["longdesc"] = "{} is a Power Fencing agent that connects to iLO device. It logs into \ 55 | device via ssh and reboot a specified outlet.\ 56 | \n.P\n\ 57 | WARNING: The monitor-action is prone to timeouts. Use the fence_ilo-equivalent \ 58 | to avoid this issue.".format(os.path.basename(__file__)) 59 | docs["vendorurl"] = "http://www.hp.com" 60 | docs["symlink"] = [("fence_ilo3_ssh", "Fence agent for HP iLO3 over SSH"), 61 | ("fence_ilo4_ssh", "Fence agent for HP iLO4 over SSH"), 62 | ("fence_ilo5_ssh", "Fence agent for HP iLO5 over SSH")] 63 | show_docs(options, docs) 64 | 65 | options["eol"] = "\r" 66 | 67 | conn = fence_login(options) 68 | conn.send_eol("SMCLP") 69 | 70 | ## 71 | ## Fence operations 72 | #### 73 | result = fence_action(conn, options, set_power_status, get_power_status, None, reboot_cycle) 74 | fence_logout(conn, "exit") 75 | sys.exit(result) 76 | 77 | if __name__ == "__main__": 78 | main() 79 | -------------------------------------------------------------------------------- /agents/intelmodular/fence_intelmodular.py: -------------------------------------------------------------------------------- 1 | #!@PYTHON@ -tt 2 | 3 | # Tested with an Intel MFSYS25 using firmware package 2.6 Should work with an 4 | # MFSYS35 as well. 5 | # 6 | # Notes: 7 | # 8 | # The manual and firmware release notes says SNMP is read only. This is not 9 | # true, as per the MIBs that ship with the firmware you can write to 10 | # the bladePowerLed oid to control the servers. 11 | # 12 | # Thanks Matthew Kent for original agent and testing. 13 | 14 | import sys 15 | import atexit 16 | sys.path.append("@FENCEAGENTSLIBDIR@") 17 | from fencing import * 18 | from fencing_snmp import FencingSnmp 19 | 20 | ### CONSTANTS ### 21 | # From INTELCORPORATION-MULTI-FLEX-SERVER-BLADES-MIB.my that ships with 22 | # firmware updates 23 | STATUSES_OID = ".1.3.6.1.4.1.343.2.19.1.2.10.202.1.1.6" 24 | 25 | # Status constants returned as value from SNMP 26 | STATUS_UP = 2 27 | STATUS_DOWN = 0 28 | 29 | # Status constants to set as value to SNMP 30 | STATUS_SET_ON = 2 31 | STATUS_SET_OFF = 3 32 | 33 | ### FUNCTIONS ### 34 | 35 | def get_power_status(conn, options): 36 | (_, status) = conn.get("%s.%s"% (STATUSES_OID, options["--plug"])) 37 | return status == str(STATUS_UP) and "on" or "off" 38 | 39 | def set_power_status(conn, options): 40 | conn.set("%s.%s" % (STATUSES_OID, options["--plug"]), 41 | (options["--action"] == "on" and STATUS_SET_ON or STATUS_SET_OFF)) 42 | 43 | def get_outlets_status(conn, options): 44 | result = {} 45 | 46 | res_blades = conn.walk(STATUSES_OID, 30) 47 | 48 | for x in res_blades: 49 | port_num = x[0].split('.')[-1] 50 | 51 | port_alias = "" 52 | port_status = (x[1] == str(STATUS_UP) and "on" or "off") 53 | 54 | result[port_num] = (port_alias, port_status) 55 | 56 | return result 57 | 58 | # Main agent method 59 | def main(): 60 | device_opt = ["ipaddr", "login", "passwd", "no_login", "no_password", 61 | "port", "snmp_version", "snmp"] 62 | 63 | atexit.register(atexit_handler) 64 | 65 | options = check_input(device_opt, process_input(device_opt)) 66 | 67 | docs = {} 68 | docs["shortdesc"] = "Fence agent for Intel Modular" 69 | docs["longdesc"] = "fence_intelmodular is a Power Fencing agent \ 70 | which can be used with Intel Modular device (tested on Intel MFSYS25, should \ 71 | work with MFSYS35 as well). \ 72 | \n.P\n\ 73 | Note: Since firmware update version 2.7, SNMP v2 write support is \ 74 | removed, and replaced by SNMP v3 support. So agent now has default \ 75 | SNMP version 3. If you are using older firmware, please supply -d \ 76 | for command line and snmp_version option for your cluster.conf." 77 | docs["vendorurl"] = "http://www.intel.com" 78 | show_docs(options, docs) 79 | 80 | # Operate the fencing device 81 | result = fence_action(FencingSnmp(options), options, set_power_status, get_power_status, get_outlets_status) 82 | 83 | sys.exit(result) 84 | 85 | if __name__ == "__main__": 86 | main() 87 | -------------------------------------------------------------------------------- /agents/kdump/fence_kdump_send.8: -------------------------------------------------------------------------------- 1 | .TH fence_kdump_send 8 2 | .SH NAME 3 | fence_kdump_send - send kdump acknowlegement message to cluster nodes 4 | .SH SYNOPSIS 5 | .B 6 | fence_kdump_send 7 | [\fIOPTIONS]\fR... [NODE]... 8 | .SH DESCRIPTION 9 | \fIfence_kdump_send\fP is a utility used to send messages that 10 | acknowledge that the node has entered the kdump crash recovery 11 | service. This utility is intended to be used the the \fIfence_kdump\fP 12 | agent as a means detect that a failed node has entered the kdump crash 13 | recovery service. 14 | The \fIfence_kdump_send\fP utility is typically run from within the 15 | kdump kernel after a cluster node has encountered a kernel panic. Once 16 | the cluster node has entered the kdump crash recovery service, 17 | \fIfence_kdump_send\fP will periodically send messages to all cluster 18 | nodes. When the \fIfence_kdump\fP agent receives a valid message from 19 | the failed node, fencing is complete. 20 | .SH OPTIONS 21 | .TP 22 | .B -p, --ipport=\fIPORT\fP 23 | IP port number that the \fIfence_kdump\fP agent is using to listen for 24 | messages. (default: 7410) 25 | .TP 26 | .B -f, --family=\fIFAMILY\fP 27 | IP network family. Force the \fIfence_kdump_send\fP utility to use a 28 | particular network family. Value for \fIFAMILY\fP can be "auto", 29 | "ipv4", or "ipv6". (default: auto) 30 | .TP 31 | .B -c, --count=\fICOUNT\fP 32 | Number of messages to send. If \fICOUNT\fP is zero, 33 | \fIfence_kdump_send\fP will send messages indefinitely. (default: 0) 34 | .TP 35 | .B -i, --interval=\fIINTERVAL\fP 36 | Time to wait between sending a message. The value for \fIINTERVAL\fP 37 | must be greater than zero. (default: 10) 38 | .TP 39 | .B -v, --verbose 40 | Print verbose output. 41 | .TP 42 | .B -V, --version 43 | Print version and exit. 44 | .TP 45 | .B -h, --help 46 | Print usage and exit. 47 | .SH AUTHOR 48 | Ryan O'Hara 49 | .SH SEE ALSO 50 | fence_kdump(8), mkdumprd(8), kdump.conf(5) 51 | -------------------------------------------------------------------------------- /agents/kdump/message.h: -------------------------------------------------------------------------------- 1 | /* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- 2 | * 3 | * Copyright (c) Ryan O'Hara (rohara@redhat.com) 4 | * Copyright (c) Red Hat, Inc. 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License along 17 | * with this program; if not, write to the Free Software Foundation, Inc., 18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | * 20 | */ 21 | 22 | #ifndef _FENCE_KDUMP_MESSAGE_H 23 | #define _FENCE_KDUMP_MESSAGE_H 24 | 25 | #define FENCE_KDUMP_MAGIC 0x1B302A40 26 | 27 | #define FENCE_KDUMP_MSGV1 0x1 28 | 29 | typedef struct __attribute__ ((packed)) fence_kdump_msg { 30 | uint32_t magic; 31 | uint32_t version; 32 | } fence_kdump_msg_t; 33 | 34 | static inline void 35 | init_message (fence_kdump_msg_t *msg) 36 | { 37 | msg->magic = FENCE_KDUMP_MAGIC; 38 | msg->version = FENCE_KDUMP_MSGV1; 39 | } 40 | 41 | #endif /* _FENCE_KDUMP_MESSAGE_H */ 42 | -------------------------------------------------------------------------------- /agents/kdump/version.h: -------------------------------------------------------------------------------- 1 | /* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- 2 | * 3 | * Copyright (c) Ryan O'Hara (rohara@redhat.com) 4 | * Copyright (c) Red Hat, Inc. 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License along 17 | * with this program; if not, write to the Free Software Foundation, Inc., 18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | * 20 | */ 21 | 22 | #ifndef _FENCE_KDUMP_VERSION_H 23 | #define _FENCE_KDUMP_VERSION_H 24 | 25 | #define FENCE_KDUMP_VERSION "0.1" 26 | 27 | static inline void 28 | print_version (const char *self) 29 | { 30 | fprintf (stdout, "%s %s\n", basename (self), FENCE_KDUMP_VERSION); 31 | } 32 | 33 | #endif /* _FENCE_KDUMP_VERSION_H */ 34 | -------------------------------------------------------------------------------- /agents/ldom/fence_ldom.py: -------------------------------------------------------------------------------- 1 | #!@PYTHON@ -tt 2 | 3 | ## 4 | ## The Following Agent Has Been Tested On - LDOM 1.0.3 5 | ## The interface is backward compatible so it will work 6 | ## with 1.0, 1.0.1 and .2 too. 7 | ## 8 | ##### 9 | 10 | import sys, re, pexpect 11 | import atexit 12 | sys.path.append("@FENCEAGENTSLIBDIR@") 13 | from fencing import * 14 | from fencing import fail_usage 15 | 16 | COMMAND_PROMPT_REG = r"\[PEXPECT\]$" 17 | COMMAND_PROMPT_NEW = "[PEXPECT]" 18 | 19 | # Start comunicating after login. Prepare good environment. 20 | def start_communication(conn, options): 21 | conn.send_eol("PS1='" + COMMAND_PROMPT_NEW + "'") 22 | res = conn.expect([pexpect.TIMEOUT, COMMAND_PROMPT_REG], int(options["--shell-timeout"])) 23 | if res == 0: 24 | #CSH stuff 25 | conn.send_eol("set prompt='" + COMMAND_PROMPT_NEW + "'") 26 | conn.log_expect(COMMAND_PROMPT_REG, int(options["--shell-timeout"])) 27 | 28 | def get_power_status(conn, options): 29 | start_communication(conn, options) 30 | 31 | conn.send_eol("ldm ls") 32 | 33 | conn.log_expect(COMMAND_PROMPT_REG, int(options["--shell-timeout"])) 34 | 35 | result = {} 36 | 37 | #This is status of mini finite automata. 0 = we didn't found NAME and STATE, 1 = we did 38 | fa_status = 0 39 | 40 | for line in conn.before.splitlines(): 41 | domain = re.search(r"^(\S+)\s+(\S+)\s+.*$", line) 42 | 43 | if domain != None: 44 | if fa_status == 0 and domain.group(1) == "NAME" and domain.group(2) == "STATE": 45 | fa_status = 1 46 | elif fa_status == 1: 47 | result[domain.group(1)] = ("", (domain.group(2).lower() == "bound" and "off" or "on")) 48 | 49 | if not options["--action"] in ['monitor', 'list']: 50 | if not options["--plug"] in result: 51 | fail_usage("Failed: You have to enter existing logical domain!") 52 | else: 53 | return result[options["--plug"]][1] 54 | else: 55 | return result 56 | 57 | def set_power_status(conn, options): 58 | start_communication(conn, options) 59 | 60 | cmd_line = "ldm "+ (options["--action"] == "on" and "start" or "stop -f") + " \"" + options["--plug"] + "\"" 61 | 62 | conn.send_eol(cmd_line) 63 | 64 | conn.log_expect(COMMAND_PROMPT_REG, int(options["--power-timeout"])) 65 | 66 | def main(): 67 | device_opt = ["ipaddr", "login", "passwd", "cmd_prompt", "secure", "port"] 68 | 69 | atexit.register(atexit_handler) 70 | 71 | all_opt["secure"]["default"] = "1" 72 | all_opt["cmd_prompt"]["default"] = [r"\ $"] 73 | 74 | options = check_input(device_opt, process_input(device_opt)) 75 | 76 | docs = {} 77 | docs["shortdesc"] = "Fence agent for Sun LDOM" 78 | docs["longdesc"] = "fence_ldom is a Power Fencing agent \ 79 | which can be used with LDoms virtual machines. This agent works \ 80 | so, that run ldm command on host machine. So ldm must be directly \ 81 | runnable.\ 82 | \n.P\n\ 83 | Very useful parameter is -c (or cmd_prompt in stdin mode). This \ 84 | must be set to something, what is displayed after successful login \ 85 | to host machine. Default string is space on end of string (default \ 86 | for root in bash). But (for example) csh use ], so in that case you \ 87 | must use parameter -c with argument ]. Very similar situation is, \ 88 | if you use bash and login to host machine with other user than \ 89 | root. Than prompt is $, so again, you must use parameter -c." 90 | docs["vendorurl"] = "http://www.sun.com" 91 | show_docs(options, docs) 92 | 93 | ## 94 | ## Operate the fencing device 95 | #### 96 | conn = fence_login(options) 97 | result = fence_action(conn, options, set_power_status, get_power_status, get_power_status) 98 | fence_logout(conn, "logout") 99 | sys.exit(result) 100 | 101 | if __name__ == "__main__": 102 | main() 103 | -------------------------------------------------------------------------------- /agents/manual/fence_ack_manual.8: -------------------------------------------------------------------------------- 1 | .TH FENCE_ACK_MANUAL 8 2009-12-21 cluster cluster 2 | 3 | .SH NAME 4 | fence_ack_manual \- a program to override fenced fencing operations 5 | 6 | .SH SYNOPSIS 7 | .B fence_ack_manual 8 | [OPTIONS] 9 | .I nodename 10 | 11 | .SH DESCRIPTION 12 | When 13 | .BR fenced (8) 14 | fails to fence a node, it retries indefinately. 15 | .BR fence_ack_manual (8) 16 | tells fenced to stop retrying and consider the node fenced. 17 | 18 | .P 19 | It is important that this only be done after the node has been manually 20 | turned off or prevented from writing to shared storage. 21 | Without this manual action and verification, the storage that fencing 22 | protects may become corrupted. 23 | 24 | .P 25 | When fenced fences a node that has no fence devices defined in the cluster 26 | configuration, the fencing operation fails. This failure will be repeated 27 | indefinately until fence_ack_manual is run by an operator to indicate 28 | the node is in a safe state to proceed. 29 | (Defining no fencing devices for node is the equivalent of using the 30 | fence_manual agent in previous versions.) 31 | 32 | .SH OPTIONS 33 | .TP 34 | .B \-h 35 | Print a help message describing available options, then exit. 36 | 37 | .SH SEE ALSO 38 | .BR fenced (8) 39 | 40 | -------------------------------------------------------------------------------- /agents/manual/fence_ack_manual.in: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Manual override after fencing has failed. 4 | # 5 | 6 | if [ "$1" = "-n" ]; then 7 | shift 8 | fi 9 | 10 | if [ -z "$1" ] || [ "${1:0:1}" = "-" ]; then 11 | echo "usage:" 12 | echo " $0 " 13 | echo " $0 -n " 14 | echo 15 | echo "The -n flag exists to preserve compatibility with previous " 16 | echo "releases of $0, and is no longer required." 17 | exit 1 18 | fi 19 | 20 | declare answer 21 | 22 | echo "About to override fencing for $1." 23 | echo "Improper use of this command can cause severe file system damage." 24 | echo 25 | read -p "Continue [NO/absolutely]? " answer 26 | 27 | if [ "$answer" != "absolutely" ]; then 28 | echo "Aborted." 29 | exit 1 30 | fi 31 | 32 | while ! [ -e @clustervarrun@/fenced_override ]; do 33 | sleep 1 34 | done 35 | 36 | echo $1>@clustervarrun@/fenced_override 37 | echo Done 38 | -------------------------------------------------------------------------------- /agents/netio/fence_netio.py: -------------------------------------------------------------------------------- 1 | #!@PYTHON@ -tt 2 | 3 | import sys, re, pexpect 4 | import atexit 5 | sys.path.append("@FENCEAGENTSLIBDIR@") 6 | from fencing import * 7 | from fencing import fspawn, fail, EC_LOGIN_DENIED, run_delay 8 | 9 | def get_power_status(conn, options): 10 | conn.send_eol("port %s" % options["--plug"]) 11 | re_status = re.compile(r"250 [01imt]") 12 | conn.log_expect(re_status, int(options["--shell-timeout"])) 13 | status = { 14 | "0" : "off", 15 | "1" : "on", 16 | "i" : "reboot", 17 | "m" : "manual", 18 | "t" : "timer" 19 | }[conn.after.split()[1]] 20 | 21 | return status 22 | 23 | def set_power_status(conn, options): 24 | action = { 25 | "on" : "1", 26 | "off" : "0", 27 | "reboot" : "i" 28 | }[options["--action"]] 29 | 30 | conn.send_eol("port %s %s" % (options["--plug"], action)) 31 | conn.log_expect("250 OK", int(options["--shell-timeout"])) 32 | 33 | def get_outlet_list(conn, options): 34 | result = {} 35 | 36 | try: 37 | # the NETIO-230B has 4 ports, counting start at 1 38 | for plug in ["1", "2", "3", "4"]: 39 | conn.send_eol("port setup %s" % plug) 40 | conn.log_expect("250 .+", int(options["--shell-timeout"])) 41 | # the name is enclosed in "", drop those with [1:-1] 42 | name = conn.after.split()[1][1:-1] 43 | result[plug] = (name, "unknown") 44 | except Exception as exn: 45 | print(str(exn)) 46 | 47 | return result 48 | 49 | def main(): 50 | device_opt = ["ipaddr", "login", "passwd", "port", "telnet"] 51 | 52 | atexit.register(atexit_handler) 53 | 54 | all_opt["ipport"]["default"] = "1234" 55 | 56 | opt = process_input(device_opt) 57 | opt["eol"] = "\r\n" 58 | options = check_input(device_opt, opt) 59 | 60 | docs = {} 61 | docs["shortdesc"] = "Power Fencing agent for Koukaam NETIO-230B" 62 | docs["longdesc"] = "fence_netio is a Power Fencing agent which can be \ 63 | used with the Koukaam NETIO-230B Power Distribution Unit. It logs into \ 64 | device via telnet and reboots a specified outlet. Lengthy telnet connections \ 65 | should be avoided while a GFS cluster is running because the connection will \ 66 | block any necessary fencing actions." 67 | docs["vendorurl"] = "http://www.koukaam.se/" 68 | show_docs(options, docs) 69 | 70 | ## 71 | ## Operate the fencing device 72 | ## We can not use fence_login(), username and passwd are sent on one line 73 | #### 74 | run_delay(options) 75 | try: 76 | conn = fspawn(options, options["--telnet-path"]) 77 | conn.send("set binary\n") 78 | conn.send("open %s -%s\n"%(options["--ip"], options["--ipport"])) 79 | 80 | conn.read_nonblocking(size=100, timeout=int(options["--shell-timeout"])) 81 | conn.log_expect("100 HELLO .*", int(options["--shell-timeout"])) 82 | conn.send_eol("login %s %s" % (options["--username"], options["--password"])) 83 | conn.log_expect("250 OK", int(options["--shell-timeout"])) 84 | except pexpect.EOF: 85 | fail(EC_LOGIN_DENIED) 86 | except pexpect.TIMEOUT: 87 | fail(EC_LOGIN_DENIED) 88 | 89 | result = fence_action(conn, options, set_power_status, get_power_status, get_outlet_list) 90 | fence_logout(conn, "quit\n") 91 | sys.exit(result) 92 | 93 | if __name__ == "__main__": 94 | main() 95 | -------------------------------------------------------------------------------- /agents/raritan/fence_raritan.py: -------------------------------------------------------------------------------- 1 | #!@PYTHON@ -tt 2 | 3 | import sys, re, pexpect 4 | import atexit 5 | sys.path.append("@FENCEAGENTSLIBDIR@") 6 | from fencing import * 7 | from fencing import fspawn, fail, EC_LOGIN_DENIED, run_delay 8 | 9 | def get_power_status(conn, options): 10 | conn.send_eol("show -d properties=powerState %s" % options["--plug"]) 11 | re_status = re.compile(r".*powerState is [12].*") 12 | conn.log_expect(re_status, int(options["--shell-timeout"])) 13 | status = { 14 | #"0" : "off", 15 | "1" : "on", 16 | "2" : "off", 17 | }[conn.after.split()[2]] 18 | 19 | return status 20 | 21 | def set_power_status(conn, options): 22 | action = { 23 | "on" : "on", 24 | "off" : "off", 25 | }[options["--action"]] 26 | 27 | conn.send_eol("set %s powerState=%s" % (options["--plug"], action)) 28 | 29 | def main(): 30 | device_opt = ["ipaddr", "login", "passwd", "port", "telnet"] 31 | 32 | atexit.register(atexit_handler) 33 | 34 | opt = process_input(device_opt) 35 | 36 | all_opt["ipport"]["default"] = "23" 37 | 38 | opt["eol"] = "\r\n" 39 | options = check_input(device_opt, opt) 40 | 41 | docs = {} 42 | docs["shortdesc"] = "Power Fencing agent for Raritan Dominion PX" 43 | docs["longdesc"] = "fence_raritan is a Power Fencing agent which can be \ 44 | used with the Raritan DPXS12-20 Power Distribution Unit. It logs into \ 45 | device via telnet and reboots a specified outlet. Lengthy telnet connections \ 46 | should be avoided while a GFS cluster is running because the connection will \ 47 | block any necessary fencing actions." 48 | docs["vendorurl"] = "http://www.raritan.com/" 49 | show_docs(options, docs) 50 | 51 | # add support also for delay before login which is very useful for 2-node clusters 52 | run_delay(options) 53 | 54 | # Convert pure port/plug number to /system1/outlet${plug} 55 | try: 56 | plug_int = int(options["--plug"]) 57 | options["--plug"] = "/system1/outlet" + str(plug_int) 58 | except ValueError: 59 | pass 60 | ## 61 | ## Operate the fencing device 62 | ## We can not use fence_login(), username and passwd are sent on one line 63 | #### 64 | try: 65 | conn = fspawn(options, options["--telnet-path"], encoding="latin1") 66 | conn.send("set binary\n") 67 | conn.send("open %s -%s\n"%(options["--ip"], options["--ipport"])) 68 | conn.read_nonblocking(size=100, timeout=int(options["--shell-timeout"])) 69 | conn.log_expect("Login.*", int(options["--shell-timeout"])) 70 | conn.send_eol("%s" % (options["--username"])) 71 | conn.log_expect("Password.*", int(options["--shell-timeout"])) 72 | conn.send_eol("%s" % (options["--password"])) 73 | conn.log_expect("clp.*", int(options["--shell-timeout"])) 74 | except pexpect.EOF: 75 | fail(EC_LOGIN_DENIED) 76 | except pexpect.TIMEOUT: 77 | fail(EC_LOGIN_DENIED) 78 | 79 | result = 0 80 | if options["--action"] != "monitor": 81 | result = fence_action(conn, options, set_power_status, get_power_status) 82 | 83 | fence_logout(conn, "exit\n") 84 | sys.exit(result) 85 | 86 | if __name__ == "__main__": 87 | main() 88 | -------------------------------------------------------------------------------- /agents/rcd_serial/fence_rcd_serial.py: -------------------------------------------------------------------------------- 1 | #!@PYTHON@ -tt 2 | 3 | # Copyright 2018 Infoxchange, Danielle Madeley, Sam McLeod-Jones 4 | 5 | # Controls an RCD serial device 6 | # Ported from stonith/rcd_serial.c 7 | 8 | # The Following Agent Has Been Tested On: 9 | # CentOS Linux release 7.5.1804 10 | 11 | # Resource example: 12 | # primitive stonith_node_1 ocf:rcd_serial_py params port="/dev/ttyS0" time=1000 hostlist=stonith_node_1 stonith-timeout=5s 13 | 14 | import sys 15 | import atexit 16 | import os 17 | import struct 18 | import logging 19 | import time 20 | from fcntl import ioctl 21 | from termios import TIOCMBIC, TIOCMBIS, TIOCM_RTS, TIOCM_DTR 22 | from time import sleep 23 | 24 | sys.path.append("@FENCEAGENTSLIBDIR@") 25 | from fencing import * 26 | 27 | class RCDSerial(object): 28 | """Control class for serial device""" 29 | 30 | def __init__(self, port='/dev/ttyS0'): 31 | self.fd = fd = os.open(port, os.O_RDONLY | os.O_NDELAY) 32 | logging.debug("Opened %s on fd %i", port, fd) 33 | ioctl(fd, TIOCMBIC, struct.pack('I', TIOCM_RTS | TIOCM_DTR)) 34 | 35 | def close(self): 36 | """Close the serial device""" 37 | logging.debug("Closing serial device") 38 | ret = os.close(self.fd) 39 | 40 | return ret 41 | 42 | def toggle_pin(self, pin=TIOCM_DTR, time=1000): 43 | """Toggle the pin high for the time specified""" 44 | 45 | logging.debug("Set pin high") 46 | ioctl(self.fd, TIOCMBIS, struct.pack('I', pin)) 47 | 48 | sleep(float(time) / 1000.) 49 | 50 | logging.debug("Set pin low") 51 | ioctl(self.fd, TIOCMBIC, struct.pack('I', pin)) 52 | 53 | def reboot_device(conn, options): 54 | conn.toggle_pin(time=options["--power-wait"]) 55 | return True 56 | 57 | def main(): 58 | device_opt = ["serial_port", "no_status", "no_password", "no_login", "method", "no_on", "no_off"] 59 | 60 | atexit.register(atexit_handler) 61 | 62 | all_opt["serial_port"] = { 63 | "getopt" : ":", 64 | "longopt" : "serial-port", 65 | "help":"--serial-port=[port] Port of the serial device (e.g. /dev/ttyS0)", 66 | "required" : "1", 67 | "shortdesc" : "Port of the serial device", 68 | "default" : "/dev/ttyS0", 69 | "order": 1 70 | } 71 | 72 | all_opt["method"]["default"] = "cycle" 73 | all_opt["power_wait"]["default"] = "2" 74 | all_opt["method"]["help"] = "-m, --method=[method] Method to fence (onoff|cycle) (Default: cycle)" 75 | 76 | options = check_input(device_opt, process_input(device_opt)) 77 | 78 | docs = {} 79 | docs["shortdesc"] = "rcd_serial fence agent" 80 | docs["longdesc"] = "fence_rcd_serial is a Power Fencing agent that \ 81 | operates a serial cable that toggles a reset of an opposing server using the \ 82 | reset switch on its motherboard. The cable itself is simple with no power, \ 83 | network or moving parts. An example of the cable is available here: \ 84 | https://smcleod.net/rcd-stonith/ and the circuit design is available in the \ 85 | fence-agents src as SVG" 86 | docs["vendorurl"] = "https://github.com/sammcj/fence_rcd_serial" 87 | show_docs(options, docs) 88 | 89 | if options["--action"] in ["off", "reboot"]: 90 | time.sleep(int(options["--delay"])) 91 | 92 | ## Operate the fencing device 93 | conn = RCDSerial(port=options["--serial-port"]) 94 | result = fence_action(conn, options, None, None, reboot_cycle_fn=reboot_device) 95 | conn.close() 96 | 97 | sys.exit(result) 98 | 99 | if __name__ == "__main__": 100 | main() 101 | 102 | -------------------------------------------------------------------------------- /agents/rsa/fence_rsa.py: -------------------------------------------------------------------------------- 1 | #!@PYTHON@ -tt 2 | 3 | ##### 4 | ## 5 | ## The Following Agent Has Been Tested On: 6 | ## Main GFEP25A & Boot GFBP25A 7 | ## 8 | ##### 9 | 10 | import sys, re 11 | import atexit 12 | sys.path.append("@FENCEAGENTSLIBDIR@") 13 | from fencing import * 14 | 15 | def get_power_status(conn, options): 16 | conn.send_eol("power state") 17 | conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) 18 | 19 | match = re.compile(r"Power: (.*)", re.IGNORECASE).search(conn.before) 20 | if match != None: 21 | status = match.group(1) 22 | else: 23 | status = "undefined" 24 | 25 | return status.lower().strip() 26 | 27 | def set_power_status(conn, options): 28 | conn.send_eol("power " + options["--action"]) 29 | conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) 30 | 31 | def main(): 32 | device_opt = ["ipaddr", "login", "passwd", "cmd_prompt", "secure", "telnet"] 33 | 34 | atexit.register(atexit_handler) 35 | 36 | all_opt["login_timeout"]["default"] = 10 37 | all_opt["cmd_prompt"]["default"] = [">"] 38 | # This device will not allow us to login even with LANG=C 39 | all_opt["ssh_options"]["default"] = "-F /dev/null" 40 | 41 | options = check_input(device_opt, process_input(device_opt)) 42 | 43 | docs = {} 44 | docs["shortdesc"] = "Fence agent for IBM RSA" 45 | docs["longdesc"] = "fence_rsa is a Power Fencing agent \ 46 | which can be used with the IBM RSA II management interface. It \ 47 | logs into an RSA II device via telnet and reboots the associated \ 48 | machine. Lengthy telnet connections to the RSA II device should \ 49 | be avoided while a GFS cluster is running because the connection \ 50 | will block any necessary fencing actions." 51 | docs["vendorurl"] = "http://www.ibm.com" 52 | show_docs(options, docs) 53 | 54 | ## 55 | ## Operate the fencing device 56 | ###### 57 | conn = fence_login(options) 58 | result = fence_action(conn, options, set_power_status, get_power_status, None) 59 | fence_logout(conn, "exit") 60 | sys.exit(result) 61 | 62 | if __name__ == "__main__": 63 | main() 64 | -------------------------------------------------------------------------------- /agents/rsb/fence_rsb.py: -------------------------------------------------------------------------------- 1 | #!@PYTHON@ -tt 2 | 3 | import sys, re 4 | import atexit 5 | sys.path.append("@FENCEAGENTSLIBDIR@") 6 | from fencing import * 7 | 8 | def get_power_status(conn, options): 9 | conn.send("2") 10 | conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) 11 | status = re.compile(r"Power Status[\s]*: (on|off)", re.IGNORECASE).search(conn.before).group(1) 12 | conn.send("0") 13 | conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) 14 | 15 | return status.lower().strip() 16 | 17 | def set_power_status(conn, options): 18 | action = { 19 | 'on' : "4", 20 | 'off': "1" 21 | }[options["--action"]] 22 | 23 | conn.send("2") 24 | conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) 25 | conn.send_eol(action) 26 | conn.log_expect(["want to power " + options["--action"], 27 | "yes/no", "'yes' or 'no'"], int(options["--shell-timeout"])) 28 | conn.send_eol("yes") 29 | conn.log_expect("any key to continue", int(options["--power-timeout"])) 30 | conn.send_eol("") 31 | conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) 32 | conn.send_eol("0") 33 | conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) 34 | 35 | def main(): 36 | device_opt = ["ipaddr", "login", "passwd", "secure", "cmd_prompt", "telnet"] 37 | 38 | atexit.register(atexit_handler) 39 | 40 | all_opt["cmd_prompt"]["default"] = ["to quit:"] 41 | 42 | opt = process_input(device_opt) 43 | 44 | if "--ssh" not in opt and "--ipport" not in opt: 45 | # set default value like it should be set as usually 46 | all_opt["ipport"]["default"] = "3172" 47 | opt["--ipport"] = all_opt["ipport"]["default"] 48 | 49 | options = check_input(device_opt, opt) 50 | 51 | docs = {} 52 | docs["shortdesc"] = "Power Fencing agent for Fujitsu-Siemens RSB" 53 | docs["longdesc"] = "fence_rsb is a Power Fencing agent \ 54 | which can be used with the Fujitsu-Siemens RSB management interface. It logs \ 55 | into device via telnet/ssh and reboots a specified outlet. Lengthy telnet/ssh \ 56 | connections should be avoided while a GFS cluster is running because the connection \ 57 | will block any necessary fencing actions." 58 | docs["vendorurl"] = "http://www.fujitsu.com" 59 | show_docs(options, docs) 60 | 61 | ## 62 | ## Operate the fencing device 63 | #### 64 | conn = fence_login(options) 65 | result = fence_action(conn, options, set_power_status, get_power_status, None) 66 | fence_logout(conn, "0") 67 | sys.exit(result) 68 | 69 | if __name__ == "__main__": 70 | main() 71 | -------------------------------------------------------------------------------- /agents/virsh/fence_virsh.py: -------------------------------------------------------------------------------- 1 | #!@PYTHON@ -tt 2 | 3 | # The Following Agent Has Been Tested On: 4 | # 5 | # Virsh 0.3.3 on RHEL 5.2 with xen-3.0.3-51 6 | # 7 | 8 | import sys, re 9 | import time 10 | import atexit 11 | sys.path.append("@FENCEAGENTSLIBDIR@") 12 | from fencing import * 13 | from fencing import fail_usage 14 | 15 | def get_name_or_uuid(options): 16 | return options["--uuid"] if "--uuid" in options else options["--plug"] 17 | 18 | def get_outlets_status(conn, options): 19 | if "--use-sudo" in options: 20 | prefix = options["--sudo-path"] + " " 21 | else: 22 | prefix = "" 23 | 24 | conn.sendline(prefix + "virsh list --all") 25 | conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) 26 | 27 | result = {} 28 | 29 | #This is status of mini finite automata. 0 = we didn't found Id and Name, 1 = we did 30 | fa_status = 0 31 | 32 | for line in conn.before.splitlines(): 33 | domain = re.search(r"^\s*(\S+)\s+(\S+)\s+(\S+).*$", line) 34 | 35 | if domain != None: 36 | if fa_status == 0 and domain.group(1).lower() == "id" and domain.group(2).lower() == "name": 37 | fa_status = 1 38 | elif fa_status == 1: 39 | result[domain.group(2)] = ("", 40 | (domain.group(3).lower() in ["running", "blocked", "idle", "no state", "paused"] and "on" or "off")) 41 | return result 42 | 43 | def get_power_status(conn, options): 44 | prefix = options["--sudo-path"] + " " if "--use-sudo" in options else "" 45 | conn.sendline(prefix + "virsh domstate %s" % (get_name_or_uuid(options))) 46 | conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) 47 | 48 | for line in conn.before.splitlines(): 49 | if line.strip() in ["running", "blocked", "idle", "no state", "paused"]: 50 | return "on" 51 | if "error: failed to get domain" in line.strip() and "--missing-as-off" in options: 52 | return "off" 53 | if "error:" in line.strip(): 54 | fail_usage("Failed: You have to enter existing name/UUID of virtual machine!") 55 | 56 | return "off" 57 | 58 | def set_power_status(conn, options): 59 | prefix = options["--sudo-path"] + " " if "--use-sudo" in options else "" 60 | conn.sendline(prefix + "virsh %s " % 61 | (options["--action"] == "on" and "start" or "destroy") + get_name_or_uuid(options)) 62 | 63 | conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) 64 | time.sleep(int(options["--power-wait"])) 65 | 66 | def main(): 67 | device_opt = ["ipaddr", "login", "passwd", "cmd_prompt", "secure", "port", "sudo", "missing_as_off"] 68 | 69 | atexit.register(atexit_handler) 70 | 71 | all_opt["secure"]["default"] = "1" 72 | all_opt["cmd_prompt"]["default"] = [r"\[EXPECT\]#"] 73 | all_opt["ssh_options"]["default"] = "-t '/bin/bash -c \"" + r"PS1=\\[EXPECT\\]# " + "/bin/bash --noprofile --norc\"'" 74 | 75 | options = check_input(device_opt, process_input(device_opt)) 76 | 77 | docs = {} 78 | docs["shortdesc"] = "Fence agent for virsh" 79 | docs["longdesc"] = "fence_virsh is a Power Fencing agent \ 80 | which can be used with the virtual machines managed by libvirt. \ 81 | It logs via ssh to a dom0 and there run virsh command, which does \ 82 | all work. \ 83 | \n.P\n\ 84 | By default, virsh needs root account to do properly work. So you \ 85 | must allow ssh login in your sshd_config." 86 | docs["vendorurl"] = "http://libvirt.org" 87 | show_docs(options, docs) 88 | 89 | ## Operate the fencing device 90 | conn = fence_login(options) 91 | result = fence_action(conn, options, set_power_status, get_power_status, get_outlets_status) 92 | fence_logout(conn, "quit") 93 | sys.exit(result) 94 | 95 | if __name__ == "__main__": 96 | main() 97 | -------------------------------------------------------------------------------- /agents/virt/Makefile.am: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | ############################################################################### 3 | ## 4 | ## Copyright (C) 2009-2021 Red Hat, Inc. 5 | ## 6 | ## This copyrighted material is made available to anyone wishing to use, 7 | ## modify, copy, or redistribute it subject to the terms and conditions 8 | ## of the GNU General Public License v.2. 9 | ## 10 | ############################################################################### 11 | ############################################################################### 12 | 13 | MAINTAINERCLEANFILES = Makefile.in 14 | 15 | EXTRA_DIST = docs/architecture.txt docs/fence_virt.txt \ 16 | docs/README docs/TODO include \ 17 | fence_virtd.service.in 18 | 19 | SUBDIRS = config common client server man 20 | 21 | all-local: fence_virtd.service 22 | 23 | clean-local: 24 | rm -f $(SPEC) fence_virtd.service 25 | 26 | fence_virtd.service: fence_virtd.service.in 27 | SBINDIR="@sbindir@"; \ 28 | INITCONFDIR="@initconfdir@"; \ 29 | cat $^ > $@ ; \ 30 | echo "EnvironmentFile=-$$INITCONFDIR/fence_virtd" >> $@ ;\ 31 | echo "ExecStart=$$SBINDIR/fence_virtd \$$FENCE_VIRTD_ARGS" >> $@ 32 | -------------------------------------------------------------------------------- /agents/virt/client/Makefile.am: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | ############################################################################### 3 | ## 4 | ## Copyright (C) 2009-2019 Red Hat, Inc. 5 | ## 6 | ## This copyrighted material is made available to anyone wishing to use, 7 | ## modify, copy, or redistribute it subject to the terms and conditions 8 | ## of the GNU General Public License v.2 9 | ## 10 | ############################################################################### 11 | ############################################################################### 12 | 13 | MAINTAINERCLEANFILES = Makefile.in 14 | 15 | sbin_PROGRAMS = fence_virt 16 | 17 | TARGET = $(sbin_PROGRAMS) 18 | 19 | fence_virt_SOURCES = mcast.c serial.c main.c options.c tcp.c vsock.c 20 | 21 | fence_virt_CFLAGS = $(VIRT_AM_CFLAGS) $(nss_CFLAGS) $(xml2_CFLAGS) $(PTHREAD_CFLAGS) $(AM_CFLAGS) 22 | 23 | fence_virt_LDFLAGS = $(VIRT_AM_LDFLAGS) $(COMMON_LDFLAGS) 24 | fence_virt_LDADD = $(VIRT_COMMON_LIBS) $(nss_LIBS) $(xml2_LIBS) $(PTHREAD_LIBS) 25 | 26 | if xvmcompat 27 | install-exec-hook: fence_virt 28 | (cd $(DESTDIR)/${sbindir}; $(LN_S) -nf $^ fence_xvm) 29 | 30 | uninstall-hook: 31 | (cd $(DESTDIR)/${sbindir}; rm -f fence_xvm) 32 | endif 33 | 34 | fence_virt.delay-check: fence_virt 35 | $(eval INPUT=$(subst .delay-check,,$@)) 36 | test `/usr/bin/time -p ./$(INPUT) -w 10 -n test $(FENCE_TEST_ARGS) -- 2>&1 |\ 37 | awk -F"[. ]" -vOFS= '/real/ {print $$2,$$3}' | tail -n 1` -ge 1000 || \ 38 | /usr/bin/time -p ./$(INPUT) -w 0 -n test $(FENCE_TEST_ARGS) -- 39 | 40 | include $(top_srcdir)/make/agentccheck.mk 41 | -------------------------------------------------------------------------------- /agents/virt/common/Makefile.am: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | ############################################################################### 3 | ## 4 | ## Copyright (C) 2009-2019 Red Hat, Inc. 5 | ## 6 | ## This copyrighted material is made available to anyone wishing to use, 7 | ## modify, copy, or redistribute it subject to the terms and conditions 8 | ## of the GNU General Public License v.2. 9 | ## 10 | ############################################################################### 11 | ############################################################################### 12 | 13 | MAINTAINERCLEANFILES = Makefile.in 14 | 15 | noinst_LTLIBRARIES = libfence_virt.la 16 | 17 | libfence_virt_la_SOURCES = mcast.c ip_lookup.c simple_auth.c tcp.c \ 18 | debug.c fdops.c log.c 19 | 20 | libfence_virt_la_CFLAGS = $(VIRT_AM_CFLAGS) $(nss_CFLAGS) $(AM_CFLAGS) -Wno-cast-align 21 | 22 | libfence_virt_la_LDFLAGS = $(VIRT_AM_LDFLAGS) $(VIRT_COMMON_LDFLAGS) 23 | 24 | libfence_virt_la_LIBADD = $(nss_LIBS) 25 | -------------------------------------------------------------------------------- /agents/virt/common/debug.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Red Hat, Inc. 2006 3 | 4 | This program is free software; you can redistribute it and/or modify it 5 | under the terms of the GNU General Public License as published by the 6 | Free Software Foundation; either version 2, or (at your option) any 7 | later version. 8 | 9 | This program is distributed in the hope that it will be useful, but 10 | WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program; see the file COPYING. If not, write to the 16 | Free Software Foundation, Inc., 675 Mass Ave, Cambridge, 17 | MA 02139, USA. 18 | */ 19 | 20 | #include "config.h" 21 | 22 | #include 23 | #include "debug.h" 24 | 25 | static int _debug = 0; 26 | 27 | void 28 | dset(int threshold) 29 | { 30 | _debug = threshold; 31 | dbg_printf(3, "Debugging threshold is now %d\n", threshold); 32 | } 33 | 34 | int 35 | dget(void) 36 | { 37 | return _debug; 38 | } 39 | -------------------------------------------------------------------------------- /agents/virt/common/log.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Syslog wrapper that does not block 3 | * 4 | * Lon Hohberger, 2009 5 | */ 6 | 7 | #include "config.h" 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include "list.h" 23 | 24 | struct log_entry { 25 | list_head(); 26 | char *message; 27 | int sev; 28 | int bufsz; 29 | }; 30 | 31 | #define MAX_QUEUE_LENGTH 10 32 | #define LOGLEN 256 33 | 34 | static struct log_entry *_log_entries = NULL; 35 | static pthread_mutex_t log_mutex = PTHREAD_MUTEX_INITIALIZER; 36 | static pthread_cond_t log_cond = PTHREAD_COND_INITIALIZER; 37 | static int log_size = 0; 38 | static int dropped = 0; 39 | static pthread_t thread_id = 0; 40 | 41 | void __real_syslog(int severity, const char *fmt, ...); 42 | void __wrap_syslog(int severity, const char *fmt, ...); 43 | void __wrap_closelog(void); 44 | 45 | static void * 46 | _log_thread(void *arg) 47 | { 48 | struct timeval tv; 49 | struct timespec ts; 50 | struct log_entry *entry; 51 | 52 | do { 53 | gettimeofday(&tv, NULL); 54 | ts.tv_sec = tv.tv_sec + 10; 55 | ts.tv_nsec = tv.tv_usec; 56 | 57 | pthread_mutex_lock(&log_mutex); 58 | 59 | while (!(entry = _log_entries)) { 60 | if (pthread_cond_timedwait(&log_cond, 61 | &log_mutex, 62 | &ts) == ETIMEDOUT) 63 | goto out; 64 | } 65 | 66 | list_remove(&_log_entries, entry); 67 | --log_size; 68 | if (log_size < 0) 69 | raise(SIGSEGV); 70 | pthread_mutex_unlock(&log_mutex); 71 | 72 | __real_syslog(entry->sev, entry->message); 73 | free(entry->message); 74 | free(entry); 75 | } while (1); 76 | 77 | out: 78 | thread_id = (pthread_t)0; 79 | pthread_mutex_unlock(&log_mutex); 80 | return NULL; 81 | } 82 | 83 | 84 | static int 85 | insert_entry(int sev, char *buf, int bufsz) 86 | { 87 | struct log_entry *lent; 88 | pthread_attr_t attrs; 89 | 90 | lent = malloc(sizeof(*lent)); 91 | if (!lent) 92 | return -1; 93 | lent->sev = sev; 94 | lent->message = buf; 95 | lent->bufsz = bufsz; 96 | 97 | pthread_mutex_lock(&log_mutex); 98 | if (log_size >= MAX_QUEUE_LENGTH) { 99 | free(lent->message); 100 | free(lent); 101 | 102 | ++dropped; 103 | lent = (struct log_entry *)(le(_log_entries)->le_prev); 104 | 105 | lent->sev = LOG_WARNING; 106 | snprintf(lent->message, lent->bufsz, 107 | "%d message(s) lost due to syslog load\n", 108 | dropped + 1); 109 | /* Dropped +1 because we overwrote a message to 110 | * give the 'dropped' message */ 111 | } else { 112 | ++log_size; 113 | dropped = 0; 114 | list_insert(&_log_entries, lent); 115 | } 116 | 117 | if (!thread_id) { 118 | pthread_attr_init(&attrs); 119 | pthread_attr_setinheritsched(&attrs, PTHREAD_INHERIT_SCHED); 120 | 121 | if (pthread_create(&thread_id, &attrs, _log_thread, NULL) < 0) 122 | thread_id = 0; 123 | pthread_mutex_unlock(&log_mutex); 124 | } else { 125 | pthread_mutex_unlock(&log_mutex); 126 | pthread_cond_signal(&log_cond); 127 | } 128 | 129 | return 0; 130 | } 131 | 132 | 133 | __attribute__((__format__ (__printf__, 2, 0))) 134 | void 135 | __wrap_syslog(int severity, const char *fmt, ...) 136 | { 137 | va_list args; 138 | char *logmsg; 139 | 140 | logmsg = malloc(LOGLEN); 141 | if (!logmsg) 142 | return; 143 | memset(logmsg, 0, LOGLEN); 144 | 145 | va_start(args, fmt); 146 | vsnprintf(logmsg + strlen(logmsg), LOGLEN - strlen(logmsg), 147 | fmt, args); 148 | va_end(args); 149 | 150 | insert_entry(severity, logmsg, LOGLEN); 151 | 152 | return; 153 | } 154 | 155 | 156 | void __real_closelog(void); 157 | 158 | void 159 | __wrap_closelog(void) 160 | { 161 | struct log_entry *lent; 162 | #ifdef DEBUG 163 | int lost = 0; 164 | #endif 165 | 166 | if (thread_id != 0) { 167 | pthread_cancel(thread_id); 168 | pthread_join(thread_id, NULL); 169 | thread_id = 0; 170 | } 171 | __real_closelog(); 172 | while (_log_entries) { 173 | #ifdef DEBUG 174 | ++lost; 175 | #endif 176 | lent = _log_entries; 177 | list_remove(&_log_entries, lent); 178 | free(lent->message); 179 | free(lent); 180 | } 181 | 182 | #ifdef DEBUG 183 | printf("%d lost\n", lost); 184 | #endif 185 | } 186 | 187 | 188 | #ifdef STANDALONE 189 | int 190 | main(int argc, char**argv) 191 | { 192 | int x; 193 | 194 | for (x = 0; x < 100; x++) { 195 | syslog(1, "Yo %d\n", x); 196 | } 197 | sleep(1); 198 | 199 | closelog(); 200 | 201 | return 0; 202 | } 203 | 204 | #endif 205 | -------------------------------------------------------------------------------- /agents/virt/config/Makefile.am: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | ############################################################################### 3 | ## 4 | ## Copyright (C) 2009-2019 Red Hat, Inc. 5 | ## 6 | ## This copyrighted material is made available to anyone wishing to use, 7 | ## modify, copy, or redistribute it subject to the terms and conditions 8 | ## of the GNU General Public License v.2. 9 | ## 10 | ############################################################################### 11 | ############################################################################### 12 | 13 | MAINTAINERCLEANFILES = Makefile.in 14 | 15 | EXTRA_DIST = config.l config.y fence_virt.conf 16 | 17 | noinst_LIBRARIES = libsimpleconfig.a 18 | 19 | libsimpleconfig_a_SOURCES = \ 20 | simpleconfig.c 21 | 22 | nodist_libsimpleconfig_a_SOURCES = \ 23 | y.tab.c \ 24 | config.c 25 | 26 | libsimpleconfig_a_CFLAGS = $(VIRT_AM_CFLAGS) $(AM_CFLAGS) -Wno-unused 27 | 28 | noinst_HEADERS = config-stack.h 29 | 30 | 31 | sysconf_DATA = fence_virt.conf 32 | 33 | # local rules 34 | y.tab.c: config.y 35 | $(YACC) -d $^ 36 | 37 | config.c: y.tab.c config.l 38 | $(LEX) -oconfig.c $(srcdir)/config.l 39 | 40 | install-exec-hook: 41 | chmod 600 $(DESTDIR)$(sysconfdir)/fence_virt.conf 42 | 43 | clean-local: 44 | rm -f config.tab.c config.tab.h config.c y.tab.c y.tab.h 45 | -------------------------------------------------------------------------------- /agents/virt/config/config-stack.h: -------------------------------------------------------------------------------- 1 | #ifndef _CONFIG_STACK_H 2 | #define _CONFIG_STACK_H 3 | 4 | int yyparse (void); 5 | extern FILE *yyin; 6 | 7 | struct value { 8 | char *id; 9 | char *val; 10 | struct value *next; 11 | }; 12 | 13 | 14 | struct node { 15 | char *id; 16 | char *val; 17 | struct node *nodes; 18 | struct value *values; 19 | struct node *next; 20 | }; 21 | 22 | 23 | struct parser_context { 24 | struct value *val_list; 25 | struct node *node_list; 26 | struct parser_context *next; 27 | }; 28 | 29 | extern struct value *val_list; 30 | extern struct node *node_list; 31 | extern struct parser_context *context_stack; 32 | 33 | int _sc_value_add(char *id, char *val, struct value **list); 34 | int _sc_node_add(char *id, char *val, struct value *vallist, 35 | struct node *nodelist, struct node **list); 36 | 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /agents/virt/config/config.l: -------------------------------------------------------------------------------- 1 | %{ 2 | #include "config.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "config-stack.h" 8 | #include "y.tab.h" 9 | #include "simpleconfig.h" 10 | 11 | /* Some distributions can't use the output from flex without help */ 12 | #define ECHO if(fwrite( yytext, yyleng, 1, yyout )) 13 | 14 | struct value *val_list = NULL; 15 | struct node *node_list = NULL; 16 | struct parser_context *context_stack = NULL; 17 | 18 | int _line_count = 1; 19 | 20 | %} 21 | %% 22 | [\n] { 23 | ++_line_count; 24 | } 25 | 26 | [ \t]* {} 27 | 28 | \#[^\n]* {} 29 | 30 | "{" { 31 | struct parser_context *c = NULL; 32 | //printf("obrace\n"); 33 | 34 | c = malloc(sizeof(*c)); 35 | assert(c); 36 | 37 | c->next = context_stack; 38 | c->val_list = val_list; 39 | c->node_list = node_list; 40 | 41 | context_stack = c; 42 | val_list = NULL; 43 | node_list = NULL; 44 | 45 | return T_OBRACE; 46 | } 47 | 48 | "}" { 49 | return T_CBRACE; 50 | } 51 | 52 | ";" { 53 | return T_SEMI; 54 | } 55 | 56 | "=" { 57 | return T_EQ; 58 | } 59 | 60 | [^ \t{};=\"\n]+ { 61 | yylval.sval = strdup(yytext); 62 | return T_ID; 63 | } 64 | 65 | \"[^\"]+\" { 66 | yylval.sval = strdup(yytext+1); 67 | yylval.sval[strlen(yytext)-2] = 0; 68 | return T_VAL; 69 | } 70 | 71 | %% 72 | int 73 | yywrap(void) 74 | { 75 | return 1; 76 | } 77 | 78 | 79 | #ifdef STANDALONE 80 | int 81 | main(int argc, char *argv[]) 82 | { 83 | char value[80]; 84 | config_object_t *c = NULL; 85 | 86 | yyout = fopen("/dev/null","w"); 87 | 88 | c = sc_init(); 89 | sc_parse(c, NULL); 90 | sc_dump(c, stdout); 91 | if (argc == 2) { 92 | if (sc_get(c, argv[1], value, sizeof(value)) == 0) 93 | printf("%s = %s\n", argv[1], value); 94 | else 95 | printf("Not found\n"); 96 | } else if (argc == 3) { 97 | printf("---------\n"); 98 | if (sc_set(c, argv[1], argv[2]) == 0) 99 | sc_dump(c, stdout); 100 | } 101 | 102 | sc_release(c); 103 | 104 | return 0; 105 | } 106 | #endif 107 | -------------------------------------------------------------------------------- /agents/virt/config/config.y: -------------------------------------------------------------------------------- 1 | %{ 2 | #include "config.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "config-stack.h" 8 | 9 | extern int yylex (void); 10 | int yyerror(const char *foo); 11 | 12 | int 13 | _sc_value_add(char *id, char *val, struct value **list) 14 | { 15 | struct value *v; 16 | 17 | v = malloc(sizeof(*v)); 18 | assert(v); 19 | 20 | memset(v, 0, sizeof(*v)); 21 | v->id = id; 22 | v->val = val; 23 | //snprintf(v->id, sizeof(v->id), "%s", id); 24 | //snprintf(v->val, sizeof(v->val), "%s", val); 25 | //printf("add %s %s on to %p\n", id, val, *list); 26 | 27 | v->next = *list; 28 | *list = v; 29 | 30 | //printf("new list %p\n", *list); 31 | return 0; 32 | } 33 | 34 | 35 | int 36 | _sc_node_add(char *id, char *val, struct value *vallist, 37 | struct node *nodelist, struct node **list) 38 | { 39 | struct node *n; 40 | 41 | n = malloc(sizeof(*n)); 42 | assert(n); 43 | 44 | //printf("nodes %p values %p\n", nodelist, vallist); 45 | 46 | memset(n, 0, sizeof(*n)); 47 | //snprintf(n->id, sizeof(n->id), "%s", id); 48 | n->id = id; /* malloc'd during parsing */ 49 | n->val = val; /* malloc'd during parsing */ 50 | n->values = vallist; 51 | n->nodes = nodelist; 52 | n->next = *list; 53 | *list = n; 54 | 55 | return 0; 56 | } 57 | 58 | %} 59 | 60 | %token T_ID 61 | %token T_VAL 62 | %token T_OBRACE T_CBRACE T_EQ T_SEMI 63 | 64 | %start stuff 65 | 66 | %union { 67 | char *sval; 68 | int ival; 69 | } 70 | 71 | %% 72 | node: 73 | T_ID T_OBRACE stuff T_CBRACE { 74 | struct parser_context *c = NULL; 75 | 76 | c = context_stack; 77 | _sc_node_add($1, NULL, val_list, node_list, &c->node_list); 78 | val_list = c->val_list; 79 | node_list = c->node_list; 80 | context_stack = c->next; 81 | 82 | free(c); 83 | } 84 | | 85 | T_ID T_EQ T_VAL T_OBRACE stuff T_CBRACE { 86 | struct parser_context *c = NULL; 87 | 88 | c = context_stack; 89 | _sc_node_add($1, $3, val_list, node_list, &c->node_list); 90 | val_list = c->val_list; 91 | node_list = c->node_list; 92 | context_stack = c->next; 93 | 94 | free(c); 95 | } 96 | | 97 | T_ID T_OBRACE T_CBRACE { 98 | struct parser_context *c = NULL; 99 | 100 | c = context_stack; 101 | _sc_node_add($1, NULL, val_list, node_list, &c->node_list); 102 | val_list = c->val_list; 103 | node_list = c->node_list; 104 | context_stack = c->next; 105 | 106 | free(c); 107 | } 108 | | 109 | T_ID T_EQ T_VAL T_OBRACE T_CBRACE { 110 | struct parser_context *c = NULL; 111 | 112 | c = context_stack; 113 | _sc_node_add($1, $3, val_list, node_list, &c->node_list); 114 | val_list = c->val_list; 115 | node_list = c->node_list; 116 | context_stack = c->next; 117 | 118 | free(c); 119 | } 120 | ; 121 | 122 | stuff: 123 | node stuff | assign stuff | node | assign 124 | ; 125 | 126 | assign: 127 | T_ID T_EQ T_VAL T_SEMI { 128 | _sc_value_add($1, $3, &val_list); 129 | } 130 | ; 131 | %% 132 | 133 | extern int _line_count; 134 | 135 | int 136 | yyerror(const char *foo) 137 | { 138 | printf("%s on line %d\n", foo, _line_count); 139 | return 0; 140 | } 141 | -------------------------------------------------------------------------------- /agents/virt/config/fence_virt.conf: -------------------------------------------------------------------------------- 1 | fence_virtd { 2 | listener = "multicast"; 3 | backend = "libvirt"; 4 | } 5 | 6 | listeners { 7 | multicast { 8 | key_file = "/etc/cluster/fence_xvm.key"; 9 | address = "225.0.0.12"; 10 | # Needed on Fedora systems 11 | interface = "virbr0"; 12 | } 13 | } 14 | 15 | backends { 16 | libvirt { 17 | uri = "qemu:///system"; 18 | } 19 | } 20 | 21 | -------------------------------------------------------------------------------- /agents/virt/docs/TODO: -------------------------------------------------------------------------------- 1 | High Priority / Blockers for v1.0; 2 | 3 | * endian-clean / 64-bit clean data structure analysis 4 | 5 | Future Stuff: 6 | 7 | * clean up development bits so third parties can develop plugins 8 | -------------------------------------------------------------------------------- /agents/virt/docs/architecture.txt: -------------------------------------------------------------------------------- 1 | The actual architecture of fence_virtd is very simple. We have a set 2 | of listener plugins which listens for fencing requests for virtual 3 | machines. 4 | 5 | These plugins are assigned callbacks which are entry functions in to 6 | the backend plugins. The backend plugins perform the actual fencing 7 | request. 8 | 9 | In the middle, we have only enough code to provide basic integration 10 | functions between the listener and backend plugins. This includes a 11 | very simple confiugration plugin which we pass to each of the plugins. 12 | 13 | Because we are passing function pointers in to the plugins themselves 14 | for configuration (rather than having the plugins call an API directly, 15 | for example), we are able to swap out the configuration subsystem for 16 | other, more full-featured configuration systems, such as libccs. 17 | -------------------------------------------------------------------------------- /agents/virt/fence_virtd.service.in: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Fence-Virt system host daemon 3 | Documentation=man:fence_virtd(8) 4 | Documentation=man:fence_virt.conf(5) 5 | 6 | After=basic.target 7 | After=network.target 8 | After=syslog.target 9 | After=libvirtd.service 10 | After=corosync.service 11 | 12 | Requires=basic.target 13 | Requires=network.target 14 | 15 | [Install] 16 | WantedBy=multi-user.target 17 | 18 | [Service] 19 | Type=forking 20 | Restart=on-failure 21 | Environment="FENCE_VIRTD_ARGS=-w" 22 | 23 | # Autogenerated below here 24 | -------------------------------------------------------------------------------- /agents/virt/include/bcast.h: -------------------------------------------------------------------------------- 1 | #ifndef _XVM_MCAST_H 2 | #define _XVM_MCAST_H 3 | 4 | #define IPV4_MCAST_DEFAULT "225.0.0.12" 5 | #define IPV6_MCAST_DEFAULT "ff05::3:1" 6 | 7 | int ipv4_recv_sk(char *addr, int port); 8 | int ipv4_send_sk(char *src_addr, char *addr, int port, 9 | struct sockaddr *src, socklen_t slen, 10 | int ttl); 11 | int ipv6_recv_sk(char *addr, int port); 12 | int ipv6_send_sk(char *src_addr, char *addr, int port, 13 | struct sockaddr *src, socklen_t slen, 14 | int ttl); 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /agents/virt/include/client.h: -------------------------------------------------------------------------------- 1 | #ifndef _CLIENT_H 2 | #define _CLIENT_H 3 | 4 | int tcp_fence_virt(fence_virt_args_t *args); 5 | int serial_fence_virt(fence_virt_args_t *args); 6 | int mcast_fence_virt(fence_virt_args_t *args); 7 | int vsock_fence_virt(fence_virt_args_t *args); 8 | void do_read_hostlist(int fd, int timeout); 9 | #endif 10 | -------------------------------------------------------------------------------- /agents/virt/include/debug.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Red Hat, Inc. 2007 3 | 4 | This program is free software; you can redistribute it and/or modify it 5 | under the terms of the GNU General Public License as published by the 6 | Free Software Foundation; either version 2, or (at your option) any 7 | later version. 8 | 9 | This program is distributed in the hope that it will be useful, but 10 | WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program; see the file COPYING. If not, write to the 16 | Free Software Foundation, Inc., 675 Mass Ave, Cambridge, 17 | MA 02139, USA. 18 | */ 19 | #ifndef _DBG_H 20 | #define _DBG_H 21 | 22 | void dset(int); 23 | int dget(void); 24 | 25 | #define dbg_printf(level, fmt, args...) \ 26 | do { \ 27 | if (dget()>=level) \ 28 | printf(fmt, ##args); \ 29 | } while(0) 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /agents/virt/include/fdops.h: -------------------------------------------------------------------------------- 1 | #ifndef _FDOPS_H 2 | #define _FDOPS_H 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | int _select_retry(int fdmax, fd_set * rfds, fd_set * wfds, fd_set * xfds, 9 | struct timeval *timeout); 10 | ssize_t _write_retry(int fd, void *buf, int count, struct timeval * timeout); 11 | ssize_t _read_retry(int sockfd, void *buf, int count, 12 | struct timeval * timeout); 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /agents/virt/include/history.h: -------------------------------------------------------------------------------- 1 | #ifndef _HISTORY_H 2 | #define _HISTORY_H 3 | 4 | typedef struct _history_node { 5 | list_head(); 6 | void *data; 7 | time_t when; 8 | } history_node; 9 | 10 | typedef int (*history_compare_fn)(void *, void *); 11 | 12 | typedef struct _history_info { 13 | history_node *hist; 14 | history_compare_fn compare_func; 15 | time_t timeout; 16 | size_t element_size; 17 | } history_info_t; 18 | 19 | history_info_t *history_init(history_compare_fn func, 20 | time_t expiration, size_t element_size); 21 | int history_check(history_info_t *hinfo, void *stuff); 22 | int history_record(history_info_t *hinfo, void *data); 23 | int history_wipe(history_info_t *hinfo); 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /agents/virt/include/ip_lookup.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Red Hat, Inc. 2004,2006 3 | 4 | The Magma Cluster API Library is free software; you can redistribute 5 | it and/or modify it under the terms of the GNU Lesser General Public 6 | License as published by the Free Software Foundation; either version 7 | 2.1 of the License, or (at your option) any later version. 8 | 9 | The Magma Cluster API Library is distributed in the hope that it will 10 | be useful, but WITHOUT ANY WARRANTY; without even the implied warranty 11 | of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | Lesser General Public License for more details. 13 | 14 | You should have received a copy of the GNU Lesser General Public 15 | License along with this library; if not, write to the Free Software 16 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 17 | USA. 18 | */ 19 | /** @file 20 | * Header for ip_lookup.c 21 | */ 22 | #ifndef _IP_LOOKUP_H 23 | #define _IP_LOOKUP_H 24 | 25 | #include 26 | 27 | typedef struct _ip_address { 28 | TAILQ_ENTRY(_ip_address) ipa_entries; 29 | char ipa_family; 30 | char *ipa_address; 31 | } ip_addr_t; 32 | 33 | typedef TAILQ_HEAD(_ip_list, _ip_address) ip_list_t; 34 | 35 | int ip_search(ip_list_t *ipl, char *ip_name); 36 | int ip_free_list(ip_list_t *ipl); 37 | int ip_build_list(ip_list_t *ipl); 38 | int ip_lookup(char *, struct addrinfo **); 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /agents/virt/include/list.h: -------------------------------------------------------------------------------- 1 | #ifndef _LIST_H 2 | #define _LIST_H 3 | 4 | /** 5 | Simple list handlig macros. 6 | Needs rewrite or inclusion of /usr/include/linux/list.h as a replacement. 7 | */ 8 | 9 | /* Must be first if structure is going to use it. */ 10 | struct list_entry { 11 | struct list_entry *le_next, *le_prev; 12 | }; 13 | 14 | #define list_head() struct list_entry _list_head 15 | 16 | #define le(p) (&((*p)._list_head)) 17 | 18 | #define list_insert(list, newnode) \ 19 | do { \ 20 | if (!(*list)) { \ 21 | le(newnode)->le_next = \ 22 | le(newnode)->le_prev = le(newnode); \ 23 | *list = (void *)le(newnode); \ 24 | } else { \ 25 | le(*list)->le_prev->le_next = le(newnode); \ 26 | le(newnode)->le_next = le(*list); \ 27 | le(newnode)->le_prev = le(*list)->le_prev; \ 28 | le(*list)->le_prev = le(newnode); \ 29 | } \ 30 | } while (0) 31 | 32 | 33 | #define list_prepend(list, newnode) \ 34 | do { \ 35 | list_insert(list, newnode); \ 36 | *list = newnode; \ 37 | } while (0) 38 | 39 | 40 | #define list_remove(list, oldnode) \ 41 | do { \ 42 | if (le(oldnode) == le(*list)) { \ 43 | *list = (void *)le(*list)->le_next; \ 44 | } \ 45 | if (le(oldnode) == le(*list)) { \ 46 | le(oldnode)->le_next = NULL; \ 47 | le(oldnode)->le_prev = NULL; \ 48 | *list = NULL; \ 49 | } else { \ 50 | le(oldnode)->le_next->le_prev = le(oldnode)->le_prev; \ 51 | le(oldnode)->le_prev->le_next = le(oldnode)->le_next; \ 52 | le(oldnode)->le_prev = NULL; \ 53 | le(oldnode)->le_next = NULL; \ 54 | } \ 55 | } while (0) 56 | 57 | 58 | /* 59 | * list_for(list, tmp, counter) { 60 | * stuff; 61 | * } 62 | * 63 | * counter = # of items in list when done. 64 | * * sets cnt to 0 before even checking list; 65 | * * checks for valid list 66 | * * traverses list, incrementing counter. If we get to the for loop, 67 | * there must be at least one item in the list 68 | * * cnt ends up being the number of items in the list. 69 | */ 70 | #define list_for(list, curr, cnt) \ 71 | if ((!(cnt=0)) && (*list != NULL)) \ 72 | for (curr = *list; \ 73 | (cnt == 0) || (curr != *list); \ 74 | curr = (void*)le(curr)->le_next, \ 75 | cnt++) 76 | 77 | #define list_for_rev(list, curr, cnt) \ 78 | if ((!(cnt=0)) && (*list != NULL)) \ 79 | for (curr = (void *)(le(*list)->le_prev); \ 80 | (cnt == 0) || ((void *)curr != le(*list)->le_prev); \ 81 | curr = (void*)(le(curr)->le_prev), \ 82 | cnt++) 83 | 84 | #endif 85 | -------------------------------------------------------------------------------- /agents/virt/include/mcast.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Red Hat, Inc. 2006 3 | 4 | This program is free software; you can redistribute it and/or modify it 5 | under the terms of the GNU General Public License as published by the 6 | Free Software Foundation; either version 2, or (at your option) any 7 | later version. 8 | 9 | This program is distributed in the hope that it will be useful, but 10 | WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program; see the file COPYING. If not, write to the 16 | Free Software Foundation, Inc., 675 Mass Ave, Cambridge, 17 | MA 02139, USA. 18 | */ 19 | #ifndef _XVM_MCAST_H 20 | #define _XVM_MCAST_H 21 | 22 | #define IPV4_MCAST_DEFAULT "225.0.0.12" 23 | #define IPV6_MCAST_DEFAULT "ff05::3:1" 24 | 25 | int ipv4_recv_sk(char *addr, int port, unsigned int ifindex); 26 | int ipv4_send_sk(char *src_addr, char *addr, int port, 27 | struct sockaddr *src, socklen_t slen); 28 | int ipv6_recv_sk(char *addr, int port, unsigned int ifindex); 29 | int ipv6_send_sk(char *src_addr, char *addr, int port, 30 | struct sockaddr *src, socklen_t slen); 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /agents/virt/include/options.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Red Hat, Inc. 2006 3 | 4 | This program is free software; you can redistribute it and/or modify it 5 | under the terms of the GNU General Public License as published by the 6 | Free Software Foundation; either version 2, or (at your option) any 7 | later version. 8 | 9 | This program is distributed in the hope that it will be useful, but 10 | WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program; see the file COPYING. If not, write to the 16 | Free Software Foundation, Inc., 675 Mass Ave, Cambridge, 17 | MA 02139, USA. 18 | */ 19 | #ifndef _XVM_OPTIONS_H 20 | #define _XVM_OPTIONS_H 21 | 22 | typedef enum { 23 | F_FOREGROUND = 0x1, 24 | F_NOCCS = 0x2, 25 | F_ERR = 0x4, 26 | F_HELP = 0x8, 27 | F_USE_UUID = 0x10, 28 | F_VERSION = 0x20, 29 | F_CCSERR = 0x40, 30 | F_CCSFAIL = 0x80, 31 | F_NOCLUSTER = 0x100 32 | } arg_flags_t; 33 | 34 | typedef enum { 35 | MODE_MULTICAST = 0, 36 | /*MODE_BROADCAST = 1,*/ 37 | MODE_SERIAL = 2, 38 | MODE_VMCHANNEL = 3, 39 | MODE_TCP = 4, 40 | MODE_VSOCK = 5 41 | } client_mode_t; 42 | 43 | typedef struct { 44 | char *domain; 45 | fence_cmd_t op; 46 | client_mode_t mode; 47 | int debug; 48 | int timeout; 49 | int delay; 50 | int retr_time; 51 | arg_flags_t flags; 52 | 53 | struct network_args { 54 | char *addr; 55 | char *ipaddr; 56 | char *key_file; 57 | uint32_t cid; 58 | int port; 59 | fence_hash_t hash; 60 | fence_auth_type_t auth; 61 | int family; 62 | unsigned int ifindex; 63 | } net; 64 | 65 | struct serial_args { 66 | char *device; /* Serial device */ 67 | char *speed; 68 | char *address; /* vmchannel IP */ 69 | } serial; 70 | } fence_virt_args_t; 71 | 72 | /* Private structure for commandline / stdin fencing args */ 73 | struct arg_info { 74 | const char opt; 75 | const char *opt_desc; 76 | const char *stdin_opt; 77 | const char *obsoletes; 78 | int deprecated; 79 | int eh; 80 | const char *content_type; 81 | const char *default_value; 82 | const char *desc; 83 | void (*assign)(fence_virt_args_t *, struct arg_info *, char *); 84 | }; 85 | 86 | 87 | /* Get options */ 88 | void args_init(fence_virt_args_t *args); 89 | void args_finalize(fence_virt_args_t *args); 90 | 91 | void args_get_getopt(int argc, char **argv, const char *optstr, 92 | fence_virt_args_t *args); 93 | void args_get_stdin(const char *optstr, fence_virt_args_t *args); 94 | void args_get_ccs(const char *optstr, fence_virt_args_t *args); 95 | void args_usage(char *progname, const char *optstr, int print_stdin); 96 | void args_print(fence_virt_args_t *args); 97 | void args_metadata(char *progname, const char *optstr); 98 | 99 | #endif 100 | -------------------------------------------------------------------------------- /agents/virt/include/server_plugin.h: -------------------------------------------------------------------------------- 1 | /* */ 2 | 3 | #ifndef _SERVER_PLUGIN_H 4 | #define _SERVER_PLUGIN_H 5 | 6 | #include "config.h" 7 | 8 | #define PLUGIN_VERSION_LISTENER ((double)0.3) 9 | #define PLUGIN_VERSION_BACKEND ((double)0.2) 10 | 11 | typedef void * listener_context_t; 12 | typedef void * backend_context_t; 13 | 14 | /* These callbacks hand requests off to the 15 | appropriate backend. */ 16 | 17 | /* Do nothing. Returns 1 (failure) to caller */ 18 | typedef int (*fence_null_callback)(const char *vm_name, 19 | void *priv); 20 | 21 | /* Turn the VM 'off'. Returns 0 to caller if successful or 22 | nonzero if unsuccessful. */ 23 | typedef int (*fence_off_callback)(const char *vm_name, const char *src, 24 | uint32_t seqno, void *priv); 25 | 26 | /* Turn the VM 'on'. Returns 0 to caller if successful or 27 | nonzero if unsuccessful. */ 28 | typedef int (*fence_on_callback)(const char *vm_name, const char *src, 29 | uint32_t seqno, void *priv); 30 | 31 | /* Reboot a VM. Returns 0 to caller if successful or 32 | nonzero if unsuccessful. */ 33 | typedef int (*fence_reboot_callback)(const char *vm_name, const char *src, 34 | uint32_t seqno, void *priv); 35 | 36 | /* Get status of a VM. Returns 0 to caller if VM is alive or 37 | nonzero if VM is not alive. */ 38 | typedef int (*fence_status_callback)(const char *vm_name, 39 | void *priv); 40 | 41 | /* Get status of backend. Returns 0 to caller if backend 42 | is responding to requests. */ 43 | typedef int (*fence_devstatus_callback)(void *priv); 44 | 45 | 46 | /* VMs available to fence. Returns 0 to caller if backend 47 | is responding to requests and a host list can be produced */ 48 | typedef int (*hostlist_callback)(const char *vm_name, const char *uuid, 49 | int state, void *arg); 50 | typedef int (*fence_hostlist_callback)(hostlist_callback cb, 51 | void *arg, void *priv); 52 | 53 | typedef int (*backend_init_fn)(backend_context_t *c, 54 | config_object_t *config); 55 | typedef int (*backend_cleanup_fn)(backend_context_t c); 56 | 57 | typedef struct _fence_callbacks { 58 | fence_null_callback null; 59 | fence_off_callback off; 60 | fence_on_callback on; 61 | fence_reboot_callback reboot; 62 | fence_status_callback status; 63 | fence_devstatus_callback devstatus; 64 | fence_hostlist_callback hostlist; 65 | } fence_callbacks_t; 66 | 67 | typedef struct backend_plugin { 68 | const char *name; 69 | const char *version; 70 | const fence_callbacks_t *callbacks; 71 | backend_init_fn init; 72 | backend_cleanup_fn cleanup; 73 | } backend_plugin_t; 74 | 75 | double backend_plugin_version(void); 76 | const backend_plugin_t * backend_plugin_info(void); 77 | 78 | #define BACKEND_VER_SYM backend_plugin_version 79 | #define BACKEND_INFO_SYM backend_plugin_info 80 | #define BACKEND_VER_STR "backend_plugin_version" 81 | #define BACKEND_INFO_STR "backend_plugin_info" 82 | 83 | typedef int (*listener_init_fn)(listener_context_t *c, 84 | const fence_callbacks_t *cb, 85 | config_object_t *config, 86 | map_object_t *map, 87 | void *priv); 88 | typedef int (*listener_dispatch_fn)(listener_context_t c, 89 | struct timeval *timeout); 90 | typedef int (*listener_cleanup_fn)(listener_context_t c); 91 | 92 | 93 | typedef struct listener_plugin { 94 | const char *name; 95 | const char *version; 96 | listener_init_fn init; 97 | listener_dispatch_fn dispatch; 98 | listener_cleanup_fn cleanup; 99 | } listener_plugin_t; 100 | 101 | double listener_plugin_version(void); 102 | const listener_plugin_t * listener_plugin_info(void); 103 | 104 | #define LISTENER_VER_SYM listener_plugin_version 105 | #define LISTENER_INFO_SYM listener_plugin_info 106 | #define LISTENER_VER_STR "listener_plugin_version" 107 | #define LISTENER_INFO_STR "listener_plugin_info" 108 | 109 | typedef enum { 110 | PLUGIN_NONE = 0, 111 | PLUGIN_LISTENER = 1, 112 | PLUGIN_BACKEND = 2 113 | } plugin_type_t; 114 | 115 | #ifdef __cplusplus 116 | extern "C" { 117 | #endif 118 | 119 | const backend_plugin_t *plugin_find_backend(const char *name); 120 | const listener_plugin_t *plugin_find_listener(const char *name); 121 | 122 | void plugin_dump(void); 123 | int plugin_load(const char *filename); 124 | void plugin_unload(void); 125 | int plugin_search(const char *pathname); 126 | 127 | #ifdef __cplusplus 128 | } 129 | #endif 130 | #endif 131 | -------------------------------------------------------------------------------- /agents/virt/include/simple_auth.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Red Hat, Inc. 2006 3 | 4 | This program is free software; you can redistribute it and/or modify it 5 | under the terms of the GNU General Public License as published by the 6 | Free Software Foundation; either version 2, or (at your option) any 7 | later version. 8 | 9 | This program is distributed in the hope that it will be useful, but 10 | WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program; see the file COPYING. If not, write to the 16 | Free Software Foundation, Inc., 675 Mass Ave, Cambridge, 17 | MA 02139, USA. 18 | */ 19 | #ifndef _XVM_SIMPLE_AUTH_H 20 | #define _XVM_SIMPLE_AUTH_H 21 | 22 | #include 23 | 24 | /* 2-way challenge/response simple auth */ 25 | #define DEFAULT_KEY_FILE "/etc/cluster/fence_xvm.key" 26 | 27 | int read_key_file(char *, char *, size_t); 28 | int sock_challenge(int, fence_auth_type_t, void *, size_t, int); 29 | int sock_response(int, fence_auth_type_t, void *, size_t, int); 30 | int sign_request(fence_req_t *, void *, size_t); 31 | int verify_request(fence_req_t *, fence_hash_t, void *, size_t); 32 | 33 | /* SSL certificate-based authentication TBD */ 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /agents/virt/include/simpleconfig.h: -------------------------------------------------------------------------------- 1 | #ifndef _SIMPLECONFIG_H 2 | #define _SIMPLECONFIG_H 3 | 4 | typedef int (*config_get_t)(void *config, const char *key, 5 | char *value, size_t valuesz); 6 | typedef int (*config_set_t)(void *config, const char *key, 7 | const char *value); 8 | typedef int (*config_parse_t)(const char *filename, void **config); 9 | typedef int (*config_free_t)(void *config); 10 | typedef void (*config_dump_t)(void *config, FILE *fp); 11 | 12 | /* 13 | * We use an abstract object here so we do not have to link loadable 14 | * modules against the configuration library. 15 | */ 16 | 17 | typedef struct { 18 | config_get_t get; 19 | config_set_t set; 20 | config_parse_t parse; 21 | config_free_t free; 22 | config_dump_t dump; 23 | void *info; 24 | } config_object_t; 25 | 26 | /* 27 | * These macros may be called from within a loadable module 28 | */ 29 | #define sc_get(obj, key, value, valuesz) \ 30 | obj->get(obj->info, key, value, valuesz) 31 | #define sc_set(obj, key, value) \ 32 | obj->set(obj->info, key, value) 33 | #define sc_parse(obj, filename) \ 34 | obj->parse(filename, &obj->info) 35 | #define sc_free(obj) \ 36 | obj->free(obj->info) 37 | #define sc_dump(obj, fp) \ 38 | obj->dump(obj->info, fp) 39 | 40 | /* 41 | * Do not call the below functions from loadable modules. Doing so 42 | * requires linking the configuration library in to the modules, which 43 | * is what we want to avoid. 44 | */ 45 | 46 | /* Returns a copy of our simple config object */ 47 | config_object_t *sc_init(void); 48 | 49 | /* Frees a previously-allocated copy of our simple config object */ 50 | void sc_release(config_object_t *c); 51 | 52 | int check_file_permissions(const char *fname); 53 | 54 | int do_configure(config_object_t *config, const char *filename); 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /agents/virt/include/static_map.h: -------------------------------------------------------------------------------- 1 | #ifndef _STATIC_MAP_H 2 | #define _STATIC_MAP_H 3 | 4 | typedef int (*map_load_t)(void *config, void **perm_info); 5 | typedef int (*map_check_t)(void *info, const char *src, const char *tgt_uuid, const char *tgt_name); 6 | typedef void (*map_cleanup_t)(void **info); 7 | 8 | typedef struct { 9 | map_load_t load; 10 | map_check_t check; 11 | map_cleanup_t cleanup; 12 | void *info; 13 | } map_object_t; 14 | 15 | /* 16 | * These macros may be called from within a loadable module 17 | */ 18 | #define map_load(obj, config) \ 19 | obj->load(config, &obj->info) 20 | #define map_check(obj, src, tgt_uuid) \ 21 | obj->check(obj->info, src, tgt_uuid, NULL) 22 | #define map_check2(obj, src, tgt_uuid, tgt_name) \ 23 | obj->check(obj->info, src, tgt_uuid, tgt_name) 24 | #define map_free(obj) \ 25 | obj->cleanup(obj->info) 26 | 27 | /* Returns a copy of our simple config object */ 28 | void *map_init(void); 29 | 30 | /* Frees a previously-allocated copy of our simple config object */ 31 | void map_release(void *c); 32 | 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /agents/virt/include/tcp.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Red Hat, Inc. 2006 3 | 4 | This program is free software; you can redistribute it and/or modify it 5 | under the terms of the GNU General Public License as published by the 6 | Free Software Foundation; either version 2, or (at your option) any 7 | later version. 8 | 9 | This program is distributed in the hope that it will be useful, but 10 | WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program; see the file COPYING. If not, write to the 16 | Free Software Foundation, Inc., 675 Mass Ave, Cambridge, 17 | MA 02139, USA. 18 | */ 19 | #ifndef _XVM_TCP_H 20 | #define _XVM_TCP_H 21 | 22 | int ipv4_connect(struct in_addr *in_addr, uint16_t port, int timeout); 23 | int ipv6_connect(struct in6_addr *in6_addr, uint16_t port, int timeout); 24 | int ipv4_listen(const char *addr_str, uint16_t port, int backlog); 25 | int ipv6_listen(const char *addr_str, uint16_t port, int backlog); 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /agents/virt/include/tcp_listener.h: -------------------------------------------------------------------------------- 1 | #ifndef __TCP_LISTENER_H 2 | #define __TCP_LISTENER_H 3 | 4 | #define IPV4_TCP_ADDR_DEFAULT "127.0.0.1" 5 | #define IPV6_TCP_ADDR_DEFAULT "::1" 6 | 7 | #endif 8 | -------------------------------------------------------------------------------- /agents/virt/man/.gitignore: -------------------------------------------------------------------------------- 1 | fence_virt.8 2 | fence_virt.wiki 3 | -------------------------------------------------------------------------------- /agents/virt/man/Makefile.am: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | ############################################################################### 3 | ## 4 | ## Copyright (C) 2009-2021 Red Hat, Inc. 5 | ## 6 | ## This copyrighted material is made available to anyone wishing to use, 7 | ## modify, copy, or redistribute it subject to the terms and conditions 8 | ## of the GNU General Public License v.2. 9 | ## 10 | ############################################################################### 11 | ############################################################################### 12 | 13 | MAINTAINERCLEANFILES = Makefile.in 14 | 15 | dist_man8_MANS = fence_xvm.8 fence_virtd.8 16 | dist_man5_MANS = fence_virt.conf.5 17 | man8_MANS = fence_virt.8 18 | 19 | fence_virt.8: $(top_builddir)/agents/virt/client/fence_virt $(top_srcdir)/lib/fence2man.xsl 20 | set -e && \ 21 | ../client/$(@:%.8=%) -o metadata > .$(@F).tmp && \ 22 | xmllint --noout --relaxng $(top_srcdir)/lib/metadata.rng .$(@F).tmp && \ 23 | xsltproc $(top_srcdir)/lib/fence2man.xsl .$(@F).tmp > $@ 24 | xsltproc $(top_srcdir)/lib/fence2wiki.xsl .$(@F).tmp | grep -v ' $(@F:%.8=%.wiki) 25 | 26 | 27 | clean-local: 28 | rm -f fence_virt.8* .*.8.tmp *.wiki 29 | -------------------------------------------------------------------------------- /agents/virt/man/fence_virtd.8: -------------------------------------------------------------------------------- 1 | .TH FENCE_AGENT 8 2010-01-05 "fence_virtd (Fence Agent)" 2 | .SH NAME 3 | fence_virtd - Fencing host for virtual machines 4 | 5 | .SH DESCRIPTION 6 | .P 7 | fence_virtd is a host daemon designed to route fencing requests for 8 | virtual machines. 9 | 10 | Fence_virt and fence_xvm talk to fence_virtd, which supports multiple backend plugins, including: 11 | - libvirt for single-node operation 12 | - Corosync CPG and libvirt when using Linux-cluster release 3.0.0 or later 13 | - libvirt-qpid for multi-node, non-cluster operation 14 | 15 | For compatibility, fence_xvm from linux-cluster release 2 may talk to fence_virtd. 16 | 17 | .P 18 | fence_virtd accepts a few options on the command line, but most options 19 | are read from fence_virt.conf. 20 | 21 | .SH PARAMETERS 22 | .TP 23 | .B -d 24 | . 25 | Specify debug level, e.g. "-d99" 26 | 27 | .TP 28 | .B -c 29 | . 30 | Interactively prompt user for configuration information 31 | 32 | .TP 33 | .B -f 34 | . 35 | Specify an alternate configuration file instead of /etc/fence_virt.conf 36 | 37 | .TP 38 | .B -F 39 | . 40 | Do not fork into background after starting (overrides any setting in fence_virt.conf) 41 | 42 | .TP 43 | .B -w 44 | . 45 | Wait for backend to be available (overrides any setting in fence_virt.conf) 46 | 47 | .TP 48 | .B -p 49 | . 50 | Specify the full path to the pid file used to record the active process pid. 51 | 52 | .SH SEE ALSO 53 | fence_virt(8), fence_xvm(8), fence(8), fence_virt.conf(5) 54 | -------------------------------------------------------------------------------- /agents/virt/man/fence_xvm.8: -------------------------------------------------------------------------------- 1 | .so man8/fence_virt.8 2 | -------------------------------------------------------------------------------- /agents/virt/server/Makefile.am: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | ############################################################################### 3 | ## 4 | ## Copyright (C) 2009-2021 Red Hat, Inc. 5 | ## 6 | ## This copyrighted material is made available to anyone wishing to use, 7 | ## modify, copy, or redistribute it subject to the terms and conditions 8 | ## of the GNU General Public License v.2. 9 | ## 10 | ############################################################################### 11 | ############################################################################### 12 | 13 | MAINTAINERCLEANFILES = Makefile.in 14 | 15 | noinst_HEADERS = cpg.h serial.h uuid-test.h virt.h 16 | 17 | sbin_PROGRAMS = fence_virtd 18 | 19 | # 20 | # daemon 21 | # 22 | fence_virtd_SOURCES = main.c plugin.c config.c static_map.c uuid-test.c \ 23 | daemon_init.c 24 | 25 | fence_virtd_CFLAGS = $(VIRT_AM_CFLAGS) \ 26 | $(nss_CFLAGS) $(xml2_CFLAGS) $(uuid_CFLAGS) $(PTHREAD_CFLAGS) \ 27 | $(AM_CFLAGS) 28 | 29 | fence_virtd_LDADD = $(VIRT_CONFIG_LIBS) $(VIRT_COMMON_LIBS) \ 30 | $(nss_LIBS) $(xml2_LIBS) $(uuid_LIBS) $(PTHREAD_LIBS) $(dl_LIBS) 31 | 32 | fence_virtd_LDFLAGS = $(VIRT_AM_LDFLAGS) $(VIRT_COMMON_LDFLAGS) 33 | 34 | virt_la_SOURCES = libvirt.c virt.c uuid-test.c 35 | cpg_la_SOURCES = cpg-virt.c cpg.c virt.c uuid-test.c 36 | multicast_la_SOURCES = mcast.c history.c 37 | tcp_la_SOURCES = tcp.c history.c 38 | vsock_la_SOURCES = vsock.c history.c 39 | serial_la_SOURCES = virt-serial.c virt-sockets.c serial.c history.c 40 | 41 | fence_virtd_CFLAGS += -DMODULE_PATH=\"$(libdir)/fence-virt/\" 42 | 43 | fvlibdir = $(libdir)/fence-virt 44 | 45 | fvlib_LTLIBRARIES = 46 | 47 | MODULESCFLAGS = $(VIRT_AM_CFLAGS) $(AM_CFLAGS) 48 | MODULESLDFLAGS = $(VIRT_AM_LDFLAGS) $(VIRT_COMMON_LDFLAGS) -module -avoid-version -export-dynamic 49 | MODULESLIBADD = $(VIRT_COMMON_LIBS) 50 | 51 | if modlibvirt 52 | fvlib_LTLIBRARIES += virt.la 53 | virt_la_CFLAGS = $(MODULESCFLAGS) $(nss_CFLAGS) $(virt_CFLAGS) 54 | virt_la_LDFLAGS = $(MODULESLDFLAGS) 55 | virt_la_LIBADD = $(MODULESLIBADD) $(nss_LIBS) $(virt_LIBS) $(uuid_LIBS) 56 | endif 57 | if modcpg 58 | fvlib_LTLIBRARIES += cpg.la 59 | cpg_la_CFLAGS = $(MODULESCFLAGS) $(nss_CFLAGS) $(cpg_CFLAGS) $(virt_CFLAGS) 60 | cpg_la_LDFLAGS = $(MODULESLDFLAGS) 61 | cpg_la_LIBADD = $(MODULESLIBADD) $(nss_LIBS) $(cpg_LIBS) $(virt_LIBS) $(uuid_LIBS) 62 | endif 63 | if modmulticast 64 | fvlib_LTLIBRARIES += multicast.la 65 | multicast_la_CFLAGS = $(MODULESCFLAGS) $(nss_CFLAGS) 66 | multicast_la_LDFLAGS = $(MODULESLDFLAGS) 67 | multicast_la_LIBADD = $(MODULESLIBADD) $(nss_LIBS) 68 | endif 69 | if modserial 70 | fvlib_LTLIBRARIES += serial.la 71 | serial_la_CFLAGS = $(MODULESCFLAGS) $(nss_CFLAGS) $(xml2_CFLAGS) $(virt_CFLAGS) 72 | serial_la_LDFLAGS = $(MODULESLDFLAGS) 73 | serial_la_LIBADD = $(MODULESLIBADD) $(nss_LIBS) $(xml2_LIBS) $(virt_LIBS) 74 | endif 75 | if modtcp 76 | fvlib_LTLIBRARIES += tcp.la 77 | tcp_la_CFLAGS = $(MODULESCFLAGS) $(nss_CFLAGS) 78 | tcp_la_LDFLAGS = $(MODULESLDFLAGS) 79 | tcp_la_LIBADD = $(MODULESLIBADD) $(nss_LIBS) 80 | endif 81 | if modvsock 82 | fvlib_LTLIBRARIES += vsock.la 83 | vsock_la_CFLAGS = $(MODULESCFLAGS) $(nss_CFLAGS) 84 | vsock_la_LDFLAGS = $(MODULESLDFLAGS) 85 | vsock_la_LIBADD = $(MODULESLIBADD) $(nss_LIBS) 86 | endif 87 | -------------------------------------------------------------------------------- /agents/virt/server/cpg.h: -------------------------------------------------------------------------------- 1 | #ifndef __FENCE_VIRTD_CPG_H 2 | #define __FENCE_VIRTD_CPG_H 3 | 4 | struct cpg_fence_req { 5 | char vm_name[128]; 6 | int request; 7 | uint32_t seqno; 8 | uint32_t response; 9 | }; 10 | 11 | typedef void (*request_callback_fn)(void *data, size_t len, uint32_t nodeid, 12 | uint32_t seqno); 13 | typedef void (*confchange_callback_fn)(const struct cpg_address *m, size_t len); 14 | 15 | int cpg_start( const char *name, 16 | request_callback_fn func, 17 | request_callback_fn store_func, 18 | confchange_callback_fn join, 19 | confchange_callback_fn leave); 20 | 21 | int cpg_get_ids(uint32_t *me, uint32_t *high); 22 | int cpg_stop(void); 23 | int cpg_send_req(void *data, size_t len, uint32_t *seqno); 24 | int cpg_wait_reply(void **data, size_t *len, uint32_t seqno); 25 | int cpg_send_reply(void *data, size_t len, uint32_t nodeid, uint32_t seqno); 26 | int cpg_send_vm_state(virt_state_t *vs); 27 | 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /agents/virt/server/history.c: -------------------------------------------------------------------------------- 1 | #include "config.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "history.h" 12 | 13 | history_info_t * 14 | history_init(history_compare_fn func, time_t expiration, size_t element_size) 15 | { 16 | history_info_t *hist; 17 | 18 | errno = EINVAL; 19 | if (!func || !expiration || !element_size) 20 | return NULL; 21 | 22 | hist = malloc(sizeof(*hist)); 23 | if (!hist) 24 | return NULL; 25 | memset(hist, 0, sizeof(*hist)); 26 | 27 | hist->timeout = expiration; 28 | hist->element_size = element_size; 29 | hist->compare_func = func; 30 | 31 | return hist; 32 | } 33 | 34 | 35 | /* 36 | * Purge our history when the entries time out. 37 | * 38 | * Returns 1 if a matching history node was found, or 0 39 | * if not. 40 | */ 41 | int 42 | history_check(history_info_t *hinfo, void *stuff) 43 | { 44 | history_node *entry = NULL; 45 | time_t now; 46 | int x; 47 | 48 | if (!hinfo) 49 | return 0; /* XXX */ 50 | 51 | if (!hinfo->hist) 52 | return 0; 53 | 54 | now = time(NULL); 55 | 56 | loop_again: 57 | list_for((&hinfo->hist), entry, x) { 58 | if (entry->when < (now - hinfo->timeout)) { 59 | list_remove((&hinfo->hist), entry); 60 | free(entry->data); 61 | free(entry); 62 | goto loop_again; 63 | } 64 | 65 | if (hinfo->compare_func(entry->data, stuff)) { 66 | return 1; 67 | } 68 | } 69 | return 0; 70 | } 71 | 72 | 73 | int 74 | history_record(history_info_t *hinfo, void *data) 75 | { 76 | history_node *entry = NULL; 77 | 78 | errno = EINVAL; 79 | if (!data || !hinfo) 80 | return -1; 81 | 82 | if (history_check(hinfo, data) == 1) { 83 | errno = EEXIST; 84 | return -1; 85 | } 86 | 87 | entry = malloc(sizeof(*entry)); 88 | if (!entry) { 89 | return -1; 90 | } 91 | memset(entry, 0, sizeof(*entry)); 92 | 93 | entry->data = malloc(hinfo->element_size); 94 | if (!entry->data) { 95 | free(entry); 96 | errno = ENOMEM; 97 | return -1; 98 | } 99 | 100 | memcpy(entry->data, data, hinfo->element_size); 101 | entry->when = time(NULL); 102 | list_insert((&hinfo->hist), entry); 103 | return 0; 104 | } 105 | 106 | 107 | int 108 | history_wipe(history_info_t *hinfo) 109 | { 110 | history_node *entry = NULL; 111 | 112 | if (!hinfo) 113 | return -1; 114 | 115 | while (hinfo->hist) { 116 | entry = hinfo->hist; 117 | list_remove((&hinfo->hist), entry); 118 | free(entry->data); 119 | free(entry); 120 | } 121 | 122 | /* User must free(hinfo); */ 123 | return 0; 124 | } 125 | -------------------------------------------------------------------------------- /agents/virt/server/serial.h: -------------------------------------------------------------------------------- 1 | #ifndef __VIRT_SERIAL_H 2 | #define __VIRT_SERIAL_H 3 | 4 | #include 5 | 6 | /* virt-sockets.c */ 7 | int domain_sock_setup(const char *domain, const char *socket_path); 8 | int domain_sock_close(const char *domain); 9 | int domain_sock_fdset(fd_set *set, int *max); 10 | 11 | /* Find the domain name associated with a FD */ 12 | int domain_sock_name(int fd, char *outbuf, size_t buflen); 13 | int domain_sock_cleanup(void); 14 | 15 | /* virt-serial.c - event thread control functions */ 16 | int start_event_listener(const char *uri, const char *path, int mode, int *wake_fd); 17 | int stop_event_listener(void); 18 | 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /agents/virt/server/uuid-test.c: -------------------------------------------------------------------------------- 1 | #include "config.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "uuid-test.h" 8 | 9 | int 10 | is_uuid(const char *value) 11 | { 12 | uuid_t id; 13 | char test_value[37]; 14 | 15 | if (strlen(value) < 36) { 16 | return 0; 17 | } 18 | 19 | memset(id, 0, sizeof(uuid_t)); 20 | 21 | if (uuid_is_null(id) < 0) { 22 | errno = EINVAL; 23 | return -1; 24 | } 25 | 26 | if (uuid_parse(value, id) < 0) { 27 | return 0; 28 | } 29 | 30 | memset(test_value, 0, sizeof(test_value)); 31 | uuid_unparse(id, test_value); 32 | 33 | if (strcasecmp(value, test_value)) { 34 | return 0; 35 | } 36 | 37 | return 1; 38 | } 39 | 40 | #ifdef STANDALONE 41 | #include 42 | 43 | int 44 | main(int argc, char **argv) 45 | { 46 | int ret; 47 | 48 | if (argc < 2) { 49 | printf("Usage: uuidtest \n"); 50 | return 1; 51 | } 52 | 53 | ret = is_uuid(argv[1]); 54 | if (ret == 0) { 55 | printf("%s is NOT a uuid\n", argv[1]); 56 | } else if (ret == 1) { 57 | printf("%s is a uuid\n", argv[1]); 58 | } else { 59 | printf("Error: %s\n", strerror(errno)); 60 | return 1; 61 | } 62 | 63 | return 0; 64 | } 65 | 66 | #endif 67 | -------------------------------------------------------------------------------- /agents/virt/server/uuid-test.h: -------------------------------------------------------------------------------- 1 | #ifndef __UUID_TEST_H 2 | #define __UUID_TEST_H 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | int is_uuid(const char *value); 9 | 10 | #ifdef __cplusplus 11 | } 12 | #endif 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /agents/virt/server/virt.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Red Hat, Inc. 2006-2017 3 | 4 | This program is free software; you can redistribute it and/or modify it 5 | under the terms of the GNU General Public License as published by the 6 | Free Software Foundation; either version 2, or (at your option) any 7 | later version. 8 | 9 | This program is distributed in the hope that it will be useful, but 10 | WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program; see the file COPYING. If not, write to the 16 | Free Software Foundation, Inc., 675 Mass Ave, Cambridge, 17 | MA 02139, USA. 18 | */ 19 | 20 | #ifndef _VIRT_H 21 | #define _VIRT_H 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | #include "xvm.h" 28 | 29 | typedef struct { 30 | uint32_t s_owner; 31 | int32_t s_state; 32 | } vm_state_t; 33 | 34 | typedef struct { 35 | char v_name[MAX_DOMAINNAME_LENGTH + 1]; 36 | char v_uuid[MAX_DOMAINNAME_LENGTH + 1]; 37 | vm_state_t v_state; 38 | } virt_state_t; 39 | 40 | /** 41 | This is stored in our private checkpoint section. 42 | */ 43 | typedef struct _virt_list { 44 | uint32_t vm_count; 45 | virt_state_t vm_states[0]; 46 | } virt_list_t; 47 | 48 | virt_list_t *vl_get(virConnectPtr *vp, int vp_count, int my_id); 49 | void vl_print(virt_list_t *vl); 50 | void vl_free(virt_list_t *old); 51 | virt_state_t *vl_find_uuid(virt_list_t *vl, const char *name); 52 | virt_state_t *vl_find_name(virt_list_t *vl, const char *name); 53 | int vl_add(virt_list_t **vl, virt_state_t *vm); 54 | int vl_update(virt_list_t **vl, virt_state_t *vm); 55 | int vl_remove_by_owner(virt_list_t **vl, uint32_t owner); 56 | 57 | int vm_off(virConnectPtr *vp, int vp_count, const char *vm_name); 58 | int vm_on(virConnectPtr *vp, int vp_count, const char *vm_name); 59 | int vm_status(virConnectPtr *vp, int vp_count, const char *vm_name); 60 | int vm_reboot(virConnectPtr *vp, int vp_count, const char *vm_name); 61 | 62 | #endif 63 | -------------------------------------------------------------------------------- /agents/zvm/fence_zvm_man_page: -------------------------------------------------------------------------------- 1 | .TH fence_zvm 8 2 | 3 | .SH NAME 4 | fence_zvm - Power Fencing agent for GFS on System z z/VM Clusters 5 | 6 | .SH SYNOPSIS 7 | .B 8 | fence_zvm 9 | [\fIOPTION\fR]... 10 | 11 | .SH DESCRIPTION 12 | fence_zvm is a Power Fencing agent used on a GFS virtual machine in a System z z/VM cluster. 13 | It uses the SMAPI interface to recycle an active image. 14 | 15 | fence_zvm accepts options on the command line as well as from stdin. 16 | fence_node sends the options through stdin when it execs the agent. 17 | fence_zvm can be run by itself with command line options which is useful 18 | for testing. 19 | 20 | Vendor URL: http://www.sinenomine.net 21 | 22 | .SH OPTIONS 23 | .TP 24 | \fB-o --action\fP 25 | Fencing action: "off" - deactivate virtual machine; "on" - activate virtual machine; "metadata" - display device metadata" - describe fence agent parameters; "status" - state of virtual machine 26 | .TP 27 | \fB--delay\fP \fIseconds\fP 28 | Time to delay fencing action in seconds 29 | .TP 30 | \fB-n --plug\fP \fItarget\fP 31 | Name of virtual machine to recycle. 32 | .TP 33 | \fB-h --help\fP 34 | Print out a help message describing available options, then exit. 35 | .TP 36 | \fB-a --ip\fP \fIsmapi Server\fP 37 | \fBName\fP of SMAPI server virtual machine. To be consistent with other fence agents this name is a little misleading: it is the name of the virtual machine not its IP address or hostname. 38 | .TP 39 | \fB--zvmsys\fP \fIz/VM System\fP 40 | \fBName\fP of z/VM on which the SMAPI server virtual machine resides. Optional - defaults to system on which the node is running. 41 | .TP 42 | \fB-h --help\fP 43 | Display usage information 44 | .TP 45 | \fI-t --timeout = < shutdown timeout >\fP 46 | Amount of \fIgrace\fP time to give the virtual machine to shutdown cleanly before being 47 | forcibly terminated. Currently, this option is ignored. 48 | 49 | .SH STDIN PARAMETERS 50 | .TP 51 | \fIagent = < param >\fP 52 | This option is used by fence_node(8) and is ignored by fence_zvm. 53 | .TP 54 | \fIaction = < action >\fP 55 | Fencing action: "off" - fence off device; "metadata" - display device metadata; "status" - state of device 56 | .TP 57 | \fIport = < target >\fP 58 | Name of virtual machine to recycle. 59 | .TP 60 | \fIipaddr= < server name >\fP 61 | \fBName\fP of SMAPI server virtual machine. To be consistent with other fence agents thisname is a little misleading: it is the name of the virtual machine not its IP address or hostname. 62 | .TP 63 | \fItimeout = < shutdown timeout >\fP 64 | Amount of \fIgrace\fP time to give the virtual machine to shutdown cleanly before being 65 | forcibly terminated. Currently, this option is ignored. 66 | 67 | .SH SEE ALSO 68 | fence(8), fenced(8), fence_node(8) 69 | 70 | .SH NOTES 71 | To use this agent the z/VM SMAPI service needs to be configured to allow the virtual 72 | machine running this agent to connect to it and issue the image_recycle operation. 73 | This involves updating the VSMWORK1 AUTHLIST VMSYS:VSMWORK1. file. The entry should look 74 | something similar to this: 75 | 76 | .nf 77 | Column 1 Column 66 Column 131 78 | | | | 79 | V V V 80 | XXXXXXXX ALL IMAGE_CHARACTERISTICS 81 | .fi 82 | 83 | Where XXXXXXX is the name of the virtual machine used in the authuser field of the request. This virtual machine also has to be authorized 84 | to access the system's directory manager. 85 | 86 | In addition, the VM directory entry that defines this virtual machine requires the 87 | IUCV ANY statement (or IUCV ). This authorizes use of IUCV 88 | to connect to the SMAPI server. 89 | -------------------------------------------------------------------------------- /autogen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Run this to generate all the initial makefiles, etc. 3 | # ("-I make" is superfluous, kept only for legacy purposes, if any) 4 | autoreconf -i -I make -v && echo Now run ./configure and make 5 | -------------------------------------------------------------------------------- /doc/COPYRIGHT: -------------------------------------------------------------------------------- 1 | Unless specified otherwise in the "exceptions section" below: 2 | 3 | Copyright (C) 1997-2003 Sistina Software, Inc. All rights reserved. 4 | Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved. 5 | 6 | Exceptions: 7 | 8 | agents/raritan_px3/*: 9 | Copyright (c) 2021 SUSE LLC 10 | Contributed by Thomas Renninger 11 | 12 | agents/ibmz/*: 13 | Copyright (c) 2020 IBM Corp. 14 | Contributed by Paulo de Rezende Pinatti 15 | 16 | agents/hds_cb/*: 17 | Copyright (C) 2012 Matthew Clark. 18 | Author: Matthew Clark 19 | 20 | agents/xenapi/*: 21 | Copyright (C) 2011 Matthew Clark. 22 | Author: Matthew Clark 23 | 24 | agents/apc_snmp/powernet369.mib: 25 | Copyright (c) 2005 American Power Conversion, Inc. 26 | PowerNet is a Trademark of American Power Conversion Corp. 27 | 28 | agents/eaton_snmp/fence_eaton_snmp.py: 29 | Copyright (c) 2011 eaton.com 30 | Author: Arnaud Quette 31 | 32 | agents/ifmib/fence_ifmib.py: 33 | Copyright (C) 2008-2011 Ross Vandegrift. 34 | Written by Ross Vandegrift 35 | 36 | agents/intelmodular/fence_intelmodular.pl: 37 | Contributed by Matthew Kent 38 | 39 | agents/ipmilan/expect.{c,h}: 40 | Copyright (C) 2000 Alan Robertson 41 | 42 | agents/node_assassin/* 43 | Copyright (C) 2009-2011 Madison Kelly/Alteeve's Niche! 44 | Author: Digimer 45 | 46 | agents/ecloud/fence_ecloud.py: 47 | Copyright (C) 2022 ANS Group Limited 48 | Author: Dane Elwell 49 | 50 | agents/ovm/fence_ovm.py 51 | Copyright (C) 2023 NTT COMWARE 52 | Author: Teruyoshi Kaneko 53 | 54 | man/fence_ifmib.8: 55 | Copyright (C) 2008-2011 Ross Vandegrift. 56 | Written by Ross Vandegrift 57 | 58 | Authors as known by current RCS as of the time of writing: 59 | 60 | Abhijith Das 61 | Adam Manthei 62 | A. J. Lewis 63 | Alasdair G. Kergon 64 | Andrew Price 65 | Benjamin Marzinski 66 | Bob Peterson 67 | Chris Feist 68 | Christine Caulfield 69 | Daniel Phillips 70 | David Teigland 71 | Fabio M. Di Nitto 72 | James Parsons 73 | Joel Becker 74 | Jonathan Brassow 75 | jparsons 76 | Ken Preslan 77 | Klaus Wenninger 78 | Lon Hohberger 79 | Marc - A. Dahlhaus 80 | Marek 'marx' Grac 81 | Mark Hlawatschek 82 | Michael Conrad Tadpol Tilstra 83 | Patrick Caulfield 84 | Robert Peterson 85 | Ross Vandegrift 86 | Ryan McCabe 87 | Ryan O'Hara 88 | Stanko Kupcevic 89 | Steven Whitehouse 90 | Wendy Cheng 91 | -------------------------------------------------------------------------------- /doc/Makefile.am: -------------------------------------------------------------------------------- 1 | MAINTAINERCLEANFILES = Makefile.in 2 | 3 | dist_doc_DATA = COPYING.applications \ 4 | COPYING.libraries \ 5 | COPYRIGHT \ 6 | README.licence 7 | -------------------------------------------------------------------------------- /doc/README.licence: -------------------------------------------------------------------------------- 1 | The Red Hat Cluster is a collection of free software built on top of different 2 | libraries and applications. 3 | 4 | For a detailed list of authors and copyright holders, please check the 5 | included COPYRIGHT file. 6 | 7 | Libraries: 8 | 9 | You can redistribute them and/or modify them under the terms of the GNU Lesser 10 | General Public License as published by the Free Software Foundation; either 11 | version 2.1 of the License, or (at your option) any later version. 12 | 13 | The libraries are distributed in the hope that they will be useful, but WITHOUT 14 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 15 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 16 | details. 17 | 18 | Applications: 19 | 20 | You can redistribute them and/or modify them under the terms of the GNU General 21 | Public License as published by the Free Software Foundation; either version 22 | 2 of the License, or (at your option) any later version. 23 | 24 | The applications are distributed in the hope that they will be useful, but 25 | WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 26 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 27 | details. 28 | 29 | A copy of each license is included for your convenience in COPYING.applications 30 | and COPYING.libraries. 31 | 32 | If missing, write to the Free Software Foundation, Inc., 51 Franklin St, 33 | Fifth Floor, Boston, MA 02110-1301 USA. 34 | -------------------------------------------------------------------------------- /docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM opensuse/leap:15.5 2 | 3 | RUN zypper in -y \ 4 | git \ 5 | autoconf \ 6 | automake \ 7 | libtool \ 8 | make \ 9 | gcc \ 10 | libcorosync-devel \ 11 | libxslt1 \ 12 | libxslt-tools \ 13 | python3-devel \ 14 | python3-httplib2 \ 15 | python3-pexpect \ 16 | python3-pycurl \ 17 | python3-requests \ 18 | python3-suds-jurko \ 19 | python3-openwsman \ 20 | python3-boto3 \ 21 | python3-novaclient \ 22 | python3-keystoneclient \ 23 | mozilla-nss-devel \ 24 | mozilla-nspr-devel \ 25 | libvirt-devel \ 26 | libxml2-devel \ 27 | flex \ 28 | bison \ 29 | libuuid-devel \ 30 | systemd 31 | 32 | WORKDIR /code 33 | VOLUME /code 34 | ENTRYPOINT ["./docker/entrypoint.sh"] 35 | -------------------------------------------------------------------------------- /docker/README.md: -------------------------------------------------------------------------------- 1 | # Dockerfile to build the fence-agents locally 2 | 3 | Usage is as follows: 4 | 5 | ``` 6 | podman build -f docker/Dockerfile -t fence-agents:main . 7 | podman run -it -v $PWD:/code --rm localhost/fence-agents:main 8 | ``` 9 | 10 | In case you are running docker replace `podman` with `docker` and it should work the same. 11 | -------------------------------------------------------------------------------- /docker/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/bash 2 | 3 | echo "### Running autogen" 4 | ./autogen.sh 5 | echo "### Running configure" 6 | ./configure 7 | echo "### Running make" 8 | make 9 | -------------------------------------------------------------------------------- /fence-agents.pc.in: -------------------------------------------------------------------------------- 1 | prefix = @prefix@ 2 | exec_prefix = @exec_prefix@ 3 | 4 | Name: @PACKAGE_NAME@ 5 | Description: fence agents for use with Pacemaker 6 | URL: https://github.com/ClusterLabs/fence-agents/ 7 | Version: @PACKAGE_VERSION@ 8 | -------------------------------------------------------------------------------- /lib/Makefile.am: -------------------------------------------------------------------------------- 1 | MAINTAINERCLEANFILES = Makefile.in 2 | 3 | TARGET = fencing.py fencing_snmp.py azure_fence.py 4 | 5 | if BUILD_XENAPILIB 6 | TARGET += XenAPI.py 7 | endif 8 | 9 | SRC = fencing.py.py fencing_snmp.py.py XenAPI.py.py azure_fence.py.py check_used_options.py 10 | 11 | XSL = fence2man.xsl fence2rng.xsl fence2wiki.xsl 12 | 13 | FASRNG = fence.rng.head fence.rng.tail metadata.rng 14 | 15 | EXTRA_DIST = $(SRC) $(XSL) $(FASRNG) 16 | 17 | SUBDIRS = tests 18 | 19 | fencelibdir = ${FENCEAGENTSLIBDIR} 20 | 21 | fencelib_DATA = $(TARGET) 22 | 23 | rngdir = ${CLUSTERDATA}/relaxng 24 | 25 | rng_DATA = $(XSL) $(FASRNG) 26 | 27 | azure_fence.py: fencing.py 28 | fencing_snmp.py: fencing.py 29 | check_used_options.py: fencing.py 30 | 31 | include $(top_srcdir)/make/fencebuild.mk 32 | 33 | xml-check: all 34 | xml-upload: all 35 | test-fencing: all 36 | 37 | clean-man: 38 | -------------------------------------------------------------------------------- /lib/check_used_options.py: -------------------------------------------------------------------------------- 1 | ## Check if fence agent uses only options["--??"] which are defined in fencing library or 2 | ## fence agent itself 3 | ## 4 | ## Usage: ./check_used_options.py fence-agent (e.g. lpar/fence_lpar.py) 5 | ## 6 | 7 | import sys, re 8 | sys.path.append("@FENCEAGENTSLIBDIR@") 9 | from fencing import all_opt 10 | 11 | def main(): 12 | agent = sys.argv[1] 13 | 14 | available = {} 15 | 16 | ## all_opt from fencing library are imported 17 | for k in list(all_opt.keys()): 18 | if "longopt" in all_opt[k]: 19 | available["--" + all_opt[k]["longopt"]] = True 20 | 21 | ## add UUID which is derived automatically from --plug if possible 22 | available["--uuid"] = True 23 | 24 | ## all_opt defined in fence agent are found 25 | agent_file = open(agent) 26 | opt_re = re.compile(r"\s*all_opt\[\"([^\"]*)\"\] = {") 27 | opt_longopt_re = re.compile(r"\"longopt\"\s*:\s*\"([^\"]*)\"") 28 | 29 | in_opt = False 30 | for line in agent_file: 31 | if opt_re.search(line) != None: 32 | in_opt = True 33 | if in_opt and opt_longopt_re.search(line) != None: 34 | available["--" + opt_longopt_re.search(line).group(1)] = True 35 | in_opt = False 36 | 37 | ## check if all options are defined 38 | agent_file = open(agent) 39 | option_use_re = re.compile(r"options\[\"(-[^\"]*)\"\]") 40 | option_in_re = re.compile(r"\"(-[^\"]*)\" in options") 41 | option_has_re = re.compile(r"options.has_key\(\"(-[^\"]*)\"\)") 42 | 43 | counter = 0 44 | without_errors = True 45 | for line in agent_file: 46 | counter += 1 47 | 48 | for option in option_use_re.findall(line): 49 | if option not in available: 50 | print("ERROR on line %d in %s: option %s is not defined" % (counter, agent, option_use_re.search(line).group(1))) 51 | without_errors = False 52 | 53 | for option in option_in_re.findall(line): 54 | if option not in available: 55 | print("ERROR on line %d in %s: option %s is not defined" % (counter, agent, option_has_re.search(line).group(1))) 56 | without_errors = False 57 | 58 | for option in option_has_re.findall(line): 59 | print("ERROR on line %d in %s: option %s: has_key() not supported in Python 3" % (counter, agent, option_has_re.search(line).group(1))) 60 | without_errors = False 61 | 62 | if without_errors: 63 | sys.exit(0) 64 | else: 65 | sys.exit(1) 66 | 67 | if __name__ == "__main__": 68 | main() 69 | -------------------------------------------------------------------------------- /lib/fence.rng.head: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /lib/fence.rng.tail: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /lib/fence2man.xsl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | .TP 7 | .B 8 | .B 9 | . 10 | 11 | 12 | ( 13 | 14 | 15 | 16 | | 17 | 18 | 19 | ) 20 | 21 | This parameter is always required. 22 | 23 | (Default Value: 24 | 25 | 26 | 27 | ) 28 | 29 | 30 | Obsoletes: 31 | 32 | 33 | 34 | 35 | 36 | 37 | .TP 38 | \fB \fP 39 | 40 | Power on machine. 41 | Power off machine. 42 | Enable fabric access. 43 | Disable fabric access. 44 | Reboot machine. 45 | Pulse a diagnostic interrupt to the processor(s). 46 | Check the health of fence device 47 | Display the XML metadata describing this resource. 48 | List available plugs with aliases/virtual machines if there is support for more then one device. Returns N/A otherwise. 49 | List available plugs with aliases/virtual machines and their power state if it can be obtained without additional commands. 50 | This returns the status of the plug/virtual machine. 51 | Validate if all required parameters are entered. 52 | 53 | The operational behavior of this is not known. 54 | 55 | 56 | 57 | 58 | .TH FENCE_AGENT 8 2009-10-20 " (Fence Agent)" 59 | .SH NAME 60 | - 61 | 62 | .P 63 | - (symlink) 64 | 65 | .SH DESCRIPTION 66 | .P 67 | 68 | .P 69 | The fence agent accepts options on the command line as well 70 | as from stdin. Fenced sends parameters through stdin when it execs the 71 | agent. The agent can be run by itself with command 72 | line options. This is useful for testing and for turning outlets on or off 73 | from scripts. 74 | 75 | Vendor URL: 76 | 77 | .SH PARAMETERS 78 | getopt 79 | .SH ACTIONS 80 | 81 | .SH STDIN PARAMETERS 82 | stdin 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | \\ 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /lib/fence2wiki.xsl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | [=#] 6 | ||='''''' =||='''''' =|| 7 | || '''Name Of The Argument For STDIN''' || '''Name Of The Argument For Command-Line''' || '''Default Value''' ||'''Description''' || 8 | 9 | 10 | 11 | || || || {{{}}} || || 12 | 13 | 14 | -------------------------------------------------------------------------------- /lib/fencing_snmp.py.py: -------------------------------------------------------------------------------- 1 | #!@PYTHON@ -tt 2 | 3 | # For example of use please see fence_cisco_mds 4 | 5 | import re, pexpect 6 | import logging 7 | from fencing import * 8 | from fencing import fail, fail_usage, EC_TIMED_OUT, run_delay, frun 9 | 10 | __all__ = ['FencingSnmp'] 11 | 12 | ## do not add code here. 13 | class FencingSnmp: 14 | def __init__(self, options): 15 | self.options = options 16 | run_delay(options) 17 | 18 | def quote_for_run(self, string): 19 | return string.replace(r"'", "'\\''") 20 | 21 | def complete_missed_params(self): 22 | mapping = [[ 23 | ['snmp-priv-passwd', 'password', '!snmp-sec-level'], 24 | 'self.options["--snmp-sec-level"]="authPriv"' 25 | ], [ 26 | ['!snmp-version', 'community', '!username', '!snmp-priv-passwd', '!password'], 27 | 'self.options["--snmp-version"]="2c"' 28 | ]] 29 | 30 | for val in mapping: 31 | e = val[0] 32 | 33 | res = True 34 | 35 | for item in e: 36 | if item[0] == '!' and "--" + item[1:] in self.options: 37 | res = False 38 | break 39 | 40 | if item[0] != '!' and "--" + item[0:] not in self.options: 41 | res = False 42 | break 43 | 44 | if res: 45 | exec(val[1]) 46 | 47 | def prepare_cmd(self, command): 48 | cmd = "%s -m '' -Oeqn "% (command) 49 | 50 | self.complete_missed_params() 51 | 52 | #mapping from our option to snmpcmd option 53 | mapping = (('snmp-version', 'v'), ('community', 'c')) 54 | 55 | for item in mapping: 56 | if "--" + item[0] in self.options: 57 | cmd += " -%s '%s'"% (item[1], self.quote_for_run(self.options["--" + item[0]])) 58 | 59 | # Some options make sense only for v3 (and for v1/2c can cause "problems") 60 | if ("--snmp-version" in self.options) and (self.options["--snmp-version"] == "3"): 61 | # Mapping from our options to snmpcmd options for v3 62 | mapping_v3 = (('snmp-auth-prot', 'a'), ('snmp-sec-level', 'l'), ('snmp-priv-prot', 'x'), \ 63 | ('snmp-priv-passwd', 'X'), ('password', 'A'), ('username', 'u')) 64 | for item in mapping_v3: 65 | if "--"+item[0] in self.options: 66 | cmd += " -%s '%s'"% (item[1], self.quote_for_run(self.options["--" + item[0]])) 67 | 68 | force_ipvx = "" 69 | 70 | if "--inet6-only" in self.options: 71 | force_ipvx = "udp6:" 72 | 73 | if "--inet4-only" in self.options: 74 | force_ipvx = "udp:" 75 | 76 | cmd += " '%s%s%s'"% (force_ipvx, self.quote_for_run(self.options["--ip"]), 77 | "--ipport" in self.options and self.quote_for_run(":" + str(self.options["--ipport"])) or "") 78 | return cmd 79 | 80 | def run_command(self, command, additional_timeout=0): 81 | try: 82 | logging.debug("%s\n", command) 83 | 84 | (res_output, res_code) = frun(command, 85 | int(self.options["--shell-timeout"]) + 86 | int(self.options["--login-timeout"]) + 87 | additional_timeout, True) 88 | 89 | if res_code == None: 90 | fail(EC_TIMED_OUT) 91 | 92 | logging.debug("%s\n", res_output) 93 | 94 | if (res_code != 0) or (re.search(r"^Error ", res_output, re.MULTILINE) != None): 95 | fail_usage("Returned %d: %s"% (res_code, res_output)) 96 | except pexpect.ExceptionPexpect: 97 | fail_usage("Cannot run command %s"%(command)) 98 | 99 | return res_output 100 | 101 | def get(self, oid, additional_timeout=0): 102 | cmd = "%s '%s'"% (self.prepare_cmd(self.options["--snmpget-path"]), self.quote_for_run(oid)) 103 | 104 | output = self.run_command(cmd, additional_timeout).splitlines() 105 | 106 | return output[len(output)-1].split(None, 1) 107 | 108 | def set(self, oid, value, additional_timeout=0): 109 | mapping = ((int, 'i'), (str, 's')) 110 | 111 | type_of_value = '' 112 | 113 | for item in mapping: 114 | if isinstance(value, item[0]): 115 | type_of_value = item[1] 116 | break 117 | 118 | cmd = "%s '%s' %s '%s'" % (self.prepare_cmd(self.options["--snmpset-path"]), 119 | self.quote_for_run(oid), type_of_value, self.quote_for_run(str(value))) 120 | 121 | self.run_command(cmd, additional_timeout) 122 | 123 | def walk(self, oid, additional_timeout=0): 124 | cmd = "%s '%s'"% (self.prepare_cmd(self.options["--snmpwalk-path"]), self.quote_for_run(oid)) 125 | 126 | output = self.run_command(cmd, additional_timeout).splitlines() 127 | 128 | return [x.split(None, 1) for x in output if x.startswith(".")] 129 | -------------------------------------------------------------------------------- /lib/metadata.rng: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | boolean 32 | string 33 | second 34 | integer 35 | 36 | 37 | 38 | 39 | select 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 0 76 | 1 77 | 78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /lib/tests/Makefile.am: -------------------------------------------------------------------------------- 1 | MAINTAINERCLEANFILES = Makefile.in 2 | 3 | EXTRA_DIST = test_fencing.py 4 | -------------------------------------------------------------------------------- /m4/PKG_CHECK_VAR.m4: -------------------------------------------------------------------------------- 1 | dnl PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE, 2 | dnl [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) 3 | dnl ------------------------------------------- 4 | dnl Since: 0.28 5 | dnl 6 | dnl Retrieves the value of the pkg-config variable for the given module. 7 | dnl 8 | dnl Origin (declared license: GPLv2+ with less restrictive exception): 9 | dnl https://cgit.freedesktop.org/pkg-config/tree/pkg.m4.in?h=pkg-config-0.29.1#n261 10 | dnl (AS_VAR_COPY replaced with backward-compatible equivalent and guard 11 | dnl to prefer system-wide variant by Jan Pokorny ) 12 | 13 | m4_ifndef([PKG_CHECK_VAR],[ 14 | AC_DEFUN([PKG_CHECK_VAR], 15 | [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl 16 | AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl 17 | 18 | _PKG_CONFIG([$1], [variable="][$3]["], [$2]) 19 | dnl AS_VAR_COPY([$1], [pkg_cv_][$1]) 20 | $1=AS_VAR_GET([pkg_cv_][$1]) 21 | 22 | AS_VAR_IF([$1], [""], [$5], [$4])dnl 23 | ])dnl PKG_CHECK_VAR 24 | ])dnl m4_ifndef 25 | -------------------------------------------------------------------------------- /m4/ac_python_module.m4: -------------------------------------------------------------------------------- 1 | dnl @synopsis AC_PYTHON_MODULE(modname[, fatal]) 2 | dnl 3 | dnl Checks for Python module. 4 | dnl 5 | dnl If fatal is non-empty then absence of a module will trigger an 6 | dnl error. 7 | dnl 8 | dnl @category InstalledPackages 9 | dnl @author Andrew Collier . 10 | dnl @version 2004-07-14 11 | dnl @license AllPermissive 12 | 13 | AC_DEFUN([AC_PYTHON_MODULE],[ 14 | AC_MSG_CHECKING(python module: $1) 15 | $PYTHON -c "import $1" 2>/dev/null 16 | if test $? -eq 0; 17 | then 18 | AC_MSG_RESULT(yes) 19 | eval AS_TR_CPP(HAVE_PYMOD_$1)=yes 20 | else 21 | AC_MSG_RESULT(no) 22 | eval AS_TR_CPP(HAVE_PYMOD_$1)=no 23 | # 24 | if test -n "$2" 25 | then 26 | AC_MSG_ERROR(failed to find required module $1) 27 | exit 1 28 | fi 29 | fi 30 | ]) 31 | -------------------------------------------------------------------------------- /m4/ax_check_link_flag.m4: -------------------------------------------------------------------------------- 1 | # =========================================================================== 2 | # https://www.gnu.org/software/autoconf-archive/ax_check_link_flag.html 3 | # =========================================================================== 4 | # 5 | # SYNOPSIS 6 | # 7 | # AX_CHECK_LINK_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT]) 8 | # 9 | # DESCRIPTION 10 | # 11 | # Check whether the given FLAG works with the linker or gives an error. 12 | # (Warnings, however, are ignored) 13 | # 14 | # ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on 15 | # success/failure. 16 | # 17 | # If EXTRA-FLAGS is defined, it is added to the linker's default flags 18 | # when the check is done. The check is thus made with the flags: "LDFLAGS 19 | # EXTRA-FLAGS FLAG". This can for example be used to force the linker to 20 | # issue an error when a bad flag is given. 21 | # 22 | # INPUT gives an alternative input source to AC_LINK_IFELSE. 23 | # 24 | # NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this 25 | # macro in sync with AX_CHECK_{PREPROC,COMPILE}_FLAG. 26 | # 27 | # LICENSE 28 | # 29 | # Copyright (c) 2008 Guido U. Draheim 30 | # Copyright (c) 2011 Maarten Bosmans 31 | # 32 | # This program is free software: you can redistribute it and/or modify it 33 | # under the terms of the GNU General Public License as published by the 34 | # Free Software Foundation, either version 3 of the License, or (at your 35 | # option) any later version. 36 | # 37 | # This program is distributed in the hope that it will be useful, but 38 | # WITHOUT ANY WARRANTY; without even the implied warranty of 39 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General 40 | # Public License for more details. 41 | # 42 | # You should have received a copy of the GNU General Public License along 43 | # with this program. If not, see . 44 | # 45 | # As a special exception, the respective Autoconf Macro's copyright owner 46 | # gives unlimited permission to copy, distribute and modify the configure 47 | # scripts that are the output of Autoconf when processing the Macro. You 48 | # need not follow the terms of the GNU General Public License when using 49 | # or distributing such scripts, even though portions of the text of the 50 | # Macro appear in them. The GNU General Public License (GPL) does govern 51 | # all other use of the material that constitutes the Autoconf Macro. 52 | # 53 | # This special exception to the GPL applies to versions of the Autoconf 54 | # Macro released by the Autoconf Archive. When you make and distribute a 55 | # modified version of the Autoconf Macro, you may extend this special 56 | # exception to the GPL to apply to your modified version as well. 57 | 58 | #serial 5 59 | 60 | AC_DEFUN([AX_CHECK_LINK_FLAG], 61 | [AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF 62 | AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_ldflags_$4_$1])dnl 63 | AC_CACHE_CHECK([whether the linker accepts $1], CACHEVAR, [ 64 | ax_check_save_flags=$LDFLAGS 65 | LDFLAGS="$LDFLAGS $4 $1" 66 | AC_LINK_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])], 67 | [AS_VAR_SET(CACHEVAR,[yes])], 68 | [AS_VAR_SET(CACHEVAR,[no])]) 69 | LDFLAGS=$ax_check_save_flags]) 70 | AS_VAR_IF(CACHEVAR,yes, 71 | [m4_default([$2], :)], 72 | [m4_default([$3], :)]) 73 | AS_VAR_POPDEF([CACHEVAR])dnl 74 | ])dnl AX_CHECK_LINK_FLAGS 75 | -------------------------------------------------------------------------------- /make/agentccheck.mk: -------------------------------------------------------------------------------- 1 | DATADIR:=$(abs_top_srcdir)/tests/data/metadata 2 | TEST_TARGET=$(filter-out $(TEST_TARGET_SKIP),$(TARGET)) 3 | 4 | check: $(TEST_TARGET:%=%.xml-check) $(SYMTARGET:%=%.xml-check) $(TEST_TARGET:%=%.delay-check) $(TEST_TARGET:%=%.rng-check) 5 | delay-check: $(TEST_TARGET:%=%.delay-check) $(SYMTARGET:%=%.delay-check) 6 | xml-check: $(TEST_TARGET:%=%.xml-check) $(SYMTARGET:%=%.xml-check) 7 | xml-upload: $(TEST_TARGET:%=%.xml-upload) $(SYMTARGET:%=%.xml-upload) 8 | 9 | %.xml-check: % 10 | $(eval INPUT=$(subst .xml-check,,$@)) 11 | $(eval TEMPFILE = $(shell mktemp)) 12 | ./$(INPUT) -o metadata > $(TEMPFILE) 13 | diff $(TEMPFILE) $(DATADIR)/$(INPUT).xml 14 | rm $(TEMPFILE) 15 | 16 | %.xml-upload: % 17 | $(eval INPUT=$(subst .xml-upload,,$@)) 18 | ./$(INPUT) -o metadata > $(DATADIR)/$(INPUT).xml 19 | 20 | # If test will fail, rerun fence agents to show problems 21 | %.delay-check: % 22 | $(eval INPUT=$(subst .delay-check,,$@)) 23 | test `/usr/bin/time -p ./$(INPUT) --delay 10 $(FENCE_TEST_ARGS) -- 2>&1 |\ 24 | awk -F"[. ]" -vOFS= '/real/ {print $$2,$$3}' | tail -n 1` -ge 1000 || \ 25 | /usr/bin/time -p ./$(INPUT) --delay 0 $(FENCE_TEST_ARGS) -- 26 | 27 | %.rng-check: % 28 | $(eval INPUT=$(subst .rng-check,,$@)) 29 | ./$(INPUT) -o metadata | \ 30 | xsltproc ${abs_top_srcdir}/lib/fence2rng.xsl - | \ 31 | sed -e 's/ rha:description=/ description=/g' -e 's/ rha:name=/ name=/g' | \ 32 | xmllint --nsclean --noout -; 33 | -------------------------------------------------------------------------------- /make/agentpycheck.mk: -------------------------------------------------------------------------------- 1 | DATADIR:=$(abs_top_srcdir)/tests/data/metadata 2 | AWK_VAL='BEGIN {store=-1} /name=".*_path"/ || /name=".*_file"/ {store=2} {if (store!=0) {print}; store--}' 3 | 4 | TEST_TARGET=$(filter-out $(TEST_TARGET_SKIP),$(TARGET)) 5 | 6 | check: $(TEST_TARGET:%=%.xml-check) $(SYMTARGET:%=%.xml-check) $(TEST_TARGET:%=%.delay-check) $(TEST_TARGET:%=%.rng-check) test-fencing 7 | delay-check: $(TEST_TARGET:%=%.delay-check) $(SYMTARGET:%=%.delay-check) 8 | xml-check: $(TEST_TARGET:%=%.xml-check) $(SYMTARGET:%=%.xml-check) 9 | xml-upload: $(TEST_TARGET:%=%.xml-upload) $(SYMTARGET:%=%.xml-upload) 10 | 11 | %.xml-check: %.8 12 | $(eval INPUT=$(subst .xml-check,,$(@F))) 13 | for x in $(INPUT) `PYTHONPATH=$(abs_top_srcdir)/lib:$(abs_top_builddir)/lib $(PYTHON) $(@D)/$(INPUT) -o metadata | grep symlink | sed -e "s/.*\(fence.*\)\" .*/\1/g"`; do \ 14 | TEMPFILE=$$(mktemp); \ 15 | PYTHONPATH=$(abs_top_srcdir)/lib:$(abs_top_builddir)/lib $(PYTHON) $(@D)/$$x -o metadata | $(AWK) $(AWK_VAL) > $$TEMPFILE && \ 16 | diff $$TEMPFILE $(DATADIR)/$$x.xml || exit 1 && \ 17 | rm $$TEMPFILE; \ 18 | done 19 | 20 | %.xml-upload: %.8 21 | $(eval INPUT=$(subst .xml-upload,,$(@F))) 22 | for x in $(INPUT) `PYTHONPATH=$(abs_top_srcdir)/lib:$(abs_top_builddir)/lib $(PYTHON) $(@D)/$(INPUT) -o metadata | grep symlink | sed -e "s/.*\(fence.*\)\" .*/\1/g"`; do \ 23 | PYTHONPATH=$(abs_top_srcdir)/lib:$(abs_top_builddir)/lib $(PYTHON) $(@D)/$$x -o metadata | $(AWK) $(AWK_VAL) > $(DATADIR)/$$x.xml; \ 24 | done 25 | 26 | # If test will fail, rerun fence agents to show problems 27 | %.delay-check: % 28 | $(eval INPUT=$(subst .delay-check,,$(@F))) 29 | for x in $(INPUT) `PYTHONPATH=$(abs_top_srcdir)/lib:$(abs_top_builddir)/lib $(PYTHON) $(@D)/$(INPUT) -o metadata | grep symlink | sed -e "s/.*\(fence.*\)\" .*/\1/g"`; do \ 30 | test `PYTHONPATH=$(abs_top_srcdir)/lib:$(abs_top_builddir)/lib /usr/bin/time -p \ 31 | sh -c "printf 'delay=10\n $(FENCE_TEST_ARGS)' | $(PYTHON) $(@D)/$$x" 2>&1 |\ 32 | awk -F"[. ]" -vOFS= '/real/ {print $$2,$$3}'` -ge 1000 || ( \ 33 | PYTHONPATH=$(abs_top_srcdir)/lib:$(abs_top_builddir)/lib /usr/bin/time -p \ 34 | sh -c "printf 'delay=0\n $(FENCE_TEST_ARGS)' | $(PYTHON) $(@D)/$$x"; false ); \ 35 | done 36 | 37 | %.rng-check: % 38 | $(eval INPUT=$(subst .rng-check,,$(@F))) 39 | for x in $(INPUT) `PYTHONPATH=$(abs_top_srcdir)/lib:$(abs_top_builddir)/lib $(PYTHON) $(@D)/$(INPUT) -o metadata | grep symlink | sed -e "s/.*\(fence.*\)\" .*/\1/g"`; do \ 40 | PYTHONPATH=$(abs_top_srcdir)/lib:$(abs_top_builddir)/lib $(PYTHON) $(@D)/$$x -o metadata | \ 41 | xsltproc ${abs_top_srcdir}/lib/fence2rng.xsl - | \ 42 | sed -e 's/ rha:description=/ description=/g' -e 's/ rha:name=/ name=/g' | \ 43 | xmllint --nsclean --noout -; \ 44 | done 45 | 46 | test-fencing: 47 | PYTHONPATH=$(abs_top_builddir)/lib $(PYTHON) $(abs_top_srcdir)/lib/tests/test_fencing.py 48 | -------------------------------------------------------------------------------- /make/fencebuild.mk: -------------------------------------------------------------------------------- 1 | define gen_agent_from_py 2 | mkdir -p `dirname $@` 3 | cat $(abs_srcdir)/$@.py | \ 4 | sed \ 5 | -e 's#@''PYTHON@#${PYTHON}#g' \ 6 | -e 's#@''RELEASE_VERSION@#${VERSION}#g' \ 7 | -e 's#@''FENCEAGENTSLIBDIR@#${FENCEAGENTSLIBDIR}#g' \ 8 | -e 's#@''LOGDIR@#${LOGDIR}#g' \ 9 | -e 's#@''INITCONFDIR@#${initconfdir}#g' \ 10 | -e 's#@''SBINDIR@#${sbindir}#g' \ 11 | -e 's#@''LIBEXECDIR@#${libexecdir}#g' \ 12 | -e 's#@''FENCETMPDIR@#${FENCETMPDIR}#g' \ 13 | -e 's#@''SBDPID_PATH@#${SBDPID_PATH}#g' \ 14 | -e 's#@''IPMITOOL_PATH@#${IPMITOOL_PATH}#g' \ 15 | -e 's#@''OPENSTACK_PATH@#${OPENSTACK_PATH}#g' \ 16 | -e 's#@''AMTTOOL_PATH@#${AMTTOOL_PATH}#g' \ 17 | -e 's#@''GNUTLSCLI_PATH@#${GNUTLSCLI_PATH}#g' \ 18 | -e 's#@''COROSYNC_CMAPCTL_PATH@#${COROSYNC_CMAPCTL_PATH}#g' \ 19 | -e 's#@''SG_PERSIST_PATH@#${SG_PERSIST_PATH}#g' \ 20 | -e 's#@''SG_TURS_PATH@#${SG_TURS_PATH}#g' \ 21 | -e 's#@''VGS_PATH@#${VGS_PATH}#g' \ 22 | -e 's#@''SUDO_PATH@#${SUDO_PATH}#g' \ 23 | -e 's#@''SSH_PATH@#${SSH_PATH}#g' \ 24 | -e 's#@''TELNET_PATH@#${TELNET_PATH}#g' \ 25 | -e 's#@''MPATH_PATH@#${MPATH_PATH}#g' \ 26 | -e 's#@''SBD_PATH@#${SBD_PATH}#g' \ 27 | -e 's#@''STORE_PATH@#${CLUSTERVARRUN}#g' \ 28 | -e 's#@''SUDO_PATH@#${SUDO_PATH}#g' \ 29 | -e 's#@''SNMPWALK_PATH@#${SNMPWALK_PATH}#g' \ 30 | -e 's#@''SNMPSET_PATH@#${SNMPSET_PATH}#g' \ 31 | -e 's#@''SNMPGET_PATH@#${SNMPGET_PATH}#g' \ 32 | -e 's#@''NOVA_PATH@#${NOVA_PATH}#g' \ 33 | -e 's#@''POWERMAN_PATH@#${POWERMAN_PATH}#g' \ 34 | -e 's#@''PING_CMD@#${PING_CMD}#g' \ 35 | -e 's#@''PING6_CMD@#${PING6_CMD}#g' \ 36 | -e 's#@''PING4_CMD@#${PING4_CMD}#g' \ 37 | > $@ 38 | 39 | if [ 0 -eq `echo "$(@)" | grep fence_ > /dev/null 2>&1; echo $$?` ]; then \ 40 | PYTHONPATH=$(abs_top_srcdir)/lib:$(abs_top_builddir)/lib $(PYTHON) $(top_srcdir)/lib/check_used_options.py $@; \ 41 | else true ; fi 42 | 43 | for x in `PYTHONPATH=$(abs_top_srcdir)/lib:$(abs_top_builddir)/lib $(PYTHON) $(@) -o metadata | grep symlink | sed -e "s/.*\(fence.*\)\" .*/\1/g"`; do \ 44 | cp -f $(@) $(@D)/$$x; \ 45 | $(MAKE) $(@D)/$$x.8; \ 46 | done 47 | endef 48 | 49 | # dependency, one on one 50 | $(foreach t,$(TARGET),$(eval $(t) : $(t:=.py))) 51 | 52 | # rule 53 | $(TARGET): $(abs_top_builddir)/config.status 54 | $(call gen_agent_from_py) 55 | 56 | clean-local: clean-man 57 | rm -f $(CLEAN_TARGET:%.8=%) $(CLEAN_TARGET_ADDITIONAL) $(mpathdata_SCRIPTS) $(scsidata_SCRIPTS) */*.pyc *.pyc */*.wiki 58 | 59 | if [ "$(abs_builddir)" = "$(abs_top_builddir)/lib" ]; then \ 60 | rm -rf $(TARGET) __pycache__; \ 61 | fi 62 | 63 | install-exec-hook: $(TARGET) 64 | if [ -n "$(man8dir)" ]; then \ 65 | echo " $(MKDIR_P) '$(DESTDIR)$(man8dir)'"; \ 66 | $(MKDIR_P) "$(DESTDIR)$(man8dir)" || exit 1; \ 67 | fi 68 | for p in $(TARGET); do \ 69 | dir=`dirname $$p`; \ 70 | for x in `PYTHONPATH=$(abs_top_srcdir)/lib:$(abs_top_builddir)/lib $(PYTHON) $$p -o metadata | grep symlink | sed -e "s/.*\(fence.*\)\" .*/\1/g"`; do \ 71 | echo " $(INSTALL_SCRIPT) $$dir/$$x '$(DESTDIR)$(sbindir)'"; \ 72 | $(INSTALL_SCRIPT) $$dir/$$x "$(DESTDIR)$(sbindir)" || exit $$?; \ 73 | echo " $(INSTALL_DATA) '$$dir/$$x.8' '$(DESTDIR)$(man8dir)'"; \ 74 | $(INSTALL_DATA) "$$dir/$$x.8" "$(DESTDIR)$(man8dir)" || exit $$?; \ 75 | done; \ 76 | done 77 | 78 | uninstall-hook: $(TARGET) 79 | files=`for p in $(TARGET); do \ 80 | for x in \`PYTHONPATH=$(abs_top_srcdir)/lib:$(abs_top_builddir)/lib $(PYTHON) $$p -o metadata | grep symlink | sed -e "s/.*\(fence.*\)\" .*/\1/g"\`; do \ 81 | echo " rm -f '$(DESTDIR)$(sbindir)/$$x'"; \ 82 | rm -f "$(DESTDIR)$(sbindir)/$$x"; \ 83 | echo " rm -f '$(DESTDIR)$(man8dir)/$$x.8'"; \ 84 | rm -f "$(DESTDIR)$(man8dir)/$$x.8"; \ 85 | done; \ 86 | done` 87 | -------------------------------------------------------------------------------- /make/fenceman.mk: -------------------------------------------------------------------------------- 1 | %.8: % $(top_srcdir)/lib/fence2man.xsl 2 | set -e && \ 3 | PYTHONPATH=$(abs_srcdir)/lib:$(abs_builddir)/../lib:$(abs_builddir)/lib \ 4 | $(PYTHON) $* -o manpage > $(@D)/.$(@F).tmp && \ 5 | xmllint --noout --relaxng $(top_srcdir)/lib/metadata.rng $(@D)/.$(@F).tmp && \ 6 | xsltproc $(top_srcdir)/lib/fence2man.xsl $(@D)/.$(@F).tmp > $@ 7 | xsltproc $(top_srcdir)/lib/fence2wiki.xsl $(@D)/.$(@F).tmp | grep -v ' $(@D)/$(@F:%.8=%.wiki) 8 | 9 | clean-man: 10 | $(eval CLEAN_TARGET=$(shell find . -name "*.8" | grep -v "kdump/fence_kdump_send.8\|manual/fence_ack_manual.8\|virt/man/fence_xvm.8\|virt/man/fence_virt.8\|virt/man/fence_virtd.8")) 11 | rm -f $(CLEAN_TARGET) */.*.8.tmp */*.wiki 12 | -------------------------------------------------------------------------------- /make/release.mk: -------------------------------------------------------------------------------- 1 | # to build official release tarballs, handle tagging and publish. 2 | 3 | project = fence-agents 4 | 5 | deliverables = $(project)-$(version).sha256 \ 6 | $(project)-$(version).tar.bz2 \ 7 | $(project)-$(version).tar.gz \ 8 | $(project)-$(version).tar.xz 9 | 10 | 11 | .PHONY: all 12 | all: tag tarballs 13 | 14 | 15 | .PHONY: checks 16 | checks: 17 | ifeq (,$(version)) 18 | @echo ERROR: need to define version= 19 | @exit 1 20 | endif 21 | @if [ ! -d .git ]; then \ 22 | echo This script needs to be executed from top level cluster git tree; \ 23 | exit 1; \ 24 | fi 25 | @if [ -n "$$(git status --untracked-files=no --porcelain 2>/dev/null)" ]; then \ 26 | echo Stash or rollback the uncommitted changes in git first; \ 27 | exit 1; \ 28 | fi 29 | 30 | 31 | .PHONY: setup 32 | setup: checks 33 | ./autogen.sh 34 | ./configure 35 | $(MAKE) maintainer-clean 36 | 37 | 38 | .PHONY: tag 39 | tag: setup ./tag-$(version) 40 | 41 | tag-$(version): 42 | ifeq (,$(release)) 43 | @echo Building test release $(version), no tagging 44 | echo '$(version)' > .tarball-version 45 | else 46 | # following will be captured by git-version-gen automatically 47 | git tag -a -m "v$(version) release" v$(version) HEAD 48 | @touch $@ 49 | endif 50 | 51 | 52 | .PHONY: tarballs 53 | tarballs: tag 54 | ./autogen.sh 55 | ./configure 56 | $(MAKE) distcheck 57 | 58 | 59 | .PHONY: sha256 60 | sha256: $(project)-$(version).sha256 61 | 62 | $(deliverables): tarballs 63 | 64 | $(project)-$(version).sha256: 65 | # checksum anything from deliverables except for in-prep checksums file 66 | sha256sum $(deliverables:$@=) | sort -k2 > $@ 67 | 68 | 69 | .PHONY: publish 70 | publish: 71 | ifeq (,$(release)) 72 | @echo Building test release $(version), no publishing! 73 | else 74 | git push --follow-tags origin 75 | @echo Hey you! Yeah you, looking somewhere else! 76 | @echo Remember to notify cluster-devel/RH and users/ClusterLabs MLs. 77 | endif 78 | 79 | 80 | .PHONY: clean 81 | clean: 82 | rm -rf $(project)* tag-* .tarball-version 83 | -------------------------------------------------------------------------------- /systemd/Makefile.am: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2017 Oyvind Albrigtsen 3 | # 4 | # This program is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; either version 2 7 | # of the License, or (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program; if not, write to the Free Software 16 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 17 | # 18 | 19 | MAINTAINERCLEANFILES = Makefile.in 20 | 21 | if HAVE_SYSTEMD 22 | tmpfilesdir = $(SYSTEMD_TMPFILES_DIR) 23 | tmpfiles_DATA = fence-agents.conf 24 | endif 25 | -------------------------------------------------------------------------------- /systemd/fence-agents.conf.in: -------------------------------------------------------------------------------- 1 | d @FENCETMPDIR@ 1755 root root 2 | -------------------------------------------------------------------------------- /tests/actions.d/list.cfg: -------------------------------------------------------------------------------- 1 | name = "List plugs and check port 6" 2 | actions = [ { "command" : "list", "return_code" : "^0$" } ] 3 | -------------------------------------------------------------------------------- /tests/actions.d/power-on-off.cfg: -------------------------------------------------------------------------------- 1 | name = "Power ON & OFF" 2 | actions = [ { "command" : "on", "return_code" : "^0$" }, { "command" : "status", "return_code" : "^0$" }, { "command" : "off", "return_code" : "^0$" }, { "command" : "status", "return_code" : "^2$" } ] 3 | -------------------------------------------------------------------------------- /tests/actions.d/sleep.cfg: -------------------------------------------------------------------------------- 1 | name = "Pure Sleep" 2 | actions = [ { "command" : "sleep(1)", "return_code" : "^0$" }, { "command" : "sleep(3)", "return_code" : "^0$" }, { "command" : "sleep(5)", "return_code" : "^0$" } ] 3 | -------------------------------------------------------------------------------- /tests/actions.d/status.cfg: -------------------------------------------------------------------------------- 1 | name = "Simple Status" 2 | actions = [ { "command" : "status", "return_code" : "^[02]$" }, { "command" : "sleep(1)", "return_code" : "^0$" } ] 3 | -------------------------------------------------------------------------------- /tests/data/metadata/fence_kdump.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | fence_kdump is an I/O fencing agent to be used with the kdump 4 | crash recovery service. When the fence_kdump agent is invoked, 5 | it will listen for a message from the failed node that acknowledges 6 | that the failed node it executing the kdump crash kernel. 7 | Note that fence_kdump is not a replacement for traditional 8 | fencing methods. The fence_kdump agent can only detect that a 9 | node has entered the kdump crash recovery service. This allows the 10 | kdump crash recovery service complete without being preempted by 11 | traditional power fencing methods. 12 | 13 | Note: the "off" action listen for message from failed node that 14 | acknowledges node has entered kdump crash recovery service. If a valid 15 | message is received from the failed node, the node is considered to be 16 | fenced and the agent returns success. Failure to receive a valid 17 | message from the failed node in the given timeout period results in 18 | fencing failure. When multiple node names/IP addresses are specified 19 | a single valid message is sufficient for success. This is useful when 20 | single node can send message via several different IP addresses. 21 | 22 | http://www.kernel.org/pub/linux/utils/kernel/kexec/ 23 | 24 | 25 | 26 | 27 | List of names or IP addresses of node to be fenced. This option is 28 | required for the "off" action. Multiple values separated by commas 29 | can be specified. All values must be of same IP network family. 30 | 31 | 32 | 33 | 34 | IP port number that the fence_kdump agent will use to listen for 35 | messages. 36 | 37 | 38 | 39 | 40 | IP network family. Force the fence_kdump agent to use a specific 41 | family. The value for FAMILY can be "auto", "ipv4", or 42 | "ipv6". 43 | 44 | 45 | 46 | 47 | Fencing action to perform. The value for ACTION can be either 48 | "off" or "metadata". 49 | 50 | 51 | 52 | 53 | Number of seconds to wait for message from failed node. If no message 54 | is received within TIMEOUT seconds, the fence_kdump agent 55 | returns failure. 56 | 57 | 58 | 59 | 60 | Print verbose output 61 | 62 | 63 | 64 | 65 | Print version 66 | 67 | 68 | 69 | 70 | Print usage 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /tests/data/metadata/fence_virt.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | fence_virt is a Power Fencing agent which can be used with virtual machines. 4 | 5 | NOTE: reboot-action does not power on nodes that are powered off. 6 | https://libvirt.org 7 | 8 | 9 | 10 | 11 | Specify (stdin) or increment (command line) debug level 12 | 13 | 14 | 15 | 16 | Serial device (default=/dev/ttyS1) 17 | 18 | 19 | 20 | 21 | Serial Parameters (default=115200,8N1) 22 | 23 | 24 | 25 | 26 | VM Channel IP address (default=10.0.2.179) 27 | 28 | 29 | 30 | 31 | TCP, Multicast, VMChannel, or VM socket port (default=1229) 32 | 33 | 34 | 35 | 36 | Virtual Machine (domain name) to fence 37 | 38 | 39 | 40 | 41 | Virtual Machine (domain name) to fence 42 | 43 | 44 | 45 | 46 | Fencing action (null, off, on, [reboot], status, list, list-status, monitor, validate-all, metadata) 47 | 48 | 49 | 50 | 51 | Fencing timeout (in seconds; default=30) 52 | 53 | 54 | 55 | 56 | IP address to connect to in TCP mode (default=127.0.0.1 / ::1) 57 | 58 | 59 | 60 | 61 | vm socket CID to connect to in vsock mode 62 | 63 | 64 | 65 | 66 | Authentication (none, sha1, [sha256], sha512) 67 | 68 | 69 | 70 | 71 | Packet hash strength (none, sha1, [sha256], sha512) 72 | 73 | 74 | 75 | 76 | Shared key file (default=/etc/cluster/fence_xvm.key) 77 | 78 | 79 | 80 | 81 | Fencing delay (in seconds; default=0) 82 | 83 | 84 | 85 | 86 | Virtual Machine (domain name) to fence (deprecated; use port) 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /tests/devices.d/dummy-with_action.cfg: -------------------------------------------------------------------------------- 1 | name = "Dummy fence device configuration" 2 | agent = "/bin/true" 3 | [options] 4 | login = "foo", "--username", "-l" 5 | passwd = "bar", "--password", "-p" 6 | ipaddr = "fence.example.com", "--ip", "-a" 7 | port = "1", "--plug" 8 | action = "status", "--action", "-o" 9 | 10 | -------------------------------------------------------------------------------- /tests/devices.d/dummy.cfg: -------------------------------------------------------------------------------- 1 | name = "Dummy fence device configuration" 2 | agent = "/home/marx/GIT/fence-agents/agents/dummy/fence_dummy" 3 | [options] 4 | -------------------------------------------------------------------------------- /tests/devices.d/invalid-missing_option.cfg: -------------------------------------------------------------------------------- 1 | name = "Invalid device definition: Both short and long options are missing" 2 | agent = "/bin/true" 3 | [options] 4 | login = "foo" 5 | -------------------------------------------------------------------------------- /tests/devices.d/true-with_action.cfg: -------------------------------------------------------------------------------- 1 | name = "Dummy fence device configuration" 2 | agent = "/bin/true" 3 | [options] 4 | login = [ "foo", "--username", "-l" ] 5 | passwd = [ "bar", "--password", "-p" ] 6 | ipaddr = [ "fence.example.com", "--ip", "-a" ] 7 | port = [ "1", "--plug" ] 8 | action = [ "status", "--action", "-o" ] 9 | -------------------------------------------------------------------------------- /tests/devices.d/true.cfg: -------------------------------------------------------------------------------- 1 | name = "Dummy fence device configuration" 2 | agent = "/bin/true" 3 | [options] 4 | login = [ "foo", "--username", "-l" ] 5 | passwd = [ "bar", "--password", "-p" ] 6 | ipaddr = [ "fence.example.com", "--ip", "-a" ] 7 | port = [ "1", "--plug" ] 8 | 9 | -------------------------------------------------------------------------------- /tests/fence_testing_test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import unittest 4 | import fence_testing 5 | 6 | class TestPrepareCommand(unittest.TestCase): 7 | DEVICE_MISSING_OPTION = "devices.d/invalid-missing_option.cfg" 8 | DEVICE_CORRECT = "devices.d/true.cfg" 9 | DEVICE_CORRECT_WITH_ACTION = "devices.d/true-with_action.cfg" 10 | 11 | def test_missing_device(self): 12 | self.assertRaises(fence_testing._prepare_command, None, "getopt") 13 | 14 | def test_missing_option(self): 15 | self.assertRaises(AssertionError, fence_testing._prepare_command, self.DEVICE_MISSING_OPTION, "stdin") 16 | 17 | def test_valid_methods(self): 18 | fence_testing._prepare_command(self.DEVICE_CORRECT, "getopt") 19 | fence_testing._prepare_command(self.DEVICE_CORRECT, "longopt") 20 | fence_testing._prepare_command(self.DEVICE_CORRECT, "stdin") 21 | 22 | def test_invalid_method(self): 23 | self.assertRaises(AssertionError, fence_testing._prepare_command, self.DEVICE_CORRECT, "invalid") 24 | 25 | def test_is_action_ignored(self): 26 | (command1, _) = fence_testing._prepare_command(self.DEVICE_CORRECT, "getopt") 27 | (command2, _) = fence_testing._prepare_command(self.DEVICE_CORRECT_WITH_ACTION, "getopt") 28 | self.assertEqual(command1, command2) 29 | 30 | def test_is_stdin_empty(self): 31 | (_, stdin) = fence_testing._prepare_command(self.DEVICE_CORRECT, "getopt") 32 | self.assertEqual(None, stdin) 33 | (_, stdin) = fence_testing._prepare_command(self.DEVICE_CORRECT, "longopt") 34 | self.assertEqual(None, stdin) 35 | 36 | def test_prepared_command_getopt(self): 37 | ## Test also fallback to longopt if short is not present 38 | (command, _) = fence_testing._prepare_command(self.DEVICE_CORRECT, "getopt") 39 | self.assertEqual("/bin/true -l foo -p bar -a fence.example.com --plug 1", command) 40 | 41 | def test_prepared_command_longopt(self): 42 | (command, _) = fence_testing._prepare_command(self.DEVICE_CORRECT, "longopt") 43 | self.assertEqual("/bin/true --username foo --password bar --ip fence.example.com --plug 1", command) 44 | 45 | def test_prepared_command_stdin(self): 46 | (command, stdin) = fence_testing._prepare_command(self.DEVICE_CORRECT, "stdin") 47 | self.assertEqual("/bin/true", command) 48 | self.assertEqual("login=foo\npasswd=bar\nipaddr=fence.example.com\nport=1\n", stdin) 49 | 50 | class TestTestAction(unittest.TestCase): 51 | def test_valid_actions(self): 52 | pass 53 | 54 | def test_invalid_actions(self): 55 | pass 56 | 57 | def test_valid_return_code(self): 58 | pass 59 | 60 | def test_invalid_return_code(self): 61 | pass 62 | 63 | def test_valid_re_contains(self): 64 | pass 65 | 66 | def test_invalid_re_contains(self): 67 | pass 68 | 69 | if __name__ == '__main__': 70 | unittest.main() 71 | -------------------------------------------------------------------------------- /tests/test-apc2.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | from fence_testing import test_action 4 | 5 | def main(): 6 | DEVICE = "devices.d/apc-v2.cfg" 7 | 8 | ACT_STATUS = "actions.d/status.cfg" 9 | ACT_ONOFF = "actions.d/power-on-off.cfg" 10 | ACT_LIST = "actions.d/list.cfg" 11 | 12 | test_action(DEVICE, ACT_STATUS, "getopt") 13 | test_action(DEVICE, ACT_ONOFF, "stdin") 14 | test_action(DEVICE, ACT_LIST, "getopt") 15 | 16 | if __name__ == "__main__": 17 | main() -------------------------------------------------------------------------------- /tests/test-apc5.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | from fence_testing import test_action 4 | 5 | def main(): 6 | DEVICE = "devices.d/apc-v5.cfg" 7 | 8 | ACT_STATUS = "actions.d/status.cfg" 9 | ACT_ONOFF = "actions.d/power-on-off.cfg" 10 | ACT_LIST = "actions.d/list.cfg" 11 | 12 | test_action(DEVICE, ACT_STATUS, "getopt", verbose=1) 13 | # test_action(DEVICE, ACT_ONOFF, "stdin") 14 | test_action(DEVICE, ACT_LIST, "getopt") 15 | 16 | if __name__ == "__main__": 17 | main() -------------------------------------------------------------------------------- /tests/test-drac4.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | from fence_testing import test_action 4 | 5 | def main(): 6 | DRAC4 = "devices.d/dell-drac-4I.cfg" 7 | 8 | ACT_STATUS = "actions.d/status.cfg" 9 | ACT_ONOFF = "actions.d/power-on-off.cfg" 10 | 11 | test_action(DRAC4, ACT_STATUS, "getopt") 12 | test_action(DRAC4, ACT_ONOFF, "stdin") 13 | 14 | if __name__ == "__main__": 15 | main() -------------------------------------------------------------------------------- /tests/test-multi-apc2.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | from fence_testing import test_action 4 | 5 | def main(): 6 | DEVICE = "devices.d/multi-apc-v2.cfg" 7 | 8 | ACT_STATUS = "actions.d/status.cfg" 9 | ACT_ONOFF = "actions.d/power-on-off.cfg" 10 | ACT_LIST = "actions.d/list.cfg" 11 | 12 | test_action(DEVICE, ACT_STATUS, "getopt") 13 | test_action(DEVICE, ACT_ONOFF, "stdin") 14 | test_action(DEVICE, ACT_LIST, "getopt") 15 | 16 | if __name__ == "__main__": 17 | main() -------------------------------------------------------------------------------- /tests/test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | from fence_testing import test_action 4 | 5 | def main(): 6 | ## @todo: utility1 - run single 'agent' 'action' 'method' 7 | ## @todo: utility2 - run complex tests (using utility1?) -> file with test suites 8 | 9 | AGENTDEF = "devices.d/true.cfg" 10 | DUMMYDEF = "devices.d/dummy.cfg" 11 | 12 | ACT_STATUS = "actions.d/status.cfg" 13 | ACT_ONOFF = "actions.d/power-on-off.cfg" 14 | 15 | # test_action(AGENTDEF, ACTIONDEF, "stdin") 16 | # test_action(AGENTDEF, ACTIONDEF, "getopt") 17 | test_action(DUMMYDEF, ACT_STATUS, "getopt") 18 | test_action(DUMMYDEF, ACT_ONOFF, "getopt") 19 | 20 | if __name__ == "__main__": 21 | main() --------------------------------------------------------------------------------