Page MenuHomeClusterLabs Projects

No OneTemporary

This file is larger than 256 KB, so syntax highlighting was skipped.
diff --git a/Makefile.am b/Makefile.am
index e5ee3203..4560002d 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,49 +1,47 @@
-EXTRA_DIST = autogen.sh make/fencebuild.mk scripts/fenceparse \
+EXTRA_DIST = autogen.sh make/fencebuild.mk \
.version make/release.mk \
make/git-version-gen make/gitlog-to-changelog tests
AUTOMAKE_OPTIONS = foreign
MAINTAINERCLEANFILES = Makefile.in aclocal.m4 configure depcomp \
config.guess config.sub missing install-sh \
autoheader automake autoconf libtool libtoolize \
ltmain.sh compile make/clusterautoconfig.h.in \
make/clusterautoconfig.h.in~ autoscan.log \
configure.scan
-noinst_HEADERS = make/copyright.cf
-
ACLOCAL_AMFLAGS = -I m4
SUBDIRS = fence/agents/lib fence doc
install-exec-local:
$(INSTALL) -d $(DESTDIR)/$(LOGDIR)
$(INSTALL) -d $(DESTDIR)/$(CLUSTERVARRUN)
uninstall-local:
rmdir $(DESTDIR)/$(LOGDIR) || :;
rmdir $(DESTDIR)/$(CLUSTERVARRUN) || :;
BUILT_SOURCES = .version
.version:
echo $(VERSION) > $@-t && mv $@-t $@
dist-hook: gen-ChangeLog
echo $(VERSION) > $(distdir)/.tarball-version
gen_start_date = 2000-01-01
.PHONY: gen-ChangeLog
gen-ChangeLog:
if test -d .git; then \
$(top_srcdir)/make/gitlog-to-changelog \
--since=$(gen_start_date) > $(distdir)/cl-t; \
rm -f $(distdir)/ChangeLog; \
mv $(distdir)/cl-t $(distdir)/ChangeLog; \
fi
# this will get rid of "libtoolized" m4 files
maintainer-clean-local:
rm -rf $(filter-out \
$(top_srcdir)/m4/ac_python_module.m4,$(wildcard \
$(top_srcdir)/m4/*.m4))
diff --git a/fence/agents/alom/fence_alom.py b/fence/agents/alom/fence_alom.py
index 62ffd7d0..7b03dc2a 100644
--- a/fence/agents/alom/fence_alom.py
+++ b/fence/agents/alom/fence_alom.py
@@ -1,59 +1,53 @@
#!@PYTHON@ -tt
# The Following Agent Has Been Tested On:
#
# Sun(tm) Advanced Lights Out Manager CMT v1.6.1
# as found on SUN T2000 Niagara
import sys, re, time
import atexit
sys.path.append("@FENCEAGENTSLIBDIR@")
from fencing import *
-#BEGIN_VERSION_GENERATION
-RELEASE_VERSION="Sun Advanced Lights Out Manager (ALOM)"
-REDHAT_COPYRIGHT=""
-BUILD_DATE=""
-#END_VERSION_GENERATION
-
def get_power_status(conn, options):
conn.send_eol("showplatform")
conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"]))
status = re.search("standby", conn.before.lower())
result = (status != None and "off" or "on")
return result
def set_power_status(conn, options):
cmd_line = (options["--action"] == "on" and "poweron" or "poweroff -f -y")
conn.send_eol(cmd_line)
conn.log_expect(options["--command-prompt"], int(options["--power-timeout"]))
# Get the machine some time between poweron and poweroff
time.sleep(int(options["--power-timeout"]))
def main():
device_opt = ["ipaddr", "login", "passwd", "cmd_prompt", "secure"]
atexit.register(atexit_handler)
all_opt["secure"]["default"] = "1"
all_opt["cmd_prompt"]["default"] = [r"sc\>\ "]
options = check_input(device_opt, process_input(device_opt))
options["telnet_over_ssh"] = 1
docs = {}
docs["shortdesc"] = "Fence agent for Sun ALOM"
docs["longdesc"] = "fence_alom is an I/O Fencing \
agent which can be used with ALOM connected machines."
docs["vendorurl"] = "http://www.sun.com"
show_docs(options, docs)
# Operate the fencing device
conn = fence_login(options)
result = fence_action(conn, options, set_power_status, get_power_status, None)
fence_logout(conn, "logout")
sys.exit(result)
if __name__ == "__main__":
main()
diff --git a/fence/agents/amt/fence_amt.py b/fence/agents/amt/fence_amt.py
index 082f5d09..feec6e3e 100644
--- a/fence/agents/amt/fence_amt.py
+++ b/fence/agents/amt/fence_amt.py
@@ -1,134 +1,128 @@
#!@PYTHON@ -tt
import sys, re, os
import atexit
from pipes import quote
sys.path.append("@FENCEAGENTSLIBDIR@")
from fencing import *
from fencing import fail_usage, is_executable, run_command, run_delay
-#BEGIN_VERSION_GENERATION
-RELEASE_VERSION="Fence agent for Intel AMT"
-REDHAT_COPYRIGHT=""
-BUILD_DATE=""
-#END_VERSION_GENERATION
-
def get_power_status(_, options):
output = amt_run_command(options, create_command(options, "status"))
match = re.search('Powerstate:[\\s]*(..)', str(output))
status = match.group(1) if match else None
if status == None:
return "fail"
elif status == "S0": # SO = on; S3 = sleep; S5 = off
return "on"
else:
return "off"
def set_power_status(_, options):
amt_run_command(options, create_command(options, options["--action"]))
return
def reboot_cycle(_, options):
(status, _, _) = run_command(options, create_command(options, "cycle"))
return not bool(status)
def amt_run_command(options, command, timeout=None):
env = os.environ.copy()
x = quote(options["--password"])
x = x[:-1] if x.endswith("'") else x
x = x[1:] if x.startswith("'") else x
env["AMT_PASSWORD"] = x
# This is needed because setting the AMT_PASSWORD env
# variable only works when no pipe is involved. E.g.:
# - Broken:
# $ AMT_PASSWORD='foobar' echo 'y' | /usr/bin/amttool nuc2 powerdown
# 401 Unauthorized at /usr/bin/amttool line 129.
# - Working:
# $ AMT_PASSWORD='foobar' sh -c "(echo 'y' | /usr/bin/amttool nuc2 powerdown)"
# execute: powerdown
# result: pt_status: success
newcommand = "sh -c \"(%s)\"" % command
return run_command(options, newcommand, timeout, env)
def create_command(options, action):
cmd = options["--amttool-path"]
# --ip / -a
cmd += " " + options["--ip"]
# --action / -o
if action == "status":
cmd += " info"
elif action == "on":
cmd = "echo \"y\"|" + cmd
cmd += " powerup"
elif action == "off":
cmd = "echo \"y\"|" + cmd
cmd += " powerdown"
elif action == "cycle":
cmd = "echo \"y\"|" + cmd
cmd += " powercycle"
if action in ["on", "off", "cycle"] and "--boot-option" in options:
cmd += options["--boot-option"]
# --use-sudo / -d
if "--use-sudo" in options:
cmd = options["--sudo-path"] + " " + cmd
return cmd
def define_new_opts():
all_opt["boot_option"] = {
"getopt" : "b:",
"longopt" : "boot-option",
"help" : "-b, --boot-option=[option] "
"Change the default boot behavior of the machine. (pxe|hd|hdsafe|cd|diag)",
"required" : "0",
"shortdesc" : "Change the default boot behavior of the machine.",
"choices" : ["pxe", "hd", "hdsafe", "cd", "diag"],
"order" : 1
}
all_opt["amttool_path"] = {
"getopt" : ":",
"longopt" : "amttool-path",
"help" : "--amttool-path=[path] Path to amttool binary",
"required" : "0",
"shortdesc" : "Path to amttool binary",
"default" : "@AMTTOOL_PATH@",
"order": 200
}
def main():
atexit.register(atexit_handler)
device_opt = ["ipaddr", "no_login", "passwd", "boot_option", "no_port",
"sudo", "amttool_path", "method"]
define_new_opts()
all_opt["ipport"]["default"] = "16994"
options = check_input(device_opt, process_input(device_opt))
docs = {}
docs["shortdesc"] = "Fence agent for AMT"
docs["longdesc"] = "fence_amt is an I/O Fencing agent \
which can be used with Intel AMT. This agent calls support software amttool\
(http://www.kraxel.org/cgit/amtterm/)."
docs["vendorurl"] = "http://www.intel.com/"
show_docs(options, docs)
run_delay(options)
if not is_executable(options["--amttool-path"]):
fail_usage("Amttool not found or not accessible")
result = fence_action(None, options, set_power_status, get_power_status, None, reboot_cycle)
sys.exit(result)
if __name__ == "__main__":
main()
diff --git a/fence/agents/amt_ws/fence_amt_ws.py b/fence/agents/amt_ws/fence_amt_ws.py
index 5284a77a..b99f20ad 100755
--- a/fence/agents/amt_ws/fence_amt_ws.py
+++ b/fence/agents/amt_ws/fence_amt_ws.py
@@ -1,243 +1,236 @@
#!@PYTHON@ -tt
#
# Fence agent for Intel AMT (WS) based on code from the openstack/ironic project:
# https://github.com/openstack/ironic/blob/master/ironic/drivers/modules/amt/power.py
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
import sys
import atexit
import logging
sys.path.append("@FENCEAGENTSLIBDIR@")
from fencing import *
from fencing import run_delay, fail_usage, fail, EC_STATUS
import pywsman
from xml.etree import ElementTree
-
-#BEGIN_VERSION_GENERATION
-RELEASE_VERSION="Fence agent for Intel AMT (WS)"
-REDHAT_COPYRIGHT=""
-BUILD_DATE=""
-#END_VERSION_GENERATION
-
POWER_ON='2'
POWER_OFF='8'
POWER_CYCLE='10'
RET_SUCCESS = '0'
CIM_PowerManagementService = ('http://schemas.dmtf.org/wbem/wscim/1/'
'cim-schema/2/CIM_PowerManagementService')
CIM_ComputerSystem = ('http://schemas.dmtf.org/wbem/wscim/'
'1/cim-schema/2/CIM_ComputerSystem')
CIM_AssociatedPowerManagementService = ('http://schemas.dmtf.org/wbem/wscim/'
'1/cim-schema/2/'
'CIM_AssociatedPowerManagementService')
CIM_BootConfigSetting = ('http://schemas.dmtf.org/wbem/wscim/'
'1/cim-schema/2/CIM_BootConfigSetting')
CIM_BootSourceSetting = ('http://schemas.dmtf.org/wbem/wscim/'
'1/cim-schema/2/CIM_BootSourceSetting')
def xml_find(doc, namespace, item):
if doc is None:
return
tree = ElementTree.fromstring(doc.root().string())
query = ('.//{%(namespace)s}%(item)s' % {'namespace': namespace,
'item': item})
return tree.find(query)
def _generate_power_action_input(action):
method_input = "RequestPowerStateChange_INPUT"
address = 'http://schemas.xmlsoap.org/ws/2004/08/addressing'
anonymous = ('http://schemas.xmlsoap.org/ws/2004/08/addressing/'
'role/anonymous')
wsman = 'http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd'
namespace = CIM_PowerManagementService
doc = pywsman.XmlDoc(method_input)
root = doc.root()
root.set_ns(namespace)
root.add(namespace, 'PowerState', action)
child = root.add(namespace, 'ManagedElement', None)
child.add(address, 'Address', anonymous)
grand_child = child.add(address, 'ReferenceParameters', None)
grand_child.add(wsman, 'ResourceURI', CIM_ComputerSystem)
g_grand_child = grand_child.add(wsman, 'SelectorSet', None)
g_g_grand_child = g_grand_child.add(wsman, 'Selector', 'ManagedSystem')
g_g_grand_child.attr_add(wsman, 'Name', 'Name')
return doc
def get_power_status(_, options):
client = pywsman.Client(options["--ip"], int(options["--ipport"]), \
'/wsman', 'http', 'admin', options["--password"])
namespace = CIM_AssociatedPowerManagementService
client_options = pywsman.ClientOptions()
doc = client.get(client_options, namespace)
_SOAP_ENVELOPE = 'http://www.w3.org/2003/05/soap-envelope'
item = 'Fault'
fault = xml_find(doc, _SOAP_ENVELOPE, item)
if fault is not None:
logging.error("Failed to get power state for: %s port:%s", \
options["--ip"], options["--ipport"])
fail(EC_STATUS)
item = "PowerState"
try: power_state = xml_find(doc, namespace, item).text
except AttributeError:
logging.error("Failed to get power state for: %s port:%s", \
options["--ip"], options["--ipport"])
fail(EC_STATUS)
if power_state == POWER_ON:
return "on"
elif power_state == POWER_OFF:
return "off"
else:
fail(EC_STATUS)
def set_power_status(_, options):
client = pywsman.Client(options["--ip"], int(options["--ipport"]), \
'/wsman', 'http', 'admin', options["--password"])
method = 'RequestPowerStateChange'
client_options = pywsman.ClientOptions()
client_options.add_selector('Name', 'Intel(r) AMT Power Management Service')
if options["--action"] == "on":
target_state = POWER_ON
elif options["--action"] == "off":
target_state = POWER_OFF
elif options["--action"] == "reboot":
target_state = POWER_CYCLE
if options["--action"] in ["on", "off", "reboot"] \
and "--boot-option" in options:
set_boot_order(_, client, options)
doc = _generate_power_action_input(target_state)
client_doc = client.invoke(client_options, CIM_PowerManagementService, \
method, doc)
item = "ReturnValue"
return_value = xml_find(client_doc, CIM_PowerManagementService, item).text
if return_value != RET_SUCCESS:
logging.error("Failed to set power state: %s for: %s", \
options["--action"], options["--ip"])
fail(EC_STATUS)
def set_boot_order(_, client, options):
method_input = "ChangeBootOrder_INPUT"
address = 'http://schemas.xmlsoap.org/ws/2004/08/addressing'
anonymous = ('http://schemas.xmlsoap.org/ws/2004/08/addressing/'
'role/anonymous')
wsman = 'http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd'
namespace = CIM_BootConfigSetting
if options["--boot-option"] == "pxe":
device = "Intel(r) AMT: Force PXE Boot"
elif options["--boot-option"] == "hd" or "hdsafe":
device = "Intel(r) AMT: Force Hard-drive Boot"
elif options["--boot-option"] == "cd":
device = "Intel(r) AMT: Force CD/DVD Boot"
elif options["--boot-option"] == "diag":
device = "Intel(r) AMT: Force Diagnostic Boot"
else:
logging.error('Boot device: %s not supported.', \
options["--boot-option"])
return
method = 'ChangeBootOrder'
client_options = pywsman.ClientOptions()
client_options.add_selector('InstanceID', \
'Intel(r) AMT: Boot Configuration 0')
doc = pywsman.XmlDoc(method_input)
root = doc.root()
root.set_ns(namespace)
child = root.add(namespace, 'Source', None)
child.add(address, 'Address', anonymous)
grand_child = child.add(address, 'ReferenceParameters', None)
grand_child.add(wsman, 'ResourceURI', CIM_BootSourceSetting)
g_grand_child = grand_child.add(wsman, 'SelectorSet', None)
g_g_grand_child = g_grand_child.add(wsman, 'Selector', device)
g_g_grand_child.attr_add(wsman, 'Name', 'InstanceID')
if options["--boot-option"] == "hdsafe":
g_g_grand_child = g_grand_child.add(wsman, 'Selector', 'True')
g_g_grand_child.attr_add(wsman, 'Name', 'UseSafeMode')
client_doc = client.invoke(client_options, CIM_BootConfigSetting, \
method, doc)
item = "ReturnValue"
return_value = xml_find(client_doc, CIM_BootConfigSetting, item).text
if return_value != RET_SUCCESS:
logging.error("Failed to set boot device to: %s for: %s", \
options["--boot-option"], options["--ip"])
fail(EC_STATUS)
def reboot_cycle(_, options):
status = set_power_status(_, options)
return not bool(status)
def define_new_opts():
all_opt["boot_option"] = {
"getopt" : "b:",
"longopt" : "boot-option",
"help" : "-b, --boot-option=[option] "
"Change the default boot behavior of the\n"
" machine."
" (pxe|hd|hdsafe|cd|diag)",
"required" : "0",
"shortdesc" : "Change the default boot behavior of the machine.",
"choices" : ["pxe", "hd", "hdsafe", "cd", "diag"],
"order" : 1
}
def main():
atexit.register(atexit_handler)
device_opt = ["ipaddr", "no_login", "passwd", "boot_option", "no_port",
"method"]
define_new_opts()
all_opt["ipport"]["default"] = "16992"
options = check_input(device_opt, process_input(device_opt))
docs = {}
docs["shortdesc"] = "Fence agent for AMT (WS)"
docs["longdesc"] = "fence_amt_ws is an I/O Fencing agent \
which can be used with Intel AMT (WS). This agent requires \
the pywsman Python library which is included in OpenWSMAN. \
(http://openwsman.github.io/)."
docs["vendorurl"] = "http://www.intel.com/"
show_docs(options, docs)
run_delay(options)
result = fence_action(None, options, set_power_status, get_power_status, \
None, reboot_cycle)
sys.exit(result)
if __name__ == "__main__":
main()
diff --git a/fence/agents/apc/fence_apc.py b/fence/agents/apc/fence_apc.py
index 1e9c3761..24a5a423 100644
--- a/fence/agents/apc/fence_apc.py
+++ b/fence/agents/apc/fence_apc.py
@@ -1,266 +1,260 @@
#!@PYTHON@ -tt
#####
##
## The Following Agent Has Been Tested On:
##
## Model Firmware
## +---------------------------------------------+
## AP7951 AOS v2.7.0, PDU APP v2.7.3
## AP7941 AOS v3.5.7, PDU APP v3.5.6
## AP9606 AOS v2.5.4, PDU APP v2.7.3
##
## @note: ssh is very slow on AP79XX devices protocol (1) and
## cipher (des/blowfish) have to be defined
#####
import sys, re, time
import atexit
sys.path.append("@FENCEAGENTSLIBDIR@")
from fencing import *
from fencing import fail, fail_usage, EC_STATUS
-#BEGIN_VERSION_GENERATION
-RELEASE_VERSION="New APC Agent - test release on steroids"
-REDHAT_COPYRIGHT=""
-BUILD_DATE="March, 2008"
-#END_VERSION_GENERATION
-
# Fix for connection timed out issue in:
# https://bugzilla.redhat.com/show_bug.cgi?id=1342584
TIMEDOUT_DELAY = 0.5
def get_power_status(conn, options):
exp_result = 0
outlets = {}
conn.send_eol("1")
conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"]))
version = 0
admin = 0
switch = 0
if None != re.compile('.* MasterSwitch plus.*', re.IGNORECASE | re.S).match(conn.before):
switch = 1
if None != re.compile('.* MasterSwitch plus 2', re.IGNORECASE | re.S).match(conn.before):
if "--switch" not in options:
fail_usage("Failed: You have to enter physical switch number")
else:
if "--switch" not in options:
options["--switch"] = "1"
if None == re.compile('.*Outlet Management.*', re.IGNORECASE | re.S).match(conn.before):
version = 2
else:
version = 3
if None == re.compile('.*Outlet Control/Configuration.*', re.IGNORECASE | re.S).match(conn.before):
admin = 0
else:
admin = 1
if switch == 0:
if version == 2:
if admin == 0:
conn.send_eol("2")
else:
conn.send_eol("3")
else:
conn.send_eol("2")
conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"]))
conn.send_eol("1")
else:
conn.send_eol(options["--switch"])
while True:
exp_result = conn.log_expect(
["Press <ENTER>"] + options["--command-prompt"], int(options["--shell-timeout"]))
lines = conn.before.split("\n")
show_re = re.compile(r'(^|\x0D)\s*(\d+)- (.*?)\s+(ON|OFF)\s*')
for line in lines:
res = show_re.search(line)
if res != None:
outlets[res.group(2)] = (res.group(3), res.group(4))
time.sleep(TIMEDOUT_DELAY)
conn.send_eol("")
if exp_result != 0:
break
conn.send(chr(0o3))
conn.log_expect("- Logout", int(options["--shell-timeout"]))
conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"]))
if ["list", "monitor"].count(options["--action"]) == 1:
return outlets
else:
try:
(_, status) = outlets[options["--plug"]]
return status.lower().strip()
except KeyError:
fail(EC_STATUS)
def set_power_status(conn, options):
action = {
'on' : "1",
'off': "2"
}[options["--action"]]
conn.send_eol("1")
conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"]))
version = 0
admin2 = 0
admin3 = 0
switch = 0
if None != re.compile('.* MasterSwitch plus.*', re.IGNORECASE | re.S).match(conn.before):
switch = 1
## MasterSwitch has different schema for on/off actions
action = {
'on' : "1",
'off': "3"
}[options["--action"]]
if None != re.compile('.* MasterSwitch plus 2', re.IGNORECASE | re.S).match(conn.before):
if "--switch" not in options:
fail_usage("Failed: You have to enter physical switch number")
else:
if "--switch" not in options:
options["--switch"] = 1
if None == re.compile('.*Outlet Management.*', re.IGNORECASE | re.S).match(conn.before):
version = 2
else:
version = 3
if None == re.compile('.*Outlet Control/Configuration.*', re.IGNORECASE | re.S).match(conn.before):
admin2 = 0
else:
admin2 = 1
if switch == 0:
if version == 2:
if admin2 == 0:
conn.send_eol("2")
else:
conn.send_eol("3")
else:
conn.send_eol("2")
conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"]))
if None == re.compile('.*2- Outlet Restriction.*', re.IGNORECASE | re.S).match(conn.before):
admin3 = 0
else:
admin3 = 1
conn.send_eol("1")
else:
conn.send_eol(options["--switch"])
while 0 == conn.log_expect(
["Press <ENTER>"] + options["--command-prompt"], int(options["--shell-timeout"])):
time.sleep(TIMEDOUT_DELAY)
conn.send_eol("")
conn.send_eol(options["--plug"]+"")
conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"]))
if switch == 0:
if admin2 == 1:
conn.send_eol("1")
conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"]))
if admin3 == 1:
conn.send_eol("1")
conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"]))
else:
conn.send_eol("1")
conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"]))
conn.send_eol(action)
conn.log_expect("Enter 'YES' to continue or <ENTER> to cancel :", int(options["--shell-timeout"]))
conn.send_eol("YES")
conn.log_expect("Press <ENTER> to continue...", int(options["--power-timeout"]))
time.sleep(TIMEDOUT_DELAY)
conn.send_eol("")
conn.log_expect(options["--command-prompt"], int(options["--power-timeout"]))
conn.send(chr(0o3))
conn.log_expect("- Logout", int(options["--shell-timeout"]))
conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"]))
def get_power_status5(conn, options):
outlets = {}
conn.send_eol("olStatus all")
conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"]))
lines = conn.before.split("\n")
show_re = re.compile(r'^\s*(\d+): (.*): (On|Off)\s*$', re.IGNORECASE)
for line in lines:
res = show_re.search(line)
if res != None:
outlets[res.group(1)] = (res.group(2), res.group(3))
if ["list", "monitor"].count(options["--action"]) == 1:
return outlets
else:
try:
(_, status) = outlets[options["--plug"]]
return status.lower().strip()
except KeyError:
fail(EC_STATUS)
def set_power_status5(conn, options):
action = {
'on' : "olOn",
'off': "olOff"
}[options["--action"]]
conn.send_eol(action + " " + options["--plug"])
conn.log_expect(options["--command-prompt"], int(options["--power-timeout"]))
def main():
device_opt = ["ipaddr", "login", "passwd", "cmd_prompt", "secure", \
"port", "switch", "telnet"]
atexit.register(atexit_handler)
all_opt["cmd_prompt"]["default"] = ["\n>", "\napc>"]
all_opt["ssh_options"]["default"] = "-1 -c blowfish"
options = check_input(device_opt, process_input(device_opt))
docs = {}
docs["shortdesc"] = "Fence agent for APC over telnet/ssh"
docs["longdesc"] = "fence_apc is an I/O Fencing agent \
which can be used with the APC network power switch. It logs into device \
via telnet/ssh and reboots a specified outlet. Lengthy telnet/ssh connections \
should be avoided while a GFS cluster is running because the connection \
will block any necessary fencing actions."
docs["vendorurl"] = "http://www.apc.com"
show_docs(options, docs)
## Support for --plug [switch]:[plug] notation that was used before
if (("--plug" in options) == 1) and (-1 != options["--plug"].find(":")):
(switch, plug) = options["--plug"].split(":", 1)
options["--switch"] = switch
options["--plug"] = plug
##
## Operate the fencing device
####
conn = fence_login(options)
## Detect firmware version (ASCII menu vs command-line interface)
## and continue with proper action
####
result = -1
firmware_version = re.compile(r'\s*v(\d)*\.').search(conn.before)
if (firmware_version != None) and (firmware_version.group(1) in [ "5", "6" ]):
result = fence_action(conn, options, set_power_status5, get_power_status5, get_power_status5)
else:
result = fence_action(conn, options, set_power_status, get_power_status, get_power_status)
fence_logout(conn, "4")
sys.exit(result)
if __name__ == "__main__":
main()
diff --git a/fence/agents/apc_snmp/fence_apc_snmp.py b/fence/agents/apc_snmp/fence_apc_snmp.py
index f93cfa84..f68c0cb6 100644
--- a/fence/agents/apc_snmp/fence_apc_snmp.py
+++ b/fence/agents/apc_snmp/fence_apc_snmp.py
@@ -1,224 +1,218 @@
#!@PYTHON@ -tt
# The Following agent has been tested on:
# - APC Switched Rack PDU - SNMP v1
# (MB:v3.7.0 PF:v2.7.0 PN:apc_hw02_aos_270.bin AF1:v2.7.3
# AN1:apc_hw02_aos_270.bin AF1:v2.7.3 AN1:apc_hw02_rpdu_273.bin MN:AP7930 HR:B2)
# - APC Web/SNMP Management Card - SNMP v1 and v3 (noAuthNoPrivacy,authNoPrivacy, authPrivacy)
# (MB:v3.8.6 PF:v3.5.8 PN:apc_hw02_aos_358.bin AF1:v3.5.7
# AN1:apc_hw02_aos_358.bin AF1:v3.5.7 AN1:apc_hw02_rpdu_357.bin MN:AP7900 HR:B2)
# - APC Switched Rack PDU - SNMP v1
# (MB:v3.7.0 PF:v2.7.0 PN:apc_hw02_aos_270.bin AF1:v2.7.3
# AN1:apc_hw02_rpdu_273.bin MN:AP7951 HR:B2)
# - Tripplite PDUMH20HVNET 12.04.0055 - SNMP v1, v2c, v3
import sys
import atexit
import logging
sys.path.append("@FENCEAGENTSLIBDIR@")
from fencing import *
from fencing import fail_usage
from fencing_snmp import FencingSnmp
-#BEGIN_VERSION_GENERATION
-RELEASE_VERSION="APC SNMP fence agent"
-REDHAT_COPYRIGHT=""
-BUILD_DATE=""
-#END_VERSION_GENERATION
-
### CONSTANTS ###
# oid defining fence device
OID_SYS_OBJECT_ID = '.1.3.6.1.2.1.1.2.0'
### GLOBAL VARIABLES ###
# Device - see ApcRPDU, ApcMSP, ApcMS, TripplitePDU
device = None
# Port ID
port_id = None
# Switch ID
switch_id = None
# Classes describing Device params
class TripplitePDU(object):
# Rack PDU
status_oid = '.1.3.6.1.4.1.850.10.2.3.5.1.2.1.%d'
control_oid = '.1.3.6.1.4.1.850.10.2.3.5.1.4.1.%d'
outlet_table_oid = '.1.3.6.1.4.1.850.10.2.3.5.1.5'
ident_str = "Tripplite"
state_on = 2
state_off = 1
turn_on = 2
turn_off = 1
has_switches = False
class ApcRPDU(object):
# Rack PDU
status_oid = '.1.3.6.1.4.1.318.1.1.12.3.5.1.1.4.%d'
control_oid = '.1.3.6.1.4.1.318.1.1.12.3.3.1.1.4.%d'
outlet_table_oid = '.1.3.6.1.4.1.318.1.1.12.3.5.1.1.2'
ident_str = "APC rPDU"
state_on = 1
state_off = 2
turn_on = 1
turn_off = 2
has_switches = False
class ApcMSP(object):
# Master Switch+
status_oid = '.1.3.6.1.4.1.318.1.1.6.7.1.1.5.%d.1.%d'
control_oid = '.1.3.6.1.4.1.318.1.1.6.5.1.1.5.%d.1.%d'
outlet_table_oid = '.1.3.6.1.4.1.318.1.1.6.7.1.1.4'
ident_str = "APC Master Switch+"
state_on = 1
state_off = 2
turn_on = 1
turn_off = 3
has_switches = True
class ApcMS(object):
# Master Switch - seems oldest, but supported on every APC PDU
status_oid = '.1.3.6.1.4.1.318.1.1.4.4.2.1.3.%d'
control_oid = '.1.3.6.1.4.1.318.1.1.4.4.2.1.3.%d'
outlet_table_oid = '.1.3.6.1.4.1.318.1.1.4.4.2.1.4'
ident_str = "APC Master Switch (fallback)"
state_on = 1
state_off = 2
turn_on = 1
turn_off = 2
has_switches = False
class ApcMS6(object):
# Master Switch with 6.x firmware
status_oid = '.1.3.6.1.4.1.318.1.1.4.4.2.1.3.%d'
control_oid = '.1.3.6.1.4.1.318.1.1.12.3.3.1.1.4.%d'
outlet_table_oid = '1.3.6.1.4.1.318.1.1.4.4.2.1.4'
ident_str = "APC Master Switch with firmware v6.x"
state_on = 1
state_off = 2
turn_on = 1
turn_off = 2
has_switches = False
### FUNCTIONS ###
def apc_set_device(conn):
global device
agents_dir = {'.1.3.6.1.4.1.318.1.3.4.5':ApcRPDU,
'.1.3.6.1.4.1.318.1.3.4.4':ApcMSP,
'.1.3.6.1.4.1.850.1':TripplitePDU,
'.1.3.6.1.4.1.318.1.3.4.6':ApcMS6,
None:ApcMS}
# First resolve type of APC
apc_type = conn.walk(OID_SYS_OBJECT_ID)
if not ((len(apc_type) == 1) and (apc_type[0][1] in agents_dir)):
apc_type = [[None, None]]
device = agents_dir[apc_type[0][1]]
logging.debug("Trying %s"%(device.ident_str))
def apc_resolv_port_id(conn, options):
global port_id, switch_id
if device == None:
apc_set_device(conn)
# Now we resolv port_id/switch_id
if (options["--plug"].isdigit()) and ((not device.has_switches) or (options["--switch"].isdigit())):
port_id = int(options["--plug"])
if device.has_switches:
switch_id = int(options["--switch"])
else:
table = conn.walk(device.outlet_table_oid, 30)
for x in table:
if x[1].strip('"') == options["--plug"]:
t = x[0].split('.')
if device.has_switches:
port_id = int(t[len(t)-1])
switch_id = int(t[len(t)-3])
else:
port_id = int(t[len(t)-1])
if port_id == None:
fail_usage("Can't find port with name %s!"%(options["--plug"]))
def get_power_status(conn, options):
if port_id == None:
apc_resolv_port_id(conn, options)
oid = ((device.has_switches) and device.status_oid%(switch_id, port_id) or device.status_oid%(port_id))
(oid, status) = conn.get(oid)
return status == str(device.state_on) and "on" or "off"
def set_power_status(conn, options):
if port_id == None:
apc_resolv_port_id(conn, options)
oid = ((device.has_switches) and device.control_oid%(switch_id, port_id) or device.control_oid%(port_id))
conn.set(oid, (options["--action"] == "on" and device.turn_on or device.turn_off))
def get_outlets_status(conn, options):
result = {}
if device == None:
apc_set_device(conn)
res_ports = conn.walk(device.outlet_table_oid, 30)
for x in res_ports:
t = x[0].split('.')
port_num = ((device.has_switches) and "%s:%s"%(t[len(t)-3], t[len(t)-1]) or "%s"%(t[len(t)-1]))
port_name = x[1].strip('"')
port_status = ""
result[port_num] = (port_name, port_status)
return result
# Main agent method
def main():
device_opt = ["ipaddr", "login", "passwd", "no_login", "no_password", \
"port", "snmp_version", "snmp"]
atexit.register(atexit_handler)
all_opt["snmp_version"]["default"] = "1"
all_opt["community"]["default"] = "private"
options = check_input(device_opt, process_input(device_opt))
## Support for -n [switch]:[plug] notation that was used before
if ("--plug" in options) and (-1 != options["--plug"].find(":")):
(switch, plug) = options["--plug"].split(":", 1)
if switch.isdigit() and plug.isdigit():
options["--switch"] = switch
options["--plug"] = plug
if "--switch" not in options:
options["--switch"] = "1"
docs = {}
docs["shortdesc"] = "Fence agent for APC, Tripplite PDU over SNMP"
docs["longdesc"] = "fence_apc_snmp is an I/O Fencing agent \
which can be used with the APC network power switch or Tripplite PDU devices.\
It logs into a device via SNMP and reboots a specified outlet. It supports \
SNMP v1, v2c, v3 with all combinations of authenticity/privacy settings."
docs["vendorurl"] = "http://www.apc.com"
docs["symlink"] = [("fence_tripplite_snmp", "Fence agent for Tripplife over SNMP")]
show_docs(options, docs)
# Operate the fencing device
result = fence_action(FencingSnmp(options), options, set_power_status, get_power_status, get_outlets_status)
sys.exit(result)
if __name__ == "__main__":
main()
diff --git a/fence/agents/azure_arm/fence_azure_arm.py b/fence/agents/azure_arm/fence_azure_arm.py
index 72caddfc..b3e800fe 100644
--- a/fence/agents/azure_arm/fence_azure_arm.py
+++ b/fence/agents/azure_arm/fence_azure_arm.py
@@ -1,131 +1,125 @@
#!@PYTHON@ -tt
import sys, re, pexpect
import logging
import atexit
sys.path.append("@FENCEAGENTSLIBDIR@")
from fencing import *
from fencing import fail, fail_usage, EC_TIMED_OUT, run_delay
-#BEGIN_VERSION_GENERATION
-RELEASE_VERSION=""
-BUILD_DATE=""
-REDHAT_COPYRIGHT="Copyright (C) Red Hat, Inc. 2004-2010 All rights reserved."
-#END_VERSION_GENERATION
-
def get_nodes_list(compute_client, options):
result = {}
if compute_client:
rgName = options["--resourceGroup"]
vms = compute_client.virtual_machines.list(rgName)
for vm in vms:
result[vm.name] = ("", None)
return result
def get_power_status(compute_client, options):
logging.info("getting power status for VM " + options["--plug"])
if compute_client:
rgName = options["--resourceGroup"]
vmName = options["--plug"]
powerState = "unknown"
vmStatus = compute_client.virtual_machines.get(rgName, vmName, "instanceView")
for status in vmStatus.instance_view.statuses:
if status.code.startswith("PowerState"):
powerState = status.code
break
logging.info("Found power state of VM: " + powerState)
if powerState == "PowerState/running":
return "on"
return "off"
def set_power_status(compute_client, options):
logging.info("setting power status for VM " + options["--plug"] + " to " + options["--action"])
if compute_client:
rgName = options["--resourceGroup"]
vmName = options["--plug"]
if (options["--action"]=="off"):
logging.info("Deallocating " + vmName + "in resource group " + rgName)
compute_client.virtual_machines.deallocate(rgName, vmName)
elif (options["--action"]=="on"):
logging.info("Starting " + vmName + "in resource group " + rgName)
compute_client.virtual_machines.start(rgName, vmName)
def define_new_opts():
all_opt["resourceGroup"] = {
"getopt" : ":",
"longopt" : "resourceGroup",
"help" : "--resourceGroup=[name] Name of the resource group",
"shortdesc" : "Name of resource group.",
"required" : "1",
"order" : 2
}
all_opt["tenantId"] = {
"getopt" : ":",
"longopt" : "tenantId",
"help" : "--tenantId=[name] Id of the Azure Active Directory tenant",
"shortdesc" : "Id of Azure Active Directory tenant.",
"required" : "1",
"order" : 3
}
all_opt["subscriptionId"] = {
"getopt" : ":",
"longopt" : "subscriptionId",
"help" : "--subscriptionId=[name] Id of the Azure subscription",
"shortdesc" : "Id of the Azure subscription.",
"required" : "1",
"order" : 4
}
# Main agent method
def main():
compute_client = None
device_opt = ["resourceGroup", "login", "passwd", "tenantId", "subscriptionId","port"]
atexit.register(atexit_handler)
define_new_opts()
options = check_input(device_opt, process_input(device_opt))
docs = {}
docs["shortdesc"] = "Fence agent for Azure Resource Manager"
docs["longdesc"] = "Used to deallocate virtual machines and to report power state of virtual machines running in Azure"
docs["vendorurl"] = "http://www.microsoft.com"
show_docs(options, docs)
run_delay(options)
try:
from azure.common.credentials import ServicePrincipalCredentials
from azure.mgmt.compute import ComputeManagementClient
tenantid = options["--tenantId"]
servicePrincipal = options["--username"]
spPassword = options["--password"]
subscriptionId = options["--subscriptionId"]
credentials = ServicePrincipalCredentials(
client_id = servicePrincipal,
secret = spPassword,
tenant = tenantid
)
compute_client = ComputeManagementClient(
credentials,
subscriptionId
)
except ImportError:
fail_usage("Azure Resource Manager Pyhton SDK not found or not accessible")
# Operate the fencing device
result = fence_action(compute_client, options, set_power_status, get_power_status, get_nodes_list)
sys.exit(result)
if __name__ == "__main__":
main()
diff --git a/fence/agents/bladecenter/fence_bladecenter.py b/fence/agents/bladecenter/fence_bladecenter.py
index b45f3157..d670367f 100644
--- a/fence/agents/bladecenter/fence_bladecenter.py
+++ b/fence/agents/bladecenter/fence_bladecenter.py
@@ -1,111 +1,105 @@
#!@PYTHON@ -tt
#####
##
## The Following Agent Has Been Tested On:
##
## Model Firmware
## +--------------------+---------------------------+
## (1) Main application BRET85K, rev 16
## Boot ROM BRBR67D, rev 16
## Remote Control BRRG67D, rev 16
##
#####
import sys, re
import atexit
sys.path.append("@FENCEAGENTSLIBDIR@")
from fencing import *
from fencing import fail, EC_STATUS, EC_GENERIC_ERROR
-#BEGIN_VERSION_GENERATION
-RELEASE_VERSION="New Bladecenter Agent - test release on steroids"
-REDHAT_COPYRIGHT=""
-BUILD_DATE="March, 2008"
-#END_VERSION_GENERATION
-
def get_power_status(conn, options):
node_cmd = r"system:blade\[" + options["--plug"] + r"\]>"
conn.send_eol("env -T system:blade[" + options["--plug"] + "]")
i = conn.log_expect([node_cmd, "system>"], int(options["--shell-timeout"]))
if i == 1:
## Given blade number does not exist
if "--missing-as-off" in options:
return "off"
else:
fail(EC_STATUS)
conn.send_eol("power -state")
conn.log_expect(node_cmd, int(options["--shell-timeout"]))
status = conn.before.splitlines()[-1]
conn.send_eol("env -T system")
conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"]))
return status.lower().strip()
def set_power_status(conn, options):
node_cmd = r"system:blade\[" + options["--plug"] + r"\]>"
conn.send_eol("env -T system:blade[" + options["--plug"] + "]")
i = conn.log_expect([node_cmd, "system>"], int(options["--shell-timeout"]))
if i == 1:
## Given blade number does not exist
if "--missing-as-off" in options:
return
else:
fail(EC_GENERIC_ERROR)
conn.send_eol("power -"+options["--action"])
conn.log_expect(node_cmd, int(options["--shell-timeout"]))
conn.send_eol("env -T system")
conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"]))
def get_blades_list(conn, options):
outlets = {}
node_cmd = "system>"
conn.send_eol("env -T system")
conn.log_expect(node_cmd, int(options["--shell-timeout"]))
conn.send_eol("list -l 2")
conn.log_expect(node_cmd, int(options["--shell-timeout"]))
lines = conn.before.split("\r\n")
filter_re = re.compile(r"^\s*blade\[(\d+)\]\s+(.*?)\s*$")
for blade_line in lines:
res = filter_re.search(blade_line)
if res != None:
outlets[res.group(1)] = (res.group(2), "")
return outlets
def main():
device_opt = ["ipaddr", "login", "passwd", "cmd_prompt", "secure", \
"port", "missing_as_off", "telnet"]
atexit.register(atexit_handler)
all_opt["power_wait"]["default"] = "10"
all_opt["cmd_prompt"]["default"] = ["system>"]
options = check_input(device_opt, process_input(device_opt))
docs = {}
docs["shortdesc"] = "Fence agent for IBM BladeCenter"
docs["longdesc"] = "fence_bladecenter is an I/O Fencing agent \
which can be used with IBM Bladecenters with recent enough firmware that \
includes telnet support. It logs into a Brocade chasis via telnet or ssh \
and uses the command line interface to power on and off blades."
docs["vendorurl"] = "http://www.ibm.com"
show_docs(options, docs)
##
## Operate the fencing device
######
conn = fence_login(options, "(username\s*:\s*)")
result = fence_action(conn, options, set_power_status, get_power_status, get_blades_list)
fence_logout(conn, "exit")
sys.exit(result)
if __name__ == "__main__":
main()
diff --git a/fence/agents/brocade/fence_brocade.py b/fence/agents/brocade/fence_brocade.py
index 4cf039a9..9f413db6 100644
--- a/fence/agents/brocade/fence_brocade.py
+++ b/fence/agents/brocade/fence_brocade.py
@@ -1,78 +1,72 @@
#!@PYTHON@ -tt
import sys, re
import atexit
sys.path.append("@FENCEAGENTSLIBDIR@")
from fencing import *
from fencing import fail, EC_STATUS
-#BEGIN_VERSION_GENERATION
-RELEASE_VERSION="New Brocade Agent - test release on steroids"
-REDHAT_COPYRIGHT=""
-BUILD_DATE="March, 20013"
-#END_VERSION_GENERATION
-
def set_power_status(conn, options):
action = {
'on' : "portCfgPersistentEnable",
'off': "portCfgPersistentDisable"
}[options["--action"]]
conn.send_eol(action + " " + options["--plug"])
conn.log_expect(options["--command-prompt"], int(options["--power-timeout"]))
def get_power_status(conn, options):
line_re = re.compile(r'=========', re.IGNORECASE)
outlets = {}
in_index = False
conn.send_eol("switchshow")
conn.log_expect(options["--command-prompt"], int(options["--power-timeout"]))
for line in str(conn.before).split("\n"):
if line_re.search(line):
in_index = True
elif in_index and line.lstrip()[0].isdigit():
tokens = line.lstrip().split()
status = "off" if len(tokens) > 7 and tokens[7] == "Disabled" else "on"
outlets[tokens[0]] = ("", status)
if ["list", "monitor"].count(options["--action"]) == 0:
(_, status) = outlets[options["--plug"]]
return status
else:
return outlets
def main():
device_opt = ["ipaddr", "login", "passwd", "cmd_prompt", "secure", \
"port", "fabric_fencing", "telnet"]
atexit.register(atexit_handler)
all_opt["cmd_prompt"]["default"] = ["> "]
options = check_input(device_opt, process_input(device_opt))
options["eol"] = "\n"
docs = {}
docs["shortdesc"] = "Fence agent for HP Brocade over telnet/ssh"
docs["longdesc"] = "fence_brocade is an I/O Fencing agent which can be used with Brocade FC switches. \
It logs into a Brocade switch via telnet and disables a specified port. Disabling the port which a machine is \
connected to effectively fences that machine. Lengthy telnet connections to the switch should be avoided while \
a GFS cluster is running because the connection will block any necessary fencing actions. \
\
After a fence operation has taken place the fenced machine can no longer connect to the Brocade FC switch. \
When the fenced machine is ready to be brought back into the GFS cluster (after reboot) the port on the Brocade \
FC switch needs to be enabled. This can be done by running fence_brocade and specifying the enable action"
docs["vendorurl"] = "http://www.brocade.com"
show_docs(options, docs)
##
## Operate the fencing device
####
conn = fence_login(options)
result = fence_action(conn, options, set_power_status, get_power_status, get_power_status)
fence_logout(conn, "exit")
sys.exit(result)
if __name__ == "__main__":
main()
diff --git a/fence/agents/cisco_mds/fence_cisco_mds.py b/fence/agents/cisco_mds/fence_cisco_mds.py
index cb3c9605..fbb876a9 100644
--- a/fence/agents/cisco_mds/fence_cisco_mds.py
+++ b/fence/agents/cisco_mds/fence_cisco_mds.py
@@ -1,100 +1,94 @@
#!@PYTHON@ -tt
# The Following agent has been tested on:
# - Cisco MDS UROS 9134 FC (1 Slot) Chassis ("1/2/4 10 Gbps FC/Supervisor-2") Motorola, e500v2
# with BIOS 1.0.16, kickstart 4.1(1c), system 4.1(1c)
# - Cisco MDS 9124 (1 Slot) Chassis ("1/2/4 Gbps FC/Supervisor-2") Motorola, e500
# with BIOS 1.0.16, kickstart 4.1(1c), system 4.1(1c)
import sys, re
import atexit
sys.path.append("@FENCEAGENTSLIBDIR@")
from fencing import *
from fencing import fail_usage, array_to_dict
from fencing_snmp import FencingSnmp
-#BEGIN_VERSION_GENERATION
-RELEASE_VERSION="Cisco MDS 9xxx SNMP fence agent"
-REDHAT_COPYRIGHT=""
-BUILD_DATE=""
-#END_VERSION_GENERATION
-
### CONSTANTS ###
# Cisco admin status
PORT_ADMIN_STATUS_OID = ".1.3.6.1.2.1.75.1.2.2.1.1"
# IF-MIB trees for alias, status and port
ALIASES_OID = ".1.3.6.1.2.1.31.1.1.1.18"
PORTS_OID = ".1.3.6.1.2.1.2.2.1.2"
### GLOBAL VARIABLES ###
# OID converted from fc port name (fc(x)/(y))
PORT_OID = ""
### FUNCTIONS ###
# Convert cisco port name (fc(x)/(y)) to OID
def cisco_port2oid(port):
port = port.lower()
nums = re.match(r'^fc(\d+)/(\d+)$', port)
if nums and len(nums.groups()) == 2:
return "%s.%d.%d"% (PORT_ADMIN_STATUS_OID, int(nums.group(1))+21, int(nums.group(2))-1)
else:
fail_usage("Mangled port number: %s"%(port))
def get_power_status(conn, options):
(_, status) = conn.get(PORT_OID)
return status == "1" and "on" or "off"
def set_power_status(conn, options):
conn.set(PORT_OID, (options["--action"] == "on" and 1 or 2))
def get_outlets_status(conn, options):
result = {}
res_fc = conn.walk(PORTS_OID, 30)
res_aliases = array_to_dict(conn.walk(ALIASES_OID, 30))
fc_re = re.compile(r'^"fc\d+/\d+"$')
for x in res_fc:
if fc_re.match(x[1]):
port_num = x[0].split('.')[-1]
port_name = x[1].strip('"')
port_alias = (port_num in res_aliases and res_aliases[port_num].strip('"') or "")
port_status = ""
result[port_name] = (port_alias, port_status)
return result
# Main agent method
def main():
global PORT_OID
device_opt = ["fabric_fencing", "ipaddr", "login", "passwd", "no_login", "no_password", \
"port", "snmp_version", "snmp"]
atexit.register(atexit_handler)
options = check_input(device_opt, process_input(device_opt))
docs = {}
docs["shortdesc"] = "Fence agent for Cisco MDS"
docs["longdesc"] = "fence_cisco_mds is an I/O Fencing agent \
which can be used with any Cisco MDS 9000 series with SNMP enabled device."
docs["vendorurl"] = "http://www.cisco.com"
show_docs(options, docs)
if not options["--action"] in ["list", "monitor"]:
PORT_OID = cisco_port2oid(options["--plug"])
# Operate the fencing device
result = fence_action(FencingSnmp(options), options, set_power_status, get_power_status, get_outlets_status)
sys.exit(result)
if __name__ == "__main__":
main()
diff --git a/fence/agents/cisco_ucs/fence_cisco_ucs.py b/fence/agents/cisco_ucs/fence_cisco_ucs.py
index 7102c445..d509b3e0 100644
--- a/fence/agents/cisco_ucs/fence_cisco_ucs.py
+++ b/fence/agents/cisco_ucs/fence_cisco_ucs.py
@@ -1,202 +1,196 @@
#!@PYTHON@ -tt
import sys, re
import pycurl, io
import logging
import atexit
sys.path.append("@FENCEAGENTSLIBDIR@")
from fencing import *
from fencing import fail, EC_STATUS, EC_LOGIN_DENIED, run_delay
-#BEGIN_VERSION_GENERATION
-RELEASE_VERSION="New Cisco UCS Agent - test release on steroids"
-REDHAT_COPYRIGHT=""
-BUILD_DATE="March, 2008"
-#END_VERSION_GENERATION
-
RE_COOKIE = re.compile("<aaaLogin .* outCookie=\"(.*?)\"", re.IGNORECASE)
RE_STATUS = re.compile("<lsPower .*? state=\"(.*?)\"", re.IGNORECASE)
RE_GET_DN = re.compile(" dn=\"(.*?)\"", re.IGNORECASE)
RE_GET_PNDN = re.compile(" pndn=\"(.*?)\"", re.IGNORECASE)
RE_GET_DESC = re.compile(" descr=\"(.*?)\"", re.IGNORECASE)
RE_GET_OPERPOWER = re.compile(" operPower=\"(.*?)\"", re.IGNORECASE)
RE_GET_PRESENCE = re.compile(" presence=\"(.*?)\"", re.IGNORECASE)
options_global = None
def get_power_status(conn, options):
del conn
res = send_command(options, "<configResolveDn cookie=\"" + options["cookie"] +
"\" inHierarchical=\"false\" dn=\"org-root" + options["--suborg"] + "/ls-" +
options["--plug"] + "\"/>", int(options["--shell-timeout"]))
result = RE_GET_PNDN.search(res)
if result == None:
pndn = ""
else:
pndn = result.group(1)
if pndn.strip() == "":
if "--missing-as-off" in options:
return "off"
else:
fail(EC_STATUS)
res = send_command(options, "<configResolveDn cookie=\"" + options["cookie"] +
"\" inHierarchical=\"false\" dn=\"" + pndn +
"\"/>", int(options["--shell-timeout"]))
result = RE_GET_PRESENCE.search(res)
if result == None:
fail(EC_STATUS)
else:
presence_status = result.group(1)
if presence_status in ["missing", "mismatch"]:
return "off"
else:
result = RE_GET_OPERPOWER.search(res)
if result == None:
fail(EC_STATUS)
else:
power_status = result.group(1)
if power_status == "on":
return "on"
else:
return "off"
def set_power_status(conn, options):
del conn
action = {
'on' : "admin-up",
'off' : "admin-down"
}[options["--action"]]
send_command(options, "<configConfMos cookie=\"" + options["cookie"] + "\" inHierarchical=\"no\">" +
"<inConfigs><pair key=\"org-root" + options["--suborg"] + "/ls-" + options["--plug"] +
"/power\">" + "<lsPower dn=\"org-root/ls-" + options["--plug"] + "/power\" state=\"" +
action + "\" status=\"modified\" />" + "</pair></inConfigs></configConfMos>",
int(options["--shell-timeout"]))
return
def get_list(conn, options):
del conn
outlets = {}
try:
res = send_command(options, "<configResolveClass cookie=\"" + options["cookie"] +
"\" inHierarchical=\"false\" classId=\"lsServer\"/>", int(options["--shell-timeout"]))
lines = res.split("<lsServer ")
for i in range(1, len(lines)):
node_name = RE_GET_DN.search(lines[i]).group(1)
desc = RE_GET_DESC.search(lines[i]).group(1)
outlets[node_name] = (desc, None)
except AttributeError:
return {}
except IndexError:
return {}
return outlets
def send_command(opt, command, timeout):
## setup correct URL
if "--ssl" in opt or "--ssl-secure" in opt or "--ssl-insecure" in opt:
url = "https:"
else:
url = "http:"
url += "//" + opt["--ip"] + ":" + str(opt["--ipport"]) + "/nuova"
## send command through pycurl
conn = pycurl.Curl()
web_buffer = io.BytesIO()
conn.setopt(pycurl.URL, url.encode("ascii"))
conn.setopt(pycurl.HTTPHEADER, ["Content-type: text/xml"])
conn.setopt(pycurl.POSTFIELDS, command)
conn.setopt(pycurl.WRITEFUNCTION, web_buffer.write)
conn.setopt(pycurl.TIMEOUT, timeout)
if "--ssl" in opt or "--ssl-secure" in opt:
conn.setopt(pycurl.SSL_VERIFYPEER, 1)
conn.setopt(pycurl.SSL_VERIFYHOST, 2)
if "--ssl-insecure" in opt:
conn.setopt(pycurl.SSL_VERIFYPEER, 0)
conn.setopt(pycurl.SSL_VERIFYHOST, 0)
conn.perform()
result = web_buffer.getvalue().decode()
logging.debug("%s\n", command)
logging.debug("%s\n", result)
return result
def define_new_opts():
all_opt["suborg"] = {
"getopt" : ":",
"longopt" : "suborg",
"help" : "--suborg=[path] Additional path needed to access suborganization",
"required" : "0",
"shortdesc" : "Additional path needed to access suborganization",
"default" : "",
"order" : 1}
def logout():
### Logout; we do not care about result as we will end in any case
try:
send_command(options_global, "<aaaLogout inCookie=\"" + options_global["cookie"] + "\" />",
int(options_global["--shell-timeout"]))
except Exception:
pass
def main():
global options_global
device_opt = ["ipaddr", "login", "passwd", "ssl", "notls", "port", "web", "suborg", "missing_as_off"]
atexit.register(atexit_handler)
atexit.register(logout)
define_new_opts()
options_global = check_input(device_opt, process_input(device_opt))
docs = {}
docs["shortdesc"] = "Fence agent for Cisco UCS"
docs["longdesc"] = "fence_cisco_ucs is an I/O Fencing agent which can be \
used with Cisco UCS to fence machines."
docs["vendorurl"] = "http://www.cisco.com"
show_docs(options_global, docs)
run_delay(options_global)
### Login
try:
res = send_command(options_global, "<aaaLogin inName=\"" + options_global["--username"] +
"\" inPassword=\"" + options_global["--password"] + "\" />", int(options_global["--login-timeout"]))
result = RE_COOKIE.search(res)
if result == None:
## Cookie is absenting in response
fail(EC_LOGIN_DENIED)
except Exception:
fail(EC_LOGIN_DENIED)
options_global["cookie"] = result.group(1)
##
## Modify suborg to format /suborg
if options_global["--suborg"] != "":
options_global["--suborg"] = "/" + options_global["--suborg"].lstrip("/").rstrip("/")
##
## Fence operations
####
result = fence_action(None, options_global, set_power_status, get_power_status, get_list)
## Logout is done every time at atexit phase
sys.exit(result)
if __name__ == "__main__":
main()
diff --git a/fence/agents/compute/fence_compute.py b/fence/agents/compute/fence_compute.py
index 5ccd0baf..5f9fdd01 100644
--- a/fence/agents/compute/fence_compute.py
+++ b/fence/agents/compute/fence_compute.py
@@ -1,474 +1,468 @@
#!@PYTHON@ -tt
import sys
import time
import atexit
import logging
import requests.exceptions
sys.path.append("@FENCEAGENTSLIBDIR@")
from fencing import *
from fencing import fail_usage, is_executable, run_command, run_delay
-#BEGIN_VERSION_GENERATION
-RELEASE_VERSION="4.0.11"
-BUILD_DATE="(built Wed Nov 12 06:33:38 EST 2014)"
-REDHAT_COPYRIGHT="Copyright (C) Red Hat, Inc. 2004-2010 All rights reserved."
-#END_VERSION_GENERATION
-
override_status = ""
nova = None
EVACUABLE_TAG = "evacuable"
TRUE_TAGS = ['true']
def get_power_status(_, options):
global override_status
status = "unknown"
logging.debug("get action: " + options["--action"])
if len(override_status):
logging.debug("Pretending we're " + override_status)
return override_status
if nova:
try:
services = nova.services.list(host=options["--plug"])
for service in services:
logging.debug("Status of %s is %s" % (service.binary, service.state))
if service.binary == "nova-compute":
if service.state == "up":
status = "on"
elif service.state == "down":
status = "off"
else:
logging.debug("Unknown status detected from nova: " + service.state)
break
except requests.exception.ConnectionError as err:
logging.warning("Nova connection failed: " + str(err))
return status
# NOTE(sbauza); We mimic the host-evacuate module since it's only a contrib
# module which is not stable
def _server_evacuate(server, on_shared_storage):
success = False
error_message = ""
try:
logging.debug("Resurrecting instance: %s" % server)
(response, dictionary) = nova.servers.evacuate(server=server, on_shared_storage=on_shared_storage)
if response == None:
error_message = "No response while evacuating instance"
elif response.status_code == 200:
success = True
error_message = response.reason
else:
error_message = response.reason
except Exception as e:
error_message = "Error while evacuating instance: %s" % e
return {
"uuid": server,
"accepted": success,
"reason": error_message,
}
def _is_server_evacuable(server, evac_flavors, evac_images):
if server.flavor.get('id') in evac_flavors:
return True
if server.image.get('id') in evac_images:
return True
logging.debug("Instance %s is not evacuable" % server.image.get('id'))
return False
def _get_evacuable_flavors():
result = []
flavors = nova.flavors.list()
# Since the detailed view for all flavors doesn't provide the extra specs,
# we need to call each of the flavor to get them.
for flavor in flavors:
tag = flavor.get_keys().get(EVACUABLE_TAG)
if tag and tag.strip().lower() in TRUE_TAGS:
result.append(flavor.id)
return result
def _get_evacuable_images():
result = []
images = nova.images.list(detailed=True)
for image in images:
if hasattr(image, 'metadata'):
tag = image.metadata.get(EVACUABLE_TAG)
if tag and tag.strip().lower() in TRUE_TAGS:
result.append(image.id)
return result
def _host_evacuate(options):
result = True
images = _get_evacuable_images()
flavors = _get_evacuable_flavors()
servers = nova.servers.list(search_opts={'host': options["--plug"], 'all_tenants': 1 })
if options["--instance-filtering"] == "False":
logging.debug("Not evacuating anything")
evacuables = []
elif len(flavors) or len(images):
logging.debug("Filtering images and flavors: %s %s" % (repr(flavors), repr(images)))
# Identify all evacuable servers
logging.debug("Checking %s" % repr(servers))
evacuables = [server for server in servers
if _is_server_evacuable(server, flavors, images)]
logging.debug("Evacuating %s" % repr(evacuables))
else:
logging.debug("Evacuating all images and flavors")
evacuables = servers
if options["--no-shared-storage"] != "False":
on_shared_storage = False
else:
on_shared_storage = True
for server in evacuables:
logging.debug("Processing %s" % server)
if hasattr(server, 'id'):
response = _server_evacuate(server.id, on_shared_storage)
if response["accepted"]:
logging.debug("Evacuated %s from %s: %s" %
(response["uuid"], options["--plug"], response["reason"]))
else:
logging.error("Evacuation of %s on %s failed: %s" %
(response["uuid"], options["--plug"], response["reason"]))
result = False
else:
logging.error("Could not evacuate instance: %s" % server.to_dict())
# Should a malformed instance result in a failed evacuation?
# result = False
return result
def set_attrd_status(host, status, options):
logging.debug("Setting fencing status for %s to %s" % (host, status))
run_command(options, "attrd_updater -p -n evacuate -Q -N %s -U %s" % (host, status))
def set_power_status(_, options):
global override_status
override_status = ""
logging.debug("set action: " + options["--action"])
if not nova:
return
if options["--action"] == "on":
if get_power_status(_, options) != "on":
# Forcing the service back up in case it was disabled
nova.services.enable(options["--plug"], 'nova-compute')
try:
# Forcing the host back up
nova.services.force_down(
options["--plug"], "nova-compute", force_down=False)
except Exception as e:
# In theory, if force_down=False fails, that's for the exact
# same possible reasons that below with force_down=True
# eg. either an incompatible version or an old client.
# Since it's about forcing back to a default value, there is
# no real worries to just consider it's still okay even if the
# command failed
logging.info("Exception from attempt to force "
"host back up via nova API: "
"%s: %s" % (e.__class__.__name__, e))
else:
# Pretend we're 'on' so that the fencing library doesn't loop forever waiting for the node to boot
override_status = "on"
return
try:
nova.services.force_down(
options["--plug"], "nova-compute", force_down=True)
except Exception as e:
# Something went wrong when we tried to force the host down.
# That could come from either an incompatible API version
# eg. UnsupportedVersion or VersionNotFoundForAPIMethod
# or because novaclient is old and doesn't include force_down yet
# eg. AttributeError
# In that case, fallbacking to wait for Nova to catch the right state.
logging.error("Exception from attempt to force host down via nova API: "
"%s: %s" % (e.__class__.__name__, e))
# need to wait for nova to update its internal status or we
# cannot call host-evacuate
while get_power_status(_, options) != "off":
# Loop forever if need be.
#
# Some callers (such as Pacemaker) will have a timer
# running and kill us if necessary
logging.debug("Waiting for nova to update its internal state for %s" % options["--plug"])
time.sleep(1)
if not _host_evacuate(options):
sys.exit(1)
return
def fix_domain(options):
domains = {}
last_domain = None
if nova:
# Find it in nova
hypervisors = nova.hypervisors.list()
for hypervisor in hypervisors:
shorthost = hypervisor.hypervisor_hostname.split('.')[0]
if shorthost == hypervisor.hypervisor_hostname:
# Nova is not using FQDN
calculated = ""
else:
# Compute nodes are named as FQDN, strip off the hostname
calculated = hypervisor.hypervisor_hostname.replace(shorthost+".", "")
domains[calculated] = shorthost
if calculated == last_domain:
# Avoid complaining for each compute node with the same name
# One hopes they don't appear interleaved as A.com B.com A.com B.com
logging.debug("Calculated the same domain from: %s" % hypervisor.hypervisor_hostname)
elif "--domain" in options and options["--domain"] == calculated:
# Supplied domain name is valid
return
elif "--domain" in options:
# Warn in case nova isn't available at some point
logging.warning("Supplied domain '%s' does not match the one calculated from: %s"
% (options["--domain"], hypervisor.hypervisor_hostname))
last_domain = calculated
if len(domains) == 0 and "--domain" not in options:
logging.error("Could not calculate the domain names used by compute nodes in nova")
elif len(domains) == 1 and "--domain" not in options:
options["--domain"] = last_domain
return options["--domain"]
elif len(domains) == 1:
logging.error("Overriding supplied domain '%s' does not match the one calculated from: %s"
% (options["--domain"], hypervisor.hypervisor_hostname))
options["--domain"] = last_domain
return options["--domain"]
elif len(domains) > 1:
logging.error("The supplied domain '%s' did not match any used inside nova: %s"
% (options["--domain"], repr(domains)))
sys.exit(1)
return None
def fix_plug_name(options):
if options["--action"] == "list":
return
if "--plug" not in options:
return
calculated = fix_domain(options)
short_plug = options["--plug"].split('.')[0]
logging.debug("Checking target '%s' against calculated domain '%s'"% (options["--plug"], options["--domain"]))
if "--domain" not in options:
# Nothing supplied and nova not available... what to do... nothing
return
elif options["--domain"] == "":
# Ensure any domain is stripped off since nova isn't using FQDN
options["--plug"] = short_plug
elif options["--domain"] in options["--plug"]:
# Plug already contains the domain, don't re-add
return
else:
# Add the domain to the plug
options["--plug"] = short_plug + "." + options["--domain"]
def get_plugs_list(_, options):
result = {}
if nova:
hypervisors = nova.hypervisors.list()
for hypervisor in hypervisors:
longhost = hypervisor.hypervisor_hostname
shorthost = longhost.split('.')[0]
result[longhost] = ("", None)
result[shorthost] = ("", None)
return result
def create_nova_connection(options):
global nova
try:
from novaclient import client
from novaclient.exceptions import NotAcceptable
except ImportError:
fail_usage("Nova not found or not accessible")
versions = [ "2.11", "2" ]
for version in versions:
nova = client.Client(version,
options["--username"],
options["--password"],
options["--tenant-name"],
options["--auth-url"],
insecure=options["--insecure"],
region_name=options["--region-name"],
endpoint_type=options["--endpoint-type"],
http_log_debug=options.has_key("--verbose"))
try:
nova.hypervisors.list()
return
except NotAcceptable as e:
logging.warning(e)
except Exception as e:
logging.warning("Nova connection failed. %s: %s" % (e.__class__.__name__, e))
logging.warning("Couldn't obtain a supported connection to nova, tried: %s\n" % repr(versions))
def define_new_opts():
all_opt["endpoint-type"] = {
"getopt" : "e:",
"longopt" : "endpoint-type",
"help" : "-e, --endpoint-type=[endpoint] Nova Endpoint type (publicURL, internalURL, adminURL)",
"required" : "0",
"shortdesc" : "Nova Endpoint type",
"default" : "internalURL",
"order": 1,
}
all_opt["tenant-name"] = {
"getopt" : "t:",
"longopt" : "tenant-name",
"help" : "-t, --tenant-name=[tenant] Keystone Admin Tenant",
"required" : "0",
"shortdesc" : "Keystone Admin Tenant",
"default" : "",
"order": 1,
}
all_opt["auth-url"] = {
"getopt" : "k:",
"longopt" : "auth-url",
"help" : "-k, --auth-url=[url] Keystone Admin Auth URL",
"required" : "0",
"shortdesc" : "Keystone Admin Auth URL",
"default" : "",
"order": 1,
}
all_opt["region-name"] = {
"getopt" : "",
"longopt" : "region-name",
"help" : "--region-name=[region] Region Name",
"required" : "0",
"shortdesc" : "Region Name",
"default" : "",
"order": 1,
}
all_opt["insecure"] = {
"getopt" : "",
"longopt" : "insecure",
"help" : "--insecure Explicitly allow agent to perform \"insecure\" TLS (https) requests",
"required" : "0",
"shortdesc" : "Allow Insecure TLS Requests",
"default" : "False",
"order": 2,
}
all_opt["domain"] = {
"getopt" : "d:",
"longopt" : "domain",
"help" : "-d, --domain=[string] DNS domain in which hosts live, useful when the cluster uses short names and nova uses FQDN",
"required" : "0",
"shortdesc" : "DNS domain in which hosts live",
"order": 5,
}
all_opt["record-only"] = {
"getopt" : "r:",
"longopt" : "record-only",
"help" : "--record-only Record the target as needing evacuation but as yet do not intiate it",
"required" : "0",
"shortdesc" : "Only record the target as needing evacuation",
"default" : "False",
"order": 5,
}
all_opt["instance-filtering"] = {
"getopt" : "",
"longopt" : "instance-filtering",
"help" : "--instance-filtering Allow instances created from images and flavors with evacuable=true to be evacuated (or all if no images/flavors have been tagged)",
"required" : "0",
"shortdesc" : "Allow instances to be evacuated",
"default" : "True",
"order": 5,
}
all_opt["no-shared-storage"] = {
"getopt" : "",
"longopt" : "no-shared-storage",
"help" : "--no-shared-storage Disable functionality for shared storage",
"required" : "0",
"shortdesc" : "Disable functionality for dealing with shared storage",
"default" : "False",
"order": 5,
}
def main():
global override_status
atexit.register(atexit_handler)
device_opt = ["login", "passwd", "tenant-name", "auth-url", "fabric_fencing", "on_target",
"no_login", "no_password", "port", "domain", "no-shared-storage", "endpoint-type",
"record-only", "instance-filtering", "insecure", "region-name"]
define_new_opts()
all_opt["shell_timeout"]["default"] = "180"
options = check_input(device_opt, process_input(device_opt))
docs = {}
docs["shortdesc"] = "Fence agent for the automatic resurrection of OpenStack compute instances"
docs["longdesc"] = "Used to tell Nova that compute nodes are down and to reschedule flagged instances"
docs["vendorurl"] = ""
show_docs(options, docs)
if options["--record-only"] in [ "2", "Disabled", "disabled" ]:
sys.exit(0)
run_delay(options)
create_nova_connection(options)
fix_plug_name(options)
if options["--record-only"] in [ "1", "True", "true", "Yes", "yes"]:
if options["--action"] == "on":
set_attrd_status(options["--plug"], "no", options)
sys.exit(0)
elif options["--action"] in ["off", "reboot"]:
set_attrd_status(options["--plug"], "yes", options)
sys.exit(0)
elif options["--action"] in ["monitor", "status"]:
sys.exit(0)
if options["--action"] in ["off", "reboot"]:
# Pretend we're 'on' so that the fencing library will always call set_power_status(off)
override_status = "on"
if options["--action"] == "on":
# Pretend we're 'off' so that the fencing library will always call set_power_status(on)
override_status = "off"
result = fence_action(None, options, set_power_status, get_power_status, get_plugs_list, None)
sys.exit(result)
if __name__ == "__main__":
main()
diff --git a/fence/agents/docker/fence_docker.py b/fence/agents/docker/fence_docker.py
index 2bfa5eae..b2921016 100644
--- a/fence/agents/docker/fence_docker.py
+++ b/fence/agents/docker/fence_docker.py
@@ -1,164 +1,158 @@
#!@PYTHON@ -tt
import atexit
import sys
import io
import logging
import pycurl
import json
sys.path.append("@FENCEAGENTSLIBDIR@")
from fencing import fail_usage, all_opt, fence_action, atexit_handler, check_input, process_input, show_docs, run_delay
-#BEGIN_VERSION_GENERATION
-RELEASE_VERSION = ""
-REDHAT_COPYRIGHT = ""
-BUILD_DATE = ""
-#END_VERSION_GENERATION
-
def get_power_status(conn, options):
del conn
status = send_cmd(options, "containers/%s/json" % options["--plug"])
if status is None:
return None
return "on" if status["State"]["Running"] else "off"
def set_power_status(conn, options):
del conn
if options["--action"] == "on":
send_cmd(options, "containers/%s/start" % options["--plug"], True)
else:
send_cmd(options, "containers/%s/kill" % options["--plug"], True)
return
def reboot_cycle(conn, options):
del conn
send_cmd(options, "containers/%s/restart" % options["--plug"], True)
return get_power_status(conn, options)
def get_list(conn, options):
del conn
output = send_cmd(options, "containers/json?all=1")
containers = {}
for container in output:
containers[container["Id"]] = (container["Names"][0], {True:"off", False: "on"}[container["Status"][:4].lower() == "exit"])
return containers
def send_cmd(options, cmd, post = False):
url = "http%s://%s:%s/v%s/%s" % ("s" if "--ssl" in options else "", options["--ip"], options["--ipport"], options["--api-version"], cmd)
conn = pycurl.Curl()
output_buffer = io.BytesIO()
if logging.getLogger().getEffectiveLevel() < logging.WARNING:
conn.setopt(pycurl.VERBOSE, True)
conn.setopt(pycurl.HTTPGET, 1)
conn.setopt(pycurl.URL, url.encode("ascii"))
if post:
conn.setopt(pycurl.POST, 1)
conn.setopt(pycurl.POSTFIELDSIZE, 0)
conn.setopt(pycurl.WRITEFUNCTION, output_buffer.write)
conn.setopt(pycurl.TIMEOUT, int(options["--shell-timeout"]))
if "--ssl" in options:
if not (set(("--tlscert", "--tlskey", "--tlscacert")) <= set(options)):
fail_usage("Failed. If --ssl option is used, You have to also \
specify: --tlscert, --tlskey and --tlscacert")
conn.setopt(pycurl.SSL_VERIFYPEER, 1)
conn.setopt(pycurl.SSLCERT, options["--tlscert"])
conn.setopt(pycurl.SSLKEY, options["--tlskey"])
conn.setopt(pycurl.CAINFO, options["--tlscacert"])
else:
conn.setopt(pycurl.SSL_VERIFYPEER, 0)
conn.setopt(pycurl.SSL_VERIFYHOST, 0)
logging.debug("URL: " + url)
try:
conn.perform()
result = output_buffer.getvalue().decode()
return_code = conn.getinfo(pycurl.RESPONSE_CODE)
logging.debug("RESULT [" + str(return_code) + \
"]: " + result)
conn.close()
if return_code == 200:
return json.loads(result)
except pycurl.error:
logging.error("Connection failed")
except:
if result is not None:
logging.error(result)
logging.error("Cannot parse json")
return None
def main():
atexit.register(atexit_handler)
all_opt["tlscert"] = {
"getopt" : ":",
"longopt" : "tlscert",
"help" : "--tlscert "
"Path to client certificate for TLS authentication",
"required" : "0",
"shortdesc" : "Path to client certificate (PEM format) \
for TLS authentication. Required if --ssl option is used.",
"order": 2
}
all_opt["tlskey"] = {
"getopt" : ":",
"longopt" : "tlskey",
"help" : "--tlskey "
"Path to client key for TLS authentication",
"required" : "0",
"shortdesc" : "Path to client key (PEM format) for TLS \
authentication. Required if --ssl option is used.",
"order": 2
}
all_opt["tlscacert"] = {
"getopt" : ":",
"longopt" : "tlscacert",
"help" : "--tlscacert "
"Path to CA certificate for TLS authentication",
"required" : "0",
"shortdesc" : "Path to CA certificate (PEM format) for \
TLS authentication. Required if --ssl option is used.",
"order": 2
}
all_opt["api_version"] = {
"getopt" : ":",
"longopt" : "api-version",
"help" : "--api-version "
"Version of Docker Remote API (default: 1.11)",
"required" : "0",
"order" : 2,
"default" : "1.11",
}
device_opt = ["ipaddr", "no_password", "no_login", "port", "method", "web", "tlscert", "tlskey", "tlscacert", "ssl", "api_version"]
options = check_input(device_opt, process_input(device_opt))
docs = { }
docs["shortdesc"] = "Fence agent for Docker"
docs["longdesc"] = "fence_docker is I/O fencing agent which \
can be used with the Docker Engine containers. You can use this \
fence-agent without any authentication, or you can use TLS authentication \
(use --ssl option, more info about TLS authentication in docker: \
http://docs.docker.com/examples/https/)."
docs["vendorurl"] = "www.docker.io"
show_docs(options, docs)
run_delay(options)
result = fence_action(None, options, set_power_status, get_power_status, get_list, reboot_cycle)
sys.exit(result)
if __name__ == "__main__":
main()
diff --git a/fence/agents/drac/fence_drac.py b/fence/agents/drac/fence_drac.py
index f698b398..be3e9a58 100644
--- a/fence/agents/drac/fence_drac.py
+++ b/fence/agents/drac/fence_drac.py
@@ -1,68 +1,62 @@
#!@PYTHON@ -tt
import sys, re
import atexit
sys.path.append("@FENCEAGENTSLIBDIR@")
from fencing import *
-#BEGIN_VERSION_GENERATION
-RELEASE_VERSION=""
-REDHAT_COPYRIGHT=""
-BUILD_DATE=""
-#END_VERSION_GENERATION
-
def get_power_status(conn, options):
conn.send_eol("getmodinfo")
conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"]))
status = re.compile(r"\s+(on|off)\s+", re.IGNORECASE).search(conn.before).group(1)
return status.lower().strip()
def set_power_status(conn, options):
action = {
'on' : "powerup",
'off': "powerdown"
}[options["--action"]]
conn.send_eol("serveraction -d 0 " + action)
conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"]))
def main():
device_opt = ["ipaddr", "login", "passwd", "cmd_prompt", "telnet"]
atexit.register(atexit_handler)
opt = process_input(device_opt)
if "--username" in opt:
all_opt["cmd_prompt"]["default"] = ["\\[" + opt["--username"] + "\\]# "]
else:
all_opt["cmd_prompt"]["default"] = ["\\[" "username" + "\\]# "]
options = check_input(device_opt, opt)
docs = {}
docs["shortdesc"] = "I/O Fencing agent for Dell DRAC IV"
docs["longdesc"] = "fence_drac is an I/O Fencing agent which can be used with \
the Dell Remote Access Card (DRAC). This card provides remote access to controlling \
power to a server. It logs into the DRAC through the telnet interface of the card. By \
default, the telnet interface is not enabled. To enable the interface, you will need \
to use the racadm command in the racser-devel rpm available from Dell. \
\
To enable telnet on the DRAC: \
\
[root]# racadm config -g cfgSerial -o cfgSerialTelnetEnable 1 \
\
[root]# racadm racreset \
"
docs["vendorurl"] = "http://www.dell.com"
show_docs(options, docs)
##
## Operate the fencing device
####
conn = fence_login(options)
result = fence_action(conn, options, set_power_status, get_power_status, None)
fence_logout(conn, "exit")
sys.exit(result)
if __name__ == "__main__":
main()
diff --git a/fence/agents/drac5/fence_drac5.py b/fence/agents/drac5/fence_drac5.py
index df113fea..648ecd91 100644
--- a/fence/agents/drac5/fence_drac5.py
+++ b/fence/agents/drac5/fence_drac5.py
@@ -1,153 +1,147 @@
#!@PYTHON@ -tt
#####
##
## The Following Agent Has Been Tested On:
##
## DRAC Version Firmware
## +-----------------+---------------------------+
## DRAC 5 1.0 (Build 06.05.12)
## DRAC 5 1.21 (Build 07.05.04)
##
## @note: drac_version was removed
#####
import sys, re, time
import atexit
sys.path.append("@FENCEAGENTSLIBDIR@")
from fencing import *
from fencing import fail_usage
-#BEGIN_VERSION_GENERATION
-RELEASE_VERSION="New Drac5 Agent - test release on steroids"
-REDHAT_COPYRIGHT=""
-BUILD_DATE="March, 2008"
-#END_VERSION_GENERATION
-
def get_power_status(conn, options):
if options["--drac-version"] == "DRAC MC":
(_, status) = get_list_devices(conn, options)[options["--plug"]]
else:
if options["--drac-version"] == "DRAC CMC":
conn.send_eol("racadm serveraction powerstatus -m " + options["--plug"])
elif options["--drac-version"] == "DRAC 5":
conn.send_eol("racadm serveraction powerstatus")
conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"]))
status = re.compile(r"(^|: )(ON|OFF|Powering ON|Powering OFF)\s*$",
re.IGNORECASE | re.MULTILINE).search(conn.before).group(2)
if status.lower().strip() in ["on", "powering on", "powering off"]:
return "on"
else:
return "off"
def set_power_status(conn, options):
action = {
'on' : "powerup",
'off': "powerdown"
}[options["--action"]]
if options["--drac-version"] == "DRAC CMC":
conn.send_eol("racadm serveraction " + action + " -m " + options["--plug"])
elif options["--drac-version"] == "DRAC 5":
conn.send_eol("racadm serveraction " + action)
elif options["--drac-version"] == "DRAC MC":
conn.send_eol("racadm serveraction -s " + options["--plug"] + " " + action)
## Fix issue with double-enter [CR/LF]
## We need to read two additional command prompts (one from get + one from set command)
conn.log_expect(options["--command-prompt"], int(options["--power-timeout"]))
if len(conn.before.strip()) == 0:
options["eol"] = options["eol"][:-1]
conn.log_expect(options["--command-prompt"], int(options["--power-timeout"]))
conn.log_expect(options["--command-prompt"], int(options["--power-timeout"]))
def get_list_devices(conn, options):
outlets = {}
if options["--drac-version"] == "DRAC CMC":
conn.send_eol("getmodinfo")
list_re = re.compile(r"^([^\s]*?)\s+Present\s*(ON|OFF)\s*.*$")
conn.log_expect(options["--command-prompt"], int(options["--power-timeout"]))
for line in conn.before.splitlines():
if list_re.search(line):
outlets[list_re.search(line).group(1)] = ("", list_re.search(line).group(2))
elif options["--drac-version"] == "DRAC MC":
conn.send_eol("getmodinfo")
list_re = re.compile(r"^\s*([^\s]*)\s*---->\s*(.*?)\s+Present\s*(ON|OFF)\s*.*$")
conn.log_expect(options["--command-prompt"], int(options["--power-timeout"]))
for line in conn.before.splitlines():
if list_re.search(line):
outlets[list_re.search(line).group(2)] = ("", list_re.search(line).group(3))
elif options["--drac-version"] == "DRAC 5":
## DRAC 5 can be used only for one computer
## standard fence library can't handle correctly situation
## when some fence devices supported by fence agent
## works with 'list' and other should returns 'N/A'
print("N/A")
return outlets
def define_new_opts():
all_opt["drac_version"] = {
"getopt" : "d:",
"longopt" : "drac-version",
"help" : "-d, --drac-version=[version] Force DRAC version to use (DRAC 5|DRAC CMC|DRAC MC)",
"required" : "0",
"shortdesc" : "Force DRAC version to use",
"choices" : ["DRAC CMC", "DRAC MC", "DRAC 5"],
"order" : 1}
def main():
device_opt = ["ipaddr", "login", "passwd", "cmd_prompt", "secure", \
"drac_version", "port", "no_port", "telnet"]
atexit.register(atexit_handler)
define_new_opts()
all_opt["cmd_prompt"]["default"] = [r"\$", r"DRAC\/MC:"]
options = check_input(device_opt, process_input(device_opt))
docs = {}
docs["shortdesc"] = "Fence agent for Dell DRAC CMC/5"
docs["longdesc"] = "fence_drac5 is an I/O Fencing agent \
which can be used with the Dell Remote Access Card v5 or CMC (DRAC). \
This device provides remote access to controlling power to a server. \
It logs into the DRAC through the telnet/ssh interface of the card. \
By default, the telnet interface is not enabled."
docs["vendorurl"] = "http://www.dell.com"
show_docs(options, docs)
##
## Operate the fencing device
######
conn = fence_login(options)
if "--drac-version" not in options:
## autodetect from text issued by fence device
if conn.before.find("CMC") >= 0:
options["--drac-version"] = "DRAC CMC"
elif conn.before.find("DRAC 5") >= 0:
options["--drac-version"] = "DRAC 5"
elif conn.after.find("DRAC/MC") >= 0:
options["--drac-version"] = "DRAC MC"
else:
## Assume this is DRAC 5 by default as we don't want to break anything
options["--drac-version"] = "DRAC 5"
if options["--drac-version"] in ["DRAC MC", "DRAC CMC"]:
if "--plug" not in options and 0 == ["monitor", "list"].count(options["--action"]):
fail_usage("Failed: You have to enter module name (-n)")
result = fence_action(conn, options, set_power_status, get_power_status, get_list_devices)
fence_logout(conn, "exit", 1)
sys.exit(result)
if __name__ == "__main__":
main()
diff --git a/fence/agents/dummy/fence_dummy.py b/fence/agents/dummy/fence_dummy.py
index e4f1589c..8fa2d9af 100644
--- a/fence/agents/dummy/fence_dummy.py
+++ b/fence/agents/dummy/fence_dummy.py
@@ -1,139 +1,133 @@
#!@PYTHON@ -tt
import sys, random
import logging
import time
import atexit
sys.path.append("@FENCEAGENTSLIBDIR@")
from fencing import *
from fencing import fail_usage, run_delay
-#BEGIN_VERSION_GENERATION
-RELEASE_VERSION="New Dummy Agent - test release on steroids"
-REDHAT_COPYRIGHT=""
-BUILD_DATE=""
-#END_VERSION_GENERATION
-
plug_status = "on"
def get_power_status_file(conn, options):
del conn
try:
status_file = open(options["--status-file"], 'r')
except Exception:
return "off"
status = status_file.read()
status_file.close()
return status.lower()
def set_power_status_file(conn, options):
del conn
if not (options["--action"] in ["on", "off"]):
return
status_file = open(options["--status-file"], 'w')
status_file.write(options["--action"])
status_file.close()
def get_power_status_fail(conn, options):
outlets = get_outlets_fail(conn, options)
if len(outlets) == 0 or "--plug" not in options:
fail_usage("Failed: You have to enter existing machine!")
else:
return outlets[options["--plug"]][0]
def set_power_status_fail(conn, options):
global plug_status
del conn
plug_status = "unknown"
if options["--action"] == "on":
plug_status = "off"
def get_outlets_fail(conn, options):
del conn
result = {}
global plug_status
if options["--action"] == "on":
plug_status = "off"
# This fake agent has no port data to list, so we have to make
# something up for the list action.
if options.get("--action", None) == "list":
result["fake_port_1"] = [plug_status, "fake"]
result["fake_port_2"] = [plug_status, "fake"]
elif "--plug" not in options:
fail_usage("Failed: You have to enter existing machine!")
else:
port = options["--plug"]
result[port] = [plug_status, "fake"]
return result
def main():
device_opt = ["no_password", "status_file", "random_sleep_range", "type", "no_port"]
atexit.register(atexit_handler)
all_opt["status_file"] = {
"getopt" : ":",
"longopt" : "status-file",
"help":"--status-file=[file] Name of file that holds current status",
"required" : "0",
"shortdesc" : "File with status",
"default" : "/tmp/fence_dummy.status",
"order": 1
}
all_opt["random_sleep_range"] = {
"getopt" : ":",
"longopt" : "random_sleep_range",
"help":"--random_sleep_range=[seconds] Issue a sleep between 1 and [seconds]",
"required" : "0",
"shortdesc" : "Issue a sleep between 1 and X seconds. Used for testing.",
"order": 1
}
all_opt["type"] = {
"getopt" : ":",
"longopt" : "type",
"help":"--type=[type] Possible types are: file and fail",
"required" : "0",
"shortdesc" : "Type of the dummy fence agent",
"default" : "file",
"order": 1
}
options = check_input(device_opt, process_input(device_opt))
docs = {}
docs["shortdesc"] = "Dummy fence agent"
docs["longdesc"] = "fence_dummy"
docs["vendorurl"] = "http://www.example.com"
show_docs(options, docs)
run_delay(options)
# random sleep for testing
if "--random_sleep_range" in options:
val = int(options["--random_sleep_range"])
ran = random.randint(1, val)
logging.info("Random sleep for %d seconds\n", ran)
time.sleep(ran)
if options["--type"] == "fail":
result = fence_action(None, options, set_power_status_fail, get_power_status_fail, get_outlets_fail)
else:
result = fence_action(None, options, set_power_status_file, get_power_status_file, None)
sys.exit(result)
if __name__ == "__main__":
main()
diff --git a/fence/agents/eaton_snmp/fence_eaton_snmp.py b/fence/agents/eaton_snmp/fence_eaton_snmp.py
index dfd540c0..9fbc0563 100644
--- a/fence/agents/eaton_snmp/fence_eaton_snmp.py
+++ b/fence/agents/eaton_snmp/fence_eaton_snmp.py
@@ -1,235 +1,229 @@
#!@PYTHON@ -tt
# The Following agent has been tested on:
# - Eaton ePDU Managed - SNMP v1
# EATON | Powerware ePDU model: Managed ePDU (PW104MA0UB99), firmware: 01.01.01
# - Eaton ePDU Switched - SNMP v1
# EATON | Powerware ePDU model: Switched ePDU (IPV3600), firmware: 2.0.K
import sys
import atexit
import logging
sys.path.append("@FENCEAGENTSLIBDIR@")
from fencing import *
from fencing import fail_usage
from fencing_snmp import FencingSnmp
-#BEGIN_VERSION_GENERATION
-RELEASE_VERSION="Eaton SNMP fence agent"
-REDHAT_COPYRIGHT=""
-BUILD_DATE=""
-#END_VERSION_GENERATION
-
### CONSTANTS ###
# oid defining fence device
OID_SYS_OBJECT_ID = '.1.3.6.1.2.1.1.2.0'
### GLOBAL VARIABLES ###
# Device - see EatonManagedePDU, EatonSwitchedePDU
device = None
# Port ID
port_id = None
# Switch ID
switch_id = None
# Did we issue a set before get (to adjust OID with Switched ePDU)
after_set = False
# Classes describing Device params
# Managed ePDU
class EatonManagedePDU(object):
status_oid = '.1.3.6.1.4.1.534.6.6.6.1.2.2.1.3.%d'
control_oid = '.1.3.6.1.4.1.534.6.6.6.1.2.2.1.3.%d'
outlet_table_oid = '.1.3.6.1.4.1.534.6.6.6.1.2.2.1.1'
ident_str = "Eaton Managed ePDU"
state_off = 0
state_on = 1
state_cycling = 2 # FIXME: not usable with fence-agents
turn_off = 0
turn_on = 1
turn_cycle = 2 # FIXME: not usable with fence-agents
has_switches = False
# Switched ePDU (Pulizzi 2)
# NOTE: sysOID reports "20677.1", while data are actually at "20677.2"
class EatonSwitchedePDU(object):
status_oid = '.1.3.6.1.4.1.20677.2.6.3.%d.0'
control_oid = '.1.3.6.1.4.1.20677.2.6.2.%d.0'
outlet_table_oid = '.1.3.6.1.4.1.20677.2.6.3'
ident_str = "Eaton Switched ePDU"
state_off = 2
state_on = 1
state_cycling = 0 # Note: this status doesn't exist on this device
turn_off = 2
turn_on = 1
turn_cycle = 3 # FIXME: not usable with fence-agents
has_switches = False
### FUNCTIONS ###
def eaton_set_device(conn):
global device
agents_dir = {'.1.3.6.1.4.1.534.6.6.6':EatonManagedePDU,
'.1.3.6.1.4.1.20677.1':EatonSwitchedePDU,
'.1.3.6.1.4.1.20677.2':EatonSwitchedePDU}
# First resolve type of Eaton
eaton_type = conn.walk(OID_SYS_OBJECT_ID)
if not ((len(eaton_type) == 1) and (eaton_type[0][1] in agents_dir)):
eaton_type = [[None, None]]
device = agents_dir[eaton_type[0][1]]
logging.debug("Trying %s"%(device.ident_str))
def eaton_resolv_port_id(conn, options):
global port_id, switch_id
if device == None:
eaton_set_device(conn)
# Restore the increment, that was removed in main for ePDU Managed
if device.ident_str == "Eaton Switched ePDU":
options["--plug"] = str(int(options["--plug"]) + 1)
# Now we resolv port_id/switch_id
if options["--plug"].isdigit() and ((not device.has_switches) or (options["--switch"].isdigit())):
port_id = int(options["--plug"])
if device.has_switches:
switch_id = int(options["--switch"])
else:
table = conn.walk(device.outlet_table_oid, 30)
for x in table:
if x[1].strip('"') == options["--plug"]:
t = x[0].split('.')
if device.has_switches:
port_id = int(t[len(t)-1])
switch_id = int(t[len(t)-3])
else:
if device.ident_str == "Eaton Switched ePDU":
port_id = int(t[len(t)-3])
else:
port_id = int(t[len(t)-1])
if port_id == None:
# Restore index offset, to provide a valid error output on Managed ePDU
if device.ident_str != "Eaton Switched ePDU":
options["--plug"] = str(int(options["--plug"]) + 1)
fail_usage("Can't find port with name %s!"%(options["--plug"]))
def get_power_status(conn, options):
global port_id, after_set
if port_id == None:
eaton_resolv_port_id(conn, options)
# Ajust OID for Switched ePDU when the get is after a set
if after_set and device.ident_str == "Eaton Switched ePDU":
port_id -= 1
after_set = False
oid = ((device.has_switches) and device.status_oid%(switch_id, port_id) or device.status_oid%(port_id))
try:
(oid, status) = conn.get(oid)
if status == str(device.state_on):
return "on"
elif status == str(device.state_off):
return "off"
else:
return None
except Exception:
return None
def set_power_status(conn, options):
global port_id, after_set
after_set = True
if port_id == None:
eaton_resolv_port_id(conn, options)
# Controls start at #2 on Switched ePDU, since #1 is the global command
if device.ident_str == "Eaton Switched ePDU":
port_id = int(port_id)+1
oid = ((device.has_switches) and device.control_oid%(switch_id, port_id) or device.control_oid%(port_id))
conn.set(oid, (options["--action"] == "on" and device.turn_on or device.turn_off))
def get_outlets_status(conn, options):
outletCount = 0
result = {}
if device == None:
eaton_set_device(conn)
res_ports = conn.walk(device.outlet_table_oid, 30)
for x in res_ports:
outletCount += 1
status = x[1]
t = x[0].split('.')
# Plug indexing start from zero, so we substract '1' from the
# user's given plug number
if device.ident_str == "Eaton Managed ePDU":
port_num = str(int(((device.has_switches) and
"%s:%s"%(t[len(t)-3], t[len(t)-1]) or "%s"%(t[len(t)-1]))) + 1)
# Plug indexing start from zero, so we add '1'
# for the user's exposed plug number
port_name = str(int(x[1].strip('"')) + 1)
port_status = ""
result[port_num] = (port_name, port_status)
else:
# Switched ePDU do not propose an outletCount OID!
# Invalid status (ie value == '0'), retrieved via the walk,
# means the outlet is absent
port_num = str(outletCount)
port_name = str(outletCount)
port_status = ""
if status != '0':
result[port_num] = (port_name, port_status)
return result
# Main agent method
def main():
device_opt = ["ipaddr", "login", "passwd", "no_login", "no_password", \
"port", "snmp_version", "snmp"]
atexit.register(atexit_handler)
all_opt["switch"]["default"] = 1
all_opt["power_wait"]["default"] = 2
all_opt["snmp_version"]["default"] = "1"
all_opt["community"]["default"] = "private"
options = check_input(device_opt, process_input(device_opt))
# Plug indexing start from zero on ePDU Managed, so we substract '1' from
# the user's given plug number.
# For Switched ePDU, we will add this back again later.
if "--plug" in options and options["--plug"].isdigit():
options["--plug"] = str(int(options["--plug"]) - 1)
docs = {}
docs["shortdesc"] = "Fence agent for Eaton over SNMP"
docs["longdesc"] = "fence_eaton_snmp is an I/O Fencing agent \
which can be used with the Eaton network power switch. It logs \
into a device via SNMP and reboots a specified outlet. It supports \
SNMP v1 and v3 with all combinations of authenticity/privacy settings."
docs["vendorurl"] = "http://powerquality.eaton.com"
show_docs(options, docs)
# Operate the fencing device
result = fence_action(FencingSnmp(options), options, set_power_status, get_power_status, get_outlets_status)
sys.exit(result)
if __name__ == "__main__":
main()
diff --git a/fence/agents/emerson/fence_emerson.py b/fence/agents/emerson/fence_emerson.py
index ed5b5ae5..2e65cda0 100644
--- a/fence/agents/emerson/fence_emerson.py
+++ b/fence/agents/emerson/fence_emerson.py
@@ -1,68 +1,62 @@
#!@PYTHON@ -tt
import sys
import atexit
sys.path.append("@FENCEAGENTSLIBDIR@")
from fencing import *
from fencing_snmp import FencingSnmp
-#BEGIN_VERSION_GENERATION
-RELEASE_VERSION="Emerson SNMP fence agent"
-REDHAT_COPYRIGHT=""
-BUILD_DATE=""
-#END_VERSION_GENERATION
-
### CONSTANTS ###
STATUSES_OID = ".1.3.6.1.4.1.476.1.42.3.8.50.20.1.95"
CONTROL_OID = ".1.3.6.1.4.1.476.1.42.3.8.50.20.1.100"
NAMES_OID = ".1.3.6.1.4.1.476.1.42.3.8.50.20.1.10"
# Status constants returned as value from SNMP
STATUS_DOWN = 1
STATUS_UP = 2
# Status constants to set as value to SNMP
STATUS_SET_OFF = 0
STATUS_SET_ON = 1
def get_power_status(conn, options):
(_, status) = conn.get("%s.%s"% (STATUSES_OID, options["--plug"]))
return status == str(STATUS_UP) and "on" or "off"
def set_power_status(conn, options):
conn.set("%s.%s" % (CONTROL_OID, options["--plug"]),
(options["--action"] == "on" and STATUS_SET_ON or STATUS_SET_OFF))
def get_outlets_status(conn, _):
result = {}
res_outlet = conn.walk(STATUSES_OID, 30)
for outlet_info in res_outlet:
port_num = ".".join(outlet_info[0].split('.')[-3:])
port_alias = conn.get("%s.%s"% (NAMES_OID, port_num))[1]
port_status = (outlet_info[1] == str(STATUS_UP) and "on" or "off")
result[port_num] = (port_alias, port_status)
return result
def main():
device_opt = ["ipaddr", "login", "passwd", "no_login", "no_password", \
"port", "snmp_version", "snmp"]
atexit.register(atexit_handler)
all_opt["power_wait"]["default"] = "5"
options = check_input(device_opt, process_input(device_opt))
docs = {}
docs["shortdesc"] = "Fence agent for Emerson over SNMP"
docs["longdesc"] = "fence_emerson is an I/O Fencing agent \
which can be used with MPX and MPH2 managed rack PDU."
docs["vendorurl"] = "http://www.emersonnetworkpower.com"
show_docs(options, docs)
# Operate the fencing device
result = fence_action(FencingSnmp(options), options, set_power_status, get_power_status, get_outlets_status)
sys.exit(result)
if __name__ == "__main__":
main()
diff --git a/fence/agents/eps/fence_eps.py b/fence/agents/eps/fence_eps.py
index 65de6a0b..74c89b95 100644
--- a/fence/agents/eps/fence_eps.py
+++ b/fence/agents/eps/fence_eps.py
@@ -1,134 +1,128 @@
#!@PYTHON@ -tt
# The Following Agent Has Been Tested On:
# ePowerSwitch 8M+ version 1.0.0.4
import sys, re
import base64, string, socket
import logging
import atexit
sys.path.append("@FENCEAGENTSLIBDIR@")
from fencing import *
from fencing import fail, fail_usage, EC_LOGIN_DENIED, EC_TIMED_OUT, run_delay
if sys.version_info[0] > 2:
import http.client as httplib
else:
import httplib
-#BEGIN_VERSION_GENERATION
-RELEASE_VERSION="ePowerSwitch 8M+ (eps)"
-REDHAT_COPYRIGHT=""
-BUILD_DATE=""
-#END_VERSION_GENERATION
-
# Run command on EPS device.
# @param options Device options
# @param params HTTP GET parameters (without ?)
def eps_run_command(options, params):
try:
# New http connection
conn = httplib.HTTPConnection(options["--ip"])
request_str = "/"+options["--page"]
if params != "":
request_str += "?"+params
logging.debug("GET %s\n", request_str)
conn.putrequest('GET', request_str)
if "--username" in options:
if "--password" not in options:
options["--password"] = "" # Default is empty password
# String for Authorization header
auth_str = 'Basic ' + string.strip(base64.encodestring(options["--username"]+':'+options["--password"]))
logging.debug("Authorization: %s\n", auth_str)
conn.putheader('Authorization', auth_str)
conn.endheaders()
response = conn.getresponse()
logging.debug("%d %s\n", response.status, response.reason)
#Response != OK -> couldn't login
if response.status != 200:
fail(EC_LOGIN_DENIED)
result = response.read()
logging.debug("%s \n", result)
conn.close()
except socket.timeout:
fail(EC_TIMED_OUT)
except socket.error:
fail(EC_LOGIN_DENIED)
return result
def get_power_status(conn, options):
del conn
ret_val = eps_run_command(options, "")
result = {}
status = re.findall(r"p(\d{2})=(0|1)\s*\<br\>", ret_val.lower())
for out_num, out_stat in status:
result[out_num] = ("", (out_stat == "1" and "on" or "off"))
if not options["--action"] in ['monitor', 'list']:
if not options["--plug"] in result:
fail_usage("Failed: You have to enter existing physical plug!")
else:
return result[options["--plug"]][1]
else:
return result
def set_power_status(conn, options):
del conn
eps_run_command(options, "P%s=%s"%(options["--plug"], (options["--action"] == "on" and "1" or "0")))
# Define new option
def eps_define_new_opts():
all_opt["hidden_page"] = {
"getopt" : "c:",
"longopt" : "page",
"help":"-c, --page=[page] Name of hidden page (default: hidden.htm)",
"required" : "0",
"shortdesc" : "Name of hidden page",
"default" : "hidden.htm",
"order": 1
}
# Starting point of fence agent
def main():
device_opt = ["ipaddr", "login", "passwd", "no_login", "no_password", \
"port", "hidden_page", "web"]
atexit.register(atexit_handler)
eps_define_new_opts()
options = check_input(device_opt, process_input(device_opt))
docs = {}
docs["shortdesc"] = "Fence agent for ePowerSwitch"
docs["longdesc"] = "fence_eps is an I/O Fencing agent \
which can be used with the ePowerSwitch 8M+ power switch to fence \
connected machines. Fence agent works ONLY on 8M+ device, because \
this is only one, which has support for hidden page feature. \
\n.TP\n\
Agent basically works by connecting to hidden page and pass \
appropriate arguments to GET request. This means, that hidden \
page feature must be enabled and properly configured."
docs["vendorurl"] = "http://www.epowerswitch.com"
show_docs(options, docs)
run_delay(options)
#Run fence action. Conn is None, beacause we always need open new http connection
result = fence_action(None, options, set_power_status, get_power_status, get_power_status)
sys.exit(result)
if __name__ == "__main__":
main()
diff --git a/fence/agents/hds_cb/fence_hds_cb.py b/fence/agents/hds_cb/fence_hds_cb.py
index 51cf7176..375054cf 100755
--- a/fence/agents/hds_cb/fence_hds_cb.py
+++ b/fence/agents/hds_cb/fence_hds_cb.py
@@ -1,138 +1,132 @@
#!@PYTHON@ -tt
#####
##
## The Following Agent Has Been Tested On:
##
## Model Modle/Firmware
## +--------------------+---------------------------+
## (1) Main application CB2000/A0300-E-6617
##
#####
import sys, re
import atexit
sys.path.append("@FENCEAGENTSLIBDIR@")
from fencing import *
-#BEGIN_VERSION_GENERATION
-RELEASE_VERSION="New Compute Blade 2000 Agent - test release on steroids"
-REDHAT_COPYRIGHT=""
-BUILD_DATE="November, 2012"
-#END_VERSION_GENERATION
-
RE_STATUS_LINE = r"^([0-9]+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+).*$"
def get_power_status(conn, options):
#### Maybe should put a conn.log_expect here to make sure
#### we have properly entered into the main menu
conn.sendline("S") # Enter System Command Mode
conn.log_expect("SVP>", int(options["--shell-timeout"]))
conn.sendline("PC") # Enter partition control
conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"]))
result = {}
# Status can now be obtained from the output of the PC
# command. Line looks like the following:
# "P Power Condition LID lamp Mode Auto power on"
# "0 On Normal Off Basic Synchronized"
# "1 On Normal Off Basic Synchronized"
for line in conn.before.splitlines():
# populate the relevant fields based on regex
partition = re.search(RE_STATUS_LINE, line)
if partition != None:
# find the blade number defined in args
if partition.group(1) == options["--plug"]:
result = partition.group(2).lower()
# We must make sure we go back to the main menu as the
# status is checked before any fencing operations are
# executed. We could in theory save some time by staying in
# the partition control, but the logic is a little cleaner
# this way.
conn.sendline("Q") # Back to system command mode
conn.log_expect("SVP>", int(options["--shell-timeout"]))
conn.sendline("EX") # Back to system console main menu
conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"]))
return result
def set_power_status(conn, options):
action = {
'on' : "P",
'off': "F",
'reboot' : "H",
}[options["--action"]]
conn.sendline("S") # Enter System Command Mode
conn.log_expect("SVP>", int(options["--shell-timeout"]))
conn.sendline("PC") # Enter partition control
conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"]))
conn.sendline("P") # Enter power control menu
conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"]))
conn.sendline(action) # Execute action from array above
conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"]))
conn.sendline(options["--plug"]) # Select blade number from args
conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"]))
conn.sendline("Y") # Confirm action
conn.log_expect("Hit enter key.", int(options["--shell-timeout"]))
conn.sendline("") # Press the any key
conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"]))
conn.sendline("Q") # Quit back to partition control
conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"]))
conn.sendline("Q") # Quit back to system command mode
conn.log_expect("SVP>", int(options["--shell-timeout"]))
conn.sendline("EX") # Quit back to system console menu
conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"]))
def get_blades_list(conn, options):
outlets = {}
conn.sendline("S") # Enter System Command Mode
conn.log_expect("SVP>", int(options["--shell-timeout"]))
conn.sendline("PC") # Enter partition control
conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"]))
# Status can now be obtained from the output of the PC
# command. Line looks like the following:
# "P Power Condition LID lamp Mode Auto power on"
# "0 On Normal Off Basic Synchronized"
# "1 On Normal Off Basic Synchronized"
for line in conn.before.splitlines():
partition = re.search(RE_STATUS_LINE, line)
if partition != None:
outlets[partition.group(1)] = (partition.group(2), "")
conn.sendline("Q") # Quit back to system command mode
conn.log_expect("SVP>", int(options["--shell-timeout"]))
conn.sendline("EX") # Quit back to system console menu
conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"]))
return outlets
def main():
device_opt = ["ipaddr", "login", "passwd", "cmd_prompt", "secure", \
"port", "missing_as_off", "telnet"]
atexit.register(atexit_handler)
all_opt["power_wait"]["default"] = "5"
all_opt["cmd_prompt"]["default"] = [r"\) :"]
options = check_input(device_opt, process_input(device_opt))
docs = {}
docs["shortdesc"] = "Fence agent for Hitachi Compute Blade systems"
docs["longdesc"] = "fence_hds_cb is an I/O Fencing agent \
which can be used with Hitachi Compute Blades with recent enough firmware that \
includes telnet support."
docs["vendorurl"] = "http://www.hds.com"
show_docs(options, docs)
##
## Operate the fencing device
######
conn = fence_login(options)
result = fence_action(conn, options, set_power_status, get_power_status, get_blades_list)
fence_logout(conn, "X")
sys.exit(result)
if __name__ == "__main__":
main()
diff --git a/fence/agents/hpblade/fence_hpblade.py b/fence/agents/hpblade/fence_hpblade.py
index a9e712cc..b2cc94a3 100644
--- a/fence/agents/hpblade/fence_hpblade.py
+++ b/fence/agents/hpblade/fence_hpblade.py
@@ -1,140 +1,134 @@
#!@PYTHON@ -tt
#####
##
## The Following Agent Has Been Tested On:
## * HP BladeSystem c7000 Enclosure
## * HP Integrity Superdome X (BL920s)
#####
import sys, re
import pexpect
import atexit
sys.path.append("@FENCEAGENTSLIBDIR@")
from fencing import *
from fencing import fail, EC_STATUS
-#BEGIN_VERSION_GENERATION
-RELEASE_VERSION="4.0.11-HP"
-BUILD_DATE="(built Mon Mar 30 08:31:24 EDT 2015)"
-REDHAT_COPYRIGHT="Copyright (C) Red Hat, Inc. 2004-2010 All rights reserved."
-#END_VERSION_GENERATION
-
def get_enclosure_type(conn, options):
conn.send_eol("show enclosure info")
conn.log_expect(options, options["--command-prompt"], int(options["--shell-timeout"]))
type_re=re.compile(r"^\s*Enclosure Type: (\w+)(.*?)\s*$")
enclosure="unknown"
for line in conn.before.splitlines():
res = type_re.search(line)
if res != None:
enclosure=res.group(1)
if enclosure == "unknown":
fail(EC_GENERIC_ERROR)
return enclosure.lower().strip()
def get_power_status(conn, options):
if options["enc_type"] == "superdome":
cmd_send = "parstatus -M -p " + options["--plug"]
powrestr = "^partition:\\d\\s+:\\w+\\s+/(\\w+)\\s.*$"
else:
cmd_send = "show server status " + options["--plug"]
powrestr = "^\\s*Power: (.*?)\\s*$"
conn.send_eol(cmd_send)
conn.log_expect(options, options["--command-prompt"], int(options["--shell-timeout"]))
power_re = re.compile(powrestr)
status = "unknown"
for line in conn.before.splitlines():
res = power_re.search(line)
if res != None:
if options["enc_type"] == "superdome":
if res.group(1) == "DOWN":
status = "off"
else:
status = "on"
else:
status = res.group(1)
if status == "unknown":
if "--missing-as-off" in options:
return "off"
else:
fail(EC_STATUS)
return status.lower().strip()
def set_power_status(conn, options):
if options["enc_type"] == "superdome":
dev="partition "
else:
dev="server "
if options["--action"] == "on":
conn.send_eol("poweron " + dev + options["--plug"])
elif options["--action"] == "off":
conn.send_eol("poweroff " + dev + options["--plug"] + " force")
conn.log_expect(options, options["--command-prompt"], int(options["--shell-timeout"]))
def get_instances_list(conn, options):
outlets = {}
if options["enc_type"] == "superdome":
cmd_send = "parstatus -P -M"
listrestr = "^partition:(\\d+)\\s+:\\w+\\s+/(\\w+)\\s+:OK.*?:(\\w+)\\s*$"
else:
cmd_send = "show server list"
listrestr = "^\\s*(\\d+)\\s+(.*?)\\s+(.*?)\\s+OK\\s+(.*?)\\s+(.*?)\\s*$"
conn.send_eol(cmd_send)
conn.log_expect(options, options["--command-prompt"], int(options["--shell-timeout"]))
list_re = re.compile(listrestr)
for line in conn.before.splitlines():
res = list_re.search(line)
if res != None:
if options["enc_type"] == "superdome":
outlets[res.group(1)] = (res.group(3), res.group(2).lower())
else:
outlets[res.group(1)] = (res.group(2), res.group(4).lower())
return outlets
def main():
device_opt = ["ipaddr", "login", "passwd", "cmd_prompt", "secure", \
"port", "missing_as_off", "telnet"]
atexit.register(atexit_handler)
all_opt["cmd_prompt"]["default"] = ["c7000oa>"]
all_opt["login_timeout"]["default"] = "10"
options = check_input(device_opt, process_input(device_opt))
docs = {}
docs["shortdesc"] = "Fence agent for HP BladeSystem"
docs["longdesc"] = "fence_hpblade is an I/O Fencing agent \
which can be used with HP BladeSystem and HP Integrity Superdome X. \
It logs into the onboard administrator of an enclosure via telnet or \
ssh and uses the command line interface to power blades or partitions \
on or off."
docs["vendorurl"] = "http://www.hp.com"
show_docs(options, docs)
##
## Operate the fencing device
######
options["eol"] = "\n"
conn = fence_login(options)
options["enc_type"] = get_enclosure_type(conn, options)
result = fence_action(conn, options, set_power_status, get_power_status, get_instances_list)
fence_logout(conn, "exit")
sys.exit(result)
if __name__ == "__main__":
main()
diff --git a/fence/agents/ibmblade/fence_ibmblade.py b/fence/agents/ibmblade/fence_ibmblade.py
index 11ba1698..d623fff3 100644
--- a/fence/agents/ibmblade/fence_ibmblade.py
+++ b/fence/agents/ibmblade/fence_ibmblade.py
@@ -1,78 +1,72 @@
#!@PYTHON@ -tt
import sys
import atexit
sys.path.append("@FENCEAGENTSLIBDIR@")
from fencing import *
from fencing_snmp import FencingSnmp
-#BEGIN_VERSION_GENERATION
-RELEASE_VERSION="IBM Blade SNMP fence agent"
-REDHAT_COPYRIGHT=""
-BUILD_DATE=""
-#END_VERSION_GENERATION
-
### CONSTANTS ###
# From fence_ibmblade.pl
STATUSES_OID = ".1.3.6.1.4.1.2.3.51.2.22.1.5.1.1.4" # remoteControlBladePowerState
CONTROL_OID = ".1.3.6.1.4.1.2.3.51.2.22.1.6.1.1.7" # powerOnOffBlade
# Status constants returned as value from SNMP
STATUS_DOWN = 0
STATUS_UP = 1
# Status constants to set as value to SNMP
STATUS_SET_OFF = 0
STATUS_SET_ON = 1
### FUNCTIONS ###
def get_power_status(conn, options):
(_, status) = conn.get("%s.%s"% (STATUSES_OID, options["--plug"]))
return status == str(STATUS_UP) and "on" or "off"
def set_power_status(conn, options):
conn.set("%s.%s" % (CONTROL_OID, options["--plug"]),
(options["--action"] == "on" and STATUS_SET_ON or STATUS_SET_OFF))
def get_outlets_status(conn, _):
result = {}
res_blades = conn.walk(STATUSES_OID, 30)
for blade_info in res_blades:
port_num = blade_info[0].split('.')[-1]
port_alias = ""
port_status = (blade_info[1] == str(STATUS_UP) and "on" or "off")
result[port_num] = (port_alias, port_status)
return result
# Main agent method
def main():
device_opt = ["ipaddr", "login", "passwd", "no_login", "no_password", \
"port", "snmp_version", "snmp"]
atexit.register(atexit_handler)
all_opt["snmp_version"]["default"] = "1"
options = check_input(device_opt, process_input(device_opt))
docs = {}
docs["shortdesc"] = "Fence agent for IBM BladeCenter over SNMP"
docs["longdesc"] = "fence_ibmblade is an I/O Fencing agent \
which can be used with IBM BladeCenter chassis. It issues SNMP Set \
request to BladeCenter chassis, rebooting, powering up or down \
the specified Blade Server."
docs["vendorurl"] = "http://www.ibm.com"
show_docs(options, docs)
# Operate the fencing device
result = fence_action(FencingSnmp(options), options, set_power_status, get_power_status, get_outlets_status)
sys.exit(result)
if __name__ == "__main__":
main()
diff --git a/fence/agents/ifmib/fence_ifmib.py b/fence/agents/ifmib/fence_ifmib.py
index 963d3e93..d1191340 100644
--- a/fence/agents/ifmib/fence_ifmib.py
+++ b/fence/agents/ifmib/fence_ifmib.py
@@ -1,122 +1,116 @@
#!@PYTHON@ -tt
# The Following agent has been tested on:
# - Cisco MDS UROS 9134 FC (1 Slot) Chassis ("1/2/4 10 Gbps FC/Supervisor-2") Motorola, e500v2
# with BIOS 1.0.16, kickstart 4.1(1c), system 4.1(1c)
# - Cisco MDS 9124 (1 Slot) Chassis ("1/2/4 Gbps FC/Supervisor-2") Motorola, e500
# with BIOS 1.0.16, kickstart 4.1(1c), system 4.1(1c)
# - Partially with APC PDU (Network Management Card AOS v2.7.0, Rack PDU APP v2.7.3)
# Only lance if is visible
import sys
import atexit
sys.path.append("@FENCEAGENTSLIBDIR@")
from fencing import *
from fencing import fail_usage, array_to_dict
from fencing_snmp import FencingSnmp
-#BEGIN_VERSION_GENERATION
-RELEASE_VERSION="IF:MIB SNMP fence agent"
-REDHAT_COPYRIGHT=""
-BUILD_DATE=""
-#END_VERSION_GENERATION
-
### CONSTANTS ###
# IF-MIB trees for alias, status and port
ALIASES_OID = ".1.3.6.1.2.1.31.1.1.1.18"
PORTS_OID = ".1.3.6.1.2.1.2.2.1.2"
STATUSES_OID = ".1.3.6.1.2.1.2.2.1.7"
# Status constants returned as value from SNMP
STATUS_UP = 1
STATUS_DOWN = 2
STATUS_TESTING = 3
### GLOBAL VARIABLES ###
# Port number converted from port name or index
port_num = None
### FUNCTIONS ###
# Convert port index or name to port index
def port2index(conn, port):
res = None
if port.isdigit():
res = int(port)
else:
ports = conn.walk(PORTS_OID, 30)
for x in ports:
if x[1].strip('"') == port:
res = int(x[0].split('.')[-1])
break
if res == None:
fail_usage("Can't find port with name %s!"%(port))
return res
def get_power_status(conn, options):
global port_num
if port_num == None:
port_num = port2index(conn, options["--plug"])
(_, status) = conn.get("%s.%d"%(STATUSES_OID, port_num))
return status == str(STATUS_UP) and "on" or "off"
def set_power_status(conn, options):
global port_num
if port_num == None:
port_num = port2index(conn, options["--plug"])
conn.set("%s.%d" % (STATUSES_OID, port_num), (options["--action"] == "on" and STATUS_UP or STATUS_DOWN))
def get_outlets_status(conn, options):
result = {}
res_fc = conn.walk(PORTS_OID, 30)
res_aliases = array_to_dict(conn.walk(ALIASES_OID, 30))
for x in res_fc:
port_number = x[0].split('.')[-1]
port_name = x[1].strip('"')
port_alias = (port_number in res_aliases and res_aliases[port_number].strip('"') or "")
port_status = ""
result[port_name] = (port_alias, port_status)
return result
# Main agent method
def main():
device_opt = ["fabric_fencing", "ipaddr", "login", "passwd", "no_login", "no_password", \
"port", "snmp_version", "snmp"]
atexit.register(atexit_handler)
all_opt["snmp_version"]["default"] = "2c"
options = check_input(device_opt, process_input(device_opt))
docs = {}
docs["shortdesc"] = "Fence agent for IF MIB"
docs["longdesc"] = "fence_ifmib is an I/O Fencing agent \
which can be used with any SNMP IF-MIB capable device. \
\n.P\n\
It was written with managed ethernet switches in mind, in order to \
fence iSCSI SAN connections. However, there are many devices that \
support the IF-MIB interface. The agent uses IF-MIB::ifAdminStatus \
to control the state of an interface."
docs["vendorurl"] = "http://www.ietf.org/wg/concluded/ifmib.html"
show_docs(options, docs)
# Operate the fencing device
result = fence_action(FencingSnmp(options), options, set_power_status, get_power_status, get_outlets_status)
sys.exit(result)
if __name__ == "__main__":
main()
diff --git a/fence/agents/ilo/fence_ilo.py b/fence/agents/ilo/fence_ilo.py
index 36e2ba14..61245056 100644
--- a/fence/agents/ilo/fence_ilo.py
+++ b/fence/agents/ilo/fence_ilo.py
@@ -1,149 +1,143 @@
#!@PYTHON@ -tt
#####
##
## The Following Agent Has Been Tested On:
##
## iLO Version
## +---------------------------------------------+
## iLO / firmware 1.91 / RIBCL 2.22
## iLO2 / firmware 1.22 / RIBCL 2.22
## iLO2 / firmware 1.50 / RIBCL 2.22
#####
import sys, re, pexpect
import atexit
from xml.sax.saxutils import quoteattr
sys.path.append("@FENCEAGENTSLIBDIR@")
from fencing import *
from fencing import fail, EC_LOGIN_DENIED
-#BEGIN_VERSION_GENERATION
-RELEASE_VERSION="New ILO Agent - test release on steroids"
-REDHAT_COPYRIGHT=""
-BUILD_DATE="March, 2008"
-#END_VERSION_GENERATION
-
def get_power_status(conn, options):
conn.send("<LOGIN USER_LOGIN = " + quoteattr(options["--username"]) + \
" PASSWORD = " + quoteattr(options["--password"]) + ">\r\n")
conn.send("<SERVER_INFO MODE = \"read\"><GET_HOST_POWER_STATUS/>\r\n")
conn.send("</SERVER_INFO></LOGIN>\r\n")
conn.log_expect("HOST_POWER=\"(.*?)\"", int(options["--power-timeout"]))
status = conn.match.group(1)
return status.lower().strip()
def set_power_status(conn, options):
conn.send("<LOGIN USER_LOGIN = " + quoteattr(options["--username"]) + \
" PASSWORD = " + quoteattr(options["--password"]) + ">\r\n")
conn.send("<SERVER_INFO MODE = \"write\">")
if options.get("fw_processor", None) == "iLO2":
if options["fw_version"] > 1.29:
conn.send("<HOLD_PWR_BTN TOGGLE=\"yes\" />\r\n")
else:
conn.send("<HOLD_PWR_BTN />\r\n")
elif options["--ribcl-version"] < 2.21:
conn.send("<SET_HOST_POWER HOST_POWER = \"" + options["--action"] + "\" />\r\n")
else:
if options["--action"] == "off":
conn.send("<HOLD_PWR_BTN/>\r\n")
else:
conn.send("<PRESS_PWR_BTN/>\r\n")
conn.send("</SERVER_INFO></LOGIN>\r\n")
return
def define_new_opts():
all_opt["ribcl"] = {
"getopt" : "r:",
"longopt" : "ribcl-version",
"help" : "-r, --ribcl-version=[version] Force ribcl version to use",
"required" : "0",
"shortdesc" : "Force ribcl version to use",
"order" : 1}
def main():
device_opt = ["ipaddr", "login", "passwd", "ssl", "notls", "tls1.0", "ribcl"]
atexit.register(atexit_handler)
define_new_opts()
all_opt["login_timeout"]["default"] = "10"
all_opt["retry_on"]["default"] = "3"
all_opt["ssl"]["default"] = "1"
options = check_input(device_opt, process_input(device_opt))
docs = {}
docs["shortdesc"] = "Fence agent for HP iLO"
docs["longdesc"] = "fence_ilo is an I/O Fencing agent \
used for HP servers with the Integrated Light Out (iLO) PCI card.\
The agent opens an SSL connection to the iLO card. Once the SSL \
connection is established, the agent is able to communicate with \
the iLO card through an XML stream."
docs["vendorurl"] = "http://www.hp.com"
docs["symlink"] = [("fence_ilo2", "Fence agent for HP iLO2")]
show_docs(options, docs)
##
## Login and get version number
####
conn = fence_login(options)
try:
conn.send("<?xml version=\"1.0\"?>\r\n")
conn.log_expect(["</RIBCL>", "<END_RIBCL/>"], int(options["--login-timeout"]))
except pexpect.TIMEOUT:
fail(EC_LOGIN_DENIED)
except pexpect.EOF:
if "--tls1.0" in options:
fail(EC_LOGIN_DENIED)
options["--tls1.0"] = "1"
conn.close()
conn = fence_login(options)
try:
conn.send("<?xml version=\"1.0\"?>\r\n")
conn.log_expect(["</RIBCL>", "<END_RIBCL/>"], int(options["--login-timeout"]))
except pexpect.TIMEOUT:
fail(EC_LOGIN_DENIED)
except pexpect.EOF:
fail(EC_LOGIN_DENIED)
try:
version = re.compile("<RIBCL VERSION=\"(.*?)\"", re.IGNORECASE).search(conn.before).group(1)
if "--ribcl-version" not in options:
options["--ribcl-version"] = float(version)
if options["--ribcl-version"] >= 2:
conn.send("<RIBCL VERSION=\"2.0\">\r\n")
else:
conn.send("<RIBCL VERSION=\"1.2\">\r\n")
conn.send("<LOGIN USER_LOGIN = " + quoteattr(options["--username"]) + \
" PASSWORD = " + quoteattr(options["--password"]) + ">\r\n")
if options["--ribcl-version"] >= 2:
conn.send("<RIB_INFO MODE=\"read\"><GET_FW_VERSION />\r\n")
conn.send("</RIB_INFO>\r\n")
conn.log_expect(r"<GET_FW_VERSION\s*\n", int(options["--shell-timeout"]))
conn.log_expect("/>", int(options["--shell-timeout"]))
options["fw_version"] = float(re.compile(r"FIRMWARE_VERSION\s*=\s*\"(.*?)\"",
re.IGNORECASE).search(conn.before).group(1))
options["fw_processor"] = re.compile(r"MANAGEMENT_PROCESSOR\s*=\s*\"(.*?)\"",
re.IGNORECASE).search(conn.before).group(1)
conn.send("</LOGIN>\r\n")
except pexpect.TIMEOUT:
fail(EC_LOGIN_DENIED)
except pexpect.EOF:
fail(EC_LOGIN_DENIED)
##
## Fence operations
####
result = fence_action(conn, options, set_power_status, get_power_status, None)
sys.exit(result)
if __name__ == "__main__":
main()
diff --git a/fence/agents/ilo_moonshot/fence_ilo_moonshot.py b/fence/agents/ilo_moonshot/fence_ilo_moonshot.py
index c534947c..a066a9c9 100644
--- a/fence/agents/ilo_moonshot/fence_ilo_moonshot.py
+++ b/fence/agents/ilo_moonshot/fence_ilo_moonshot.py
@@ -1,69 +1,63 @@
#!@PYTHON@ -tt
import sys
import atexit
sys.path.append("@FENCEAGENTSLIBDIR@")
from fencing import *
from fencing import fail, EC_STATUS
-#BEGIN_VERSION_GENERATION
-RELEASE_VERSION=""
-REDHAT_COPYRIGHT=""
-BUILD_DATE=""
-#END_VERSION_GENERATION
-
def get_power_status(conn, options):
conn.send_eol("show node list")
conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"]))
nodes = {}
for line in conn.before.splitlines():
if len(line.split()) == 10:
nodes[line.split()[1]] = ("", line.split()[8].lower().strip())
if ["list", "monitor"].count(options["--action"]) == 1:
return nodes
else:
try:
(_, status) = nodes[options["--plug"]]
return status.lower()
except KeyError:
fail(EC_STATUS)
def set_power_status(conn, options):
if options["--action"] == "on":
conn.send_eol("set node power on %s" % (options["--plug"]))
else:
conn.send_eol("set node power off force %s" % (options["--plug"]))
conn.log_expect(options["--command-prompt"], int(options["--power-timeout"]))
return
def main():
device_opt = ["ipaddr", "login", "passwd", "secure", "cmd_prompt", "port"]
atexit.register(atexit_handler)
all_opt["secure"]["default"] = "1"
all_opt["cmd_prompt"]["default"] = ["MP>", "hpiLO->"]
options = check_input(device_opt, process_input(device_opt))
docs = {}
docs["shortdesc"] = "Fence agent for HP Moonshot iLO"
docs["longdesc"] = ""
docs["vendorurl"] = "http://www.hp.com"
show_docs(options, docs)
conn = fence_login(options)
##
## Fence operations
####
result = fence_action(conn, options, set_power_status, get_power_status, get_power_status)
fence_logout(conn, "exit")
sys.exit(result)
if __name__ == "__main__":
main()
diff --git a/fence/agents/ilo_mp/fence_ilo_mp.py b/fence/agents/ilo_mp/fence_ilo_mp.py
index f878c5c4..1ae4d3ed 100644
--- a/fence/agents/ilo_mp/fence_ilo_mp.py
+++ b/fence/agents/ilo_mp/fence_ilo_mp.py
@@ -1,64 +1,58 @@
#!@PYTHON@ -tt
import sys, re
import atexit
sys.path.append("@FENCEAGENTSLIBDIR@")
from fencing import *
-#BEGIN_VERSION_GENERATION
-RELEASE_VERSION=""
-REDHAT_COPYRIGHT=""
-BUILD_DATE=""
-#END_VERSION_GENERATION
-
def get_power_status(conn, options):
conn.send_eol("show /system1")
re_state = re.compile('EnabledState=(.*)', re.IGNORECASE)
conn.log_expect(re_state, int(options["--shell-timeout"]))
status = conn.match.group(1).lower()
if status.startswith("enabled"):
return "on"
else:
return "off"
def set_power_status(conn, options):
if options["--action"] == "on":
conn.send_eol("start /system1")
else:
conn.send_eol("stop -f /system1")
conn.log_expect(options["--command-prompt"], int(options["--power-timeout"]))
return
def main():
device_opt = ["ipaddr", "login", "passwd", "secure", "cmd_prompt", "telnet"]
atexit.register(atexit_handler)
all_opt["cmd_prompt"]["default"] = ["MP>", "hpiLO->"]
all_opt["power_wait"]["default"] = 5
options = check_input(device_opt, process_input(device_opt))
docs = {}
docs["shortdesc"] = "Fence agent for HP iLO MP"
docs["longdesc"] = ""
docs["vendorurl"] = "http://www.hp.com"
show_docs(options, docs)
conn = fence_login(options)
conn.send_eol("SMCLP")
##
## Fence operations
####
result = fence_action(conn, options, set_power_status, get_power_status)
fence_logout(conn, "exit")
sys.exit(result)
if __name__ == "__main__":
main()
diff --git a/fence/agents/ilo_ssh/fence_ilo_ssh.py b/fence/agents/ilo_ssh/fence_ilo_ssh.py
index fb2d9f3f..b0366157 100644
--- a/fence/agents/ilo_ssh/fence_ilo_ssh.py
+++ b/fence/agents/ilo_ssh/fence_ilo_ssh.py
@@ -1,74 +1,68 @@
#!@PYTHON@ -tt
import sys, re
import atexit
sys.path.append("@FENCEAGENTSLIBDIR@")
from fencing import *
-#BEGIN_VERSION_GENERATION
-RELEASE_VERSION=""
-REDHAT_COPYRIGHT=""
-BUILD_DATE=""
-#END_VERSION_GENERATION
-
def get_power_status(conn, options):
conn.send_eol("show /system1")
re_state = re.compile('EnabledState=(.*)', re.IGNORECASE)
conn.log_expect(re_state, int(options["--shell-timeout"]))
status = conn.match.group(1).lower()
if status.startswith("enabled"):
return "on"
else:
return "off"
def set_power_status(conn, options):
if options["--action"] == "on":
conn.send_eol("start /system1")
else:
conn.send_eol("power off hard")
conn.log_expect(options["--command-prompt"], int(options["--power-timeout"]))
return
def reboot_cycle(conn, options):
conn.send_eol("reset hard /system1")
conn.log_expect(options["--command-prompt"], int(options["--power-timeout"]))
return
def main():
device_opt = ["ipaddr", "login", "passwd", "secure", "cmd_prompt", "method", "telnet"]
atexit.register(atexit_handler)
all_opt["cmd_prompt"]["default"] = ["MP>", "hpiLO->"]
all_opt["power_wait"]["default"] = 5
options = check_input(device_opt, process_input(device_opt))
docs = {}
docs["shortdesc"] = "Fence agent for HP iLO over SSH"
docs["longdesc"] = "fence_ilo_ssh is a fence agent that connects to iLO device. It logs into \
device via ssh and reboot a specified outlet. "
docs["vendorurl"] = "http://www.hp.com"
docs["symlink"] = [("fence_ilo3_ssh", "Fence agent for HP iLO3 over SSH"),
("fence_ilo4_ssh", "Fence agent for HP iLO4 over SSH")]
show_docs(options, docs)
options["eol"] = "\r"
conn = fence_login(options)
conn.send_eol("SMCLP")
##
## Fence operations
####
result = fence_action(conn, options, set_power_status, get_power_status, None, reboot_cycle)
fence_logout(conn, "exit")
sys.exit(result)
if __name__ == "__main__":
main()
diff --git a/fence/agents/intelmodular/fence_intelmodular.py b/fence/agents/intelmodular/fence_intelmodular.py
index 4e1301c9..294ea4dd 100644
--- a/fence/agents/intelmodular/fence_intelmodular.py
+++ b/fence/agents/intelmodular/fence_intelmodular.py
@@ -1,92 +1,86 @@
#!@PYTHON@ -tt
# Tested with an Intel MFSYS25 using firmware package 2.6 Should work with an
# MFSYS35 as well.
#
# Notes:
#
# The manual and firmware release notes says SNMP is read only. This is not
# true, as per the MIBs that ship with the firmware you can write to
# the bladePowerLed oid to control the servers.
#
# Thanks Matthew Kent for original agent and testing.
import sys
import atexit
sys.path.append("@FENCEAGENTSLIBDIR@")
from fencing import *
from fencing_snmp import FencingSnmp
-#BEGIN_VERSION_GENERATION
-RELEASE_VERSION="Intel Modular SNMP fence agent"
-REDHAT_COPYRIGHT=""
-BUILD_DATE=""
-#END_VERSION_GENERATION
-
### CONSTANTS ###
# From INTELCORPORATION-MULTI-FLEX-SERVER-BLADES-MIB.my that ships with
# firmware updates
STATUSES_OID = ".1.3.6.1.4.1.343.2.19.1.2.10.202.1.1.6"
# Status constants returned as value from SNMP
STATUS_UP = 2
STATUS_DOWN = 0
# Status constants to set as value to SNMP
STATUS_SET_ON = 2
STATUS_SET_OFF = 3
### FUNCTIONS ###
def get_power_status(conn, options):
(_, status) = conn.get("%s.%s"% (STATUSES_OID, options["--plug"]))
return status == str(STATUS_UP) and "on" or "off"
def set_power_status(conn, options):
conn.set("%s.%s" % (STATUSES_OID, options["--plug"]),
(options["--action"] == "on" and STATUS_SET_ON or STATUS_SET_OFF))
def get_outlets_status(conn, options):
result = {}
res_blades = conn.walk(STATUSES_OID, 30)
for x in res_blades:
port_num = x[0].split('.')[-1]
port_alias = ""
port_status = (x[1] == str(STATUS_UP) and "on" or "off")
result[port_num] = (port_alias, port_status)
return result
# Main agent method
def main():
device_opt = ["ipaddr", "login", "passwd", "no_login", "no_password",
"port", "snmp_version", "snmp"]
atexit.register(atexit_handler)
options = check_input(device_opt, process_input(device_opt))
docs = {}
docs["shortdesc"] = "Fence agent for Intel Modular"
docs["longdesc"] = "fence_intelmodular is an I/O Fencing agent \
which can be used with Intel Modular device (tested on Intel MFSYS25, should \
work with MFSYS35 as well). \
\n.P\n\
Note: Since firmware update version 2.7, SNMP v2 write support is \
removed, and replaced by SNMP v3 support. So agent now has default \
SNMP version 3. If you are using older firmware, please supply -d \
for command line and snmp_version option for your cluster.conf."
docs["vendorurl"] = "http://www.intel.com"
show_docs(options, docs)
# Operate the fencing device
result = fence_action(FencingSnmp(options), options, set_power_status, get_power_status, get_outlets_status)
sys.exit(result)
if __name__ == "__main__":
main()
diff --git a/fence/agents/ipdu/fence_ipdu.py b/fence/agents/ipdu/fence_ipdu.py
index 7e648598..da34d2b6 100644
--- a/fence/agents/ipdu/fence_ipdu.py
+++ b/fence/agents/ipdu/fence_ipdu.py
@@ -1,159 +1,153 @@
#!@PYTHON@ -tt
# The Following agent has been tested on:
# IBM iPDU model 46M4002
# Firmware release OPDP_sIBM_v01.2_1
#
import sys
import atexit
import logging
sys.path.append("@FENCEAGENTSLIBDIR@")
from fencing import *
from fencing import fail_usage
from fencing_snmp import FencingSnmp
-#BEGIN_VERSION_GENERATION
-RELEASE_VERSION="IBM iPDU SNMP fence agent"
-REDHAT_COPYRIGHT=""
-BUILD_DATE=""
-#END_VERSION_GENERATION
-
### CONSTANTS ###
# oid defining fence device
OID_SYS_OBJECT_ID = '.1.3.6.1.2.1.1.2.0'
### GLOBAL VARIABLES ###
# Device - see IBM iPDU
device = None
# Port ID
port_id = None
# Switch ID
switch_id = None
# Classes describing Device params
class IBMiPDU(object):
# iPDU
status_oid = '.1.3.6.1.4.1.2.6.223.8.2.2.1.11.%d'
control_oid = '.1.3.6.1.4.1.2.6.223.8.2.2.1.11.%d'
outlet_table_oid = '.1.3.6.1.4.1.2.6.223.8.2.2.1.2'
ident_str = "IBM iPDU"
state_on = 1
state_off = 0
turn_on = 1
turn_off = 0
has_switches = False
### FUNCTIONS ###
def ipdu_set_device(conn, options):
global device
agents_dir = {'.1.3.6.1.4.1.2.6.223':IBMiPDU,
None:IBMiPDU}
# First resolve type of PDU device
pdu_type = conn.walk(OID_SYS_OBJECT_ID)
if not ((len(pdu_type) == 1) and (pdu_type[0][1] in agents_dir)):
pdu_type = [[None, None]]
device = agents_dir[pdu_type[0][1]]
logging.debug("Trying %s"%(device.ident_str))
def ipdu_resolv_port_id(conn, options):
global port_id, switch_id
if device == None:
ipdu_set_device(conn, options)
# Now we resolv port_id/switch_id
if options["--plug"].isdigit() and ((not device.has_switches) or (options["--switch"].isdigit())):
port_id = int(options["--plug"])
if device.has_switches:
switch_id = int(options["--switch"])
else:
table = conn.walk(device.outlet_table_oid, 30)
for x in table:
if x[1].strip('"') == options["--plug"]:
t = x[0].split('.')
if device.has_switches:
port_id = int(t[len(t)-1])
switch_id = int(t[len(t)-3])
else:
port_id = int(t[len(t)-1])
if port_id == None:
fail_usage("Can't find port with name %s!"%(options["--plug"]))
def get_power_status(conn, options):
if port_id == None:
ipdu_resolv_port_id(conn, options)
oid = ((device.has_switches) and device.status_oid%(switch_id, port_id) or device.status_oid%(port_id))
(oid, status) = conn.get(oid)
return status == str(device.state_on) and "on" or "off"
def set_power_status(conn, options):
if port_id == None:
ipdu_resolv_port_id(conn, options)
oid = ((device.has_switches) and device.control_oid%(switch_id, port_id) or device.control_oid%(port_id))
conn.set(oid, (options["--action"] == "on" and device.turn_on or device.turn_off))
def get_outlets_status(conn, options):
result = {}
if device == None:
ipdu_set_device(conn, options)
res_ports = conn.walk(device.outlet_table_oid, 30)
for x in res_ports:
t = x[0].split('.')
port_num = ((device.has_switches) and "%s:%s"%(t[len(t)-3], t[len(t)-1]) or "%s"%(t[len(t)-1]))
port_name = x[1].strip('"')
port_status = ""
result[port_num] = (port_name, port_status)
return result
# Main agent method
def main():
global device
device_opt = ["ipaddr", "login", "passwd", "no_login", "no_password", \
"port", "snmp_version", "snmp"]
atexit.register(atexit_handler)
all_opt["snmp_version"]["default"] = "3"
all_opt["community"]["default"] = "private"
all_opt["switch"]["default"] = "1"
device = IBMiPDU
options = check_input(device_opt, process_input(device_opt))
docs = {}
docs["shortdesc"] = "Fence agent for iPDU over SNMP"
docs["longdesc"] = "fence_ipdu is an I/O Fencing agent \
which can be used with the IBM iPDU network power switch. It logs \
into a device via SNMP and reboots a specified outlet. It supports \
SNMP v3 with all combinations of authenticity/privacy settings."
docs["vendorurl"] = "http://www.ibm.com"
show_docs(options, docs)
# Operate the fencing device
result = fence_action(FencingSnmp(options), options, set_power_status, get_power_status, get_outlets_status)
sys.exit(result)
if __name__ == "__main__":
main()
diff --git a/fence/agents/ipmilan/fence_ipmilan.py b/fence/agents/ipmilan/fence_ipmilan.py
index 6c43b185..13a14785 100644
--- a/fence/agents/ipmilan/fence_ipmilan.py
+++ b/fence/agents/ipmilan/fence_ipmilan.py
@@ -1,219 +1,213 @@
#!@PYTHON@ -tt
import sys, re, os
import atexit
from pipes import quote
sys.path.append("@FENCEAGENTSLIBDIR@")
from fencing import *
from fencing import fail_usage, is_executable, run_command, run_delay
-#BEGIN_VERSION_GENERATION
-RELEASE_VERSION=""
-REDHAT_COPYRIGHT=""
-BUILD_DATE=""
-#END_VERSION_GENERATION
-
def get_power_status(_, options):
output = _run_command(options, "status")
match = re.search('[Cc]hassis [Pp]ower is [\\s]*([a-zA-Z]{2,3})', str(output))
status = match.group(1) if match else None
return status
def set_power_status(_, options):
_run_command(options, options["--action"])
return
def reboot_cycle(_, options):
output = _run_command(options, "cycle")
return bool(re.search('chassis power control: cycle', str(output).lower()))
def reboot_diag(_, options):
output = _run_command(options, "diag")
return bool(re.search('chassis power control: diag', str(output).lower()))
def _run_command(options, action):
cmd, log_cmd = create_command(options, action)
return run_command(options, cmd, log_command=log_cmd)
def create_command(options, action):
class Cmd:
cmd = ""
log = ""
@classmethod
def append(cls, cmd, log=None):
cls.cmd += cmd
cls.log += (cmd if log is None else log)
# --use-sudo / -d
if "--use-sudo" in options:
Cmd.append(options["--sudo-path"] + " ")
Cmd.append(options["--ipmitool-path"])
# --lanplus / -L
if "--lanplus" in options and options["--lanplus"] in ["", "1"]:
Cmd.append(" -I lanplus")
else:
Cmd.append(" -I lan")
# --ip / -a
Cmd.append(" -H " + options["--ip"])
# --port / -n
if "--ipport" in options:
Cmd.append(" -p " + options["--ipport"])
# --target
if "--target" in options:
Cmd.append(" -t " + options["--target"])
# --username / -l
if "--username" in options and len(options["--username"]) != 0:
Cmd.append(" -U " + quote(options["--username"]))
# --auth / -A
if "--auth" in options:
Cmd.append(" -A " + options["--auth"])
# --password / -p
if "--password" in options:
Cmd.append(" -P " + quote(options["--password"]), " -P [set]")
else:
Cmd.append(" -P ''", " -P [set]")
# --cipher / -C
if "--cipher" in options:
Cmd.append(" -C " + options["--cipher"])
if "--privlvl" in options:
Cmd.append(" -L " + options["--privlvl"])
if "--hexadecimal-kg" in options:
Cmd.append(" -y " + options["--hexadecimal-kg"])
# --action / -o
Cmd.append(" chassis power " + action)
return (Cmd.cmd, Cmd.log)
def define_new_opts():
all_opt["lanplus"] = {
"getopt" : "P",
"longopt" : "lanplus",
"help" : "-P, --lanplus Use Lanplus to improve security of connection",
"required" : "0",
"default" : "0",
"shortdesc" : "Use Lanplus to improve security of connection",
"order": 1
}
all_opt["auth"] = {
"getopt" : "A:",
"longopt" : "auth",
"help" : "-A, --auth=[auth] IPMI Lan Auth type (md5|password|none)",
"required" : "0",
"shortdesc" : "IPMI Lan Auth type.",
"choices" : ["md5", "password", "none"],
"order": 1
}
all_opt["cipher"] = {
"getopt" : "C:",
"longopt" : "cipher",
"help" : "-C, --cipher=[cipher] Ciphersuite to use (same as ipmitool -C parameter)",
"required" : "0",
"shortdesc" : "Ciphersuite to use (same as ipmitool -C parameter)",
"order": 1
}
all_opt["privlvl"] = {
"getopt" : "L:",
"longopt" : "privlvl",
"help" : "-L, --privlvl=[level] "
"Privilege level on IPMI device (callback|user|operator|administrator)",
"required" : "0",
"shortdesc" : "Privilege level on IPMI device",
"default" : "administrator",
"choices" : ["callback", "user", "operator", "administrator"],
"order": 1
}
all_opt["ipmitool_path"] = {
"getopt" : ":",
"longopt" : "ipmitool-path",
"help" : "--ipmitool-path=[path] Path to ipmitool binary",
"required" : "0",
"shortdesc" : "Path to ipmitool binary",
"default" : "@IPMITOOL_PATH@",
"order": 200
}
all_opt["target"] = {
"getopt" : ":",
"longopt" : "target",
"help" : "--target=[targetaddress] Bridge IPMI requests to the remote target address",
"required" : "0",
"shortdesc" : "Bridge IPMI requests to the remote target address",
"order": 1
}
all_opt["hexadecimal_kg"] = {
"getopt" : ":",
"longopt" : "hexadecimal-kg",
"help" : "--hexadecimal-kg=[key] Hexadecimal-encoded Kg key for IPMIv2 authentication",
"required" : "0",
"shortdesc" : "Hexadecimal-encoded Kg key for IPMIv2 authentication",
"order": 1
}
def main():
atexit.register(atexit_handler)
device_opt = ["ipaddr", "login", "no_login", "no_password", "passwd",
"diag", "lanplus", "auth", "cipher", "privlvl", "sudo",
"ipmitool_path", "method", "target", "hexadecimal_kg"]
define_new_opts()
all_opt["power_wait"]["default"] = 2
if os.path.basename(sys.argv[0]) == "fence_ilo3":
all_opt["power_wait"]["default"] = "4"
all_opt["method"]["default"] = "cycle"
all_opt["lanplus"]["default"] = "1"
elif os.path.basename(sys.argv[0]) == "fence_ilo4":
all_opt["lanplus"]["default"] = "1"
all_opt["ipport"]["default"] = "623"
if all_opt["method"]["default"] == "cycle":
all_opt["method"]["help"] = "-m, --method=[method] Method to fence (onoff|cycle) (Default: cycle)\n" \
"WARNING! This fence agent might report success before the node is powered off. " \
"You should use -m/method onoff if your fence device works correctly with that option."
options = check_input(device_opt, process_input(device_opt))
docs = {}
docs["shortdesc"] = "Fence agent for IPMI"
docs["longdesc"] = "fence_ipmilan is an I/O Fencing agent\
which can be used with machines controlled by IPMI.\
This agent calls support software ipmitool (http://ipmitool.sf.net/). \
WARNING! This fence agent might report success before the node is powered off. \
You should use -m/method onoff if your fence device works correctly with that option."
docs["vendorurl"] = ""
docs["symlink"] = [("fence_ilo3", "Fence agent for HP iLO3"),
("fence_ilo4", "Fence agent for HP iLO4"),
("fence_imm", "Fence agent for IBM Integrated Management Module"),
("fence_idrac", "Fence agent for Dell iDRAC")]
show_docs(options, docs)
run_delay(options)
if not is_executable(options["--ipmitool-path"]):
fail_usage("Ipmitool not found or not accessible")
reboot_fn = reboot_cycle
if options["--action"] == "diag":
# Diag is a special action that can't be verified so we will reuse reboot functionality
# to minimize impact on generic library
options["--action"] = "reboot"
options["--method"] = "cycle"
reboot_fn = reboot_diag
result = fence_action(None, options, set_power_status, get_power_status, None, reboot_fn)
sys.exit(result)
if __name__ == "__main__":
main()
diff --git a/fence/agents/ironic/fence_ironic.py b/fence/agents/ironic/fence_ironic.py
index 8e5d5b0f..66d84fca 100644
--- a/fence/agents/ironic/fence_ironic.py
+++ b/fence/agents/ironic/fence_ironic.py
@@ -1,136 +1,130 @@
#!@PYTHON@ -tt
import atexit
import logging
import os
import re
import sys
from pipes import quote
sys.path.append("@FENCEAGENTSLIBDIR@")
from fencing import *
from fencing import fail_usage, is_executable, run_command, run_delay
-#BEGIN_VERSION_GENERATION
-RELEASE_VERSION=""
-REDHAT_COPYRIGHT=""
-BUILD_DATE=""
-#END_VERSION_GENERATION
-
def get_name_or_uuid(options):
return options["--uuid"] if "--uuid" in options else options["--plug"]
def get_power_status(_, options):
output = ironic_run_command(options, "status")
stdout = output[1]
match = re.search('power[\\s]*([a-zA-Z]{2,3})', str(stdout))
status = match.group(1) if match else None
return status
def set_power_status(_, options):
ironic_run_command(options, options["--action"])
return
def get_devices_list(_, options):
nodes = {}
output = ironic_run_command(options, "list")
stdout = output[1]
for line in stdout.splitlines():
uuid = "UUID"
try:
(uuid, name, state) = line.split(',')
except ValueError:
pass
if "UUID" in uuid:
continue # skip line header
match = re.search('power[\\s]*([a-zA-Z]{2,3})', state)
status = match.group(1) if match else None
nodes[uuid] = (name, status)
return nodes
def ironic_run_command(options, action, timeout=None):
cmd = options["--openstack-path"] + " baremetal"
env = os.environ.copy()
# --username / -l
if "--username" in options and len(options["--username"]) != 0:
env["OS_USERNAME"] = options["--username"]
# --password / -p
if "--password" in options:
env["OS_PASSWORD"] = options["--password"]
# --tenant-name -t
if "--tenant-name" in options:
env["OS_TENANT_NAME"] = options["--tenant-name"]
# --auth-url
if "--auth-url" in options:
env["OS_AUTH_URL"] = options["--auth-url"]
# --action / -o
if action == "status":
cmd += " show %s -c power_state --format value" % (get_name_or_uuid(options))
elif action in ["on", "off"]:
cmd += " power %s %s" % (action, get_name_or_uuid(options))
elif action == "list":
cmd += " list -c 'Instance UUID' -c Name -c 'Power State' --format csv --quote minimal"
logging.debug("cmd -> %s" % cmd)
return run_command(options, cmd, timeout, env)
def define_new_opts():
all_opt["auth-url"] = {
"getopt" : ":",
"longopt" : "auth-url",
"help" : "--auth-url=[authurl] Auth URL",
"required" : "1",
"shortdesc" : "Keystone Admin Auth URL",
"order": 1
}
all_opt["tenant-name"] = {
"getopt" : "t:",
"longopt" : "tenant-name",
"help" : "-t, --tenant-name=[tenant] Tenantname",
"required" : "0",
"shortdesc" : "Keystone Admin Tenant",
"default": "admin",
"order": 1
}
all_opt["openstack-path"] = {
"getopt" : ":",
"longopt" : "openstack-path",
"help" : "--openstack-path=[path] Path to openstack binary",
"required" : "0",
"shortdesc" : "Path to the OpenStack binary",
"default" : "@OPENSTACK_PATH@",
"order": 200
}
def main():
atexit.register(atexit_handler)
device_opt = ["login", "passwd", "port", "auth-url", "tenant-name", "openstack-path"]
define_new_opts()
options = check_input(device_opt, process_input(device_opt))
docs = {}
docs["shortdesc"] = "Fence agent for OpenStack's Ironic (Bare Metal as a service) service"
docs["longdesc"] = "fence_ironic is a Fencing agent \
which can be used with machines controlled by the Ironic service. \
This agent calls the openstack CLI. \
WARNING! This fence agent is not intended for production use. Relying on a functional ironic service for fencing is not a good design choice."
docs["vendorurl"] = "https://wiki.openstack.org/wiki/Ironic"
show_docs(options, docs)
run_delay(options)
if not is_executable(options["--openstack-path"]):
fail_usage("openstack tool not found or not accessible")
result = fence_action(None, options, set_power_status, get_power_status, get_devices_list)
sys.exit(result)
if __name__ == "__main__":
main()
diff --git a/fence/agents/ldom/fence_ldom.py b/fence/agents/ldom/fence_ldom.py
index b4d87249..0cb3320b 100644
--- a/fence/agents/ldom/fence_ldom.py
+++ b/fence/agents/ldom/fence_ldom.py
@@ -1,108 +1,102 @@
#!@PYTHON@ -tt
##
## The Following Agent Has Been Tested On - LDOM 1.0.3
## The interface is backward compatible so it will work
## with 1.0, 1.0.1 and .2 too.
##
#####
import sys, re, pexpect
import atexit
sys.path.append("@FENCEAGENTSLIBDIR@")
from fencing import *
from fencing import fail_usage
-#BEGIN_VERSION_GENERATION
-RELEASE_VERSION="Logical Domains (LDoms) fence Agent"
-REDHAT_COPYRIGHT=""
-BUILD_DATE=""
-#END_VERSION_GENERATION
-
COMMAND_PROMPT_REG = r"\[PEXPECT\]$"
COMMAND_PROMPT_NEW = "[PEXPECT]"
# Start comunicating after login. Prepare good environment.
def start_communication(conn, options):
conn.send_eol("PS1='" + COMMAND_PROMPT_NEW + "'")
res = conn.expect([pexpect.TIMEOUT, COMMAND_PROMPT_REG], int(options["--shell-timeout"]))
if res == 0:
#CSH stuff
conn.send_eol("set prompt='" + COMMAND_PROMPT_NEW + "'")
conn.log_expect(COMMAND_PROMPT_REG, int(options["--shell-timeout"]))
def get_power_status(conn, options):
start_communication(conn, options)
conn.send_eol("ldm ls")
conn.log_expect(COMMAND_PROMPT_REG, int(options["--shell-timeout"]))
result = {}
#This is status of mini finite automata. 0 = we didn't found NAME and STATE, 1 = we did
fa_status = 0
for line in conn.before.splitlines():
domain = re.search(r"^(\S+)\s+(\S+)\s+.*$", line)
if domain != None:
if fa_status == 0 and domain.group(1) == "NAME" and domain.group(2) == "STATE":
fa_status = 1
elif fa_status == 1:
result[domain.group(1)] = ("", (domain.group(2).lower() == "bound" and "off" or "on"))
if not options["--action"] in ['monitor', 'list']:
if not options["--plug"] in result:
fail_usage("Failed: You have to enter existing logical domain!")
else:
return result[options["--plug"]][1]
else:
return result
def set_power_status(conn, options):
start_communication(conn, options)
cmd_line = "ldm "+ (options["--action"] == "on" and "start" or "stop -f") + " \"" + options["--plug"] + "\""
conn.send_eol(cmd_line)
conn.log_expect(COMMAND_PROMPT_REG, int(options["--power-timeout"]))
def main():
device_opt = ["ipaddr", "login", "passwd", "cmd_prompt", "secure", "port"]
atexit.register(atexit_handler)
all_opt["secure"]["default"] = "1"
all_opt["cmd_prompt"]["default"] = [r"\ $"]
options = check_input(device_opt, process_input(device_opt))
docs = {}
docs["shortdesc"] = "Fence agent for Sun LDOM"
docs["longdesc"] = "fence_ldom is an I/O Fencing agent \
which can be used with LDoms virtual machines. This agent works \
so, that run ldm command on host machine. So ldm must be directly \
runnable.\
\n.P\n\
Very useful parameter is -c (or cmd_prompt in stdin mode). This \
must be set to something, what is displayed after successful login \
to host machine. Default string is space on end of string (default \
for root in bash). But (for example) csh use ], so in that case you \
must use parameter -c with argument ]. Very similar situation is, \
if you use bash and login to host machine with other user than \
root. Than prompt is $, so again, you must use parameter -c."
docs["vendorurl"] = "http://www.sun.com"
show_docs(options, docs)
##
## Operate the fencing device
####
conn = fence_login(options)
result = fence_action(conn, options, set_power_status, get_power_status, get_power_status)
fence_logout(conn, "logout")
sys.exit(result)
if __name__ == "__main__":
main()
diff --git a/fence/agents/lib/fencing.py.py b/fence/agents/lib/fencing.py.py
index 4001787d..f47e4133 100644
--- a/fence/agents/lib/fencing.py.py
+++ b/fence/agents/lib/fencing.py.py
@@ -1,1451 +1,1445 @@
#!@PYTHON@ -tt
import sys, getopt, time, os, uuid, pycurl, stat
import pexpect, re, syslog
import logging
import subprocess
import threading
import shlex
import socket
import textwrap
import __main__
-## do not add code here.
-#BEGIN_VERSION_GENERATION
-RELEASE_VERSION = "New fence lib agent - test release on steroids"
-REDHAT_COPYRIGHT = ""
-BUILD_DATE = "March, 2008"
-#END_VERSION_GENERATION
+RELEASE_VERSION = "@RELEASE_VERSION@"
__all__ = ['atexit_handler', 'check_input', 'process_input', 'all_opt', 'show_docs',
'fence_login', 'fence_action', 'fence_logout']
EC_OK = 0
EC_GENERIC_ERROR = 1
EC_BAD_ARGS = 2
EC_LOGIN_DENIED = 3
EC_CONNECTION_LOST = 4
EC_TIMED_OUT = 5
EC_WAITING_ON = 6
EC_WAITING_OFF = 7
EC_STATUS = 8
EC_STATUS_HMC = 9
EC_PASSWORD_MISSING = 10
EC_INVALID_PRIVILEGES = 11
all_opt = {
"help" : {
"getopt" : "h",
"longopt" : "help",
"help" : "-h, --help Display this help and exit",
"required" : "0",
"shortdesc" : "Display help and exit",
"order" : 54},
"version" : {
"getopt" : "V",
"longopt" : "version",
"help" : "-V, --version Display version information and exit",
"required" : "0",
"shortdesc" : "Display version information and exit",
"order" : 53},
"verbose" : {
"getopt" : "v",
"longopt" : "verbose",
"help" : "-v, --verbose Verbose mode",
"required" : "0",
"order" : 51},
"debug" : {
"getopt" : "D:",
"longopt" : "debug-file",
"help" : "-D, --debug-file=[debugfile] Debugging to output file",
"required" : "0",
"shortdesc" : "Write debug information to given file",
"order" : 52},
"delay" : {
"getopt" : ":",
"longopt" : "delay",
"type" : "second",
"help" : "--delay=[seconds] Wait X seconds before fencing is started",
"required" : "0",
"default" : "0",
"order" : 200},
"agent" : {
"getopt" : "",
"help" : "",
"order" : 1},
"web" : {
"getopt" : "",
"help" : "",
"order" : 1},
"force_on" : {
"getopt" : "",
"help" : "",
"order" : 1},
"action" : {
"getopt" : "o:",
"longopt" : "action",
"help" : "-o, --action=[action] Action: status, reboot (default), off or on",
"required" : "1",
"shortdesc" : "Fencing action",
"default" : "reboot",
"order" : 1},
"fabric_fencing" : {
"getopt" : "",
"help" : "",
"order" : 1},
"ipaddr" : {
"getopt" : "a:",
"longopt" : "ip",
"help" : "-a, --ip=[ip] IP address or hostname of fencing device",
"required" : "1",
"order" : 1},
"ipport" : {
"getopt" : "u:",
"longopt" : "ipport",
"type" : "integer",
"help" : "-u, --ipport=[port] TCP/UDP port to use for connection",
"required" : "0",
"shortdesc" : "TCP/UDP port to use for connection with device",
"order" : 1},
"login" : {
"getopt" : "l:",
"longopt" : "username",
"help" : "-l, --username=[name] Login name",
"required" : "?",
"order" : 1},
"no_login" : {
"getopt" : "",
"help" : "",
"order" : 1},
"no_password" : {
"getopt" : "",
"help" : "",
"order" : 1},
"no_port" : {
"getopt" : "",
"help" : "",
"order" : 1},
"no_status" : {
"getopt" : "",
"help" : "",
"order" : 1},
"no_on" : {
"getopt" : "",
"help" : "",
"order" : 1},
"no_off" : {
"getopt" : "",
"help" : "",
"order" : 1},
"telnet" : {
"getopt" : "",
"help" : "",
"order" : 1},
"diag" : {
"getopt" : "",
"help" : "",
"order" : 1},
"passwd" : {
"getopt" : "p:",
"longopt" : "password",
"help" : "-p, --password=[password] Login password or passphrase",
"required" : "0",
"order" : 1},
"passwd_script" : {
"getopt" : "S:",
"longopt" : "password-script",
"help" : "-S, --password-script=[script] Script to run to retrieve password",
"required" : "0",
"order" : 1},
"identity_file" : {
"getopt" : "k:",
"longopt" : "identity-file",
"help" : "-k, --identity-file=[filename] Identity file (private key) for SSH",
"required" : "0",
"order" : 1},
"cmd_prompt" : {
"getopt" : "c:",
"longopt" : "command-prompt",
"help" : "-c, --command-prompt=[prompt] Force Python regex for command prompt",
"required" : "0",
"order" : 1},
"secure" : {
"getopt" : "x",
"longopt" : "ssh",
"help" : "-x, --ssh Use SSH connection",
"required" : "0",
"order" : 1},
"ssh_options" : {
"getopt" : ":",
"longopt" : "ssh-options",
"help" : "--ssh-options=[options] SSH options to use",
"required" : "0",
"order" : 1},
"ssl" : {
"getopt" : "z",
"longopt" : "ssl",
"help" : "-z, --ssl Use SSL connection with verifying certificate",
"required" : "0",
"order" : 1},
"ssl_insecure" : {
"getopt" : "",
"longopt" : "ssl-insecure",
"help" : "--ssl-insecure Use SSL connection without verifying certificate",
"required" : "0",
"order" : 1},
"ssl_secure" : {
"getopt" : "",
"longopt" : "ssl-secure",
"help" : "--ssl-secure Use SSL connection with verifying certificate",
"required" : "0",
"order" : 1},
"notls" : {
"getopt" : "t",
"longopt" : "notls",
"help" : "-t, --notls "
"Disable TLS negotiation and force SSL3.0. "
"This should only be used for devices that do not support TLS1.0 and up.",
"required" : "0",
"order" : 1},
"tls1.0" : {
"getopt" : "",
"longopt" : "tls1.0",
"help" : "--tls1.0 "
"Disable TLS negotiation and force TLS1.0. "
"This should only be used for devices that do not support TLS1.1 and up.",
"required" : "0",
"order" : 1},
"port" : {
"getopt" : "n:",
"longopt" : "plug",
"help" : "-n, --plug=[id] "
"Physical plug number on device, UUID or identification of machine",
"required" : "1",
"order" : 1},
"switch" : {
"getopt" : "s:",
"longopt" : "switch",
"help" : "-s, --switch=[id] Physical switch number on device",
"required" : "0",
"order" : 1},
"exec" : {
"getopt" : "e:",
"longopt" : "exec",
"help" : "-e, --exec=[command] Command to execute",
"required" : "0",
"order" : 1},
"vmware_type" : {
"getopt" : "d:",
"longopt" : "vmware_type",
"help" : "-d, --vmware_type=[type] Type of VMware to connect",
"required" : "0",
"order" : 1},
"vmware_datacenter" : {
"getopt" : "s:",
"longopt" : "vmware-datacenter",
"help" : "-s, --vmware-datacenter=[dc] VMWare datacenter filter",
"required" : "0",
"order" : 2},
"snmp_version" : {
"getopt" : "d:",
"longopt" : "snmp-version",
"help" : "-d, --snmp-version=[version] Specifies SNMP version to use (1|2c|3)",
"required" : "0",
"shortdesc" : "Specifies SNMP version to use",
"choices" : ["1", "2c", "3"],
"order" : 1},
"community" : {
"getopt" : "c:",
"longopt" : "community",
"help" : "-c, --community=[community] Set the community string",
"required" : "0",
"order" : 1},
"snmp_auth_prot" : {
"getopt" : "b:",
"longopt" : "snmp-auth-prot",
"help" : "-b, --snmp-auth-prot=[prot] Set authentication protocol (MD5|SHA)",
"required" : "0",
"shortdesc" : "Set authentication protocol",
"choices" : ["MD5", "SHA"],
"order" : 1},
"snmp_sec_level" : {
"getopt" : "E:",
"longopt" : "snmp-sec-level",
"help" : "-E, --snmp-sec-level=[level] "
"Set security level (noAuthNoPriv|authNoPriv|authPriv)",
"required" : "0",
"shortdesc" : "Set security level",
"choices" : ["noAuthNoPriv", "authNoPriv", "authPriv"],
"order" : 1},
"snmp_priv_prot" : {
"getopt" : "B:",
"longopt" : "snmp-priv-prot",
"help" : "-B, --snmp-priv-prot=[prot] Set privacy protocol (DES|AES)",
"required" : "0",
"shortdesc" : "Set privacy protocol",
"choices" : ["DES", "AES"],
"order" : 1},
"snmp_priv_passwd" : {
"getopt" : "P:",
"longopt" : "snmp-priv-passwd",
"help" : "-P, --snmp-priv-passwd=[pass] Set privacy protocol password",
"required" : "0",
"order" : 1},
"snmp_priv_passwd_script" : {
"getopt" : "R:",
"longopt" : "snmp-priv-passwd-script",
"help" : "-R, --snmp-priv-passwd-script Script to run to retrieve privacy password",
"required" : "0",
"order" : 1},
"inet4_only" : {
"getopt" : "4",
"longopt" : "inet4-only",
"help" : "-4, --inet4-only Forces agent to use IPv4 addresses only",
"required" : "0",
"order" : 1},
"inet6_only" : {
"getopt" : "6",
"longopt" : "inet6-only",
"help" : "-6, --inet6-only Forces agent to use IPv6 addresses only",
"required" : "0",
"order" : 1},
"separator" : {
"getopt" : "C:",
"longopt" : "separator",
"help" : "-C, --separator=[char] Separator for CSV created by 'list' operation",
"default" : ",",
"required" : "0",
"order" : 100},
"login_timeout" : {
"getopt" : ":",
"longopt" : "login-timeout",
"type" : "second",
"help" : "--login-timeout=[seconds] Wait X seconds for cmd prompt after login",
"default" : "5",
"required" : "0",
"order" : 200},
"shell_timeout" : {
"getopt" : ":",
"longopt" : "shell-timeout",
"type" : "second",
"help" : "--shell-timeout=[seconds] Wait X seconds for cmd prompt after issuing command",
"default" : "3",
"required" : "0",
"order" : 200},
"power_timeout" : {
"getopt" : ":",
"longopt" : "power-timeout",
"type" : "second",
"help" : "--power-timeout=[seconds] Test X seconds for status change after ON/OFF",
"default" : "20",
"required" : "0",
"order" : 200},
"power_wait" : {
"getopt" : ":",
"longopt" : "power-wait",
"type" : "second",
"help" : "--power-wait=[seconds] Wait X seconds after issuing ON/OFF",
"default" : "0",
"required" : "0",
"order" : 200},
"missing_as_off" : {
"getopt" : "",
"longopt" : "missing-as-off",
"help" : "--missing-as-off Missing port returns OFF instead of failure",
"required" : "0",
"order" : 200},
"retry_on" : {
"getopt" : ":",
"longopt" : "retry-on",
"type" : "integer",
"help" : "--retry-on=[attempts] Count of attempts to retry power on",
"default" : "1",
"required" : "0",
"order" : 201},
"session_url" : {
"getopt" : "s:",
"longopt" : "session-url",
"help" : "-s, --session-url URL to connect to XenServer on",
"required" : "1",
"order" : 1},
"sudo" : {
"getopt" : "",
"longopt" : "use-sudo",
"help" : "--use-sudo Use sudo (without password) when calling 3rd party software",
"required" : "0",
"order" : 205},
"method" : {
"getopt" : "m:",
"longopt" : "method",
"help" : "-m, --method=[method] Method to fence (onoff|cycle) (Default: onoff)",
"required" : "0",
"shortdesc" : "Method to fence",
"default" : "onoff",
"choices" : ["onoff", "cycle"],
"order" : 1},
"telnet_path" : {
"getopt" : ":",
"longopt" : "telnet-path",
"help" : "--telnet-path=[path] Path to telnet binary",
"required" : "0",
"default" : "@TELNET_PATH@",
"order": 300},
"ssh_path" : {
"getopt" : ":",
"longopt" : "ssh-path",
"help" : "--ssh-path=[path] Path to ssh binary",
"required" : "0",
"default" : "@SSH_PATH@",
"order": 300},
"gnutlscli_path" : {
"getopt" : ":",
"longopt" : "gnutlscli-path",
"help" : "--gnutlscli-path=[path] Path to gnutls-cli binary",
"required" : "0",
"default" : "@GNUTLSCLI_PATH@",
"order": 300},
"sudo_path" : {
"getopt" : ":",
"longopt" : "sudo-path",
"help" : "--sudo-path=[path] Path to sudo binary",
"required" : "0",
"default" : "@SUDO_PATH@",
"order": 300},
"snmpwalk_path" : {
"getopt" : ":",
"longopt" : "snmpwalk-path",
"help" : "--snmpwalk-path=[path] Path to snmpwalk binary",
"required" : "0",
"default" : "@SNMPWALK_PATH@",
"order" : 300},
"snmpset_path" : {
"getopt" : ":",
"longopt" : "snmpset-path",
"help" : "--snmpset-path=[path] Path to snmpset binary",
"required" : "0",
"default" : "@SNMPSET_PATH@",
"order" : 300},
"snmpget_path" : {
"getopt" : ":",
"longopt" : "snmpget-path",
"help" : "--snmpget-path=[path] Path to snmpget binary",
"required" : "0",
"default" : "@SNMPGET_PATH@",
"order" : 300},
"snmp": {
"getopt" : "",
"help" : "",
"order" : 1},
"port_as_ip": {
"getopt" : "",
"longopt" : "port-as-ip",
"help" : "--port-as-ip Make \"port/plug\" to be an alias to IP address",
"required" : "0",
"order" : 200},
"on_target": {
"getopt" : "",
"help" : "",
"order" : 1},
"quiet": {
"getopt" : "q",
"longopt": "quiet",
"help" : "-q, --quiet Disable logging to stderr. Does not affect --verbose or --debug logging to syslog.",
"required" : "0",
"order" : 50}
}
# options which are added automatically if 'key' is encountered ("default" is always added)
DEPENDENCY_OPT = {
"default" : ["help", "debug", "verbose", "version", "action", "agent", \
"power_timeout", "shell_timeout", "login_timeout", "power_wait", "retry_on", \
"delay", "quiet"],
"passwd" : ["passwd_script"],
"sudo" : ["sudo_path"],
"secure" : ["identity_file", "ssh_options", "ssh_path"],
"telnet" : ["telnet_path"],
"ipaddr" : ["ipport", "inet4_only", "inet6_only"],
"port" : ["separator"],
"ssl" : ["ssl_secure", "ssl_insecure", "gnutlscli_path"],
"snmp" : ["snmp_auth_prot", "snmp_sec_level", "snmp_priv_prot", \
"snmp_priv_passwd", "snmp_priv_passwd_script", "community", \
"snmpset_path", "snmpget_path", "snmpwalk_path"]
}
class fspawn(pexpect.spawn):
def __init__(self, options, command):
logging.info("Running command: %s", command)
pexpect.spawn.__init__(self, command)
self.opt = options
def log_expect(self, pattern, timeout):
result = self.expect(pattern, timeout)
logging.debug("Received: %s", self.before + self.after)
return result
def send(self, message):
logging.debug("Sent: %s", message)
return pexpect.spawn.send(self, message)
# send EOL according to what was detected in login process (telnet)
def send_eol(self, message):
return self.send(message + self.opt["eol"])
def atexit_handler():
try:
sys.stdout.close()
os.close(1)
except IOError:
logging.error("%s failed to close standard output\n", sys.argv[0])
sys.exit(EC_GENERIC_ERROR)
def _add_dependency_options(options):
## Add also options which are available for every fence agent
added_opt = []
for opt in options + ["default"]:
if opt in DEPENDENCY_OPT:
added_opt.extend([y for y in DEPENDENCY_OPT[opt] if options.count(y) == 0])
if not "port" in (options + added_opt) and \
not "nodename" in (options + added_opt) and \
"ipaddr" in (options + added_opt):
added_opt.append("port_as_ip")
all_opt["port"]["help"] = "-n, --plug=[ip] IP address or hostname of fencing device " \
"(together with --port-as-ip)"
return added_opt
def fail_usage(message="", stop=True):
if len(message) > 0:
logging.error("%s\n", message)
if stop:
logging.error("Please use '-h' for usage\n")
sys.exit(EC_GENERIC_ERROR)
def fail(error_code):
message = {
EC_LOGIN_DENIED : "Unable to connect/login to fencing device",
EC_CONNECTION_LOST : "Connection lost",
EC_TIMED_OUT : "Connection timed out",
EC_WAITING_ON : "Failed: Timed out waiting to power ON",
EC_WAITING_OFF : "Failed: Timed out waiting to power OFF",
EC_STATUS : "Failed: Unable to obtain correct plug status or plug is not available",
EC_STATUS_HMC : "Failed: Either unable to obtain correct plug status, "
"partition is not available or incorrect HMC version used",
EC_PASSWORD_MISSING : "Failed: You have to set login password",
EC_INVALID_PRIVILEGES : "Failed: The user does not have the correct privileges to do the requested action."
}[error_code] + "\n"
logging.error("%s\n", message)
sys.exit(EC_GENERIC_ERROR)
def usage(avail_opt):
print("Usage:")
print("\t" + os.path.basename(sys.argv[0]) + " [options]")
print("Options:")
sorted_list = [(key, all_opt[key]) for key in avail_opt]
sorted_list.sort(key=lambda x: x[1]["order"])
for key, value in sorted_list:
if len(value["help"]) != 0:
print(" " + _join_wrap([value["help"]], first_indent=3))
def metadata(avail_opt, docs):
# avail_opt has to be unique, if there are duplicities then they should be removed
sorted_list = [(key, all_opt[key]) for key in list(set(avail_opt)) if "longopt" in all_opt[key]]
# Find keys that are going to replace inconsistent names
mapping = dict([(opt["longopt"].replace("-", "_"), key) for (key, opt) in sorted_list if (key != opt["longopt"].replace("-", "_"))])
new_options = [(key, all_opt[mapping[key]]) for key in mapping]
sorted_list.extend(new_options)
sorted_list.sort(key=lambda x: (x[1]["order"], x[0]))
print("<?xml version=\"1.0\" ?>")
print("<resource-agent name=\"" + os.path.basename(sys.argv[0]) + \
"\" shortdesc=\"" + docs["shortdesc"] + "\" >")
for (symlink, desc) in docs.get("symlink", []):
print("<symlink name=\"" + symlink + "\" shortdesc=\"" + desc + "\"/>")
print("<longdesc>" + docs["longdesc"] + "</longdesc>")
print("<vendor-url>" + docs["vendorurl"] + "</vendor-url>")
print("<parameters>")
for (key, opt) in sorted_list:
info = ""
if key in all_opt:
if key != all_opt[key].get('longopt', key).replace("-", "_"):
info = "deprecated=\"1\""
else:
info = "obsoletes=\"%s\"" % (mapping.get(key))
if "help" in opt and len(opt["help"]) > 0:
if info != "":
info = " " + info
print("\t<parameter name=\"" + key + "\" unique=\"0\" required=\"" + opt["required"] + "\"" + info + ">")
default = ""
if "default" in opt:
default = "default=\"" + _encode_html_entities(str(opt["default"])) + "\" "
mixed = opt["help"]
## split it between option and help text
res = re.compile(r"^(.*?--\S+)\s+", re.IGNORECASE | re.S).search(mixed)
if None != res:
mixed = res.group(1)
mixed = _encode_html_entities(mixed)
if not "shortdesc" in opt:
shortdesc = re.sub("\s\s+", " ", opt["help"][31:])
else:
shortdesc = opt["shortdesc"]
print("\t\t<getopt mixed=\"" + mixed + "\" />")
if "choices" in opt:
print("\t\t<content type=\"select\" "+default+" >")
for choice in opt["choices"]:
print("\t\t\t<option value=\"%s\" />" % (choice))
print("\t\t</content>")
elif opt["getopt"].count(":") > 0:
t = opt.get("type", "string")
print("\t\t<content type=\"%s\" " % (t) +default+" />")
else:
print("\t\t<content type=\"boolean\" "+default+" />")
print("\t\t<shortdesc lang=\"en\">" + shortdesc + "</shortdesc>")
print("\t</parameter>")
print("</parameters>")
print("<actions>")
(available_actions, _) = _get_available_actions(avail_opt)
if "on" in available_actions:
available_actions.remove("on")
on_target = ' on_target="1"' if avail_opt.count("on_target") else ''
print("\t<action name=\"on\"%s automatic=\"%d\"/>" % (on_target, avail_opt.count("fabric_fencing")))
for action in available_actions:
print("\t<action name=\"%s\" />" % (action))
print("</actions>")
print("</resource-agent>")
def process_input(avail_opt):
avail_opt.extend(_add_dependency_options(avail_opt))
# @todo: this should be put elsewhere?
os.putenv("LANG", "C")
os.putenv("LC_ALL", "C")
if "port_as_ip" in avail_opt:
avail_opt.append("port")
if len(sys.argv) > 1:
opt = _parse_input_cmdline(avail_opt)
else:
opt = _parse_input_stdin(avail_opt)
if "--port-as-ip" in opt and "--plug" in opt:
opt["--ip"] = opt["--plug"]
return opt
##
## This function checks input and answers if we want to have same answers
## in each of the fencing agents. It looks for possible errors and run
## password script to set a correct password
######
def check_input(device_opt, opt, other_conditions = False):
device_opt.extend(_add_dependency_options(device_opt))
options = dict(opt)
options["device_opt"] = device_opt
_update_metadata(options)
options = _set_default_values(options)
options["--action"] = options["--action"].lower()
## In special cases (show help, metadata or version) we don't need to check anything
#####
# OCF compatibility
if options["--action"] == "meta-data":
options["--action"] = "metadata"
if options["--action"] == "metadata" or any(k in options for k in ("--help", "--version")):
return options
if "--verbose" in options:
logging.getLogger().setLevel(logging.DEBUG)
## add logging to syslog
logging.getLogger().addHandler(SyslogLibHandler())
if "--quiet" not in options:
## add logging to stderr
logging.getLogger().addHandler(logging.StreamHandler(sys.stderr))
(acceptable_actions, _) = _get_available_actions(device_opt)
if 1 == device_opt.count("fabric_fencing"):
acceptable_actions.extend(["enable", "disable"])
if 0 == acceptable_actions.count(options["--action"]):
fail_usage("Failed: Unrecognised action '" + options["--action"] + "'")
## Compatibility layer
#####
if options["--action"] == "enable":
options["--action"] = "on"
if options["--action"] == "disable":
options["--action"] = "off"
if options["--action"] == "validate-all" and not other_conditions:
if not _validate_input(options, False):
fail_usage("validate-all failed")
sys.exit(EC_OK)
else:
_validate_input(options, True)
if "--debug-file" in options:
try:
debug_file = logging.FileHandler(options["--debug-file"])
debug_file.setLevel(logging.DEBUG)
logging.getLogger().addHandler(debug_file)
except IOError:
logging.error("Unable to create file %s", options["--debug-file"])
fail_usage("Failed: Unable to create file " + options["--debug-file"])
if "--snmp-priv-passwd-script" in options:
options["--snmp-priv-passwd"] = os.popen(options["--snmp-priv-passwd-script"]).read().rstrip()
if "--password-script" in options:
options["--password"] = os.popen(options["--password-script"]).read().rstrip()
return options
## Obtain a power status from possibly more than one plug
## "on" is returned if at least one plug is ON
######
def get_multi_power_fn(connection, options, get_power_fn):
status = "off"
plugs = options["--plugs"] if "--plugs" in options else [""]
for plug in plugs:
try:
options["--uuid"] = str(uuid.UUID(plug))
except ValueError:
pass
except KeyError:
pass
options["--plug"] = plug
plug_status = get_power_fn(connection, options)
if plug_status != "off":
status = plug_status
return status
def set_multi_power_fn(connection, options, set_power_fn, get_power_fn, retry_attempts=1):
plugs = options["--plugs"] if "--plugs" in options else [""]
for _ in range(retry_attempts):
for plug in plugs:
try:
options["--uuid"] = str(uuid.UUID(plug))
except ValueError:
pass
except KeyError:
pass
options["--plug"] = plug
set_power_fn(connection, options)
time.sleep(int(options["--power-wait"]))
for _ in range(int(options["--power-timeout"])):
if get_multi_power_fn(connection, options, get_power_fn) != options["--action"]:
time.sleep(1)
else:
return True
return False
def show_docs(options, docs=None):
device_opt = options["device_opt"]
if docs == None:
docs = {}
docs["shortdesc"] = "Fence agent"
docs["longdesc"] = ""
if "--help" in options:
usage(device_opt)
sys.exit(0)
if options.get("--action", "") == "metadata":
if "port_as_ip" in device_opt:
device_opt.remove("separator")
metadata(device_opt, docs)
sys.exit(0)
if "--version" in options:
- print(__main__.RELEASE_VERSION, __main__.BUILD_DATE)
- print(__main__.REDHAT_COPYRIGHT)
+ print(RELEASE_VERSION)
sys.exit(0)
def fence_action(connection, options, set_power_fn, get_power_fn, get_outlet_list=None, reboot_cycle_fn=None):
result = 0
try:
if "--plug" in options:
options["--plugs"] = options["--plug"].split(",")
## Process options that manipulate fencing device
#####
if (options["--action"] in ["list", "list-status"]) or \
((options["--action"] == "monitor") and 1 == options["device_opt"].count("port") and \
0 == options["device_opt"].count("port_as_ip")):
if 0 == options["device_opt"].count("port"):
print("N/A")
elif get_outlet_list == None:
## @todo: exception?
## This is just temporal solution, we will remove default value
## None as soon as all existing agent will support this operation
print("NOTICE: List option is not working on this device yet")
else:
options["--original-action"] = options["--action"]
options["--action"] = "list"
outlets = get_outlet_list(connection, options)
options["--action"] = options["--original-action"]
del options["--original-action"]
## keys can be numbers (port numbers) or strings (names of VM, UUID)
for outlet_id in list(outlets.keys()):
(alias, status) = outlets[outlet_id]
if status is None or (not status.upper() in ["ON", "OFF"]):
status = "UNKNOWN"
status = status.upper()
if options["--action"] == "list":
print(outlet_id + options["--separator"] + alias)
elif options["--action"] == "list-status":
print(outlet_id + options["--separator"] + alias + options["--separator"] + status)
return
if options["--action"] == "monitor" and not "port" in options["device_opt"] and "no_status" in options["device_opt"]:
# Unable to do standard monitoring because 'status' action is not available
return 0
status = None
if not "no_status" in options["device_opt"]:
status = get_multi_power_fn(connection, options, get_power_fn)
if status != "on" and status != "off":
fail(EC_STATUS)
if options["--action"] == status:
if not (status == "on" and "force_on" in options["device_opt"]):
print("Success: Already %s" % (status.upper()))
return 0
if options["--action"] == "on":
if set_multi_power_fn(connection, options, set_power_fn, get_power_fn, 1 + int(options["--retry-on"])):
print("Success: Powered ON")
else:
fail(EC_WAITING_ON)
elif options["--action"] == "off":
if set_multi_power_fn(connection, options, set_power_fn, get_power_fn):
print("Success: Powered OFF")
else:
fail(EC_WAITING_OFF)
elif options["--action"] == "reboot":
power_on = False
if options.get("--method", "").lower() == "cycle" and reboot_cycle_fn is not None:
for _ in range(1, 1 + int(options["--retry-on"])):
if reboot_cycle_fn(connection, options):
power_on = True
break
if not power_on:
fail(EC_TIMED_OUT)
else:
if status != "off":
options["--action"] = "off"
if not set_multi_power_fn(connection, options, set_power_fn, get_power_fn):
fail(EC_WAITING_OFF)
options["--action"] = "on"
try:
power_on = set_multi_power_fn(connection, options, set_power_fn, get_power_fn, int(options["--retry-on"]))
except Exception as ex:
# an error occured during power ON phase in reboot
# fence action was completed succesfully even in that case
logging.warning("%s", str(ex))
if power_on == False:
# this should not fail as node was fenced succesfully
logging.error('Timed out waiting to power ON\n')
print("Success: Rebooted")
elif options["--action"] == "status":
print("Status: " + status.upper())
if status.upper() == "OFF":
result = 2
elif options["--action"] == "monitor":
pass
except pexpect.EOF:
fail(EC_CONNECTION_LOST)
except pexpect.TIMEOUT:
fail(EC_TIMED_OUT)
except pycurl.error as ex:
logging.error("%s\n", str(ex))
fail(EC_TIMED_OUT)
except socket.timeout as ex:
logging.error("%s\n", str(ex))
fail(EC_TIMED_OUT)
return result
def fence_login(options, re_login_string=r"(login\s*: )|((?!Last )Login Name: )|(username: )|(User Name :)"):
run_delay(options)
if "eol" not in options:
options["eol"] = "\r\n"
if "--command-prompt" in options and type(options["--command-prompt"]) is not list:
options["--command-prompt"] = [options["--command-prompt"]]
try:
if "--ssl" in options:
conn = _open_ssl_connection(options)
elif "--ssh" in options and "--identity-file" not in options:
conn = _login_ssh_with_password(options, re_login_string)
elif "--ssh" in options and "--identity-file" in options:
conn = _login_ssh_with_identity_file(options)
else:
conn = _login_telnet(options, re_login_string)
except pexpect.EOF as exception:
logging.debug("%s", str(exception))
fail(EC_LOGIN_DENIED)
except pexpect.TIMEOUT as exception:
logging.debug("%s", str(exception))
fail(EC_LOGIN_DENIED)
return conn
def is_executable(path):
if os.path.exists(path):
stats = os.stat(path)
if stat.S_ISREG(stats.st_mode) and os.access(path, os.X_OK):
return True
return False
def run_command(options, command, timeout=None, env=None, log_command=None):
if timeout is None and "--power-timeout" in options:
timeout = options["--power-timeout"]
if timeout is not None:
timeout = float(timeout)
logging.info("Executing: %s\n", log_command or command)
try:
process = subprocess.Popen(shlex.split(command), stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env)
except OSError:
fail_usage("Unable to run %s\n" % command)
thread = threading.Thread(target=process.wait)
thread.start()
thread.join(timeout)
if thread.is_alive():
process.kill()
fail(EC_TIMED_OUT)
status = process.wait()
(pipe_stdout, pipe_stderr) = process.communicate()
process.stdout.close()
process.stderr.close()
logging.debug("%s %s %s\n", str(status), str(pipe_stdout), str(pipe_stderr))
return (status, pipe_stdout, pipe_stderr)
def run_delay(options):
## Delay is important for two-node clusters fencing but we do not need to delay 'status' operations
if options["--action"] in ["off", "reboot"]:
logging.info("Delay %s second(s) before logging in to the fence device", options["--delay"])
time.sleep(int(options["--delay"]))
def fence_logout(conn, logout_string, sleep=0):
# Logout is not required part of fencing but we should attempt to do it properly
# In some cases our 'exit' command is faster and we can not close connection as it
# was already closed by fencing device
try:
conn.send_eol(logout_string)
time.sleep(sleep)
conn.close()
except OSError:
pass
except pexpect.ExceptionPexpect:
pass
# Convert array of format [[key1, value1], [key2, value2], ... [keyN, valueN]] to dict, where key is
# in format a.b.c.d...z and returned dict has key only z
def array_to_dict(array):
return dict([[x[0].split(".")[-1], x[1]] for x in array])
## Own logger handler that uses old-style syslog handler as otherwise everything is sourced
## from /dev/syslog
class SyslogLibHandler(logging.StreamHandler):
"""
A handler class that correctly push messages into syslog
"""
def emit(self, record):
syslog_level = {
logging.CRITICAL:syslog.LOG_CRIT,
logging.ERROR:syslog.LOG_ERR,
logging.WARNING:syslog.LOG_WARNING,
logging.INFO:syslog.LOG_INFO,
logging.DEBUG:syslog.LOG_DEBUG,
logging.NOTSET:syslog.LOG_DEBUG,
}[record.levelno]
msg = self.format(record)
# syslos.syslog can not have 0x00 character inside or exception is thrown
syslog.syslog(syslog_level, msg.replace("\x00", "\n"))
return
def _open_ssl_connection(options):
gnutls_opts = ""
ssl_opts = ""
if "--notls" in options:
gnutls_opts = "--priority \"NORMAL:-VERS-TLS1.2:-VERS-TLS1.1:-VERS-TLS1.0:+VERS-SSL3.0\""
elif "--tls1.0" in options:
gnutls_opts = "--priority \"NORMAL:-VERS-TLS1.2:-VERS-TLS1.1:+VERS-TLS1.0:%LATEST_RECORD_VERSION\""
# --ssl is same as the --ssl-secure; it means we want to verify certificate in these cases
if "--ssl-insecure" in options:
ssl_opts = "--insecure"
command = '%s %s %s --crlf -p %s %s' % \
(options["--gnutlscli-path"], gnutls_opts, ssl_opts, options["--ipport"], options["--ip"])
try:
conn = fspawn(options, command)
except pexpect.ExceptionPexpect as ex:
logging.error("%s\n", str(ex))
sys.exit(EC_GENERIC_ERROR)
return conn
def _login_ssh_with_identity_file(options):
if "--inet6-only" in options:
force_ipvx = "-6 "
elif "--inet4-only" in options:
force_ipvx = "-4 "
else:
force_ipvx = ""
command = '%s %s %s@%s -i %s -p %s' % \
(options["--ssh-path"], force_ipvx, options["--username"], options["--ip"], \
options["--identity-file"], options["--ipport"])
if "--ssh-options" in options:
command += ' ' + options["--ssh-options"]
conn = fspawn(options, command)
result = conn.log_expect(["Enter passphrase for key '" + options["--identity-file"] + "':", \
"Are you sure you want to continue connecting (yes/no)?"] + \
options["--command-prompt"], int(options["--login-timeout"]))
if result == 1:
conn.sendline("yes")
result = conn.log_expect(
["Enter passphrase for key '" + options["--identity-file"]+"':"] + \
options["--command-prompt"], int(options["--login-timeout"]))
if result == 0:
if "--password" in options:
conn.sendline(options["--password"])
conn.log_expect(options["--command-prompt"], int(options["--login-timeout"]))
else:
fail_usage("Failed: You have to enter passphrase (-p) for identity file")
return conn
def _login_telnet(options, re_login_string):
re_login = re.compile(re_login_string, re.IGNORECASE)
re_pass = re.compile("(password)|(pass phrase)", re.IGNORECASE)
conn = fspawn(options, options["--telnet-path"])
conn.send("set binary\n")
conn.send("open %s -%s\n"%(options["--ip"], options["--ipport"]))
conn.log_expect(re_login, int(options["--login-timeout"]))
conn.send_eol(options["--username"])
## automatically change end of line separator
screen = conn.read_nonblocking(size=100, timeout=int(options["--shell-timeout"]))
if re_login.search(screen) != None:
options["eol"] = "\n"
conn.send_eol(options["--username"])
conn.log_expect(re_pass, int(options["--login-timeout"]))
elif re_pass.search(screen) == None:
conn.log_expect(re_pass, int(options["--shell-timeout"]))
try:
conn.send_eol(options["--password"])
valid_password = conn.log_expect([re_login] + \
options["--command-prompt"], int(options["--shell-timeout"]))
if valid_password == 0:
## password is invalid or we have to change EOL separator
options["eol"] = "\r"
conn.send_eol("")
screen = conn.read_nonblocking(size=100, timeout=int(options["--shell-timeout"]))
## after sending EOL the fence device can either show 'Login' or 'Password'
if re_login.search(conn.after + screen) != None:
conn.send_eol("")
conn.send_eol(options["--username"])
conn.log_expect(re_pass, int(options["--login-timeout"]))
conn.send_eol(options["--password"])
conn.log_expect(options["--command-prompt"], int(options["--login-timeout"]))
except KeyError:
fail(EC_PASSWORD_MISSING)
return conn
def _login_ssh_with_password(options, re_login_string):
re_login = re.compile(re_login_string, re.IGNORECASE)
re_pass = re.compile("(password)|(pass phrase)", re.IGNORECASE)
if "--inet6-only" in options:
force_ipvx = "-6 "
elif "--inet4-only" in options:
force_ipvx = "-4 "
else:
force_ipvx = ""
command = '%s %s %s@%s -p %s -o PubkeyAuthentication=no' % \
(options["--ssh-path"], force_ipvx, options["--username"], options["--ip"], options["--ipport"])
if "--ssh-options" in options:
command += ' ' + options["--ssh-options"]
conn = fspawn(options, command)
if "telnet_over_ssh" in options:
# This is for stupid ssh servers (like ALOM) which behave more like telnet
# (ignore name and display login prompt)
result = conn.log_expect( \
[re_login, "Are you sure you want to continue connecting (yes/no)?"],
int(options["--login-timeout"]))
if result == 1:
conn.sendline("yes") # Host identity confirm
conn.log_expect(re_login, int(options["--login-timeout"]))
conn.sendline(options["--username"])
conn.log_expect(re_pass, int(options["--login-timeout"]))
else:
result = conn.log_expect( \
["ssword:", "Are you sure you want to continue connecting (yes/no)?"],
int(options["--login-timeout"]))
if result == 1:
conn.sendline("yes")
conn.log_expect("ssword:", int(options["--login-timeout"]))
conn.sendline(options["--password"])
conn.log_expect(options["--command-prompt"], int(options["--login-timeout"]))
return conn
#
# To update metadata, we change values in all_opt
def _update_metadata(options):
device_opt = options["device_opt"]
if device_opt.count("login") and device_opt.count("no_login") == 0:
all_opt["login"]["required"] = "1"
else:
all_opt["login"]["required"] = "0"
if device_opt.count("port_as_ip"):
all_opt["ipaddr"]["required"] = "0"
all_opt["port"]["required"] = "0"
(available_actions, default_value) = _get_available_actions(device_opt)
all_opt["action"]["default"] = default_value
actions_with_default = \
[x if not x == all_opt["action"]["default"] else x + " (default)" for x in available_actions]
all_opt["action"]["help"] = \
"-o, --action=[action] Action: %s" % (_join_wrap(actions_with_default, last_separator=" or "))
if device_opt.count("ipport"):
default_value = None
default_string = None
if "default" in all_opt["ipport"]:
default_value = all_opt["ipport"]["default"]
elif device_opt.count("web") and device_opt.count("ssl"):
default_value = "80"
default_string = "(default 80, 443 if --ssl option is used)"
elif device_opt.count("telnet") and device_opt.count("secure"):
default_value = "23"
default_string = "(default 23, 22 if --ssh option is used)"
else:
tcp_ports = {"community" : "161", "secure" : "22", "telnet" : "23", "web" : "80", "ssl" : "443"}
# all cases where next command returns multiple results are covered by previous blocks
protocol = [x for x in ["community", "secure", "ssl", "web", "telnet"] if device_opt.count(x)][0]
default_value = tcp_ports[protocol]
if default_string is None:
all_opt["ipport"]["help"] = "-u, --ipport=[port] TCP/UDP port to use (default %s)" % \
(default_value)
else:
all_opt["ipport"]["help"] = "-u, --ipport=[port] TCP/UDP port to use\n" + " "*40 + default_string
def _set_default_values(options):
if "ipport" in options["device_opt"]:
if not "--ipport" in options:
if "default" in all_opt["ipport"]:
options["--ipport"] = all_opt["ipport"]["default"]
elif "community" in options["device_opt"]:
options["--ipport"] = "161"
elif "--ssh" in options or all_opt["secure"].get("default", "0") == "1":
options["--ipport"] = "22"
elif "--ssl" in options or all_opt["ssl"].get("default", "0") == "1":
options["--ipport"] = "443"
elif "--ssl-secure" in options or all_opt["ssl_secure"].get("default", "0") == "1":
options["--ipport"] = "443"
elif "--ssl-insecure" in options or all_opt["ssl_insecure"].get("default", "0") == "1":
options["--ipport"] = "443"
elif "web" in options["device_opt"]:
options["--ipport"] = "80"
elif "telnet" in options["device_opt"]:
options["--ipport"] = "23"
if "--ipport" in options:
all_opt["ipport"]["default"] = options["--ipport"]
for opt in options["device_opt"]:
if "default" in all_opt[opt] and not opt == "ipport":
getopt_long = "--" + all_opt[opt]["longopt"]
if getopt_long not in options:
options[getopt_long] = all_opt[opt]["default"]
return options
# stop = True/False : exit fence agent when problem is encountered
def _validate_input(options, stop = True):
device_opt = options["device_opt"]
valid_input = True
if "--username" not in options and \
device_opt.count("login") and (device_opt.count("no_login") == 0):
valid_input = False
fail_usage("Failed: You have to set login name", stop)
if device_opt.count("ipaddr") and "--ip" not in options and "--managed" not in options and "--target" not in options:
valid_input = False
fail_usage("Failed: You have to enter fence address", stop)
if device_opt.count("no_password") == 0:
if 0 == device_opt.count("identity_file"):
if not ("--password" in options or "--password-script" in options):
valid_input = False
fail_usage("Failed: You have to enter password or password script", stop)
else:
if not ("--password" in options or \
"--password-script" in options or "--identity-file" in options):
valid_input = False
fail_usage("Failed: You have to enter password, password script or identity file", stop)
if "--ssh" not in options and "--identity-file" in options:
valid_input = False
fail_usage("Failed: You have to use identity file together with ssh connection (-x)", stop)
if "--identity-file" in options and not os.path.isfile(options["--identity-file"]):
valid_input = False
fail_usage("Failed: Identity file " + options["--identity-file"] + " does not exist", stop)
if (0 == ["list", "list-status", "monitor"].count(options["--action"])) and \
"--plug" not in options and device_opt.count("port") and \
device_opt.count("no_port") == 0 and not device_opt.count("port_as_ip"):
valid_input = False
fail_usage("Failed: You have to enter plug number or machine identification", stop)
if "--plug" in options and len(options["--plug"].split(",")) > 1 and \
"--method" in options and options["--method"] == "cycle":
valid_input = False
fail_usage("Failed: Cannot use --method cycle for more than 1 plug", stop)
for failed_opt in _get_opts_with_invalid_choices(options):
valid_input = False
fail_usage("Failed: You have to enter a valid choice for %s from the valid values: %s" % \
("--" + all_opt[failed_opt]["longopt"], str(all_opt[failed_opt]["choices"])), stop)
for failed_opt in _get_opts_with_invalid_types(options):
valid_input = False
if all_opt[failed_opt]["type"] == "second":
fail_usage("Failed: The value you have entered for %s is not a valid time in seconds" % \
("--" + all_opt[failed_opt]["longopt"]), stop)
else:
fail_usage("Failed: The value you have entered for %s is not a valid %s" % \
("--" + all_opt[failed_opt]["longopt"], all_opt[failed_opt]["type"]), stop)
return valid_input
def _encode_html_entities(text):
return text.replace("&", "&amp;").replace('"', "&quot;").replace('<', "&lt;"). \
replace('>', "&gt;").replace("'", "&apos;")
def _prepare_getopt_args(options):
getopt_string = ""
longopt_list = []
for k in options:
if k in all_opt and all_opt[k]["getopt"] != ":":
# getopt == ":" means that opt is without short getopt, but has value
getopt_string += all_opt[k]["getopt"]
elif k not in all_opt:
fail_usage("Parse error: unknown option '"+k+"'")
if k in all_opt and "longopt" in all_opt[k]:
if all_opt[k]["getopt"].endswith(":"):
longopt_list.append(all_opt[k]["longopt"] + "=")
else:
longopt_list.append(all_opt[k]["longopt"])
return (getopt_string, longopt_list)
def _parse_input_stdin(avail_opt):
opt = {}
name = ""
mapping_longopt_names = dict([(all_opt[o].get("longopt"), o) for o in avail_opt])
for line in sys.stdin.readlines():
line = line.strip()
if (line.startswith("#")) or (len(line) == 0):
continue
(name, value) = (line + "=").split("=", 1)
name = name.replace("-", "_");
value = value[:-1]
if name in mapping_longopt_names:
name = mapping_longopt_names[name]
if avail_opt.count(name) == 0 and name in ["nodename"]:
continue
elif avail_opt.count(name) == 0:
logging.warning("Parse error: Ignoring unknown option '%s'\n", line)
continue
if all_opt[name]["getopt"].endswith(":"):
opt["--"+all_opt[name]["longopt"].rstrip(":")] = value
elif value.lower() in ["1", "yes", "on", "true"]:
opt["--"+all_opt[name]["longopt"]] = "1"
else:
logging.warning("Parse error: Ignoring option '%s' because it does not have value\n", name)
return opt
def _parse_input_cmdline(avail_opt):
filtered_opts = {}
_verify_unique_getopt(avail_opt)
(getopt_string, longopt_list) = _prepare_getopt_args(avail_opt)
try:
(entered_opt, left_arg) = getopt.gnu_getopt(sys.argv[1:], getopt_string, longopt_list)
if len(left_arg) > 0:
logging.warning("Unused arguments on command line: %s" % (str(left_arg)))
except getopt.GetoptError as error:
fail_usage("Parse error: " + error.msg)
for opt in avail_opt:
filtered_opts.update({opt : all_opt[opt]})
# Short and long getopt names are changed to consistent "--" + long name (e.g. --username)
long_opts = {}
for arg_name in list(dict(entered_opt).keys()):
all_key = [key for (key, value) in list(filtered_opts.items()) \
if "--" + value.get("longopt", "") == arg_name or "-" + value.get("getopt", "").rstrip(":") == arg_name][0]
long_opts["--" + filtered_opts[all_key]["longopt"]] = dict(entered_opt)[arg_name]
# This test is specific because it does not apply to input on stdin
if "port_as_ip" in avail_opt and not "--port-as-ip" in long_opts and "--plug" in long_opts:
fail_usage("Parser error: option -n/--plug is not recognized")
return long_opts
# for ["John", "Mary", "Eli"] returns "John, Mary and Eli"
def _join2(words, normal_separator=", ", last_separator=" and "):
if len(words) <= 1:
return "".join(words)
else:
return last_separator.join([normal_separator.join(words[:-1]), words[-1]])
def _join_wrap(words, normal_separator=", ", last_separator=" and ", first_indent=42):
x = _join2(words, normal_separator, last_separator)
wrapper = textwrap.TextWrapper()
wrapper.initial_indent = " "*first_indent
wrapper.subsequent_indent = " "*40
wrapper.width = 85
wrapper.break_on_hyphens = False
wrapper.break_long_words = False
wrapped_text = ""
for line in wrapper.wrap(x):
wrapped_text += line + "\n"
return wrapped_text.lstrip().rstrip("\n")
def _get_opts_with_invalid_choices(options):
options_failed = []
device_opt = options["device_opt"]
for opt in device_opt:
if "choices" in all_opt[opt]:
longopt = "--" + all_opt[opt]["longopt"]
possible_values_upper = [y.upper() for y in all_opt[opt]["choices"]]
if longopt in options:
options[longopt] = options[longopt].upper()
if not options["--" + all_opt[opt]["longopt"]] in possible_values_upper:
options_failed.append(opt)
return options_failed
def _get_opts_with_invalid_types(options):
options_failed = []
device_opt = options["device_opt"]
for opt in device_opt:
if "type" in all_opt[opt]:
longopt = "--" + all_opt[opt]["longopt"]
if longopt in options:
if all_opt[opt]["type"] in ["integer", "second"]:
try:
number = int(options["--" + all_opt[opt]["longopt"]])
except ValueError:
options_failed.append(opt)
return options_failed
def _verify_unique_getopt(avail_opt):
used_getopt = set()
for opt in avail_opt:
getopt_value = all_opt[opt].get("getopt", "").rstrip(":")
if getopt_value and getopt_value in used_getopt:
fail_usage("Short getopt for %s (-%s) is not unique" % (opt, getopt_value))
else:
used_getopt.add(getopt_value)
def _get_available_actions(device_opt):
available_actions = ["on", "off", "reboot", "status", "list", "list-status", \
"monitor", "metadata", "validate-all"]
default_value = "reboot"
if device_opt.count("fabric_fencing"):
available_actions.remove("reboot")
default_value = "off"
if device_opt.count("no_status"):
available_actions.remove("status")
if device_opt.count("no_on"):
available_actions.remove("on")
if device_opt.count("no_off"):
available_actions.remove("off")
if not device_opt.count("separator"):
available_actions.remove("list")
available_actions.remove("list-status")
if device_opt.count("diag"):
available_actions.append("diag")
return (available_actions, default_value)
diff --git a/fence/agents/lib/fencing_snmp.py.py b/fence/agents/lib/fencing_snmp.py.py
index 9aaf52be..7a59b88c 100644
--- a/fence/agents/lib/fencing_snmp.py.py
+++ b/fence/agents/lib/fencing_snmp.py.py
@@ -1,134 +1,128 @@
#!@PYTHON@ -tt
# For example of use please see fence_cisco_mds
import re, pexpect
import logging
from fencing import *
from fencing import fail, fail_usage, EC_TIMED_OUT, run_delay
__all__ = ['FencingSnmp']
## do not add code here.
-#BEGIN_VERSION_GENERATION
-RELEASE_VERSION = ""
-REDHAT_COPYRIGHT = ""
-BUILD_DATE = ""
-#END_VERSION_GENERATION
-
class FencingSnmp:
def __init__(self, options):
self.options = options
run_delay(options)
def quote_for_run(self, string):
return string.replace(r"'", "'\\''")
def complete_missed_params(self):
mapping = [[
['snmp-priv-passwd', 'password', '!snmp-sec-level'],
'self.options["--snmp-sec-level"]="authPriv"'
], [
['!snmp-version', 'community', '!username', '!snmp-priv-passwd', '!password'],
'self.options["--snmp-version"]="2c"'
]]
for val in mapping:
e = val[0]
res = True
for item in e:
if item[0] == '!' and "--" + item[1:] in self.options:
res = False
break
if item[0] != '!' and "--" + item[0:] not in self.options:
res = False
break
if res:
exec(val[1])
def prepare_cmd(self, command):
cmd = "%s -m '' -Oeqn "% (command)
self.complete_missed_params()
#mapping from our option to snmpcmd option
mapping = (('snmp-version', 'v'), ('community', 'c'))
for item in mapping:
if "--" + item[0] in self.options:
cmd += " -%s '%s'"% (item[1], self.quote_for_run(self.options["--" + item[0]]))
# Some options make sense only for v3 (and for v1/2c can cause "problems")
if ("--snmp-version" in self.options) and (self.options["--snmp-version"] == "3"):
# Mapping from our options to snmpcmd options for v3
mapping_v3 = (('snmp-auth-prot', 'a'), ('snmp-sec-level', 'l'), ('snmp-priv-prot', 'x'), \
('snmp-priv-passwd', 'X'), ('password', 'A'), ('username', 'u'))
for item in mapping_v3:
if "--"+item[0] in self.options:
cmd += " -%s '%s'"% (item[1], self.quote_for_run(self.options["--" + item[0]]))
force_ipvx = ""
if "--inet6-only" in self.options:
force_ipvx = "udp6:"
if "--inet4-only" in self.options:
force_ipvx = "udp:"
cmd += " '%s%s%s'"% (force_ipvx, self.quote_for_run(self.options["--ip"]),
"--ipport" in self.options and self.quote_for_run(":" + str(self.options["--ipport"])) or "")
return cmd
def run_command(self, command, additional_timemout=0):
try:
logging.debug("%s\n", command)
(res_output, res_code) = pexpect.run(command,
int(self.options["--shell-timeout"]) +
int(self.options["--login-timeout"]) +
additional_timemout, True)
if res_code == None:
fail(EC_TIMED_OUT)
logging.debug("%s\n", res_output)
if (res_code != 0) or (re.search("^Error ", res_output, re.MULTILINE) != None):
fail_usage("Returned %d: %s"% (res_code, res_output))
except pexpect.ExceptionPexpect:
fail_usage("Cannot run command %s"%(command))
return res_output
def get(self, oid, additional_timemout=0):
cmd = "%s '%s'"% (self.prepare_cmd(self.options["--snmpget-path"]), self.quote_for_run(oid))
output = self.run_command(cmd, additional_timemout).splitlines()
return output[len(output)-1].split(None, 1)
def set(self, oid, value, additional_timemout=0):
mapping = ((int, 'i'), (str, 's'))
type_of_value = ''
for item in mapping:
if isinstance(value, item[0]):
type_of_value = item[1]
break
cmd = "%s '%s' %s '%s'" % (self.prepare_cmd(self.options["--snmpset-path"]),
self.quote_for_run(oid), type_of_value, self.quote_for_run(str(value)))
self.run_command(cmd, additional_timemout)
def walk(self, oid, additional_timemout=0):
cmd = "%s '%s'"% (self.prepare_cmd(self.options["--snmpwalk-path"]), self.quote_for_run(oid))
output = self.run_command(cmd, additional_timemout).splitlines()
return [x.split(None, 1) for x in output if x.startswith(".")]
diff --git a/fence/agents/lpar/fence_lpar.py b/fence/agents/lpar/fence_lpar.py
index 5487b84c..270bbe3b 100644
--- a/fence/agents/lpar/fence_lpar.py
+++ b/fence/agents/lpar/fence_lpar.py
@@ -1,181 +1,175 @@
#!@PYTHON@ -tt
#####
##
## The Following Agent Has Been Tested On:
##
## Version
## +---------------------------------------------+
## Tested on HMC
##
#####
import sys, re
import atexit
sys.path.append("@FENCEAGENTSLIBDIR@")
from fencing import *
from fencing import fail, fail_usage, EC_STATUS_HMC
-#BEGIN_VERSION_GENERATION
-RELEASE_VERSION=""
-REDHAT_COPYRIGHT=""
-BUILD_DATE=""
-#END_VERSION_GENERATION
-
def get_power_status(conn, options):
if options["--hmc-version"] == "3":
conn.send("lssyscfg -r lpar -m " + options["--managed"] + " -n " + options["--plug"] + " -F name,state\n")
conn.log_expect(options["--command-prompt"], int(options["--power-timeout"]))
try:
status = re.compile("^" + options["--plug"] + ",(.*?),.*$",
re.IGNORECASE | re.MULTILINE).search(conn.before).group(1)
except AttributeError:
fail(EC_STATUS_HMC)
elif options["--hmc-version"] in ["4", "IVM"]:
conn.send("lssyscfg -r lpar -m "+ options["--managed"] +
" --filter 'lpar_names=" + options["--plug"] + "'\n")
conn.log_expect(options["--command-prompt"], int(options["--power-timeout"]))
try:
status = re.compile(",state=(.*?),", re.IGNORECASE).search(conn.before).group(1)
except AttributeError:
fail(EC_STATUS_HMC)
##
## Transformation to standard ON/OFF status if possible
if status in ["Running", "Open Firmware", "Shutting Down", "Starting"]:
status = "on"
else:
status = "off"
return status
def set_power_status(conn, options):
if options["--hmc-version"] == "3":
conn.send("chsysstate -o " + options["--action"] + " -r lpar -m " + options["--managed"]
+ " -n " + options["--plug"] + "\n")
conn.log_expect(options["--command-prompt"], int(options["--power-timeout"]))
elif options["--hmc-version"] in ["4", "IVM"]:
if options["--action"] == "on":
conn.send("chsysstate -o on -r lpar -m " + options["--managed"] +
" -n " + options["--plug"] +
" -f `lssyscfg -r lpar -F curr_profile " +
" -m " + options["--managed"] +
" --filter \"lpar_names=" + options["--plug"] + "\"`\n")
else:
conn.send("chsysstate -o shutdown -r lpar --immed" +
" -m " + options["--managed"] + " -n " + options["--plug"] + "\n")
conn.log_expect(options["--command-prompt"], int(options["--power-timeout"]))
def get_lpar_list(conn, options):
outlets = {}
if options["--hmc-version"] == "3":
conn.send("query_partition_names -m " + options["--managed"] + "\n")
conn.log_expect(options["--command-prompt"], int(options["--power-timeout"]))
## We have to remove first 3 lines (command + header) and last line (part of new prompt)
####
res = re.search("^.+?\n(.+?\n){2}(.*)\n.*$", conn.before, re.S)
if res == None:
fail_usage("Unable to parse output of list command")
lines = res.group(2).split("\n")
for outlet_line in lines:
outlets[outlet_line.rstrip()] = ("", "")
elif options["--hmc-version"] == "4":
conn.send("lssyscfg -r lpar -m " + options["--managed"] +
" -F name:state\n")
conn.log_expect(options["--command-prompt"], int(options["--power-timeout"]))
## We have to remove first line (command) and last line (part of new prompt)
####
res = re.search("^.+?\n(.*)\n.*$", conn.before, re.S)
if res == None:
fail_usage("Unable to parse output of list command")
lines = res.group(1).split("\n")
for outlet_line in lines:
try:
(port, status) = outlet_line.split(":")
except ValueError:
fail_usage('Output does not match expected HMC version, try different one');
outlets[port] = ("", status)
elif options["--hmc-version"] == "IVM":
conn.send("lssyscfg -r lpar -m " + options["--managed"] +
" -F name,state\n")
conn.log_expect(options["--command-prompt"], int(options["--power-timeout"]))
## We have to remove first line (command) and last line (part of new prompt)
####
res = re.search("^.+?\n(.*)\n.*$", conn.before, re.S)
if res == None:
fail_usage("Unable to parse output of list command")
lines = res.group(1).split("\n")
for outlet_line in lines:
try:
(port, status) = outlet_line.split(",")
except ValueError:
fail_usage('Output does not match expected HMC version, try different one');
outlets[port] = ("", status)
return outlets
def define_new_opts():
all_opt["managed"] = {
"getopt" : "s:",
"longopt" : "managed",
"help" : "-s, --managed=[id] Name of the managed system",
"required" : "0",
"shortdesc" : "Managed system name",
"order" : 1}
all_opt["hmc_version"] = {
"getopt" : "H:",
"longopt" : "hmc-version",
"help" : "-H, --hmc-version=[version] Force HMC version to use: (3|4|ivm) (default: 4)",
"required" : "0",
"shortdesc" : "Force HMC version to use",
"default" : "4",
"choices" : ["3", "4", "ivm"],
"order" : 1}
def main():
device_opt = ["ipaddr", "login", "passwd", "secure", "cmd_prompt", \
"port", "managed", "hmc_version"]
atexit.register(atexit_handler)
define_new_opts()
all_opt["login_timeout"]["default"] = "15"
all_opt["secure"]["default"] = "1"
all_opt["cmd_prompt"]["default"] = [r":~>", r"]\$", r"\$ "]
options = check_input(device_opt, process_input(device_opt), other_conditions = True)
docs = {}
docs["shortdesc"] = "Fence agent for IBM LPAR"
docs["longdesc"] = ""
docs["vendorurl"] = "http://www.ibm.com"
show_docs(options, docs)
if "--managed" not in options:
fail_usage("Failed: You have to enter name of managed system")
if options["--action"] == "validate-all":
sys.exit(0)
##
## Operate the fencing device
####
conn = fence_login(options)
result = fence_action(conn, options, set_power_status, get_power_status, get_lpar_list)
fence_logout(conn, "quit\r\n")
sys.exit(result)
if __name__ == "__main__":
main()
diff --git a/fence/agents/mpath/fence_mpath.py b/fence/agents/mpath/fence_mpath.py
index 5426a18d..183c38a0 100644
--- a/fence/agents/mpath/fence_mpath.py
+++ b/fence/agents/mpath/fence_mpath.py
@@ -1,251 +1,245 @@
#!@PYTHON@ -tt
import sys
import stat
import re
import os
import logging
import atexit
sys.path.append("@FENCEAGENTSLIBDIR@")
from fencing import fail_usage, run_command, atexit_handler, check_input, process_input, show_docs
from fencing import fence_action, all_opt, run_delay
-#BEGIN_VERSION_GENERATION
-RELEASE_VERSION=""
-REDHAT_COPYRIGHT=""
-BUILD_DATE=""
-#END_VERSION_GENERATION
-
def get_status(conn, options):
del conn
status = "off"
for dev in options["devices"]:
is_block_device(dev)
if options["--key"] in get_registration_keys(options, dev):
status = "on"
else:
logging.debug("No registration for key "\
+ options["--key"] + " on device " + dev + "\n")
if options["--action"] == "monitor":
dev_read(options)
return status
def set_status(conn, options):
del conn
count = 0
if options["--action"] == "on":
for dev in options["devices"]:
is_block_device(dev)
register_dev(options, dev)
if options["--key"] not in get_registration_keys(options, dev):
count += 1
logging.debug("Failed to register key "\
+ options["--key"] + "on device " + dev + "\n")
continue
dev_write(options, dev)
if get_reservation_key(options, dev) is None \
and not reserve_dev(options, dev) \
and get_reservation_key(options, dev) is None:
count += 1
logging.debug("Failed to create reservation (key="\
+ options["--key"] + ", device=" + dev + ")\n")
else:
dev_keys = dev_read(options)
for dev in options["devices"]:
is_block_device(dev)
if options["--key"] in get_registration_keys(options, dev):
preempt_abort(options, dev_keys[dev], dev)
for dev in options["devices"]:
if options["--key"] in get_registration_keys(options, dev):
count += 1
logging.debug("Failed to remove key "\
+ options["--key"] + " on device " + dev + "\n")
continue
if not get_reservation_key(options, dev):
count += 1
logging.debug("No reservation exists on device " + dev + "\n")
if count:
logging.error("Failed to verify " + str(count) + " device(s)")
sys.exit(1)
#run command, returns dict, ret["err"] = exit code; ret["out"] = output
def run_cmd(options, cmd):
ret = {}
if "--use-sudo" in options:
prefix = options["--sudo-path"] + " "
else:
prefix = ""
(ret["err"], ret["out"], _) = run_command(options, prefix + cmd)
ret["out"] = "".join([i for i in ret["out"] if i is not None])
return ret
# check if device exist and is block device
def is_block_device(dev):
if not os.path.exists(dev):
fail_usage("Failed: device \"" + dev + "\" does not exist")
if not stat.S_ISBLK(os.stat(dev).st_mode):
fail_usage("Failed: device \"" + dev + "\" is not a block device")
# cancel registration
def preempt_abort(options, host, dev):
cmd = options["--mpathpersist-path"] + " -o --preempt-abort --prout-type=5 --param-rk=" + host +" --param-sark=" + options["--key"] +"-d " + dev
return not bool(run_cmd(options, cmd)["err"])
def register_dev(options, dev):
cmd = options["--mpathpersist-path"] + " -o --register --param-sark=" + options["--key"] + " -d " + dev
#cmd return code != 0 but registration can be successful
return not bool(run_cmd(options, cmd)["err"])
def reserve_dev(options, dev):
cmd = options["--mpathpersist-path"] + " -o --reserv --prout-type=5 --param-rk=" + options["--key"] + " -d " + dev
return not bool(run_cmd(options, cmd)["err"])
def get_reservation_key(options, dev):
cmd = options["--mpathpersist-path"] + " -i -r -d " + dev
out = run_cmd(options, cmd)
if out["err"]:
fail_usage("Cannot get reservation key")
match = re.search(r"\s+key\s*=\s*0x(\S+)\s+", out["out"], re.IGNORECASE)
return match.group(1) if match else None
def get_registration_keys(options, dev):
keys = []
cmd = options["--mpathpersist-path"] + " -i -k -d " + dev
out = run_cmd(options, cmd)
if out["err"]:
fail_usage("Cannot get registration keys")
for line in out["out"].split("\n"):
match = re.search(r"\s+0x(\S+)\s*", line)
if match:
keys.append(match.group(1))
return keys
def dev_write(options, dev):
file_path = options["--store-path"] + "/mpath.devices"
if not os.path.isdir(options["--store-path"]):
os.makedirs(options["--store-path"])
try:
store_fh = open(file_path, "a+")
except IOError:
fail_usage("Failed: Cannot open file \""+ file_path + "\"")
out = store_fh.read()
if not re.search(r"^" + dev + r"\s+", out):
store_fh.write(dev + "\t" + options["--key"] + "\n")
store_fh.close()
def dev_read(options):
dev_key = {}
file_path = options["--store-path"] + "/mpath.devices"
try:
store_fh = open(file_path, "r")
except IOError:
fail_usage("Failed: Cannot open file \"" + file_path + "\"")
# get not empty lines from file
for (device, key) in [line.strip().split() for line in store_fh if line.strip()]:
dev_key[device] = key
store_fh.close()
return dev_key
def define_new_opts():
all_opt["devices"] = {
"getopt" : "d:",
"longopt" : "devices",
"help" : "-d, --devices=[devices] List of devices to use for current operation",
"required" : "1",
"shortdesc" : "List of devices to use for current operation. Devices can \
be comma-separated list of device-mapper multipath devices (eg. /dev/mapper/3600508b400105df70000e00000ac0000 or /dev/mapper/mpath1). \
Each device must support SCSI-3 persistent reservations.",
"order": 1
}
all_opt["key"] = {
"getopt" : "k:",
"longopt" : "key",
"help" : "-k, --key=[key] Key to use for the current operation",
"required" : "1",
"shortdesc" : "Key to use for the current operation. This key should be \
unique to a node and have to be written in /etc/multipath.conf. For the \"on\" action, the key specifies the key use to \
register the local node. For the \"off\" action, this key specifies the key to \
be removed from the device(s).",
"order": 1
}
all_opt["mpathpersist_path"] = {
"getopt" : ":",
"longopt" : "mpathpersist-path",
"help" : "--mpathpersist-path=[path] Path to mpathpersist binary",
"required" : "0",
"shortdesc" : "Path to mpathpersist binary",
"default" : "@MPATH_PATH@",
"order": 200
}
all_opt["store_path"] = {
"getopt" : ":",
"longopt" : "store-path",
"help" : "--store-path=[path] Path to directory containing cached keys",
"required" : "0",
"shortdesc" : "Path to directory where fence agent can store information",
"default" : "@STORE_PATH@",
"order": 200
}
def main():
atexit.register(atexit_handler)
device_opt = ["no_login", "no_password", "devices", "key", "sudo", \
"fabric_fencing", "on_target", "store_path", "mpathpersist_path", "force_on"]
define_new_opts()
options = check_input(device_opt, process_input(device_opt), other_conditions=True)
docs = {}
docs["shortdesc"] = "Fence agent for multipath persistent reservation"
docs["longdesc"] = "fence_mpath is an I/O fencing agent that uses SCSI-3 \
persistent reservations to control access multipath devices. Underlying \
devices must support SCSI-3 persistent reservations (SPC-3 or greater) as \
well as the \"preempt-and-abort\" subcommand.\nThe fence_mpath agent works by \
having a unique key for each node that has to be set in /etc/multipath.conf. \
Once registered, a single node will become the reservation holder \
by creating a \"write exclusive, registrants only\" reservation on the \
device(s). The result is that only registered nodes may write to the \
device(s). When a node failure occurs, the fence_mpath agent will remove the \
key belonging to the failed node from the device(s). The failed node will no \
longer be able to write to the device(s). A manual reboot is required."
docs["vendorurl"] = "https://www.sourceware.org/dm/"
show_docs(options, docs)
run_delay(options)
# Input control BEGIN
if not "--key" in options:
fail_usage("Failed: key is required")
if options["--action"] == "validate-all":
sys.exit(0)
options["devices"] = options["--devices"].split(",")
if not options["devices"]:
fail_usage("Failed: No devices found")
# Input control END
result = fence_action(None, options, set_status, get_status)
sys.exit(result)
if __name__ == "__main__":
main()
diff --git a/fence/agents/netio/fence_netio.py b/fence/agents/netio/fence_netio.py
index 6dc6a1ad..4fb59cff 100755
--- a/fence/agents/netio/fence_netio.py
+++ b/fence/agents/netio/fence_netio.py
@@ -1,100 +1,94 @@
#!@PYTHON@ -tt
import sys, re, pexpect
import atexit
sys.path.append("@FENCEAGENTSLIBDIR@")
from fencing import *
from fencing import fspawn, fail, EC_LOGIN_DENIED, run_delay
-#BEGIN_VERSION_GENERATION
-RELEASE_VERSION=""
-REDHAT_COPYRIGHT=""
-BUILD_DATE=""
-#END_VERSION_GENERATION
-
def get_power_status(conn, options):
conn.send_eol("port %s" % options["--plug"])
re_status = re.compile("250 [01imt]")
conn.log_expect(re_status, int(options["--shell-timeout"]))
status = {
"0" : "off",
"1" : "on",
"i" : "reboot",
"m" : "manual",
"t" : "timer"
}[conn.after.split()[1]]
return status
def set_power_status(conn, options):
action = {
"on" : "1",
"off" : "0",
"reboot" : "i"
}[options["--action"]]
conn.send_eol("port %s %s" % (options["--plug"], action))
conn.log_expect("250 OK", int(options["--shell-timeout"]))
def get_outlet_list(conn, options):
result = {}
try:
# the NETIO-230B has 4 ports, counting start at 1
for plug in ["1", "2", "3", "4"]:
conn.send_eol("port setup %s" % plug)
conn.log_expect("250 .+", int(options["--shell-timeout"]))
# the name is enclosed in "", drop those with [1:-1]
name = conn.after.split()[1][1:-1]
result[plug] = (name, "unknown")
except Exception as exn:
print(str(exn))
return result
def main():
device_opt = ["ipaddr", "login", "passwd", "port", "telnet"]
atexit.register(atexit_handler)
all_opt["ipport"]["default"] = "1234"
opt = process_input(device_opt)
opt["eol"] = "\r\n"
options = check_input(device_opt, opt)
docs = {}
docs["shortdesc"] = "I/O Fencing agent for Koukaam NETIO-230B"
docs["longdesc"] = "fence_netio is an I/O Fencing agent which can be \
used with the Koukaam NETIO-230B Power Distribution Unit. It logs into \
device via telnet and reboots a specified outlet. Lengthy telnet connections \
should be avoided while a GFS cluster is running because the connection will \
block any necessary fencing actions."
docs["vendorurl"] = "http://www.koukaam.se/"
show_docs(options, docs)
##
## Operate the fencing device
## We can not use fence_login(), username and passwd are sent on one line
####
run_delay(options)
try:
conn = fspawn(options, options["--telnet-path"])
conn.send("set binary\n")
conn.send("open %s -%s\n"%(options["--ip"], options["--ipport"]))
conn.read_nonblocking(size=100, timeout=int(options["--shell-timeout"]))
conn.log_expect("100 HELLO .*", int(options["--shell-timeout"]))
conn.send_eol("login %s %s" % (options["--username"], options["--password"]))
conn.log_expect("250 OK", int(options["--shell-timeout"]))
except pexpect.EOF:
fail(EC_LOGIN_DENIED)
except pexpect.TIMEOUT:
fail(EC_LOGIN_DENIED)
result = fence_action(conn, options, set_power_status, get_power_status, get_outlet_list)
fence_logout(conn, "quit\n")
sys.exit(result)
if __name__ == "__main__":
main()
diff --git a/fence/agents/powerman/fence_powerman.py b/fence/agents/powerman/fence_powerman.py
index d9ab8495..962fdb8f 100755
--- a/fence/agents/powerman/fence_powerman.py
+++ b/fence/agents/powerman/fence_powerman.py
@@ -1,265 +1,257 @@
#!/usr/bin/env python
import os
import time
from datetime import datetime
import sys
import subprocess
import re
import atexit
sys.path.append("@FENCEAGENTSLIBDIR@")
from fencing import *
from fencing import is_executable, fail_usage, run_delay
import logging
-
-#BEGIN_VERSION_GENERATION
-RELEASE_VERSION="Powerman Fencing Agent"
-REDHAT_COPYRIGHT=""
-BUILD_DATE=""
-#END_VERSION_GENERATION
-
-
#### important!!! #######
class PowerMan:
"""Python wrapper for calling powerman commands
This class makes calls to a powerman deamon for a cluster of computers.
The make-up of such a call looks something like:
$ pm -h elssd1:10101 <option> <node>
where option is something like --off, --on, --cycle and where node is
elssd8, or whatever values are setup in powerman.conf. Note that powerman
itself must be configured for this fence agent to work.
"""
def __init__(self, powerman_path, server_name, port):
"""
Args:
server_name: (string) host or ip of powerman server
port: (str) port number that the powerman server is listening on
"""
self.powerman_path = powerman_path
self.server_name = server_name
self.port = port
self.server_and_port = server_name + ":" + str(port)
self.base_cmd = [
self.powerman_path,
"--server-host",
self.server_and_port
]
def _run(self, cmd, only_first_line):
# Args:
# cmd: (list) commands and arguments to pass to the program_name
run_this = self.base_cmd + cmd
try:
popen = subprocess.Popen(run_this, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
out = popen.communicate()
except OSError as e:
logging.error("_run command error: %s\n", e)
sys.exit(1)
if only_first_line == True:
result_line = out[0].decode().strip()
return (result_line, popen.returncode)
else:
result_list = []
for line in out:
result_list.append(line)
return (result_list, popen.returncode)
def is_running(self):
"""simple query to see if powerman server is responding. Returns boolean"""
cmd = ["-q"] # just check if we get a response from the server
result, ret_code = self._run(cmd, True)
if ret_code != 0:
return False
return True
## Some devices respond to on or off actions as if the action was successful,
## when it was not.
##
## This is not unique to powerman, and so fence_action ignores the return code
## from the set_power_fn and queries the device to confirm the power status of
## the machine.
##
## For this reason we do not do a query ourself, retry, etc. in on() or off().
def on(self, host):
logging.debug("PowerMan on: %s\n", host)
cmd = ["--on", host]
try:
result, ret_code = self._run(cmd, True)
except OSError as e:
logging.error("PowerMan Error: The command '--on' failed: %s\n", e)
return -1
except ValueError as e:
logging.error("PowerMan Error: Popen: invalid arguments: %s\n", e)
return -1
logging.debug("pm.on result: %s ret_code: %s\n", result, ret_code)
return ret_code
def off(self, host):
logging.debug("PowerMan off: %s\n", host)
cmd = ["--off", host]
try:
result, ret_code = self._run(cmd, True)
except OSError as e:
logging.error("PowerMan Error: The command '%s' failed: %s\n", cmd, e)
return -1
except ValueError as e:
logging.error("PowerMan Error: Popen: invalid arguments: %s\n", e)
return -1
logging.debug("pm.off result: %s ret_code: %s\n", result, ret_code)
return ret_code
def list(self):
## Error checking here is faulty. Try passing
## invalid args, e.g. --query --exprange to see failure
cmd = ["-q","--exprange"]
try:
result, ret_code = self._run(cmd, False)
except OSError as e:
logging.error("PowerMan Error: The command '%s' failed: %s\n", cmd, e)
return -1
except ValueError as e:
logging.error("PowerMan Error: Popen: invalid arguments: %s\n", e)
return -1
if ret_code < 0:
# there was an error with the command
return ret_code
else:
state = {}
for line in result[0].split('\n'):
if len(line) > 2:
fields = line.split(':')
if len(fields) == 2:
state[fields[0]] = (fields[0],fields[1])
return state
def query(self, host):
cmd = ["--query", host]
try:
result, ret_code = self._run(cmd, True)
except OSError as e:
logging.error("PowerMan Error: The command '%s' failed: %s\n", cmd, e)
return -1
except ValueError as e:
logging.error("PowerMan Error: Popen: invalid arguments: %s\n", e)
return -1
if ret_code < 0:
# there was an error with the command
return ret_code
else:
res = result.split('\n')
res = [r.split() for r in res]
# find the host in command's returned output
for lst in res:
if lst[0] == 'No' and lst[1] == 'such' and lst[2] == 'nodes:':
return -1
if host in lst:
return lst[0][:-1] # lst[0] would be 'off:'-- this removes the colon
# host isn't in the output
return -1
def get_power_status(conn, options):
logging.debug("get_power_status function:\noptions: %s\n", str(options))
pm = PowerMan(options['--powerman-path'], options['--ip'], options['--ipport'])
# if Pacemaker is checking the status of the Powerman server...
if options['--action'] == 'monitor':
if pm.is_running():
logging.debug("Powerman is running\n")
return "on"
logging.debug("Powerman is NOT running\n")
return "error"
else:
status = pm.query(options['--plug'])
if isinstance(int, type(status)):
# query only returns ints on error
logging.error("get_power_status: query returned %s\n", str(status))
fail(EC_STATUS)
return status
def set_power_status(conn, options):
logging.debug("set_power_status function:\noptions: %s", str(options))
pm = PowerMan(options['--powerman-path'], options['--ip'], options['--ipport'])
action = options["--action"]
if action == "on":
pm.on(options['--plug'])
elif action == "off":
pm.off(options['--plug'])
return
def get_list(conn, options):
logging.debug("get_list function:\noptions: %s", str(options))
pm = PowerMan(options['--powerman-path'], options['--ip'], options['--ipport'])
outlets = pm.list()
logging.debug("get_list outlets.keys: %s", str(outlets.keys()))
return outlets
def define_new_opts():
all_opt["powerman_path"] = {
"getopt" : ":",
"longopt" : "powerman-path",
"help" : "--powerman-path=[path] Path to powerman binary",
"required" : "0",
"shortdesc" : "Path to powerman binary",
"default" : "@POWERMAN_PATH@",
"order": 200
}
def main():
device_opt = [
'ipaddr',
'no_password',
'no_login',
'powerman_path',
]
atexit.register(atexit_handler)
define_new_opts()
# redefine default values for the options given by fencing.py
# these 3 different values are derived from the lssd test cluster and may
# need to adjusted depending on how other systems fare
all_opt['ipport']['default'] = '10101'
all_opt['delay']['default'] = '3'
all_opt['power_wait']['default'] = '3'
options = check_input(device_opt, process_input(device_opt))
docs = {}
docs["shortdesc"] = "Fence Agent for Powerman"
docs["longdesc"] = "This is a Pacemaker Fence Agent for the \
Powerman management utility that was designed for LLNL systems."
docs["vendorurl"] = "https://github.com/chaos/powerman"
show_docs(options, docs)
run_delay(options)
if not is_executable(options["--powerman-path"]):
fail_usage("Powerman not found or not executable at path " + options["--powerman-path"])
# call the fencing.fence_action function, passing in my various fence functions
result = fence_action(
None,
options,
set_power_status,
get_power_status,
get_list,
None
)
sys.exit(result)
if __name__ == "__main__":
main()
diff --git a/fence/agents/pve/fence_pve.py b/fence/agents/pve/fence_pve.py
index 7ae6372e..c11f8c12 100755
--- a/fence/agents/pve/fence_pve.py
+++ b/fence/agents/pve/fence_pve.py
@@ -1,193 +1,186 @@
#!@PYTHON@ -tt
# This agent uses Proxmox VE API
# Thanks to Frank Brendel (author of original perl fence_pve)
# for help with writing and testing this agent.
import sys
import json
import pycurl
import io
import atexit
import logging
sys.path.append("@FENCEAGENTSLIBDIR@")
from fencing import fail, EC_LOGIN_DENIED, atexit_handler, all_opt, check_input, process_input, show_docs, fence_action, run_delay
if sys.version_info[0] > 2: import urllib.parse as urllib
else: import urllib
-#BEGIN_VERSION_GENERATION
-RELEASE_VERSION=""
-BUILD_DATE=""
-REDHAT_COPYRIGHT=""
-#END_VERSION_GENERATION
-
-
def get_power_status(conn, options):
del conn
state = {"running" : "on", "stopped" : "off"}
if options["--nodename"] is None:
nodes = send_cmd(options, "nodes")
if type(nodes) is not dict or "data" not in nodes or type(nodes["data"]) is not list:
return None
for node in nodes["data"]: # lookup the node holding the vm
if type(node) is not dict or "node" not in node:
return None
options["--nodename"] = node["node"]
status = get_power_status(None, options)
if status is not None:
logging.info("vm found on node: " + options["--nodename"])
break
else:
options["--nodename"] = None
return status
else:
cmd = "nodes/" + options["--nodename"] + "/qemu/" + options["--plug"] + "/status/current"
result = send_cmd(options, cmd)
if type(result) is dict and "data" in result:
if type(result["data"]) is dict and "status" in result["data"]:
if result["data"]["status"] in state:
return state[result["data"]["status"]]
return None
def set_power_status(conn, options):
del conn
action = {
'on' : "start",
'off': "stop"
}[options["--action"]]
cmd = "nodes/" + options["--nodename"] + "/qemu/" + options["--plug"] + "/status/" + action
send_cmd(options, cmd, post={"skiplock":1})
def get_outlet_list(conn, options):
del conn
nodes = send_cmd(options, "nodes")
outlets = dict()
if type(nodes) is not dict or "data" not in nodes or type(nodes["data"]) is not list:
return None
for node in nodes["data"]:
if type(node) is not dict or "node" not in node:
return None
vms = send_cmd(options, "nodes/" + node["node"] + "/qemu")
if type(vms) is not dict or "data" not in vms or type(vms["data"]) is not list:
return None
for vm in vms["data"]:
outlets[vm["vmid"]] = [vm["name"], vm["status"]]
return outlets
def get_ticket(options):
post = {'username': options["--username"], 'password': options["--password"]}
result = send_cmd(options, "access/ticket", post=post)
if type(result) is dict and "data" in result:
if type(result["data"]) is dict and "ticket" in result["data"] and "CSRFPreventionToken" in result["data"]:
return {
"ticket" : str("PVEAuthCookie=" + result["data"]["ticket"] + "; " + \
"version=0; path=/; domain=" + options["--ip"] + \
"; port=" + str(options["--ipport"]) + "; path_spec=0; secure=1; " + \
"expires=7200; discard=0"),
"CSRF_token" : str("CSRFPreventionToken: " + result["data"]["CSRFPreventionToken"])
}
return None
def send_cmd(options, cmd, post=None):
url = options["url"] + cmd
conn = pycurl.Curl()
output_buffer = io.BytesIO()
if logging.getLogger().getEffectiveLevel() < logging.WARNING:
conn.setopt(pycurl.VERBOSE, True)
conn.setopt(pycurl.HTTPGET, 1)
conn.setopt(pycurl.URL, url.encode("ascii"))
if "auth" in options and options["auth"] is not None:
conn.setopt(pycurl.COOKIE, options["auth"]["ticket"])
conn.setopt(pycurl.HTTPHEADER, [options["auth"]["CSRF_token"]])
if post is not None:
if "skiplock" in post:
conn.setopt(conn.CUSTOMREQUEST, 'POST')
else:
conn.setopt(pycurl.POSTFIELDS, urllib.urlencode(post))
conn.setopt(pycurl.WRITEFUNCTION, output_buffer.write)
conn.setopt(pycurl.TIMEOUT, int(options["--shell-timeout"]))
if "--ssl" in options or "--ssl-secure" in options:
conn.setopt(pycurl.SSL_VERIFYPEER, 1)
conn.setopt(pycurl.SSL_VERIFYHOST, 2)
else:
conn.setopt(pycurl.SSL_VERIFYPEER, 0)
conn.setopt(pycurl.SSL_VERIFYHOST, 0)
logging.debug("URL: " + url)
try:
conn.perform()
result = output_buffer.getvalue().decode()
logging.debug("RESULT [" + str(conn.getinfo(pycurl.RESPONSE_CODE)) + \
"]: " + result)
conn.close()
return json.loads(result)
except pycurl.error:
logging.error("Connection failed")
except:
logging.error("Cannot parse json")
return None
def main():
atexit.register(atexit_handler)
all_opt["node_name"] = {
"getopt" : "N:",
"longopt" : "nodename",
"help" : "-N, --nodename "
"Node on which machine is located",
"required" : "0",
"shortdesc" : "Node on which machine is located. "
"(Optional, will be automatically determined)",
"order": 2
}
device_opt = ["ipaddr", "login", "passwd", "web", "port", "node_name"]
all_opt["login"]["required"] = "0"
all_opt["login"]["default"] = "root@pam"
all_opt["ipport"]["default"] = "8006"
all_opt["port"]["shortdesc"] = "Id of the virtual machine."
all_opt["ipaddr"]["shortdesc"] = "IP Address or Hostname of a node " +\
"within the Proxmox cluster."
options = check_input(device_opt, process_input(device_opt))
docs = {}
docs["shortdesc"] = "Fencing agent for the Proxmox Virtual Environment"
docs["longdesc"] = "The fence_pve agent can be used to fence virtual \
machines acting as nodes in a virtualized cluster."
docs["vendorurl"] = "http://www.proxmox.com/"
show_docs(options, docs)
run_delay(options)
if "--nodename" not in options or not options["--nodename"]:
options["--nodename"] = None
options["url"] = "https://" + options["--ip"] + ":" + str(options["--ipport"]) + "/api2/json/"
options["auth"] = get_ticket(options)
if options["auth"] is None:
fail(EC_LOGIN_DENIED)
# Workaround for unsupported API call on some Proxmox hosts
outlets = get_outlet_list(None, options) # Unsupported API-Call will result in value: None
if outlets is None:
result = fence_action(None, options, set_power_status, get_power_status, None)
sys.exit(result)
result = fence_action(None, options, set_power_status, get_power_status, get_outlet_list)
sys.exit(result)
if __name__ == "__main__":
main()
diff --git a/fence/agents/raritan/fence_raritan.py b/fence/agents/raritan/fence_raritan.py
index 36f2beaa..17fa0f5f 100644
--- a/fence/agents/raritan/fence_raritan.py
+++ b/fence/agents/raritan/fence_raritan.py
@@ -1,90 +1,84 @@
#!@PYTHON@ -tt
import sys, re, pexpect
import atexit
sys.path.append("@FENCEAGENTSLIBDIR@")
from fencing import *
from fencing import fspawn, fail, EC_LOGIN_DENIED, run_delay
-#BEGIN_VERSION_GENERATION
-RELEASE_VERSION=""
-REDHAT_COPYRIGHT=""
-BUILD_DATE=""
-#END_VERSION_GENERATION
-
# --plug should include path to the outlet # such as port 1:
# /system1/outlet1
def get_power_status(conn, options):
conn.send_eol("show -d properties=powerState %s" % options["--plug"])
re_status = re.compile(".*powerState is [12].*")
conn.log_expect(re_status, int(options["--shell-timeout"]))
status = {
#"0" : "off",
"1" : "on",
"2" : "off",
}[conn.after.split()[2]]
return status
def set_power_status(conn, options):
action = {
"on" : "on",
"off" : "off",
}[options["--action"]]
conn.send_eol("set %s powerState=%s" % (options["--plug"], action))
def main():
device_opt = ["ipaddr", "login", "passwd", "port", "telnet"]
atexit.register(atexit_handler)
opt = process_input(device_opt)
all_opt["ipport"]["default"] = "23"
opt["eol"] = "\r\n"
options = check_input(device_opt, opt)
docs = {}
docs["shortdesc"] = "I/O Fencing agent for Raritan Dominion PX"
docs["longdesc"] = "fence_raritan is an I/O Fencing agent which can be \
used with the Raritan DPXS12-20 Power Distribution Unit. It logs into \
device via telnet and reboots a specified outlet. Lengthy telnet connections \
should be avoided while a GFS cluster is running because the connection will \
block any necessary fencing actions."
docs["vendorurl"] = "http://www.raritan.com/"
show_docs(options, docs)
# add support also for delay before login which is very useful for 2-node clusters
run_delay(options)
##
## Operate the fencing device
## We can not use fence_login(), username and passwd are sent on one line
####
try:
conn = fspawn(options, options["--telnet-path"])
conn.send("set binary\n")
conn.send("open %s -%s\n"%(options["--ip"], options["--ipport"]))
conn.read_nonblocking(size=100, timeout=int(options["--shell-timeout"]))
conn.log_expect("Login.*", int(options["--shell-timeout"]))
conn.send_eol("%s" % (options["--username"]))
conn.log_expect("Password.*", int(options["--shell-timeout"]))
conn.send_eol("%s" % (options["--password"]))
conn.log_expect("clp.*", int(options["--shell-timeout"]))
except pexpect.EOF:
fail(EC_LOGIN_DENIED)
except pexpect.TIMEOUT:
fail(EC_LOGIN_DENIED)
result = 0
if options["--action"] != "monitor":
result = fence_action(conn, options, set_power_status, get_power_status)
fence_logout(conn, "exit\n")
sys.exit(result)
if __name__ == "__main__":
main()
diff --git a/fence/agents/rcd_serial/fence_rcd_serial.py b/fence/agents/rcd_serial/fence_rcd_serial.py
index 01489513..4b80f420 100644
--- a/fence/agents/rcd_serial/fence_rcd_serial.py
+++ b/fence/agents/rcd_serial/fence_rcd_serial.py
@@ -1,107 +1,100 @@
#!@PYTHON@ -tt
# Copyright 2015 Infoxchange, Danielle Madeley, Sam McLeod-Jones
# Controls an RCD serial device
# Ported from stonith/rcd_serial.c
# The Following Agent Has Been Tested On:
# CentOS Linux release 7.1.1503
# Resource example:
# primitive stonith_node_1 ocf:rcd_serial_py params port="/dev/ttyS0" time=1000 hostlist=stonith_node_1 stonith-timeout=5s
import sys
import atexit
import os
import struct
import logging
import time
from fcntl import ioctl
from termios import TIOCMBIC, TIOCMBIS, TIOCM_RTS, TIOCM_DTR
from time import sleep
sys.path.append("@FENCEAGENTSLIBDIR@")
from fencing import *
-#BEGIN_VERSION_GENERATION
-RELEASE_VERSION="rcd_serial (serial reset) fence agent"
-REDHAT_COPYRIGHT=""
-BUILD_DATE="22 Jul 2015"
-#END_VERSION_GENERATION
-
-
class RCDSerial(object):
"""Control class for serial device"""
def __init__(self, port='/dev/ttyS0'):
self.fd = fd = os.open(port, os.O_RDONLY | os.O_NDELAY)
logging.debug("Opened %s on fd %i", port, fd)
ioctl(fd, TIOCMBIC, struct.pack('I', TIOCM_RTS | TIOCM_DTR))
def close(self):
"""Close the serial device"""
logging.debug("Closing serial device")
ret = os.close(self.fd)
return ret
def toggle_pin(self, pin=TIOCM_DTR, time=1000):
"""Toggle the pin high for the time specified"""
logging.debug("Set pin high")
ioctl(self.fd, TIOCMBIS, struct.pack('I', pin))
sleep(float(time) / 1000.)
logging.debug("Set pin low")
ioctl(self.fd, TIOCMBIC, struct.pack('I', pin))
def reboot_device(conn, options):
conn.toggle_pin(time=options["--power-wait"])
return True
def main():
device_opt = ["serial_port", "no_status", "no_password", "no_login", "method", "no_on", "no_off"]
atexit.register(atexit_handler)
all_opt["serial_port"] = {
"getopt" : ":",
"longopt" : "serial-port",
"help":"--serial-port=[port] Port of the serial device (e.g. /dev/ttyS0)",
"required" : "1",
"shortdesc" : "Port of the serial device",
"default" : "/dev/ttyS0",
"order": 1
}
all_opt["method"]["default"] = "cycle"
all_opt["power_wait"]["default"] = "2"
all_opt["method"]["help"] = "-m, --method=[method] Method to fence (onoff|cycle) (Default: cycle)"
options = check_input(device_opt, process_input(device_opt))
docs = {}
docs["shortdesc"] = "rcd_serial fence agent"
docs["longdesc"] = "fence_rcd_serial operates a serial cable that toggles a \
reset of an opposing server using the reset switch on its motherboard. The \
cable itself is simple with no power, network or moving parts. An example of \
the cable is available here: https://smcleod.net/rcd-stonith/ and the circuit \
design is available in the fence-agents src as SVG"
docs["vendorurl"] = "http://www.scl.co.uk/rcd_serial/"
show_docs(options, docs)
if options["--action"] in ["off", "reboot"]:
time.sleep(int(options["--delay"]))
## Operate the fencing device
conn = RCDSerial(port=options["--serial-port"])
result = fence_action(conn, options, None, None, reboot_cycle_fn=reboot_device)
conn.close()
sys.exit(result)
if __name__ == "__main__":
main()
diff --git a/fence/agents/rhevm/fence_rhevm.py b/fence/agents/rhevm/fence_rhevm.py
index 1977543c..0594e66b 100644
--- a/fence/agents/rhevm/fence_rhevm.py
+++ b/fence/agents/rhevm/fence_rhevm.py
@@ -1,207 +1,200 @@
#!@PYTHON@ -tt
import sys, re
import pycurl, io
import logging
import atexit
sys.path.append("@FENCEAGENTSLIBDIR@")
from fencing import *
from fencing import fail, EC_STATUS, run_delay
-#BEGIN_VERSION_GENERATION
-RELEASE_VERSION="New RHEV-M Agent - test release on steroids"
-REDHAT_COPYRIGHT=""
-BUILD_DATE="March, 2008"
-#END_VERSION_GENERATION
-
-
RE_GET_ID = re.compile("<vm( .*)? id=\"(.*?)\"", re.IGNORECASE)
RE_STATUS = re.compile("<state>(.*?)</state>", re.IGNORECASE)
RE_GET_NAME = re.compile("<name>(.*?)</name>", re.IGNORECASE)
def get_power_status(conn, options):
del conn
### Obtain real ID from name
res = send_command(options, "vms/?search=name%3D" + options["--plug"])
result = RE_GET_ID.search(res)
if result == None:
# Unable to obtain ID needed to access virtual machine
fail(EC_STATUS)
options["id"] = result.group(2)
result = RE_STATUS.search(res)
if result == None:
# We were able to parse ID so output is correct
# in some cases it is possible that RHEV-M output does not
# contain <status> line. We can assume machine is OFF then
return "off"
else:
status = result.group(1)
if status.lower() == "down":
return "off"
else:
return "on"
def set_power_status(conn, options):
del conn
action = {
'on' : "start",
'off' : "stop"
}[options["--action"]]
url = "vms/" + options["id"] + "/" + action
send_command(options, url, "POST")
def get_list(conn, options):
del conn
outlets = {}
try:
res = send_command(options, "vms")
lines = res.split("<vm ")
for i in range(1, len(lines)):
name = RE_GET_NAME.search(lines[i]).group(1)
status = RE_STATUS.search(lines[i]).group(1)
outlets[name] = ("", status)
except AttributeError:
return {}
except IndexError:
return {}
return outlets
def send_command(opt, command, method="GET"):
## setup correct URL
if "--ssl" in opt or "--ssl-secure" in opt or "--ssl-insecure" in opt:
url = "https:"
else:
url = "http:"
if opt.has_key("--api-path"):
api_path = opt["--api-path"]
else:
api_path = "/ovirt-engine/api"
if opt.has_key("--disable-http-filter"):
http_filter = 'false'
else:
http_filter = 'true'
url += "//" + opt["--ip"] + ":" + str(opt["--ipport"]) + api_path + "/" + command
## send command through pycurl
conn = pycurl.Curl()
web_buffer = io.BytesIO()
conn.setopt(pycurl.URL, url.encode("ascii"))
conn.setopt(pycurl.HTTPHEADER, [
"Version: 3",
"Content-type: application/xml",
"Accept: application/xml",
"Prefer: persistent-auth",
"Filter: {}".format(http_filter),
])
if "cookie" in opt:
conn.setopt(pycurl.COOKIE, opt["cookie"])
else:
conn.setopt(pycurl.HTTPAUTH, pycurl.HTTPAUTH_BASIC)
conn.setopt(pycurl.USERPWD, opt["--username"] + ":" + opt["--password"])
if "--use-cookies" in opt:
conn.setopt(pycurl.COOKIEFILE, "")
conn.setopt(pycurl.TIMEOUT, int(opt["--shell-timeout"]))
if "--ssl" in opt or "--ssl-secure" in opt:
conn.setopt(pycurl.SSL_VERIFYPEER, 1)
conn.setopt(pycurl.SSL_VERIFYHOST, 2)
if "--ssl-insecure" in opt:
conn.setopt(pycurl.SSL_VERIFYPEER, 0)
conn.setopt(pycurl.SSL_VERIFYHOST, 0)
if method == "POST":
conn.setopt(pycurl.POSTFIELDS, "<action />")
conn.setopt(pycurl.WRITEFUNCTION, web_buffer.write)
conn.perform()
if "cookie" not in opt and "--use-cookies" in opt:
cookie = ""
for c in conn.getinfo(pycurl.INFO_COOKIELIST):
tokens = c.split("\t",7)
cookie = cookie + tokens[5] + "=" + tokens[6] + ";"
opt["cookie"] = cookie
result = web_buffer.getvalue().decode()
logging.debug("%s\n", command)
logging.debug("%s\n", result)
return result
def define_new_opts():
all_opt["use_cookies"] = {
"getopt" : "",
"longopt" : "use-cookies",
"help" : "--use-cookies Reuse cookies for authentication",
"required" : "0",
"shortdesc" : "Reuse cookies for authentication",
"order" : 1}
all_opt["api_path"] = {
"getopt" : ":",
"longopt" : "api-path",
"help" : "--api-path=[path] The path part of the API URL",
"default" : "/ovirt-engine/api",
"required" : "0",
"shortdesc" : "The path part of the API URL",
"order" : 2}
all_opt["disable_http_filter"] = {
"getopt" : "",
"longopt" : "disable-http-filter",
"help" : "--disable-http-filter Set HTTP Filter header to false",
"required" : "0",
"shortdesc" : "Set HTTP Filter header to false",
"order" : 3}
def main():
device_opt = [
"ipaddr",
"api_path",
"login",
"passwd",
"ssl",
"notls",
"web",
"port",
"use_cookies",
"disable_http_filter",
]
atexit.register(atexit_handler)
define_new_opts()
all_opt["power_wait"]["default"] = "1"
options = check_input(device_opt, process_input(device_opt))
docs = {}
docs["shortdesc"] = "Fence agent for RHEV-M REST API"
docs["longdesc"] = "fence_rhevm is an I/O Fencing agent which can be \
used with RHEV-M REST API to fence virtual machines."
docs["vendorurl"] = "http://www.redhat.com"
show_docs(options, docs)
##
## Fence operations
####
run_delay(options)
result = fence_action(None, options, set_power_status, get_power_status, get_list)
sys.exit(result)
if __name__ == "__main__":
main()
diff --git a/fence/agents/rsa/fence_rsa.py b/fence/agents/rsa/fence_rsa.py
index 7b24ea64..44fdd9d0 100644
--- a/fence/agents/rsa/fence_rsa.py
+++ b/fence/agents/rsa/fence_rsa.py
@@ -1,69 +1,63 @@
#!@PYTHON@ -tt
#####
##
## The Following Agent Has Been Tested On:
## Main GFEP25A & Boot GFBP25A
##
#####
import sys, re
import atexit
sys.path.append("@FENCEAGENTSLIBDIR@")
from fencing import *
-#BEGIN_VERSION_GENERATION
-RELEASE_VERSION="New RSA2 Agent - test release on steroids"
-REDHAT_COPYRIGHT=""
-BUILD_DATE=""
-#END_VERSION_GENERATION
-
def get_power_status(conn, options):
conn.send_eol("power state")
conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"]))
match = re.compile("Power: (.*)", re.IGNORECASE).search(conn.before)
if match != None:
status = match.group(1)
else:
status = "undefined"
return status.lower().strip()
def set_power_status(conn, options):
conn.send_eol("power " + options["--action"])
conn.log_expect(options["--command-prompt"], int(options["--power-timeout"]))
def main():
device_opt = ["ipaddr", "login", "passwd", "cmd_prompt", "secure", "telnet"]
atexit.register(atexit_handler)
all_opt["login_timeout"]["default"] = 10
all_opt["cmd_prompt"]["default"] = [">"]
# This device will not allow us to login even with LANG=C
all_opt["ssh_options"]["default"] = "-F /dev/null"
options = check_input(device_opt, process_input(device_opt))
docs = {}
docs["shortdesc"] = "Fence agent for IBM RSA"
docs["longdesc"] = "fence_rsa is an I/O Fencing agent \
which can be used with the IBM RSA II management interface. It \
logs into an RSA II device via telnet and reboots the associated \
machine. Lengthy telnet connections to the RSA II device should \
be avoided while a GFS cluster is running because the connection \
will block any necessary fencing actions."
docs["vendorurl"] = "http://www.ibm.com"
show_docs(options, docs)
##
## Operate the fencing device
######
conn = fence_login(options)
result = fence_action(conn, options, set_power_status, get_power_status, None)
fence_logout(conn, "exit")
sys.exit(result)
if __name__ == "__main__":
main()
diff --git a/fence/agents/rsb/fence_rsb.py b/fence/agents/rsb/fence_rsb.py
index 725398d2..45355f51 100755
--- a/fence/agents/rsb/fence_rsb.py
+++ b/fence/agents/rsb/fence_rsb.py
@@ -1,76 +1,70 @@
#!@PYTHON@ -tt
import sys, re
import atexit
sys.path.append("@FENCEAGENTSLIBDIR@")
from fencing import *
-#BEGIN_VERSION_GENERATION
-RELEASE_VERSION=""
-REDHAT_COPYRIGHT=""
-BUILD_DATE=""
-#END_VERSION_GENERATION
-
def get_power_status(conn, options):
conn.send("2")
conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"]))
status = re.compile(r"Power Status[\s]*: (on|off)", re.IGNORECASE).search(conn.before).group(1)
conn.send("0")
conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"]))
return status.lower().strip()
def set_power_status(conn, options):
action = {
'on' : "4",
'off': "1"
}[options["--action"]]
conn.send("2")
conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"]))
conn.send_eol(action)
conn.log_expect(["want to power " + options["--action"],
"yes/no", "'yes' or 'no'"], int(options["--shell-timeout"]))
conn.send_eol("yes")
conn.log_expect("any key to continue", int(options["--power-timeout"]))
conn.send_eol("")
conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"]))
conn.send_eol("0")
conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"]))
def main():
device_opt = ["ipaddr", "login", "passwd", "secure", "cmd_prompt", "telnet"]
atexit.register(atexit_handler)
all_opt["cmd_prompt"]["default"] = ["to quit:"]
opt = process_input(device_opt)
if "--ssh" not in opt and "--ipport" not in opt:
# set default value like it should be set as usually
all_opt["ipport"]["default"] = "3172"
opt["--ipport"] = all_opt["ipport"]["default"]
options = check_input(device_opt, opt)
docs = {}
docs["shortdesc"] = "I/O Fencing agent for Fujitsu-Siemens RSB"
docs["longdesc"] = "fence_rsb is an I/O Fencing agent \
which can be used with the Fujitsu-Siemens RSB management interface. It logs \
into device via telnet/ssh and reboots a specified outlet. Lengthy telnet/ssh \
connections should be avoided while a GFS cluster is running because the connection \
will block any necessary fencing actions."
docs["vendorurl"] = "http://www.fujitsu.com"
show_docs(options, docs)
##
## Operate the fencing device
####
conn = fence_login(options)
result = fence_action(conn, options, set_power_status, get_power_status, None)
fence_logout(conn, "0")
sys.exit(result)
if __name__ == "__main__":
main()
diff --git a/fence/agents/sanbox2/fence_sanbox2.py b/fence/agents/sanbox2/fence_sanbox2.py
index e298a3e7..679d1d98 100644
--- a/fence/agents/sanbox2/fence_sanbox2.py
+++ b/fence/agents/sanbox2/fence_sanbox2.py
@@ -1,157 +1,151 @@
#!@PYTHON@ -tt
#####
##
## The Following Agent Has Been Tested On:
##
## Version Firmware
## +-----------------+---------------------------+
#####
import sys, re, pexpect
import logging
import atexit
sys.path.append("@FENCEAGENTSLIBDIR@")
from fencing import *
from fencing import fail, EC_TIMED_OUT, EC_GENERIC_ERROR
-#BEGIN_VERSION_GENERATION
-RELEASE_VERSION="New Sanbox2 Agent - test release on steroids"
-REDHAT_COPYRIGHT=""
-BUILD_DATE="March, 2008"
-#END_VERSION_GENERATION
-
def get_power_status(conn, options):
status_trans = {
'online' : "on",
'offline' : "off"
}
try:
conn.send_eol("show port " + options["--plug"])
conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"]))
except pexpect.TIMEOUT:
try:
conn.send_eol("admin end")
conn.send_eol("exit")
conn.close()
except Exception:
pass
fail(EC_TIMED_OUT)
status = re.compile(r".*AdminState\s+(online|offline)\s+",
re.IGNORECASE | re.MULTILINE).search(conn.before).group(1)
try:
return status_trans[status.lower().strip()]
except KeyError:
return "PROBLEM"
def set_power_status(conn, options):
action = {
'on' : "online",
'off' : "offline"
}[options["--action"]]
try:
conn.send_eol("set port " + options["--plug"] + " state " + action)
conn.log_expect(options["--command-prompt"], int(options["--power-timeout"]))
except pexpect.TIMEOUT:
try:
conn.send_eol("admin end")
conn.send_eol("exit")
conn.close()
except Exception:
pass
fail(EC_TIMED_OUT)
try:
conn.send_eol("set port " + options["--plug"] + " state " + action)
conn.log_expect(options["--command-prompt"], int(options["--power-timeout"]))
except pexpect.TIMEOUT:
try:
conn.send_eol("admin end")
conn.send_eol("exit")
conn.close()
except Exception:
pass
fail(EC_TIMED_OUT)
def get_list_devices(conn, options):
outlets = {}
try:
conn.send_eol("show port")
conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"]))
list_re = re.compile(r"^\s+(\d+?)\s+(Online|Offline)\s+", re.IGNORECASE)
for line in conn.before.splitlines():
if list_re.search(line):
status = {
'online' : "ON",
'offline' : "OFF"
}[list_re.search(line).group(2).lower()]
outlets[list_re.search(line).group(1)] = ("", status)
except pexpect.TIMEOUT:
try:
conn.send_eol("admin end")
conn.send_eol("exit")
conn.close()
except Exception:
pass
fail(EC_TIMED_OUT)
return outlets
def main():
device_opt = ["fabric_fencing", "ipaddr", "login", "passwd", "cmd_prompt", \
"port", "telnet"]
atexit.register(atexit_handler)
all_opt["cmd_prompt"]["default"] = [" #> "]
options = check_input(device_opt, process_input(device_opt))
docs = {}
docs["shortdesc"] = "Fence agent for QLogic SANBox2 FC switches"
docs["longdesc"] = "fence_sanbox2 is an I/O Fencing agent which can be used with \
QLogic SANBox2 FC switches. It logs into a SANBox2 switch via telnet and disables a specified \
port. Disabling the port which a machine is connected to effectively fences that machine. \
Lengthy telnet connections to the switch should be avoided while a GFS cluster is running \
because the connection will block any necessary fencing actions."
docs["vendorurl"] = "http://www.qlogic.com"
show_docs(options, docs)
##
## Operate the fencing device
##
conn = fence_login(options)
conn.send_eol("admin start")
conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"]))
if re.search(r"\(admin\)", conn.before, re.MULTILINE) == None:
## Someone else is in admin section, we can't enable/disable
## ports so we will rather exit
logging.error("Failed: Unable to switch to admin section\n")
sys.exit(EC_GENERIC_ERROR)
result = fence_action(conn, options, set_power_status, get_power_status, get_list_devices)
##
## Logout from system
######
try:
conn.send_eol("admin end")
conn.send_eol("exit\n")
conn.close()
except OSError:
pass
except pexpect.ExceptionPexpect:
pass
sys.exit(result)
if __name__ == "__main__":
main()
diff --git a/fence/agents/sbd/fence_sbd.py b/fence/agents/sbd/fence_sbd.py
index d09b97e1..b1df70ac 100644
--- a/fence/agents/sbd/fence_sbd.py
+++ b/fence/agents/sbd/fence_sbd.py
@@ -1,421 +1,415 @@
#!@PYTHON@ -tt
import sys, stat
import logging
import os
import atexit
sys.path.append("@FENCEAGENTSLIBDIR@")
from fencing import fail_usage, run_command, fence_action, all_opt
from fencing import atexit_handler, check_input, process_input, show_docs
from fencing import run_delay
-#BEGIN_VERSION_GENERATION
-RELEASE_VERSION=""
-REDHAT_COPYRIGHT=""
-BUILD_DATE=""
-#END_VERSION_GENERATION
-
DEVICE_INIT = 1
DEVICE_NOT_INIT = -3
PATH_NOT_EXISTS = -1
PATH_NOT_BLOCK = -2
def is_block_device(filename):
"""Checks if a given path is a valid block device
Key arguments:
filename -- the file to check
Return codes:
True if it's a valid block device
False, otherwise
"""
try:
mode = os.lstat(filename).st_mode
except OSError:
return False
else:
return stat.S_ISBLK(mode)
def is_link(filename):
"""Checks if a given path is a link.
Key arguments:
filename -- the file to check
Return codes:
True if it's a link
False, otherwise
"""
try:
mode = os.lstat(filename).st_mode
except OSError:
return False
else:
return stat.S_ISLNK(mode)
def check_sbd_device(options, device_path):
"""checks that a given sbd device exists and is initialized
Key arguments:
options -- options dictionary
device_path -- device path to check
Return Codes:
1 / DEVICE_INIT if the device exists and is initialized
-1 / PATH_NOT_EXISTS if the path does not exists
-2 / PATH_NOT_BLOCK if the path exists but is not a valid block device
-3 / DEVICE_NOT_INIT if the sbd device is not initialized
"""
# First of all we need to check if the device is valid
if not os.path.exists(device_path):
return PATH_NOT_EXISTS
# We need to check if device path is a symbolic link. If so we resolve that
# link.
if is_link(device_path):
link_target = os.readlink(device_path)
device_path = os.path.join(os.path.dirname(device_path), link_target)
# As second step we make sure it's a valid block device
if not is_block_device(device_path):
return PATH_NOT_BLOCK
cmd = "%s -d %s dump" % (options["--sbd-path"], device_path)
(return_code, out, err) = run_command(options, cmd)
for line in out.split("\n"):
if len(line) == 0:
continue
# If we read "NOT dumped" something went wrong, e.g. the device is not
# initialized.
if "NOT dumped" in line:
return DEVICE_NOT_INIT
return DEVICE_INIT
def generate_sbd_command(options, command, arguments=None):
"""Generates a sbd command based on given arguments.
Return Value:
generated sbd command (string)
"""
cmd = options["--sbd-path"]
# add "-d" for each sbd device
for device in parse_sbd_devices(options):
cmd += " -d %s" % device
cmd += " %s %s" % (command, arguments)
return cmd
def send_sbd_message(conn, options, plug, message):
"""Sends a message to all sbd devices.
Key arguments:
conn -- connection structure
options -- options dictionary
plug -- plug to sent the message to
message -- message to send
Return Value:
(return_code, out, err) Tuple containing the error code,
"""
del conn
arguments = "%s %s" % (plug, message)
cmd = generate_sbd_command(options, "message", arguments)
(return_code, out, err) = run_command(options, cmd)
return (return_code, out, err)
def get_msg_timeout(options):
"""Reads the configured sbd message timeout from each device.
Key arguments:
options -- options dictionary
Return Value:
msg_timeout (integer, seconds)
"""
# get the defined msg_timeout
msg_timeout = -1 # default sbd msg timeout
cmd = generate_sbd_command(options, "dump")
(return_code, out, err) = run_command(options, cmd)
for line in out.split("\n"):
if len(line) == 0:
continue
if "msgwait" in line:
tmp_msg_timeout = int(line.split(':')[1])
if -1 != msg_timeout and tmp_msg_timeout != msg_timeout:
logging.warn(\
"sbd message timeouts differ in different devices")
# we only save the highest timeout
if tmp_msg_timeout > msg_timeout:
msg_timeout = tmp_msg_timeout
return msg_timeout
def set_power_status(conn, options):
"""send status to sbd device (poison pill)
Key arguments:
conn -- connection structure
options -- options dictionary
Return Value:
return_code -- action result (bool)
"""
target_status = options["--action"]
plug = options["--plug"]
return_code = 99
out = ""
err = ""
# Map fencing actions to sbd messages
if "on" == target_status:
(return_code, out, err) = send_sbd_message(conn, options, plug, "clear")
elif "off" == target_status:
(return_code, out, err) = send_sbd_message(conn, options, plug, "off")
elif "reboot" == target_status:
(return_code, out, err) = send_sbd_message(conn, options, plug, "reset")
if 0 != return_code:
logging.error("sending message to sbd device(s) \
failed with return code %d", return_code)
logging.error("DETAIL: output on stdout was \"%s\"", out)
logging.error("DETAIL: output on stderr was \"%s\"", err)
return not bool(return_code)
def reboot_cycle(conn, options):
"""" trigger reboot by sbd messages
Key arguments:
conn -- connection structure
options -- options dictionary
Return Value:
return_code -- action result (bool)
"""
plug = options["--plug"]
return_code = 99
out = ""
err = ""
(return_code, out, err) = send_sbd_message(conn, options, plug, "reset")
return not bool(return_code)
def get_power_status(conn, options):
"""Returns the status of a specific node.
Key arguments:
conn -- connection structure
options -- option dictionary
Return Value:
status -- status code (string)
"""
status = "UNKWNOWN"
plug = options["--plug"]
nodelist = get_node_list(conn, options)
# We need to check if the specified plug / node a already a allocated slot
# on the device.
if plug not in nodelist:
logging.error("node \"%s\" not found in node list", plug)
else:
status = nodelist[plug][1]
return status
def translate_status(sbd_status):
"""Translates the sbd status to fencing status.
Key arguments:
sbd_status -- status to translate (string)
Return Value:
status -- fencing status (string)
"""
status = "UNKNOWN"
# Currently we only accept "clear" to be marked as online. Eventually we
# should also check against "test"
online_status = ["clear"]
offline_status = ["reset", "off"]
if any(online_status_element in sbd_status \
for online_status_element in online_status):
status = "on"
if any(offline_status_element in sbd_status \
for offline_status_element in offline_status):
status = "off"
return status
def get_node_list(conn, options):
"""Returns a list of hostnames, registerd on the sbd device.
Key arguments:
conn -- connection options
options -- options
Return Value:
nodelist -- dictionary wich contains all node names and there status
"""
del conn
nodelist = {}
cmd = generate_sbd_command(options, "list")
(return_code, out, err) = run_command(options, cmd)
for line in out.split("\n"):
if len(line) == 0:
continue
# if we read "unreadable" something went wrong
if "NOT dumped" in line:
return nodelist
words = line.split()
port = words[1]
sbd_status = words[2]
nodelist[port] = (port, translate_status(sbd_status))
return nodelist
def parse_sbd_devices(options):
"""Returns an array of all sbd devices.
Key arguments:
options -- options dictionary
Return Value:
devices -- array of device paths
"""
devices = [str.strip(dev) \
for dev in str.split(options["--devices"], ",")]
return devices
def define_new_opts():
"""Defines the all opt list
"""
all_opt["devices"] = {
"getopt" : ":",
"longopt" : "devices",
"help":"--devices=[device_a,device_b] \
Comma separated list of sbd devices",
"required" : "1",
"shortdesc" : "SBD Device",
"order": 1
}
all_opt["sbd_path"] = {
"getopt" : ":",
"longopt" : "sbd-path",
"help" : "--sbd-path=[path] Path to SBD binary",
"required" : "0",
"default" : "@SBD_PATH@",
"order": 200
}
def main():
"""Main function
"""
# We need to define "no_password" otherwise we will be ask about it if
# we don't provide any password.
device_opt = ["no_password", "devices", "port", "method", "sbd_path"]
# close stdout if we get interrupted
atexit.register(atexit_handler)
define_new_opts()
all_opt["method"]["default"] = "cycle"
all_opt["method"]["help"] = "-m, --method=[method] Method to fence (onoff|cycle) (Default: cycle)"
options = check_input(device_opt, process_input(device_opt))
# fill the needed variables to generate metadata and help text output
docs = {}
docs["shortdesc"] = "Fence agent for sbd"
docs["longdesc"] = "fence_sbd is I/O Fencing agent \
which can be used in environments where sbd can be used (shared storage)."
docs["vendorurl"] = ""
show_docs(options, docs)
# We need to check if --devices is given and not empty.
if "--devices" not in options:
fail_usage("No SBD devices specified. \
At least one SBD device is required.")
run_delay(options)
# We need to check if the provided sbd_devices exists. We need to do
# that for every given device.
for device_path in parse_sbd_devices(options):
logging.debug("check device \"%s\"", device_path)
return_code = check_sbd_device(options, device_path)
if PATH_NOT_EXISTS == return_code:
logging.error("\"%s\" does not exist", device_path)
elif PATH_NOT_BLOCK == return_code:
logging.error("\"%s\" is not a valid block device", device_path)
elif DEVICE_NOT_INIT == return_code:
logging.error("\"%s\" is not initialized", device_path)
elif DEVICE_INIT != return_code:
logging.error("UNKNOWN error while checking \"%s\"", device_path)
# If we get any error while checking the device we need to exit at this
# point.
if DEVICE_INIT != return_code:
exit(return_code)
# we check against the defined timeouts. If the pacemaker timeout is smaller
# then that defined within sbd we should report this.
power_timeout = int(options["--power-timeout"])
sbd_msg_timeout = get_msg_timeout(options)
if power_timeout <= sbd_msg_timeout:
logging.warn("power timeout needs to be \
greater then sbd message timeout")
result = fence_action(\
None, \
options, \
set_power_status, \
get_power_status, \
get_node_list, \
reboot_cycle)
sys.exit(result)
if __name__ == "__main__":
main()
diff --git a/fence/agents/scsi/fence_scsi.py b/fence/agents/scsi/fence_scsi.py
index 37ff1d38..aac7ea62 100644
--- a/fence/agents/scsi/fence_scsi.py
+++ b/fence/agents/scsi/fence_scsi.py
@@ -1,498 +1,492 @@
#!@PYTHON@ -tt
import sys
import stat
import re
import os
import time
import logging
import atexit
import hashlib
import ctypes
sys.path.append("@FENCEAGENTSLIBDIR@")
from fencing import fail_usage, run_command, atexit_handler, check_input, process_input, show_docs, fence_action, all_opt
from fencing import run_delay
-#BEGIN_VERSION_GENERATION
-RELEASE_VERSION=""
-REDHAT_COPYRIGHT=""
-BUILD_DATE=""
-#END_VERSION_GENERATION
-
STORE_PATH = "/var/run/cluster/fence_scsi"
def get_status(conn, options):
del conn
status = "off"
for dev in options["devices"]:
is_block_device(dev)
reset_dev(options, dev)
if options["--key"] in get_registration_keys(options, dev):
status = "on"
else:
logging.debug("No registration for key "\
+ options["--key"] + " on device " + dev + "\n")
if options["--action"] == "on":
status = "off"
break
return status
def set_status(conn, options):
del conn
count = 0
if options["--action"] == "on":
set_key(options)
for dev in options["devices"]:
is_block_device(dev)
register_dev(options, dev)
if options["--key"] not in get_registration_keys(options, dev):
count += 1
logging.debug("Failed to register key "\
+ options["--key"] + "on device " + dev + "\n")
continue
dev_write(dev, options)
if get_reservation_key(options, dev) is None \
and not reserve_dev(options, dev) \
and get_reservation_key(options, dev) is None:
count += 1
logging.debug("Failed to create reservation (key="\
+ options["--key"] + ", device=" + dev + ")\n")
else:
host_key = get_key()
if host_key == options["--key"].lower():
fail_usage("Failed: keys cannot be same. You can not fence yourself.")
for dev in options["devices"]:
is_block_device(dev)
if options["--key"] in get_registration_keys(options, dev):
preempt_abort(options, host_key, dev)
for dev in options["devices"]:
if options["--key"] in get_registration_keys(options, dev):
count += 1
logging.debug("Failed to remove key "\
+ options["--key"] + " on device " + dev + "\n")
continue
if not get_reservation_key(options, dev):
count += 1
logging.debug("No reservation exists on device " + dev + "\n")
if count:
logging.error("Failed to verify " + str(count) + " device(s)")
sys.exit(1)
# check if host is ready to execute actions
def do_action_monitor(options):
# Check if required binaries are installed
if bool(run_cmd(options, options["--sg_persist-path"] + " -V")["err"]):
logging.error("Unable to run " + options["--sg_persist-path"])
return 1
elif bool(run_cmd(options, options["--sg_turs-path"] + " -V")["err"]):
logging.error("Unable to run " + options["--sg_turs-path"])
return 1
elif ("--devices" not in options and
bool(run_cmd(options, options["--vgs-path"] + " --version")["err"])):
logging.error("Unable to run " + options["--vgs-path"])
return 1
# Keys have to be present in order to fence/unfence
get_key()
dev_read()
return 0
#run command, returns dict, ret["err"] = exit code; ret["out"] = output
def run_cmd(options, cmd):
ret = {}
(ret["err"], ret["out"], _) = run_command(options, cmd)
ret["out"] = "".join([i for i in ret["out"] if i is not None])
return ret
# check if device exist and is block device
def is_block_device(dev):
if not os.path.exists(dev):
fail_usage("Failed: device \"" + dev + "\" does not exist")
if not stat.S_ISBLK(os.stat(dev).st_mode):
fail_usage("Failed: device \"" + dev + "\" is not a block device")
# cancel registration
def preempt_abort(options, host, dev):
reset_dev(options,dev)
cmd = options["--sg_persist-path"] + " -n -o -A -T 5 -K " + host + " -S " + options["--key"] + " -d " + dev
return not bool(run_cmd(options, cmd)["err"])
def reset_dev(options, dev):
return run_cmd(options, options["--sg_turs-path"] + " " + dev)["err"]
def register_dev(options, dev):
dev = os.path.realpath(dev)
if re.search(r"^dm", dev[5:]):
for slave in get_mpath_slaves(dev):
register_dev(options, slave)
return True
reset_dev(options, dev)
cmd = options["--sg_persist-path"] + " -n -o -I -S " + options["--key"] + " -d " + dev
cmd += " -Z" if "--aptpl" in options else ""
#cmd return code != 0 but registration can be successful
return not bool(run_cmd(options, cmd)["err"])
def reserve_dev(options, dev):
reset_dev(options,dev)
cmd = options["--sg_persist-path"] + " -n -o -R -T 5 -K " + options["--key"] + " -d " + dev
return not bool(run_cmd(options, cmd)["err"])
def get_reservation_key(options, dev):
reset_dev(options,dev)
cmd = options["--sg_persist-path"] + " -n -i -r -d " + dev
out = run_cmd(options, cmd)
if out["err"]:
fail_usage("Cannot get reservation key")
match = re.search(r"\s+key=0x(\S+)\s+", out["out"], re.IGNORECASE)
return match.group(1) if match else None
def get_registration_keys(options, dev):
reset_dev(options,dev)
keys = []
cmd = options["--sg_persist-path"] + " -n -i -k -d " + dev
out = run_cmd(options, cmd)
if out["err"]:
fail_usage("Cannot get registration keys")
for line in out["out"].split("\n"):
match = re.search(r"\s+0x(\S+)\s*", line)
if match:
keys.append(match.group(1))
return keys
def get_cluster_id(options):
cmd = options["--corosync-cmap-path"] + " totem.cluster_name"
match = re.search(r"\(str\) = (\S+)\n", run_cmd(options, cmd)["out"])
return hashlib.md5(match.group(1)).hexdigest() if match else fail_usage("Failed: cannot get cluster name")
def get_node_id(options):
cmd = options["--corosync-cmap-path"] + " nodelist."
match = re.search(r".(\d).ring._addr \(str\) = " + options["--nodename"] + "\n", run_cmd(options, cmd)["out"])
return match.group(1) if match else fail_usage("Failed: unable to parse output of corosync-cmapctl or node does not exist")
def generate_key(options):
return "%.4s%.4d" % (get_cluster_id(options), int(get_node_id(options)))
# save node key to file
def set_key(options):
file_path = options["store_path"] + ".key"
if not os.path.isdir(os.path.dirname(options["store_path"])):
os.makedirs(os.path.dirname(options["store_path"]))
try:
f = open(file_path, "w")
except IOError:
fail_usage("Failed: Cannot open file \""+ file_path + "\"")
f.write(options["--key"].lower() + "\n")
f.close()
# read node key from file
def get_key(fail=True):
file_path = STORE_PATH + ".key"
try:
f = open(file_path, "r")
except IOError:
if fail:
fail_usage("Failed: Cannot open file \""+ file_path + "\"")
else:
return None
return f.readline().strip().lower()
def dev_write(dev, options):
file_path = options["store_path"] + ".dev"
if not os.path.isdir(os.path.dirname(options["store_path"])):
os.makedirs(os.path.dirname(options["store_path"]))
try:
f = open(file_path, "a+")
except IOError:
fail_usage("Failed: Cannot open file \""+ file_path + "\"")
out = f.read()
if not re.search(r"^" + dev + "\s+", out):
f.write(dev + "\n")
f.close()
def dev_read(fail=True):
file_path = STORE_PATH + ".dev"
try:
f = open(file_path, "r")
except IOError:
if fail:
fail_usage("Failed: Cannot open file \"" + file_path + "\"")
else:
return None
# get not empty lines from file
devs = [line.strip() for line in f if line.strip()]
f.close()
return devs
def dev_delete(options):
file_path = options["store_path"] + ".dev"
os.remove(file_path) if os.path.exists(file_path) else None
def get_clvm_devices(options):
devs = []
cmd = options["--vgs-path"] + " " +\
"--noheadings " +\
"--separator : " +\
"--sort pv_uuid " +\
"--options vg_attr,pv_name "+\
"--config 'global { locking_type = 0 } devices { preferred_names = [ \"^/dev/dm\" ] }'"
out = run_cmd(options, cmd)
if out["err"]:
fail_usage("Failed: Cannot get clvm devices")
for line in out["out"].split("\n"):
if 'c' in line.split(":")[0]:
devs.append(line.split(":")[1])
return devs
def get_mpath_slaves(dev):
if dev[:5] == "/dev/":
dev = dev[5:]
slaves = [i for i in os.listdir("/sys/block/" + dev + "/slaves/") if i[:1] != "."]
if slaves[0][:2] == "dm":
slaves = get_mpath_slaves(slaves[0])
else:
slaves = ["/dev/" + x for x in slaves]
return slaves
def define_new_opts():
all_opt["devices"] = {
"getopt" : "d:",
"longopt" : "devices",
"help" : "-d, --devices=[devices] List of devices to use for current operation",
"required" : "0",
"shortdesc" : "List of devices to use for current operation. Devices can \
be comma-separated list of raw devices (eg. /dev/sdc). Each device must support SCSI-3 \
persistent reservations.",
"order": 1
}
all_opt["nodename"] = {
"getopt" : "n:",
"longopt" : "nodename",
"help" : "-n, --nodename=[nodename] Name of the node to be fenced",
"required" : "0",
"shortdesc" : "Name of the node to be fenced. The node name is used to \
generate the key value used for the current operation. This option will be \
ignored when used with the -k option.",
"order": 1
}
all_opt["key"] = {
"getopt" : "k:",
"longopt" : "key",
"help" : "-k, --key=[key] Key to use for the current operation",
"required" : "0",
"shortdesc" : "Key to use for the current operation. This key should be \
unique to a node. For the \"on\" action, the key specifies the key use to \
register the local node. For the \"off\" action, this key specifies the key to \
be removed from the device(s).",
"order": 1
}
all_opt["aptpl"] = {
"getopt" : "a",
"longopt" : "aptpl",
"help" : "-a, --aptpl Use the APTPL flag for registrations",
"required" : "0",
"shortdesc" : "Use the APTPL flag for registrations. This option is only used for the 'on' action.",
"order": 1
}
all_opt["logfile"] = {
"getopt" : ":",
"longopt" : "logfile",
"help" : "-f, --logfile Log output (stdout and stderr) to file",
"required" : "0",
"shortdesc" : "Log output (stdout and stderr) to file",
"order": 5
}
all_opt["corosync-cmap_path"] = {
"getopt" : ":",
"longopt" : "corosync-cmap-path",
"help" : "--corosync-cmap-path=[path] Path to corosync-cmapctl binary",
"required" : "0",
"shortdesc" : "Path to corosync-cmapctl binary",
"default" : "@COROSYNC_CMAPCTL_PATH@",
"order": 300
}
all_opt["sg_persist_path"] = {
"getopt" : ":",
"longopt" : "sg_persist-path",
"help" : "--sg_persist-path=[path] Path to sg_persist binary",
"required" : "0",
"shortdesc" : "Path to sg_persist binary",
"default" : "@SG_PERSIST_PATH@",
"order": 300
}
all_opt["sg_turs_path"] = {
"getopt" : ":",
"longopt" : "sg_turs-path",
"help" : "--sg_turs-path=[path] Path to sg_turs binary",
"required" : "0",
"shortdesc" : "Path to sg_turs binary",
"default" : "@SG_TURS_PATH@",
"order": 300
}
all_opt["vgs_path"] = {
"getopt" : ":",
"longopt" : "vgs-path",
"help" : "--vgs-path=[path] Path to vgs binary",
"required" : "0",
"shortdesc" : "Path to vgs binary",
"default" : "@VGS_PATH@",
"order": 300
}
def scsi_check_get_verbose():
try:
f = open("/etc/sysconfig/watchdog", "r")
except IOError:
return False
match = re.search(r"^\s*verbose=yes", "".join(f.readlines()), re.MULTILINE)
f.close()
return bool(match)
def scsi_check(hardreboot=False):
if len(sys.argv) >= 3 and sys.argv[1] == "repair":
return int(sys.argv[2])
options = {}
options["--sg_turs-path"] = "@SG_TURS_PATH@"
options["--sg_persist-path"] = "@SG_PERSIST_PATH@"
options["--power-timeout"] = "5"
if scsi_check_get_verbose():
logging.getLogger().setLevel(logging.DEBUG)
devs = dev_read(fail=False)
if not devs:
logging.error("No devices found")
return 0
key = get_key(fail=False)
if not key:
logging.error("Key not found")
return 0
for dev in devs:
if key in get_registration_keys(options, dev):
logging.debug("key " + key + " registered with device " + dev)
return 0
else:
logging.debug("key " + key + " not registered with device " + dev)
logging.debug("key " + key + " registered with any devices")
if hardreboot == True:
libc = ctypes.cdll['libc.so.6']
libc.reboot(0x1234567)
return 2
def main():
atexit.register(atexit_handler)
device_opt = ["no_login", "no_password", "devices", "nodename", "key",\
"aptpl", "fabric_fencing", "on_target", "corosync-cmap_path",\
"sg_persist_path", "sg_turs_path", "logfile", "vgs_path", "force_on"]
define_new_opts()
all_opt["delay"]["getopt"] = "H:"
#fence_scsi_check
if os.path.basename(sys.argv[0]) == "fence_scsi_check":
sys.exit(scsi_check())
elif os.path.basename(sys.argv[0]) == "fence_scsi_check_hardreboot":
sys.exit(scsi_check(True))
options = check_input(device_opt, process_input(device_opt), other_conditions=True)
docs = {}
docs["shortdesc"] = "Fence agent for SCSI persistent reservation"
docs["longdesc"] = "fence_scsi is an I/O fencing agent that uses SCSI-3 \
persistent reservations to control access to shared storage devices. These \
devices must support SCSI-3 persistent reservations (SPC-3 or greater) as \
well as the \"preempt-and-abort\" subcommand.\nThe fence_scsi agent works by \
having each node in the cluster register a unique key with the SCSI \
device(s). Once registered, a single node will become the reservation holder \
by creating a \"write exclusive, registrants only\" reservation on the \
device(s). The result is that only registered nodes may write to the \
device(s). When a node failure occurs, the fence_scsi agent will remove the \
key belonging to the failed node from the device(s). The failed node will no \
longer be able to write to the device(s). A manual reboot is required."
docs["vendorurl"] = ""
show_docs(options, docs)
run_delay(options)
# backward compatibility layer BEGIN
if "--logfile" in options:
try:
logfile = open(options["--logfile"], 'w')
sys.stderr = logfile
sys.stdout = logfile
except IOError:
fail_usage("Failed: Unable to create file " + options["--logfile"])
# backward compatibility layer END
options["store_path"] = STORE_PATH
# Input control BEGIN
stop_after_error = False if options["--action"] == "validate-all" else True
if options["--action"] == "monitor":
sys.exit(do_action_monitor(options))
if not (("--nodename" in options and options["--nodename"])\
or ("--key" in options and options["--key"])):
fail_usage("Failed: nodename or key is required", stop_after_error)
if not ("--key" in options and options["--key"]):
options["--key"] = generate_key(options)
if options["--key"] == "0" or not options["--key"]:
fail_usage("Failed: key cannot be 0", stop_after_error)
if options["--action"] == "validate-all":
sys.exit(0)
options["--key"] = options["--key"].lstrip('0')
if not ("--devices" in options and options["--devices"].split(",")):
options["devices"] = get_clvm_devices(options)
else:
options["devices"] = options["--devices"].split(",")
if not options["devices"]:
fail_usage("Failed: No devices found")
# Input control END
result = fence_action(None, options, set_status, get_status)
sys.exit(result)
if __name__ == "__main__":
main()
diff --git a/fence/agents/vbox/fence_vbox.py b/fence/agents/vbox/fence_vbox.py
index 489c2284..5491b9b3 100644
--- a/fence/agents/vbox/fence_vbox.py
+++ b/fence/agents/vbox/fence_vbox.py
@@ -1,142 +1,135 @@
#!@PYTHON@ -tt
# The Following Agent Has Been Tested On:
#
# VirtualBox 5.0.4 x64 on openSUSE 13.2
#
import sys
import re
import time
import atexit
sys.path.append("@FENCEAGENTSLIBDIR@")
from fencing import *
from fencing import fail_usage
-
-#BEGIN_VERSION_GENERATION
-RELEASE_VERSION = "VirtualBox fence agent"
-REDHAT_COPYRIGHT = ""
-BUILD_DATE = ""
-#END_VERSION_GENERATION
-
def _invoke(conn, options, *cmd):
prefix = options["--sudo-path"] + " " if "--use-sudo" in options else ""
conn.send_eol(prefix + options["--vboxmanage-path"] + " " + " ".join(cmd))
conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"]))
def get_outlets_status(conn, options):
_domain_re = re.compile(r'^\"(.*)\" \{(.*)\}$')
result = {}
_invoke(conn, options, "list", "vms")
for line in conn.before.splitlines():
# format: "<domain>" {<uuid>}
domain = _domain_re.search(line.strip())
if domain is not None:
result[domain.group(1)] = (domain.group(2), "off")
_invoke(conn, options, "list", "runningvms")
for line in conn.before.splitlines():
# format: "<domain>" {<uuid>}
domain = _domain_re.search(line.strip())
if domain is not None:
result[domain.group(1)] = (domain.group(2), "on")
return result
def get_power_status(conn, options):
outlets = get_outlets_status(conn, options)
if options["--plug"] in outlets:
return outlets[options["--plug"]][1]
right_uuid_line = [outlets[o] for o in outlets.keys() if outlets[o][0] == options["--plug"]]
if len(right_uuid_line):
return right_uuid_line[0][1]
if "--missing-as-off" in options:
return "off"
fail_usage("Failed: You have to enter existing name/UUID of virtual machine!")
def set_power_status(conn, options):
if options["--action"] == "on":
_invoke(conn, options, "startvm", '"%s"' % options["--plug"], "--type", "headless")
else:
_invoke(conn, options, "controlvm", '"%s"' % options["--plug"], "poweroff")
def define_new_opts():
all_opt["vboxmanage_path"] = {
"getopt" : ":",
"longopt" : "vboxmanage-path",
"help" : "--vboxmanage-path=[path] Path to VBoxManage on the host",
"required" : "0",
"shortdesc" : "Path to VBoxManage on the host",
"default" : "VBoxManage",
"order" : 200
}
all_opt["host_os"] = {
"getopt" : ":",
"longopt" : "host-os",
"help" : "--host-os=[os] Operating system of the host",
"required" : "0",
"shortdesc" : "Operating system of the host",
"choices" : ["linux", "macos", "windows"],
"default" : "linux",
"order" : 200
}
def main():
device_opt = ["ipaddr", "login", "passwd", "cmd_prompt", "secure", "port", "sudo",
"missing_as_off", "vboxmanage_path", "host_os"]
define_new_opts()
atexit.register(atexit_handler)
all_opt["secure"]["default"] = "1"
all_opt["cmd_prompt"]["default"] = [r"\[EXPECT\]#\ "]
all_opt["ssh_options"]["default"] = "-t '/bin/bash -c \"" + r"PS1=\\[EXPECT\\]#\ " + "/bin/bash --noprofile --norc\"'"
opt = process_input(device_opt)
opt["logout_string"] = "quit"
if "--host-os" in opt and "--vboxmanage-path" not in opt:
if opt["--host-os"] == "linux":
opt["--vboxmanage-path"] = "VBoxManage"
elif opt["--host-os"] == "macos":
opt["--vboxmanage-path"] = "/Applications/VirtualBox.app/Contents/MacOS/VBoxManage"
opt["logout_string"] = "exit"
elif opt["--host-os"] == "windows":
opt["--vboxmanage-path"] = "\"/Program Files/Oracle/VirtualBox/VBoxManage.exe"
opt["--command-prompt"] = ""
opt["--ssh-options"] = ""
options = check_input(device_opt, opt)
options["eol"] = "\n"
docs = {}
docs["shortdesc"] = "Fence agent for VirtualBox"
docs["longdesc"] = "fence_vbox is an I/O Fencing agent \
which can be used with the virtual machines managed by VirtualBox. \
It logs via ssh to a dom0 where it runs VBoxManage to do all of \
the work. \
\n.P\n\
By default, vbox needs to log in as a user that is a member of the \
vboxusers group. Also, you must allow ssh login in your sshd_config."
docs["vendorurl"] = "https://www.virtualbox.org/"
show_docs(options, docs)
# Operate the fencing device
conn = fence_login(options)
result = fence_action(conn, options, set_power_status, get_power_status, get_outlets_status)
fence_logout(conn, opt["logout_string"])
sys.exit(result)
if __name__ == "__main__":
main()
diff --git a/fence/agents/virsh/fence_virsh.py b/fence/agents/virsh/fence_virsh.py
index baa5ee09..7ccda2f8 100644
--- a/fence/agents/virsh/fence_virsh.py
+++ b/fence/agents/virsh/fence_virsh.py
@@ -1,102 +1,96 @@
#!@PYTHON@ -tt
# The Following Agent Has Been Tested On:
#
# Virsh 0.3.3 on RHEL 5.2 with xen-3.0.3-51
#
import sys, re
import time
import atexit
sys.path.append("@FENCEAGENTSLIBDIR@")
from fencing import *
from fencing import fail_usage
-#BEGIN_VERSION_GENERATION
-RELEASE_VERSION="Virsh fence agent"
-REDHAT_COPYRIGHT=""
-BUILD_DATE=""
-#END_VERSION_GENERATION
-
def get_name_or_uuid(options):
return options["--uuid"] if "--uuid" in options else options["--plug"]
def get_outlets_status(conn, options):
if "--use-sudo" in options:
prefix = options["--sudo-path"] + " "
else:
prefix = ""
conn.sendline(prefix + "virsh list --all")
conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"]))
result = {}
#This is status of mini finite automata. 0 = we didn't found Id and Name, 1 = we did
fa_status = 0
for line in conn.before.splitlines():
domain = re.search(r"^\s*(\S+)\s+(\S+)\s+(\S+).*$", line)
if domain != None:
if fa_status == 0 and domain.group(1).lower() == "id" and domain.group(2).lower() == "name":
fa_status = 1
elif fa_status == 1:
result[domain.group(2)] = ("",
(domain.group(3).lower() in ["running", "blocked", "idle", "no state", "paused"] and "on" or "off"))
return result
def get_power_status(conn, options):
prefix = options["--sudo-path"] + " " if "--use-sudo" in options else ""
conn.sendline(prefix + "virsh domstate %s" % (get_name_or_uuid(options)))
conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"]))
for line in conn.before.splitlines():
if line.strip() in ["running", "blocked", "idle", "no state", "paused"]:
return "on"
if "error: failed to get domain" in line.strip() and "--missing-as-off" in options:
return "off"
if "error:" in line.strip():
fail_usage("Failed: You have to enter existing name/UUID of virtual machine!")
return "off"
def set_power_status(conn, options):
prefix = options["--sudo-path"] + " " if "--use-sudo" in options else ""
conn.sendline(prefix + "virsh %s " %
(options["--action"] == "on" and "start" or "destroy") + get_name_or_uuid(options))
conn.log_expect(options["--command-prompt"], int(options["--power-timeout"]))
time.sleep(int(options["--power-wait"]))
def main():
device_opt = ["ipaddr", "login", "passwd", "cmd_prompt", "secure", "port", "sudo", "missing_as_off"]
atexit.register(atexit_handler)
all_opt["secure"]["default"] = "1"
all_opt["cmd_prompt"]["default"] = [r"\[EXPECT\]#\ "]
all_opt["ssh_options"]["default"] = "-t '/bin/bash -c \"" + r"PS1=\\[EXPECT\\]#\ " + "/bin/bash --noprofile --norc\"'"
options = check_input(device_opt, process_input(device_opt))
docs = {}
docs["shortdesc"] = "Fence agent for virsh"
docs["longdesc"] = "fence_virsh is an I/O Fencing agent \
which can be used with the virtual machines managed by libvirt. \
It logs via ssh to a dom0 and there run virsh command, which does \
all work. \
\n.P\n\
By default, virsh needs root account to do properly work. So you \
must allow ssh login in your sshd_config."
docs["vendorurl"] = "http://libvirt.org"
show_docs(options, docs)
## Operate the fencing device
conn = fence_login(options)
result = fence_action(conn, options, set_power_status, get_power_status, get_outlets_status)
fence_logout(conn, "quit")
sys.exit(result)
if __name__ == "__main__":
main()
diff --git a/fence/agents/vmware/fence_vmware.py b/fence/agents/vmware/fence_vmware.py
index 8bb061e4..8dd0297c 100644
--- a/fence/agents/vmware/fence_vmware.py
+++ b/fence/agents/vmware/fence_vmware.py
@@ -1,342 +1,336 @@
#!@PYTHON@ -tt
#
# The Following agent has been tested on:
# vmrun 2.0.0 build-116503 (from VMware Server 2.0) against:
# VMware ESX 4.0.0
# VMware vCenter 4.0.0
# VMware ESX 3.5
# VMware Server 2.0.0
# VMware ESXi 3.5 update 2
# VMware Server 1.0.7 (works but list/status show only running VMs)
#
# VI Perl API 1.6 against:
# VMware ESX 4.0.0
# VMware vCenter 4.0.0
# VMware ESX 3.5
# VMware ESXi 3.5 update 2
# VMware Virtual Center 2.5
#
# VMware vSphere SDK for Perl 4.0.0 against:
# VMware ESX 4.0.0
# VMware vCenter 4.0.0
#
import sys, re, pexpect
import logging
import atexit
sys.path.append("@FENCEAGENTSLIBDIR@")
from fencing import *
from fencing import fail, fail_usage, EC_TIMED_OUT, run_delay
-#BEGIN_VERSION_GENERATION
-RELEASE_VERSION="VMware Agent using VI Perl API and/or VIX vmrun command"
-REDHAT_COPYRIGHT=""
-BUILD_DATE=""
-#END_VERSION_GENERATION
-
### CONSTANTS ####
# VMware type is ESX/ESXi/VC
VMWARE_TYPE_ESX = 0
# VMware type is Server 1.x
VMWARE_TYPE_SERVER1 = 1
# VMware type is Server 2.x and/or ESX 3.5 up2, ESXi 3.5 up2, VC 2.5 up2
VMWARE_TYPE_SERVER2 = 2
# Minimum required version of vmrun command
VMRUN_MINIMUM_REQUIRED_VERSION = 2
# Default path to vmhelper command
VMHELPER_COMMAND = "fence_vmware_helper"
# Default path to vmrun command
VMRUN_COMMAND = "/usr/bin/vmrun"
# Default type of vmware
VMWARE_DEFAULT_TYPE = "esx"
#### GLOBAL VARIABLES ####
# Internal type. One of VMWARE_TYPE_, set by #vmware_check_vmware_type
vmware_internal_type = VMWARE_TYPE_ESX
# If ESX is disconnected, say, that VM is off (don't return previous state)
vmware_disconnected_hack = False
### FUNCTIONS ####
#Split string in simplified DSV format to array of items
def dsv_split(dsv_str):
delimiter_c = ':'
escape_c = '\\'
res = []
status = 0
tmp_str = ""
for x in dsv_str:
if status == 0:
if x == delimiter_c:
res.append(tmp_str)
tmp_str = ""
elif x == escape_c:
status = 1
else:
tmp_str += x
elif status == 1:
if x == delimiter_c:
tmp_str += delimiter_c
elif x == escape_c:
tmp_str += escape_c
else:
tmp_str += escape_c+x
status = 0
if tmp_str != "":
res.append(tmp_str)
return res
# Quote string for proper existence in quoted string used for pexpect.run function
# Ex. test'this will return test'\''this. So pexpect run will really pass ' to argument
def quote_for_run(text):
dstr = ''
for c in text:
if c == r"'":
dstr += "'\\''"
else:
dstr += c
return dstr
# Return string with command and additional parameters (something like vmrun -h 'host'
def vmware_prepare_command(options, add_login_params, additional_params):
res = options["--exec"]
if add_login_params:
if vmware_internal_type == VMWARE_TYPE_ESX:
res += " --server '%s' --username '%s' --password '%s' "% (quote_for_run(options["--ip"]),
quote_for_run(options["--username"]),
quote_for_run(options["--password"]))
elif vmware_internal_type == VMWARE_TYPE_SERVER2:
res += " -h 'https://%s/sdk' -u '%s' -p '%s' -T server "% (quote_for_run(options["--ip"]),
quote_for_run(options["--username"]),
quote_for_run(options["--password"]))
elif vmware_internal_type == VMWARE_TYPE_SERVER1:
host_name_array = options["--ip"].split(':')
res += " -h '%s' -u '%s' -p '%s' -T server1 "% (quote_for_run(host_name_array[0]),
quote_for_run(options["--username"]),
quote_for_run(options["--password"]))
if len(host_name_array) > 1:
res += "-P '%s' "% (quote_for_run(host_name_array[1]))
if "--vmware-datacenter" in options and vmware_internal_type == VMWARE_TYPE_ESX:
res += "--datacenter '%s' "% (quote_for_run(options["--vmware-datacenter"]))
if additional_params != "":
res += additional_params
return res
# Run command with timeout and parameters. Internaly uses vmware_prepare_command. Returns string
# with output from vmrun command. If something fails (command not found, exit code is not 0), fail_usage
# function is called (and never return).
def vmware_run_command(options, add_login_params, additional_params, additional_timeout):
command = vmware_prepare_command(options, add_login_params, additional_params)
try:
logging.debug("%s\n", command)
(res_output, res_code) = pexpect.run(command,
int(options["--shell-timeout"]) + int(options["--login-timeout"]) + additional_timeout, True)
if res_code == None:
fail(EC_TIMED_OUT)
if res_code != 0 and add_login_params:
logging.debug("%s\n", res_output)
fail_usage("%s returned %s"% (options["--exec"], res_output))
else:
logging.debug("%s\n", res_output)
except pexpect.ExceptionPexpect:
fail_usage("Cannot run command %s"% (options["--exec"]))
return res_output
# Get outlet list with status as hash table. If you will use add_vm_name, only VM with vmname is
# returned. This is used in get_status function
def vmware_get_outlets_vi(options, add_vm_name):
outlets = {}
if add_vm_name:
all_machines = vmware_run_command(options, True,
("--operation status --vmname '%s'"% (quote_for_run(options["--plug"]))), 0)
else:
all_machines = vmware_run_command(options, True, "--operation list", int(options["--power-timeout"]))
all_machines_array = all_machines.splitlines()
for machine in all_machines_array:
machine_array = dsv_split(machine)
if len(machine_array) == 4:
if machine_array[0] in outlets:
fail_usage("Failed. More machines with same name %s found!"%(machine_array[0]))
if vmware_disconnected_hack:
outlets[machine_array[0]] = ("", (
((machine_array[2].lower() in ["poweredon"]) and
(machine_array[3].lower() == "connected"))
and "on" or "off"))
else:
outlets[machine_array[0]] = ("", ((machine_array[2].lower() in ["poweredon"]) and "on" or "off"))
return outlets
# Get outlet list with status as hash table.
def vmware_get_outlets_vix(options):
outlets = {}
running_machines = vmware_run_command(options, True, "list", 0)
running_machines_array = running_machines.splitlines()[1:]
if vmware_internal_type == VMWARE_TYPE_SERVER2:
all_machines = vmware_run_command(options, True, "listRegisteredVM", 0)
all_machines_array = all_machines.splitlines()[1:]
elif vmware_internal_type == VMWARE_TYPE_SERVER1:
all_machines_array = running_machines_array
for machine in all_machines_array:
if machine != "":
outlets[machine] = ("", ((machine in running_machines_array) and "on" or "off"))
return outlets
def get_outlets_status(conn, options):
del conn
if vmware_internal_type == VMWARE_TYPE_ESX:
return vmware_get_outlets_vi(options, False)
if vmware_internal_type == VMWARE_TYPE_SERVER1 or vmware_internal_type == VMWARE_TYPE_SERVER2:
return vmware_get_outlets_vix(options)
def get_power_status(conn, options):
if vmware_internal_type == VMWARE_TYPE_ESX:
outlets = vmware_get_outlets_vi(options, True)
else:
outlets = get_outlets_status(conn, options)
if vmware_internal_type == VMWARE_TYPE_SERVER2 or vmware_internal_type == VMWARE_TYPE_ESX:
if not options["--plug"] in outlets:
fail_usage("Failed: You have to enter existing name of virtual machine!")
else:
return outlets[options["--plug"]][1]
elif vmware_internal_type == VMWARE_TYPE_SERVER1:
return (options["--plug"] in outlets) and "on" or "off"
def set_power_status(conn, options):
del conn
if vmware_internal_type == VMWARE_TYPE_ESX:
additional_params = "--operation %s --vmname '%s'" % \
((options["--action"] == "on" and "on" or "off"), quote_for_run(options["--plug"]))
elif vmware_internal_type == VMWARE_TYPE_SERVER1 or vmware_internal_type == VMWARE_TYPE_SERVER2:
additional_params = "%s '%s'" % \
((options["--action"] == "on" and "start" or "stop"), quote_for_run(options["--plug"]))
if options["--action"] == "off":
additional_params += " hard"
vmware_run_command(options, True, additional_params, int(options["--power-timeout"]))
# Returns True, if user uses supported vmrun version (currently >=2.0.0) otherwise False.
def vmware_is_supported_vmrun_version(options):
vmware_help_str = vmware_run_command(options, False, "", 0)
version_re = re.search(r"vmrun version (\d\.(\d[\.]*)*)", vmware_help_str.lower())
if version_re == None:
return False # Looks like this "vmrun" is not real vmrun
version_array = version_re.group(1).split(".")
try:
if int(version_array[0]) < VMRUN_MINIMUM_REQUIRED_VERSION:
return False
except Exception:
return False
return True
# Check vmware type, set vmware_internal_type to one of VMWARE_TYPE_ value and
# options["--exec"] to path (if not specified)
def vmware_check_vmware_type(options):
global vmware_internal_type
options["--vmware_type"] = options["--vmware_type"].lower()
if options["--vmware_type"] == "esx":
vmware_internal_type = VMWARE_TYPE_ESX
if "--exec" not in options:
options["--exec"] = VMHELPER_COMMAND
elif options["--vmware_type"] == "server2":
vmware_internal_type = VMWARE_TYPE_SERVER2
if "--exec" not in options:
options["--exec"] = VMRUN_COMMAND
elif options["--vmware_type"] == "server1":
vmware_internal_type = VMWARE_TYPE_SERVER1
if "--exec" not in options:
options["--exec"] = VMRUN_COMMAND
else:
fail_usage("vmware_type can be esx,server2 or server1!")
# Main agent method
def main():
device_opt = ["ipaddr", "login", "passwd", "secure",
"exec", "vmware_type", "vmware_datacenter"]
atexit.register(atexit_handler)
all_opt["secure"]["default"] = "1"
all_opt["vmware_type"]["default"] = VMWARE_DEFAULT_TYPE
options = check_input(device_opt, process_input(device_opt))
docs = {}
docs["shortdesc"] = "Fence agent for VMWare"
docs["longdesc"] = "fence_vmware is an I/O Fencing agent \
which can be used with the VMware ESX, VMware ESXi or VMware Server \
to fence virtual machines.\
\n.P\n\
Before you can use this agent, it must be installed VI Perl Toolkit or \
vmrun command on every node you want to make fencing.\
\n.P\n\
VI Perl Toolkit is preferred for VMware ESX/ESXi and Virtual Center. Vmrun \
command is only solution for VMware Server 1/2 (this command will works against \
ESX/ESXi 3.5 up2 and VC up2 too, but not cluster aware!) and is available as part \
of VMware VIX API SDK package. VI Perl and VIX API SDK are both available from \
VMware web pages (not int RHEL repository!). \
\n.P\n\
You can specify type of VMware you are connecting to with \\fB-d\\fP switch \
(or \\fIvmware_type\\fR for stdin). Possible values are esx, server2 and server1.\
Default value is esx, which will use VI Perl. With server1 and server2, vmrun \
command is used.\
\n.P\n\
After you have successfully installed VI Perl Toolkit or VIX API, you should \
be able to run fence_vmware_helper (part of this agent) or vmrun command. \
This agent supports only vmrun from version 2.0.0 (VIX API 1.6.0)."
docs["vendorurl"] = "http://www.vmware.com"
show_docs(options, docs)
run_delay(options)
# Check vmware type and set path
vmware_check_vmware_type(options)
# Test user vmrun command version
if vmware_internal_type == VMWARE_TYPE_SERVER1 or vmware_internal_type == VMWARE_TYPE_SERVER2:
if not vmware_is_supported_vmrun_version(options):
fail_usage("Unsupported version of vmrun command! You must use at least version %d!" %
(VMRUN_MINIMUM_REQUIRED_VERSION))
# Operate the fencing device
result = fence_action(None, options, set_power_status, get_power_status, get_outlets_status)
sys.exit(result)
if __name__ == "__main__":
main()
diff --git a/fence/agents/vmware_soap/fence_vmware_soap.py b/fence/agents/vmware_soap/fence_vmware_soap.py
index 007a1c67..6a3b592f 100644
--- a/fence/agents/vmware_soap/fence_vmware_soap.py
+++ b/fence/agents/vmware_soap/fence_vmware_soap.py
@@ -1,262 +1,256 @@
#!@PYTHON@ -tt
import sys
import shutil, tempfile, suds
import logging, requests
import atexit
sys.path.append("@FENCEAGENTSLIBDIR@")
from suds.client import Client
from suds.sudsobject import Property
from suds.transport.http import HttpAuthenticated
from suds.transport import Reply, TransportError
from fencing import *
from fencing import fail, fail_usage, EC_STATUS, EC_LOGIN_DENIED, EC_INVALID_PRIVILEGES, EC_WAITING_ON, EC_WAITING_OFF
from fencing import run_delay
-#BEGIN_VERSION_GENERATION
-RELEASE_VERSION="New VMWare Agent - test release on steroids"
-REDHAT_COPYRIGHT=""
-BUILD_DATE="April, 2011"
-#END_VERSION_GENERATION
-
options_global = None
conn_global = None
class RequestsTransport(HttpAuthenticated):
def __init__(self, **kwargs):
self.cert = kwargs.pop('cert', None)
self.verify = kwargs.pop('verify', True)
self.session = requests.Session()
# super won't work because not using new style class
HttpAuthenticated.__init__(self, **kwargs)
def send(self, request):
self.addcredentials(request)
resp = self.session.post(request.url, data=request.message, headers=request.headers, cert=self.cert, verify=self.verify)
result = Reply(resp.status_code, resp.headers, resp.content)
return result
def soap_login(options):
run_delay(options)
if "--ssl" in options or "--ssl-secure" in options or "--ssl-insecure" in options:
if "--ssl-insecure" in options:
import ssl
from requests.packages.urllib3.exceptions import InsecureRequestWarning
if hasattr(ssl, '_create_unverified_context'):
ssl._create_default_https_context = ssl._create_unverified_context
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
verify = False
else:
verify = True
url = "https://"
else:
verify = False
url = "http://"
url += options["--ip"] + ":" + str(options["--ipport"]) + "/sdk"
tmp_dir = tempfile.mkdtemp()
tempfile.tempdir = tmp_dir
atexit.register(remove_tmp_dir, tmp_dir)
try:
headers = {"Content-Type" : "text/xml;charset=UTF-8", "SOAPAction" : ""}
conn = Client(url + "/vimService.wsdl", location=url, transport=RequestsTransport(verify=verify), headers=headers)
mo_ServiceInstance = Property('ServiceInstance')
mo_ServiceInstance._type = 'ServiceInstance'
ServiceContent = conn.service.RetrieveServiceContent(mo_ServiceInstance)
mo_SessionManager = Property(ServiceContent.sessionManager.value)
mo_SessionManager._type = 'SessionManager'
conn.service.Login(mo_SessionManager, options["--username"], options["--password"])
except requests.exceptions.SSLError as ex:
fail_usage("Server side certificate verification failed")
except Exception:
fail(EC_LOGIN_DENIED)
options["ServiceContent"] = ServiceContent
options["mo_SessionManager"] = mo_SessionManager
return conn
def process_results(results, machines, uuid, mappingToUUID):
for m in results.objects:
info = {}
for i in m.propSet:
info[i.name] = i.val
# Prevent error KeyError: 'config.uuid' when reaching systems which P2V failed,
# since these systems don't have a valid UUID
if "config.uuid" in info:
machines[info["name"]] = (info["config.uuid"], info["summary.runtime.powerState"])
uuid[info["config.uuid"]] = info["summary.runtime.powerState"]
mappingToUUID[m.obj.value] = info["config.uuid"]
return (machines, uuid, mappingToUUID)
def get_power_status(conn, options):
mo_ViewManager = Property(options["ServiceContent"].viewManager.value)
mo_ViewManager._type = "ViewManager"
mo_RootFolder = Property(options["ServiceContent"].rootFolder.value)
mo_RootFolder._type = "Folder"
mo_PropertyCollector = Property(options["ServiceContent"].propertyCollector.value)
mo_PropertyCollector._type = 'PropertyCollector'
ContainerView = conn.service.CreateContainerView(mo_ViewManager, recursive=1,
container=mo_RootFolder, type=['VirtualMachine'])
mo_ContainerView = Property(ContainerView.value)
mo_ContainerView._type = "ContainerView"
FolderTraversalSpec = conn.factory.create('ns0:TraversalSpec')
FolderTraversalSpec.name = "traverseEntities"
FolderTraversalSpec.path = "view"
FolderTraversalSpec.skip = False
FolderTraversalSpec.type = "ContainerView"
objSpec = conn.factory.create('ns0:ObjectSpec')
objSpec.obj = mo_ContainerView
objSpec.selectSet = [FolderTraversalSpec]
objSpec.skip = True
propSpec = conn.factory.create('ns0:PropertySpec')
propSpec.all = False
propSpec.pathSet = ["name", "summary.runtime.powerState", "config.uuid"]
propSpec.type = "VirtualMachine"
propFilterSpec = conn.factory.create('ns0:PropertyFilterSpec')
propFilterSpec.propSet = [propSpec]
propFilterSpec.objectSet = [objSpec]
try:
raw_machines = conn.service.RetrievePropertiesEx(mo_PropertyCollector, propFilterSpec)
except Exception:
fail(EC_STATUS)
(machines, uuid, mappingToUUID) = process_results(raw_machines, {}, {}, {})
# Probably need to loop over the ContinueRetreive if there are more results after 1 iteration.
while hasattr(raw_machines, 'token'):
try:
raw_machines = conn.service.ContinueRetrievePropertiesEx(mo_PropertyCollector, raw_machines.token)
except Exception:
fail(EC_STATUS)
(more_machines, more_uuid, more_mappingToUUID) = process_results(raw_machines, {}, {}, {})
machines.update(more_machines)
uuid.update(more_uuid)
mappingToUUID.update(more_mappingToUUID)
# Do not run unnecessary SOAP requests
if "--uuid" in options and options["--uuid"] in uuid:
break
if ["list", "monitor"].count(options["--action"]) == 1:
return machines
else:
if "--uuid" not in options:
if options["--plug"].startswith('/'):
## Transform InventoryPath to UUID
mo_SearchIndex = Property(options["ServiceContent"].searchIndex.value)
mo_SearchIndex._type = "SearchIndex"
vm = conn.service.FindByInventoryPath(mo_SearchIndex, options["--plug"])
try:
options["--uuid"] = mappingToUUID[vm.value]
except KeyError:
fail(EC_STATUS)
except AttributeError:
fail(EC_STATUS)
else:
## Name of virtual machine instead of path
## warning: if you have same names of machines this won't work correctly
try:
(options["--uuid"], _) = machines[options["--plug"]]
except KeyError:
fail(EC_STATUS)
except AttributeError:
fail(EC_STATUS)
try:
if uuid[options["--uuid"]] == "poweredOn":
return "on"
else:
return "off"
except KeyError:
fail(EC_STATUS)
def set_power_status(conn, options):
mo_SearchIndex = Property(options["ServiceContent"].searchIndex.value)
mo_SearchIndex._type = "SearchIndex"
vm = conn.service.FindByUuid(mo_SearchIndex, vmSearch=1, uuid=options["--uuid"])
mo_machine = Property(vm.value)
mo_machine._type = "VirtualMachine"
try:
if options["--action"] == "on":
conn.service.PowerOnVM_Task(mo_machine)
else:
conn.service.PowerOffVM_Task(mo_machine)
except suds.WebFault as ex:
if (str(ex).find("Permission to perform this operation was denied")) >= 0:
fail(EC_INVALID_PRIVILEGES)
else:
if options["--action"] == "on":
fail(EC_WAITING_ON)
else:
fail(EC_WAITING_OFF)
def remove_tmp_dir(tmp_dir):
shutil.rmtree(tmp_dir)
def logout():
try:
conn_global.service.Logout(options_global["mo_SessionManager"])
except Exception:
pass
def main():
global options_global
global conn_global
device_opt = ["ipaddr", "login", "passwd", "web", "ssl", "notls", "port"]
atexit.register(atexit_handler)
atexit.register(logout)
options_global = check_input(device_opt, process_input(device_opt))
##
## Fence agent specific defaults
#####
docs = {}
docs["shortdesc"] = "Fence agent for VMWare over SOAP API"
docs["longdesc"] = "fence_vmware_soap is an I/O Fencing agent \
which can be used with the virtual machines managed by VMWare products \
that have SOAP API v4.1+. \
\n.P\n\
Name of virtual machine (-n / port) has to be used in inventory path \
format (e.g. /datacenter/vm/Discovered virtual machine/myMachine). \
In the cases when name of yours VM is unique you can use it instead. \
Alternatively you can always use UUID to access virtual machine."
docs["vendorurl"] = "http://www.vmware.com"
show_docs(options_global, docs)
logging.basicConfig(level=logging.INFO)
logging.getLogger('suds.client').setLevel(logging.CRITICAL)
logging.getLogger("requests").setLevel(logging.CRITICAL)
logging.getLogger("urllib3").setLevel(logging.CRITICAL)
##
## Operate the fencing device
####
conn_global = soap_login(options_global)
result = fence_action(conn_global, options_global, set_power_status, get_power_status, get_power_status)
## Logout from system is done automatically via atexit()
sys.exit(result)
if __name__ == "__main__":
main()
diff --git a/fence/agents/wti/fence_wti.py b/fence/agents/wti/fence_wti.py
index a7b2f0de..68640ae6 100644
--- a/fence/agents/wti/fence_wti.py
+++ b/fence/agents/wti/fence_wti.py
@@ -1,245 +1,239 @@
#!@PYTHON@ -tt
#####
##
## The Following Agent Has Been Tested On:
##
## Version Firmware
## +-----------------+---------------------------+
## WTI RSM-8R4 ?? unable to find out ??
## WTI MPC-??? ?? unable to find out ??
## WTI IPS-800-CE v1.40h (no username) ('list' tested)
#####
import sys, re, pexpect
import atexit
import time
sys.path.append("@FENCEAGENTSLIBDIR@")
from fencing import *
from fencing import fspawn, fail, fail_usage, EC_LOGIN_DENIED
-#BEGIN_VERSION_GENERATION
-RELEASE_VERSION="New WTI Agent - test release on steroids"
-REDHAT_COPYRIGHT=""
-BUILD_DATE="March, 2008"
-#END_VERSION_GENERATION
-
def get_listing(conn, options, listing_command):
listing = ""
conn.send_eol(listing_command)
if isinstance(options["--command-prompt"], list):
re_all = list(options["--command-prompt"])
else:
re_all = [options["--command-prompt"]]
re_next = re.compile("Enter: ", re.IGNORECASE)
re_all.append(re_next)
result = conn.log_expect(re_all, int(options["--shell-timeout"]))
listing = conn.before
if result == (len(re_all) - 1):
conn.send_eol("")
conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"]))
listing += conn.before
return listing
def get_plug_status(conn, options):
listing = get_listing(conn, options, "/S")
plug_section = 0
plug_index = -1
name_index = -1
status_index = -1
plug_header = list()
outlets = {}
for line in listing.splitlines():
if (plug_section == 2) and line.find("|") >= 0 and line.startswith("PLUG") == False:
plug_line = [x.strip().lower() for x in line.split("|")]
if len(plug_line) < len(plug_header):
plug_section = -1
if ["list", "monitor"].count(options["--action"]) == 0 and \
options["--plug"].lower() == plug_line[plug_index]:
return plug_line[status_index]
else:
## We already believe that first column contains plug number
if len(plug_line[0]) != 0:
outlets[plug_line[0]] = (plug_line[name_index], plug_line[status_index])
elif plug_section == 1:
plug_section = 2
elif line.upper().startswith("PLUG"):
plug_section = 1
plug_header = [x.strip().lower() for x in line.split("|")]
plug_index = plug_header.index("plug")
name_index = plug_header.index("name")
status_index = plug_header.index("status")
if ["list", "monitor"].count(options["--action"]) == 1:
return outlets
else:
return "PROBLEM"
def get_plug_group_status_from_list(status_list):
for status in status_list:
if status == "on":
return status
return "off"
def get_plug_group_status(conn, options):
listing = get_listing(conn, options, "/SG")
outlets = {}
line_index = 0
status_index = -1
plug_index = -1
name_index = -1
lines = listing.splitlines()
while line_index < len(lines) and line_index >= 0:
line = lines[line_index]
if line.find("|") >= 0 and line.lstrip().startswith("GROUP NAME") == False:
plug_line = [x.strip().lower() for x in line.split("|")]
if ["list", "monitor"].count(options["--action"]) == 0 and \
options["--plug"].lower() == plug_line[name_index]:
plug_status = []
while line_index < len(lines) and line_index >= 0:
plug_line = [x.strip().lower() for x in lines[line_index].split("|")]
if len(plug_line) >= max(name_index, status_index) and \
len(plug_line[plug_index]) > 0 and \
(len(plug_line[name_index]) == 0 or options["--plug"].lower() == plug_line[name_index]):
## Firmware 1.43 does not have a valid value of plug on first line as only name is defined on that line
if not "---" in plug_line[status_index]:
plug_status.append(plug_line[status_index])
line_index += 1
else:
line_index = -1
return get_plug_group_status_from_list(plug_status)
else:
## We already believe that first column contains plug number
if len(plug_line[0]) != 0:
group_name = plug_line[0]
plug_line_index = line_index + 1
plug_status = []
while plug_line_index < len(lines) and plug_line_index >= 0:
plug_line = [x.strip().lower() for x in lines[plug_line_index].split("|")]
if len(plug_line[name_index]) > 0:
plug_line_index = -1
break
if len(plug_line[plug_index]) > 0:
plug_status.append(plug_line[status_index])
plug_line_index += 1
else:
plug_line_index = -1
outlets[group_name] = (group_name, get_plug_group_status_from_list(plug_status))
line_index += 1
elif line.upper().lstrip().startswith("GROUP NAME"):
plug_header = [x.strip().lower() for x in line.split("|")]
name_index = plug_header.index("group name")
plug_index = plug_header.index("plug")
status_index = plug_header.index("status")
line_index += 2
else:
line_index += 1
if ["list", "monitor"].count(options["--action"]) == 1:
results = {}
for group, status in list(outlets.items()):
results[group] = (group, status[0])
return results
else:
return "PROBLEM"
def get_power_status(conn, options):
if ["list"].count(options["--action"]) == 0:
ret = get_plug_status(conn, options)
if ret == "PROBLEM":
ret = get_plug_group_status(conn, options)
else:
ret = dict(list(get_plug_status(conn, options).items()) + \
list(get_plug_group_status(conn, options).items()))
return ret
def set_power_status(conn, options):
action = {
'on' : "/on",
'off': "/off"
}[options["--action"]]
conn.send_eol(action + " " + options["--plug"] + ",y")
conn.log_expect(options["--command-prompt"], int(options["--power-timeout"]))
def main():
device_opt = ["ipaddr", "login", "passwd", "no_login", "no_password", \
"cmd_prompt", "secure", "port", "telnet"]
atexit.register(atexit_handler)
all_opt["cmd_prompt"]["default"] = ["RSM>", "MPC>", "IPS>", "TPS>", "NBB>", "NPS>", "VMR>"]
options = check_input(device_opt, process_input(device_opt))
docs = {}
docs["shortdesc"] = "Fence agent for WTI"
docs["longdesc"] = "fence_wti is an I/O Fencing agent \
which can be used with the WTI Network Power Switch (NPS). It logs \
into an NPS via telnet or ssh and boots a specified plug. \
Lengthy telnet connections to the NPS should be avoided while a GFS cluster \
is running because the connection will block any necessary fencing actions."
docs["vendorurl"] = "http://www.wti.com"
show_docs(options, docs)
##
## Operate the fencing device
##
## @note: if it possible that this device does not need either login, password or both of them
#####
if "--ssh" not in options:
try:
if options["--action"] in ["off", "reboot"]:
time.sleep(int(options["--delay"]))
options["eol"] = "\r\n"
conn = fspawn(options, options["--telnet-path"])
conn.send("set binary\n")
conn.send("open %s -%s\n"%(options["--ip"], options["--ipport"]))
re_login = re.compile("(login: )|(Login Name: )|(username: )|(User Name :)", re.IGNORECASE)
re_prompt = re.compile("|".join(["(" + x + ")" for x in options["--command-prompt"]]), re.IGNORECASE)
result = conn.log_expect([re_login, "Password: ", re_prompt], int(options["--shell-timeout"]))
if result == 0:
if "--username" in options:
conn.send_eol(options["--username"])
result = conn.log_expect([re_login, "Password: ", re_prompt], int(options["--shell-timeout"]))
else:
fail_usage("Failed: You have to set login name")
if result == 1:
if "--password" in options:
conn.send_eol(options["--password"])
conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"]))
else:
fail_usage("Failed: You have to enter password or password script")
except pexpect.EOF:
fail(EC_LOGIN_DENIED)
except pexpect.TIMEOUT:
fail(EC_LOGIN_DENIED)
else:
conn = fence_login(options)
result = fence_action(conn, options, set_power_status, get_power_status, get_power_status)
fence_logout(conn, "/X")
sys.exit(result)
if __name__ == "__main__":
main()
diff --git a/fence/agents/xenapi/fence_xenapi.py b/fence/agents/xenapi/fence_xenapi.py
index ccddf2d9..7b91683e 100644
--- a/fence/agents/xenapi/fence_xenapi.py
+++ b/fence/agents/xenapi/fence_xenapi.py
@@ -1,227 +1,221 @@
#!@PYTHON@ -tt
#
#############################################################################
# Copyright 2011 Matthew Clark
# This file is part of fence-xenserver
#
# fence-xenserver is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
#
# fence-xenserver is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# Please let me know if you are using this script so that I can work out
# whether I should continue support for it. mattjclark0407 at hotmail dot com
#############################################################################
#############################################################################
# It's only just begun...
# Current status: completely usable. This script is now working well and,
# has a lot of functionality as a result of the fencing.py library and the
# XenAPI libary.
#############################################################################
# Please let me know if you are using this script so that I can work out
# whether I should continue support for it. mattjclark0407 at hotmail dot com
import sys
import atexit
sys.path.append("@FENCEAGENTSLIBDIR@")
from fencing import *
from fencing import run_delay
import XenAPI
-#BEGIN_VERSION_GENERATION
-RELEASE_VERSION=""
-REDHAT_COPYRIGHT=""
-BUILD_DATE=""
-#END_VERSION_GENERATION
-
EC_BAD_SESSION = 1
# Find the status of the port given in the -U flag of options.
def get_power_fn(session, options):
if "--verbose" in options:
verbose = True
else:
verbose = False
try:
# Get a reference to the vm specified in the UUID or vm_name/port parameter
vm = return_vm_reference(session, options)
# Query the VM for its' associated parameters
record = session.xenapi.VM.get_record(vm)
# Check that we are not trying to manipulate a template or a control
# domain as they show up as VM's with specific properties.
if not record["is_a_template"] and not record["is_control_domain"]:
status = record["power_state"]
if verbose:
print("UUID:", record["uuid"], "NAME:", record["name_label"], "POWER STATUS:", record["power_state"])
# Note that the VM can be in the following states (from the XenAPI document)
# Halted: VM is offline and not using any resources.
# Paused: All resources have been allocated but the VM itself is paused and its vCPUs are not running
# Running: Running
# Paused: VM state has been saved to disk and it is nolonger running. Note that disks remain in-Use while
# We want to make sure that we only return the status "off" if the machine is actually halted as the status
# is checked before a fencing action. Only when the machine is Halted is it not consuming resources which
# may include whatever you are trying to protect with this fencing action.
return status == "Halted" and "off" or "on"
except Exception as exn:
print(str(exn))
return "Error"
# Set the state of the port given in the -U flag of options.
def set_power_fn(session, options):
try:
# Get a reference to the vm specified in the UUID or vm_name/port parameter
vm = return_vm_reference(session, options)
# Query the VM for its' associated parameters
record = session.xenapi.VM.get_record(vm)
# Check that we are not trying to manipulate a template or a control
# domain as they show up as VM's with specific properties.
if not record["is_a_template"] and not record["is_control_domain"]:
if options["--action"] == "on":
# Start the VM
session.xenapi.VM.start(vm, False, True)
elif options["--action"] == "off":
# Force shutdown the VM
session.xenapi.VM.hard_shutdown(vm)
elif options["--action"] == "reboot":
# Force reboot the VM
session.xenapi.VM.hard_reboot(vm)
except Exception as exn:
print(str(exn))
# Function to populate an array of virtual machines and their status
def get_outlet_list(session, options):
result = {}
if "--verbose" in options:
verbose = True
else:
verbose = False
try:
# Return an array of all the VM's on the host
vms = session.xenapi.VM.get_all()
for vm in vms:
# Query the VM for its' associated parameters
record = session.xenapi.VM.get_record(vm)
# Check that we are not trying to manipulate a template or a control
# domain as they show up as VM's with specific properties.
if not record["is_a_template"] and not record["is_control_domain"]:
name = record["name_label"]
uuid = record["uuid"]
status = record["power_state"]
result[uuid] = (name, status)
if verbose:
print("UUID:", record["uuid"], "NAME:", name, "POWER STATUS:", record["power_state"])
except Exception as exn:
print(str(exn))
return result
# Function to initiate the XenServer session via the XenAPI library.
def connect_and_login(options):
url = options["--session-url"]
username = options["--username"]
password = options["--password"]
try:
# Create the XML RPC session to the specified URL.
session = XenAPI.Session(url)
# Login using the supplied credentials.
session.xenapi.login_with_password(username, password)
except Exception as exn:
print(str(exn))
# http://sources.redhat.com/cluster/wiki/FenceAgentAPI says that for no connectivity
# the exit value should be 1. It doesn't say anything about failed logins, so
# until I hear otherwise it is best to keep this exit the same to make sure that
# anything calling this script (that uses the same information in the web page
# above) knows that this is an error condition, not a msg signifying a down port.
sys.exit(EC_BAD_SESSION)
return session
# return a reference to the VM by either using the UUID or the vm_name/port. If the UUID is set then
# this is tried first as this is the only properly unique identifier.
# Exceptions are not handled in this function, code that calls this must be ready to handle them.
def return_vm_reference(session, options):
if "--verbose" in options:
verbose = True
else:
verbose = False
# Case where the UUID has been specified
if "--uuid" in options:
uuid = options["--uuid"].lower()
# When using the -n parameter for name, we get an error message (in verbose
# mode) that tells us that we didn't find a VM. To immitate that here we
# need to catch and re-raise the exception produced by get_by_uuid.
try:
return session.xenapi.VM.get_by_uuid(uuid)
except Exception:
if verbose:
print("No VM's found with a UUID of \"%s\"" % uuid)
raise
# Case where the vm_name/port has been specified
if "--plug" in options:
vm_name = options["--plug"]
vm_arr = session.xenapi.VM.get_by_name_label(vm_name)
# Need to make sure that we only have one result as the vm_name may
# not be unique. Average case, so do it first.
if len(vm_arr) == 1:
return vm_arr[0]
else:
if len(vm_arr) == 0:
if verbose:
print("No VM's found with a name of \"%s\"" % vm_name)
# NAME_INVALID used as the XenAPI throws a UUID_INVALID if it can't find
# a VM with the specified UUID. This should make the output look fairly
# consistent.
raise Exception("NAME_INVALID")
else:
if verbose:
print("Multiple VM's have the name \"%s\", use UUID instead" % vm_name)
raise Exception("MULTIPLE_VMS_FOUND")
# We should never get to this case as the input processing checks that either the UUID or
# the name parameter is set. Regardless of whether or not a VM is found the above if
# statements will return to the calling function (either by exception or by a reference
# to the VM).
raise Exception("VM_LOGIC_ERROR")
def main():
device_opt = ["login", "passwd", "port", "no_login", "no_password", "session_url", "web"]
atexit.register(atexit_handler)
options = check_input(device_opt, process_input(device_opt))
docs = {}
docs["shortdesc"] = "Fence agent for Citrix XenServer over XenAPI"
docs["longdesc"] = "\
fence_cxs is an I/O Fencing agent used on Citrix XenServer hosts. \
It uses the XenAPI, supplied by Citrix, to establish an XML-RPC sesssion \
to a XenServer host. Once the session is established, further XML-RPC \
commands are issued in order to switch on, switch off, restart and query \
the status of virtual machines running on the host."
docs["vendorurl"] = "http://www.xenproject.org"
show_docs(options, docs)
run_delay(options)
xen_session = connect_and_login(options)
result = fence_action(xen_session, options, set_power_fn, get_power_fn, get_outlet_list)
sys.exit(result)
if __name__ == "__main__":
main()
diff --git a/fence/agents/zvm/fence_zvmip.py b/fence/agents/zvm/fence_zvmip.py
index e5f8940a..34b8a8f9 100644
--- a/fence/agents/zvm/fence_zvmip.py
+++ b/fence/agents/zvm/fence_zvmip.py
@@ -1,195 +1,189 @@
#!@PYTHON@ -tt
import sys
import atexit
import socket
import struct
import logging
sys.path.append("@FENCEAGENTSLIBDIR@")
from fencing import *
from fencing import fail, fail_usage, run_delay, EC_LOGIN_DENIED, EC_TIMED_OUT
-#BEGIN_VERSION_GENERATION
-RELEASE_VERSION=""
-REDHAT_COPYRIGHT=""
-BUILD_DATE=""
-#END_VERSION_GENERATION
-
INT4 = 4
def open_socket(options):
try:
if "--inet6-only" in options:
protocol = socket.AF_INET6
elif "--inet4-only" in options:
protocol = socket.AF_INET
else:
protocol = 0
(_, _, _, _, addr) = socket.getaddrinfo( \
options["--ip"], options["--ipport"], protocol,
0, socket.IPPROTO_TCP, socket.AI_PASSIVE
)[0]
except socket.gaierror:
fail(EC_LOGIN_DENIED)
conn = socket.socket()
conn.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
conn.settimeout(float(options["--shell-timeout"]))
try:
conn.connect(addr)
except socket.error:
fail(EC_LOGIN_DENIED)
return conn
def smapi_pack_string(string):
return struct.pack("!i%ds" % (len(string)), len(string), string)
def prepare_smapi_command(options, smapi_function, additional_args):
packet_size = 3*INT4 + len(smapi_function) + len(options["--username"]) + len(options["--password"])
for arg in additional_args:
packet_size += INT4 + len(arg)
command = struct.pack("!i", packet_size)
command += smapi_pack_string(smapi_function)
command += smapi_pack_string(options["--username"])
command += smapi_pack_string(options["--password"])
for arg in additional_args:
command += smapi_pack_string(arg)
return command
def get_power_status(conn, options):
del conn
if options.get("--original-action", None) == "monitor":
(return_code, reason_code, images_active) = \
get_list_of_images(options, "Check_Authentication", None)
logging.debug("Check_Authenticate (%d,%d)", return_code, reason_code)
if return_code == 0:
return {}
else:
fail(EC_LOGIN_DENIED)
if options["--action"] == "list":
# '*' = list all active images
options["--plug"] = "*"
(return_code, reason_code, images_active) = \
get_list_of_images(options, "Image_Status_Query", options["--plug"])
logging.debug("Image_Status_Query results are (%d,%d)", return_code, reason_code)
if not options["--action"] == "list":
if (return_code == 0) and (reason_code == 0):
return "on"
elif (return_code == 0) and (reason_code == 12):
# We are running always with --missing-as-off because we can not check if image
# is defined or not (look at rhbz#1188750)
return "off"
else:
return "unknown"
else:
(return_code, reason_code, images_defined) = \
get_list_of_images(options, "Image_Name_Query_DM", options["--username"])
logging.debug("Image_Name_Query_DM results are (%d,%d)", return_code, reason_code)
return dict([(i, ("", "on" if i in images_active else "off")) for i in images_defined])
def set_power_status(conn, options):
conn = open_socket(options)
packet = None
if options["--action"] == "on":
packet = prepare_smapi_command(options, "Image_Activate", [options["--plug"]])
elif options["--action"] == "off":
packet = prepare_smapi_command(options, "Image_Deactivate", [options["--plug"], "IMMED"])
conn.send(packet)
request_id = struct.unpack("!i", conn.recv(INT4))[0]
(output_len, request_id, return_code, reason_code) = struct.unpack("!iiii", conn.recv(INT4 * 4))
logging.debug("Image_(De)Activate results are (%d,%d)", return_code, reason_code)
conn.close()
return
def get_list_of_images(options, command, data_as_plug):
conn = open_socket(options)
if data_as_plug is None:
packet = prepare_smapi_command(options, command, [])
else:
packet = prepare_smapi_command(options, command, [data_as_plug])
conn.send(packet)
request_id = struct.unpack("!i", conn.recv(INT4))[0]
(output_len, request_id, return_code, reason_code) = struct.unpack("!iiii", conn.recv(INT4 * 4))
images = set()
if output_len > 3*INT4:
array_len = struct.unpack("!i", conn.recv(INT4))[0]
data = ""
while True:
read_data = conn.recv(1024, socket.MSG_WAITALL)
data += read_data
if array_len == len(data):
break
elif not read_data:
logging.error("Failed: Not enough data read from socket")
fail(EC_TIMED_OUT)
parsed_len = 0
while parsed_len < array_len:
string_len = struct.unpack("!i", data[parsed_len:parsed_len+INT4])[0]
parsed_len += INT4
image_name = struct.unpack("!%ds" % (string_len), data[parsed_len:parsed_len+string_len])[0]
parsed_len += string_len
images.add(image_name)
conn.close()
return (return_code, reason_code, images)
def main():
device_opt = ["ipaddr", "login", "passwd", "port", "method", "missing_as_off"]
atexit.register(atexit_handler)
all_opt["ipport"]["default"] = "44444"
all_opt["shell_timeout"]["default"] = "5"
all_opt["missing_as_off"]["default"] = "1"
options = check_input(device_opt, process_input(device_opt), other_conditions=True)
if len(options.get("--plug", "")) > 8:
fail_usage("Failed: Name of image can not be longer than 8 characters")
if options["--action"] == "validate-all":
sys.exit(0)
docs = {}
docs["shortdesc"] = "Fence agent for use with z/VM Virtual Machines"
docs["longdesc"] = """The fence_zvm agent is intended to be used with with z/VM SMAPI service via TCP/IP
To use this agent the z/VM SMAPI service needs to be configured to allow the virtual machine running this agent to connect to it and issue
the image_recycle operation. This involves updating the VSMWORK1 AUTHLIST VMSYS:VSMWORK1. file. The entry should look something similar to
this:
Column 1 Column 66 Column 131
| | |
V V V
XXXXXXXX ALL IMAGE_OPERATIONS
Where XXXXXXX is the name of the virtual machine used in the authuser field of the request.
"""
docs["vendorurl"] = "http://www.ibm.com"
show_docs(options, docs)
run_delay(options)
result = fence_action(None, options, set_power_status, get_power_status, get_power_status)
sys.exit(result)
if __name__ == "__main__":
main()
diff --git a/make/copyright.cf b/make/copyright.cf
deleted file mode 100644
index 3801aa98..00000000
--- a/make/copyright.cf
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __COPYRIGHT_DOT_CF__
-#define __COPYRIGHT_DOT_CF__
-
-#define REDHAT_COPYRIGHT "Copyright (C) Red Hat, Inc. 2004-2010 All rights reserved."
-
-#endif /* __COPYRIGHT_DOT_CF__ */
diff --git a/make/fencebuild.mk b/make/fencebuild.mk
index a8d205e5..0a1f2bc9 100644
--- a/make/fencebuild.mk
+++ b/make/fencebuild.mk
@@ -1,84 +1,82 @@
define gen_agent_from_py
mkdir -p `dirname $@`
- bash $(top_srcdir)/scripts/fenceparse \
- $(top_srcdir)/make/copyright.cf REDHAT_COPYRIGHT \
- $(VERSION) \
- $(abs_srcdir) $@ | \
+ cat $(abs_srcdir)/$@.py | \
sed \
-e 's#@''PYTHON@#${PYTHON}#g' \
+ -e 's#@''RELEASE_VERSION#${VERSION}#g' \
-e 's#@''FENCEAGENTSLIBDIR@#${FENCEAGENTSLIBDIR}#g' \
-e 's#@''LOGDIR@#${LOGDIR}#g' \
-e 's#@''SBINDIR@#${sbindir}#g' \
-e 's#@''LIBEXECDIR@#${libexecdir}#g' \
-e 's#@''IPMITOOL_PATH@#${IPMITOOL_PATH}#g' \
-e 's#@''OPENSTACK_PATH@#${OPENSTACK_PATH}#g' \
-e 's#@''AMTTOOL_PATH@#${AMTTOOL_PATH}#g' \
-e 's#@''GNUTLSCLI_PATH@#${GNUTLSCLI_PATH}#g' \
-e 's#@''COROSYNC_CMAPCTL_PATH@#${COROSYNC_CMAPCTL_PATH}#g' \
-e 's#@''SG_PERSIST_PATH@#${SG_PERSIST_PATH}#g' \
-e 's#@''SG_TURS_PATH@#${SG_TURS_PATH}#g' \
-e 's#@''VGS_PATH@#${VGS_PATH}#g' \
-e 's#@''SUDO_PATH@#${SUDO_PATH}#g' \
-e 's#@''SSH_PATH@#${SSH_PATH}#g' \
-e 's#@''TELNET_PATH@#${TELNET_PATH}#g' \
-e 's#@''MPATH_PATH@#${MPATH_PATH}#g' \
-e 's#@''SBD_PATH@#${SBD_PATH}#g' \
-e 's#@''STORE_PATH@#${CLUSTERVARRUN}#g' \
-e 's#@''SUDO_PATH@#${SUDO_PATH}#g' \
-e 's#@''SNMPWALK_PATH@#${SNMPWALK_PATH}#g' \
-e 's#@''SNMPSET_PATH@#${SNMPSET_PATH}#g' \
-e 's#@''SNMPGET_PATH@#${SNMPGET_PATH}#g' \
-e 's#@''NOVA_PATH@#${NOVA_PATH}#g' \
-e 's#@''POWERMAN_PATH@#${POWERMAN_PATH}#g' \
> $@
if [ 0 -eq `echo "$(@)" | grep fence_ &> /dev/null; echo $$?` ]; then \
PYTHONPATH=$(abs_srcdir)/lib:$(abs_builddir)/lib $(PYTHON) $(top_srcdir)/fence/agents/lib/check_used_options.py $@; \
else true ; fi
for x in `PYTHONPATH=$(abs_srcdir)/lib:$(abs_builddir)/lib $(PYTHON) $(@) -o metadata | grep symlink | sed -e "s/.*\(fence.*\)\" .*/\1/g"`; do \
cp -f $(@) $(@D)/$$x; \
$(MAKE) $(@D)/$$x.8; \
done
endef
# dependency, one on one
$(foreach t,$(TARGET),$(eval $(t) : $(t:=.py)))
# rule
$(TARGET):
$(call gen_agent_from_py)
clean: clean-man
rm -f $(CLEAN_TARGET:%.8=%) $(CLEAN_TARGET_ADDITIONAL) $(scsidata_SCRIPTS) */*.pyc */*.wiki
if [ "$(abs_builddir)" = "$(abs_top_builddir)/fence/agents/lib" ]; then \
rm -f $(TARGET); \
fi
clean-local: clean
install-exec-hook: $(TARGET)
if [ -n "$(man8dir)" ]; then \
echo " $(MKDIR_P) '$(DESTDIR)$(man8dir)'"; \
$(MKDIR_P) "$(DESTDIR)$(man8dir)" || exit 1; \
fi
for p in $(TARGET); do \
dir=`dirname $$p`; \
for x in `PYTHONPATH=$(abs_srcdir)/lib:$(abs_builddir)/lib $(PYTHON) $$p -o metadata | grep symlink | sed -e "s/.*\(fence.*\)\" .*/\1/g"`; do \
echo " $(INSTALL_SCRIPT) $$dir/$$x '$(DESTDIR)$(sbindir)'"; \
$(INSTALL_SCRIPT) $$dir/$$x "$(DESTDIR)$(sbindir)" || exit $$?; \
echo " $(INSTALL_DATA) '$$dir/$$x.8' '$(DESTDIR)$(man8dir)'"; \
$(INSTALL_DATA) "$$dir/$$x.8" "$(DESTDIR)$(man8dir)" || exit $$?; \
done; \
done
uninstall-hook: $(TARGET)
files=`for p in $(TARGET); do \
for x in \`PYTHONPATH=$(abs_srcdir)/lib:$(abs_builddir)/lib $(PYTHON) $$p -o metadata | grep symlink | sed -e "s/.*\(fence.*\)\" .*/\1/g"\`; do \
echo " rm -f '$(DESTDIR)$(sbindir)/$$x'"; \
rm -f "$(DESTDIR)$(sbindir)/$$x"; \
echo " rm -f '$(DESTDIR)$(man8dir)/$$x.8'"; \
rm -f "$(DESTDIR)$(man8dir)/$$x.8"; \
done; \
done`
diff --git a/scripts/fenceparse b/scripts/fenceparse
deleted file mode 100644
index b6ed431f..00000000
--- a/scripts/fenceparse
+++ /dev/null
@@ -1,42 +0,0 @@
-#!/bin/bash
-
-set -e
-
-export LC_ALL=C
-
-definefile="$1"
-define="$2"
-release="$3"
-srcdir="$4"
-infile="$5"
-
-definedata="$(cat $definefile | grep "^\#define $define" | sed -e 's/.*'$define' //')"
-
-realinfile="$(ls $srcdir/$infile.*{py,pl,sh} 2>/dev/null || true)"
-
-[ -z "$realinfile" ] && exit 1
-
-interpreter="$(cat $realinfile | head -n 1 | awk -F "/" '{print $NF}')"
-interpreter="$(echo $interpreter)"
-
-case "$interpreter" in
- perl)
- start="\$"
- end=";"
- ;;
- *)
- start=""
- end=""
- ;;
-esac
-
-awk "{print}(\$1 ~ /#BEGIN_VERSION_GENERATION/){exit 0}" $realinfile
-echo ${start}RELEASE_VERSION=\"${release}\"${end}
-echo ${start}BUILD_DATE=\"\(built $(date)\)\"${end}
-if awk -v p=0 "(\$1 ~ /#BEGIN_VERSION_GENERATION/){p = 1} (\$1 ~ /#END_VERSION_GENERATION/){p = 0} {if(p==1)print}" $realinfile | \
- grep -q REDHAT_COPYRIGHT; then
- echo ${start}REDHAT_COPYRIGHT=${definedata}${end}
-fi
-awk -v p=0 "(\$1 ~ /#END_VERSION_GENERATION/){p = 1} {if(p==1)print}" $realinfile
-
-exit 0

File Metadata

Mime Type
text/x-diff
Expires
Sat, Oct 25, 2:03 AM (1 d, 16 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2619938
Default Alt Text
(335 KB)

Event Timeline