Page MenuHomeClusterLabs Projects

No OneTemporary

diff --git a/fence/agents/amt/fence_amt.py b/fence/agents/amt/fence_amt.py
index b4618312..0eb6caf8 100644
--- a/fence/agents/amt/fence_amt.py
+++ b/fence/agents/amt/fence_amt.py
@@ -1,156 +1,156 @@
#!/usr/bin/python -tt
import sys, subprocess, re
import logging
import atexit
from pipes import quote
sys.path.append("@FENCEAGENTSLIBDIR@")
from fencing import *
from fencing import fail_usage, is_executable, SUDO_PATH, LOG_MODE_VERBOSE
#BEGIN_VERSION_GENERATION
RELEASE_VERSION="Fence agent for Intel AMT"
REDHAT_COPYRIGHT=""
BUILD_DATE=""
#END_VERSION_GENERATION
def get_power_status(_, options):
cmd = create_command(options, "status")
try:
logging.debug("Running: %s" % cmd)
process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
except OSError:
fail_usage("Amttool not found or not accessible")
process.wait()
out = process.communicate()
process.stdout.close()
process.stderr.close()
logging.debug("%s\n" % str(out))
- match = re.search('Powerstate:[\\s]*(..)', str(output))
+ match = re.search('Powerstate:[\\s]*(..)', str(out))
status = match.group(1) if match else None
if (status == None):
return "fail"
elif (status == "S0"): # SO = on; S3 = sleep; S5 = off
return "on"
else:
return "off"
def set_power_status(_, options):
cmd = create_command(options, options["--action"])
try:
logging.debug("Running: %s" % cmd)
process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
except OSError:
fail_usage("Amttool not found or not accessible")
process.wait()
out = process.communicate()
process.stdout.close()
process.stderr.close()
logging.debug("%s\n" % str(out))
return
def reboot_cycle(_, options):
cmd = create_command(options, "cycle")
try:
logging.debug("Running: %s" % cmd)
process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
except OSError:
fail_usage("Amttool not found or not accessible")
status = process.wait()
out = process.communicate()
process.stdout.close()
process.stderr.close()
logging.debug("%s\n" % str(out))
return not bool(status)
def create_command(options, action):
# --password / -p
cmd = "AMT_PASSWORD=" + quote(options["--password"])
cmd += " " + options["--amttool-path"]
# --ip / -a
cmd += " " + options["--ip"]
# --action / -o
if action == "status":
cmd += " info"
elif action == "on":
cmd = "echo \"y\"|" + cmd
cmd += " powerup"
elif action == "off":
cmd = "echo \"y\"|" + cmd
cmd += " powerdown"
elif action == "cycle":
cmd = "echo \"y\"|" + cmd
cmd += " powercycle"
if action in ["on", "off", "cycle"] and options.has_key("--boot-option"):
cmd += options["--boot-option"]
# --use-sudo / -d
if options.has_key("--use-sudo"):
cmd = SUDO_PATH + " " + cmd
return cmd
def define_new_opts():
all_opt["boot_option"] = {
"getopt" : "b:",
"longopt" : "boot-option",
"help" : "-b, --boot-option=[option] "
"Change the default boot behavior of the machine. (pxe|hd|hdsafe|cd|diag)",
"required" : "0",
"shortdesc" : "Change the default boot behavior of the machine.",
"choices" : ["pxe", "hd", "hdsafe", "cd", "diag"],
"order" : 1
}
all_opt["amttool_path"] = {
"getopt" : "i:",
"longopt" : "amttool-path",
"help" : "--amttool-path=[path] Path to amttool binary",
"required" : "0",
"shortdesc" : "Path to amttool binary",
"default" : "@AMTTOOL_PATH@",
"order": 200
}
def main():
atexit.register(atexit_handler)
device_opt = [ "ipaddr", "no_login", "passwd", "boot_option", "no_port",
"sudo", "amttool_path", "method" ]
define_new_opts()
options = check_input(device_opt, process_input(device_opt))
docs = { }
docs["shortdesc"] = "Fence agent for AMT"
docs["longdesc"] = "fence_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)
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/apc_snmp/fence_apc_snmp.py b/fence/agents/apc_snmp/fence_apc_snmp.py
index d91e9e95..18102479 100644
--- a/fence/agents/apc_snmp/fence_apc_snmp.py
+++ b/fence/agents/apc_snmp/fence_apc_snmp.py
@@ -1,208 +1,209 @@
#!/usr/bin/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
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:
# 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:
# 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:
# 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:
# 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
### 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,
None:ApcMS}
# First resolve type of APC
apc_type = conn.walk(OID_SYS_OBJECT_ID)
if (not ((len(apc_type)==1) and (agents_dir.has_key(apc_type[0][1])))):
apc_type = [[None, None]]
device = agents_dir[apc_type[0][1]]
conn.log_command("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", "community" ]
atexit.register(atexit_handler)
all_opt["snmp_version"]["default"] = "1"
all_opt["community"]["default"] = "private"
options = check_input(device_opt, process_input(device_opt))
## Support for -n [switch]:[plug] notation that was used before
if ((options.has_key("--plug")) and (-1 != options["--plug"].find(":"))):
(switch, plug) = options["--plug"].split(":", 1)
if ((switch.isdigit()) and (plug.isdigit())):
options["--switch"] = switch
options["--plug"] = plug
if (not (options.has_key("--switch"))):
options["--switch"] = "1"
docs = { }
docs["shortdesc"] = "Fence agent for APC, Tripplite PDU over SNMP"
docs["longdesc"] = "fence_apc_snmp is an I/O Fencing agent \
which can be used with the APC network power switch or Tripplite PDU devices.\
It logs into a device via SNMP and reboots a specified outlet. It supports \
SNMP v1, v2c, v3 with all combinations of authenticity/privacy settings."
docs["vendorurl"] = "http://www.apc.com"
show_docs(options, docs)
# Operate the fencing device
result = fence_action(FencingSnmp(options), options, set_power_status, get_power_status, get_outlets_status)
sys.exit(result)
if __name__ == "__main__":
main()
diff --git a/fence/agents/cisco_ucs/fence_cisco_ucs.py b/fence/agents/cisco_ucs/fence_cisco_ucs.py
index 3ef7c7b3..de0f6818 100644
--- a/fence/agents/cisco_ucs/fence_cisco_ucs.py
+++ b/fence/agents/cisco_ucs/fence_cisco_ucs.py
@@ -1,165 +1,165 @@
#!/usr/bin/python -tt
import sys, re
import pycurl, StringIO
import logging
import time
import atexit
sys.path.append("@FENCEAGENTSLIBDIR@")
from fencing import *
from fencing import fail, EC_STATUS, EC_LOGIN_DENIED, LOG_MODE_VERBOSE
#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_DESC = re.compile(" descr=\"(.*?)\"", re.IGNORECASE)
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"] + "/power\"/>", int(options["--shell-timeout"]))
result = RE_STATUS.search(res)
if (result == None):
fail(EC_STATUS)
else:
status = result.group(1)
if (status == "up"):
return "on"
else:
return "off"
def set_power_status(conn, options):
del conn
action = {
'on' : "up",
'off' : "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 opt.has_key("--ssl"):
url = "https:"
else:
url = "http:"
url += "//" + opt["--ip"] + ":" + str(opt["--ipport"]) + "/nuova"
## send command through pycurl
conn = pycurl.Curl()
web_buffer = StringIO.StringIO()
conn.setopt(pycurl.URL, url)
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)
conn.setopt(pycurl.SSL_VERIFYPEER, 0)
conn.setopt(pycurl.SSL_VERIFYHOST, 0)
conn.perform()
result = web_buffer.getvalue()
logging.debug("%s\n" % command)
- logging.debug("%s\n" % results)
+ logging.debug("%s\n" % result)
return result
def define_new_opts():
all_opt["suborg"] = {
"getopt" : "s:",
"longopt" : "suborg",
"help" : "--suborg=[path] Additional path needed to access suborganization",
"required" : "0",
"shortdesc" : "Additional path needed to access suborganization",
"default" : "",
"order" : 1 }
def main():
device_opt = [ "ipaddr", "login", "passwd", "ssl", "notls", "port", "web", "suborg" ]
atexit.register(atexit_handler)
define_new_opts()
options = 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, docs)
## Do the delay of the fence device before logging in
## Delay is important for two-node clusters fencing but we do not need to delay 'status' operations
if options["--action"] in ["off", "reboot"]:
time.sleep(int(options["--delay"]))
### Login
try:
res = send_command(options, "<aaaLogin inName=\"" + options["--username"] +
"\" inPassword=\"" + options["--password"] + "\" />", int(options["--login-timeout"]))
result = RE_COOKIE.search(res)
if (result == None):
## Cookie is absenting in response
fail(EC_LOGIN_DENIED)
except:
fail(EC_LOGIN_DENIED)
options["cookie"] = result.group(1)
##
## Modify suborg to format /suborg
if options["--suborg"] != "":
options["--suborg"] = "/" + options["--suborg"].lstrip("/").rstrip("/")
##
## Fence operations
####
result = fence_action(None, options, set_power_status, get_power_status, get_list)
### Logout; we do not care about result as we will end in any case
send_command(options, "<aaaLogout inCookie=\"" + options["cookie"] + "\" />",
int(options["--shell-timeout"]))
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 9688516d..b14eef49 100644
--- a/fence/agents/eaton_snmp/fence_eaton_snmp.py
+++ b/fence/agents/eaton_snmp/fence_eaton_snmp.py
@@ -1,233 +1,234 @@
#!/usr/bin/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
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:
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:
status_oid = '.1.3.6.1.4.1.20677.2.6.3.%d.0'
control_oid = '.1.3.6.1.4.1.20677.2.6.2.%d.0'
outlet_table_oid = '.1.3.6.1.4.1.20677.2.6.3'
ident_str = "Eaton Switched ePDU"
state_off = 2
state_on = 1
state_cycling = 0 # Note: this status doesn't exist on this device
turn_off = 2
turn_on = 1
turn_cycle = 3 # FIXME: not usable with fence-agents
has_switches = False
### FUNCTIONS ###
def eaton_set_device(conn):
global device
agents_dir = {'.1.3.6.1.4.1.534.6.6.6':EatonManagedePDU,
'.1.3.6.1.4.1.20677.1':EatonSwitchedePDU,
'.1.3.6.1.4.1.20677.2':EatonSwitchedePDU }
# First resolve type of Eaton
eaton_type = conn.walk(OID_SYS_OBJECT_ID)
if (not ((len(eaton_type)==1) and (agents_dir.has_key(eaton_type[0][1])))):
eaton_type = [[None, None]]
device = agents_dir[eaton_type[0][1]]
conn.log_command("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 == True) 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:
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", "community" ]
atexit.register(atexit_handler)
all_opt["switch"]["default"] = 1
all_opt["power_wait"]["default"] = 2
all_opt["snmp_version"]["default"] = "1"
all_opt["community"]["default"] = "private"
options = check_input(device_opt, process_input(device_opt))
# Plug indexing start from zero on ePDU Managed, so we substract '1' from
# the user's given plug number.
# For Switched ePDU, we will add this back again later.
if ((options.has_key("--plug")) and (options["--plug"].isdigit())):
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/ipdu/fence_ipdu.py b/fence/agents/ipdu/fence_ipdu.py
index 83f1dd40..479e9b8d 100644
--- a/fence/agents/ipdu/fence_ipdu.py
+++ b/fence/agents/ipdu/fence_ipdu.py
@@ -1,157 +1,158 @@
#!/usr/bin/python -tt
# The Following agent has been tested on:
# IBM iPDU model 46M4002
# Firmware release OPDP_sIBM_v01.2_1
#
import sys
import atexit
sys.path.append("/usr/share/fence")
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:
# iPDU
status_oid = '.1.3.6.1.4.1.2.6.223.8.2.2.1.11.%d'
control_oid = '.1.3.6.1.4.1.2.6.223.8.2.2.1.11.%d'
outlet_table_oid = '.1.3.6.1.4.1.2.6.223.8.2.2.1.2'
ident_str = "IBM iPDU"
state_on = 1
state_off = 0
turn_on = 1
turn_off = 0
has_switches = False
### FUNCTIONS ###
def ipdu_set_device(conn, options):
global device
agents_dir = {'.1.3.6.1.4.1.2.6.223':IBMiPDU,
None:IBMiPDU}
# First resolve type of PDU device
pdu_type = conn.walk(OID_SYS_OBJECT_ID)
if (not ((len(pdu_type)==1) and (agents_dir.has_key(pdu_type[0][1])))):
pdu_type = [[None, None]]
device = agents_dir[pdu_type[0][1]]
conn.log_command("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", "community" ]
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/lib/fencing.py.py b/fence/agents/lib/fencing.py.py
index 11985d2d..73c2c4a2 100644
--- a/fence/agents/lib/fencing.py.py
+++ b/fence/agents/lib/fencing.py.py
@@ -1,1096 +1,1096 @@
#!/usr/bin/python -tt
import sys, getopt, time, os, uuid, pycurl, stat
import pexpect, re, atexit, syslog
import logging
import __main__
## do not add code here.
#BEGIN_VERSION_GENERATION
RELEASE_VERSION = "New fence lib agent - test release on steroids"
REDHAT_COPYRIGHT = ""
BUILD_DATE = "March, 2008"
#END_VERSION_GENERATION
__all__ = [ 'atexit_handler', 'check_input', 'process_input', 'all_opt', 'show_docs',
'fence_login', 'fence_action' ]
LOG_MODE_VERBOSE = 100
LOG_MODE_QUIET = 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
TELNET_PATH = "/usr/bin/telnet"
SSH_PATH = "/usr/bin/ssh"
SSL_PATH = "@GNUTLSCLI_PATH@"
SUDO_PATH = "/usr/bin/sudo"
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 Output 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",
"shortdesc" : "Verbose mode",
"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" : "f:",
"longopt" : "delay",
"help" : "--delay=[seconds] Wait X seconds before fencing is started",
"required" : "0",
"shortdesc" : "Wait X seconds before fencing is started",
"default" : "0",
"order" : 200 },
"agent" : {
"getopt" : "",
"help" : "",
"order" : 1 },
"web" : {
"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",
"shortdesc" : "IP Address or Hostname",
"order" : 1 },
"ipport" : {
"getopt" : "u:",
"longopt" : "ipport",
"help" : "-u, --ipport=[port] TCP/UDP port to use",
"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" : "?",
"shortdesc" : "Login Name",
"order" : 1 },
"no_login" : {
"getopt" : "",
"help" : "",
"order" : 1 },
"no_password" : {
"getopt" : "",
"help" : "",
"order" : 1 },
"no_port" : {
"getopt" : "",
"help" : "",
"order" : 1 },
"passwd" : {
"getopt" : "p:",
"longopt" : "password",
"help" : "-p, --password=[password] Login password or passphrase",
"required" : "0",
"shortdesc" : "Login password or passphrase",
"order" : 1 },
"passwd_script" : {
"getopt" : "S:",
"longopt" : "password-script",
"help" : "-S, --password-script=[script] Script to run to retrieve password",
"required" : "0",
"shortdesc" : "Script to retrieve password",
"order" : 1 },
"identity_file" : {
"getopt" : "k:",
"longopt" : "identity-file",
"help" : "-k, --identity-file=[filename] Identity file (private key) for ssh ",
"required" : "0",
"shortdesc" : "Identity file for ssh",
"order" : 1 },
"cmd_prompt" : {
"getopt" : "c:",
"longopt" : "command-prompt",
"help" : "-c, --command-prompt=[prompt] Force Python regex for command prompt",
"shortdesc" : "Force Python regex for command prompt",
"required" : "0",
"order" : 1 },
"secure" : {
"getopt" : "x",
"longopt" : "ssh",
"help" : "-x, --ssh Use ssh connection",
"shortdesc" : "SSH connection",
"required" : "0",
"order" : 1 },
"ssh_options" : {
"getopt" : "X:",
"longopt" : "ssh-options",
"help" : "--ssh-options=[options] SSH options to use",
"shortdesc" : "SSH options to use",
"required" : "0",
"order" : 1 },
"ssl" : {
"getopt" : "z",
"longopt" : "ssl",
"help" : "-z, --ssl Use ssl connection",
"required" : "0",
"shortdesc" : "SSL connection",
"order" : 1 },
"notls" : {
"getopt" : "t",
"longopt" : "notls",
"help" : "-t, --notls "
"Disable TLS negotiation and force SSL3.0.\n"
" "
"This should only be used for devices that do not support TLS1.0 and up.",
"required" : "0",
"shortdesc" : "Disable TLS negotiation",
"order" : 1 },
"port" : {
"getopt" : "n:",
"longopt" : "plug",
"help" : "-n, --plug=[id] Physical plug number on device, UUID or\n" +
" identification of machine",
"required" : "1",
"shortdesc" : "Physical plug number, name of virtual machine or UUID",
"order" : 1 },
"switch" : {
"getopt" : "s:",
"longopt" : "switch",
"help" : "-s, --switch=[id] Physical switch number on device",
"required" : "0",
"shortdesc" : "Physical switch number on device",
"order" : 1 },
"exec" : {
"getopt" : "e:",
"longopt" : "exec",
"help" : "-e, --exec=[command] Command to execute",
"required" : "0",
"shortdesc" : "Command to execute",
"order" : 1 },
"vmware_type" : {
"getopt" : "d:",
"longopt" : "vmware_type",
"help" : "-d, --vmware_type=[type] Type of VMware to connect",
"required" : "0",
"shortdesc" : "Type of VMware to connect",
"order" : 1 },
"vmware_datacenter" : {
"getopt" : "s:",
"longopt" : "vmware-datacenter",
"help" : "-s, --vmware-datacenter=[dc] VMWare datacenter filter",
"required" : "0",
"shortdesc" : "Show only machines in specified datacenter",
"order" : 2 },
"snmp_version" : {
"getopt" : "d:",
"longopt" : "snmp-version",
"help" : "-d, --snmp-version=[version] Specifies SNMP version to use",
"required" : "0",
"shortdesc" : "Specifies SNMP version to use (1,2c,3)",
"choices" : [ "1", "2c", "3" ],
"order" : 1 },
"community" : {
"getopt" : "c:",
"longopt" : "community",
"help" : "-c, --community=[community] Set the community string",
"required" : "0",
"shortdesc" : "Set the community string",
"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 (MD5|SHA)",
"choices" : [ "MD5" , "SHA" ],
"order" : 1},
"snmp_sec_level" : {
"getopt" : "E:",
"longopt" : "snmp-sec-level",
"help" : "-E, --snmp-sec-level=[level] Set security level\n"+
" (noAuthNoPriv|authNoPriv|authPriv)",
"required" : "0",
"shortdesc" : "Set security level (noAuthNoPriv|authNoPriv|authPriv)",
"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 (DES|AES)",
"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",
"shortdesc" : "Set privacy protocol password",
"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",
"shortdesc" : "Script to run to retrieve privacy password",
"order" : 1},
"inet4_only" : {
"getopt" : "4",
"longopt" : "inet4-only",
"help" : "-4, --inet4-only Forces agent to use IPv4 addresses only",
"required" : "0",
"shortdesc" : "Forces agent to use IPv4 addresses only",
"order" : 1 },
"inet6_only" : {
"getopt" : "6",
"longopt" : "inet6-only",
"help" : "-6, --inet6-only Forces agent to use IPv6 addresses only",
"required" : "0",
"shortdesc" : "Forces agent to use IPv6 addresses only",
"order" : 1 },
"separator" : {
"getopt" : "C:",
"longopt" : "separator",
"help" : "-C, --separator=[char] Separator for CSV created by 'list' operation",
"default" : ",",
"required" : "0",
"shortdesc" : "Separator for CSV created by operation list",
"order" : 100 },
"login_timeout" : {
"getopt" : "y:",
"longopt" : "login-timeout",
"help" : "--login-timeout=[seconds] Wait X seconds for cmd prompt after login",
"default" : "5",
"required" : "0",
"shortdesc" : "Wait X seconds for cmd prompt after login",
"order" : 200 },
"shell_timeout" : {
"getopt" : "Y:",
"longopt" : "shell-timeout",
"help" : "--shell-timeout=[seconds] Wait X seconds for cmd prompt after issuing command",
"default" : "3",
"required" : "0",
"shortdesc" : "Wait X seconds for cmd prompt after issuing command",
"order" : 200 },
"power_timeout" : {
"getopt" : "g:",
"longopt" : "power-timeout",
"help" : "--power-timeout=[seconds] Test X seconds for status change after ON/OFF",
"default" : "20",
"required" : "0",
"shortdesc" : "Test X seconds for status change after ON/OFF",
"order" : 200 },
"power_wait" : {
"getopt" : "G:",
"longopt" : "power-wait",
"help" : "--power-wait=[seconds] Wait X seconds after issuing ON/OFF",
"default" : "0",
"required" : "0",
"shortdesc" : "Wait X seconds after issuing ON/OFF",
"order" : 200 },
"missing_as_off" : {
"getopt" : "M",
"longopt" : "missing-as-off",
"help" : "--missing-as-off Missing port returns OFF instead of failure",
"required" : "0",
"shortdesc" : "Missing port returns OFF instead of failure",
"order" : 200 },
"retry_on" : {
"getopt" : "F:",
"longopt" : "retry-on",
"help" : "--retry-on=[attempts] Count of attempts to retry power on",
"default" : "1",
"required" : "0",
"shortdesc" : "Count of attempts to retry power on",
"order" : 201 },
"session_url" : {
"getopt" : "s:",
"longopt" : "session-url",
"help" : "-s, --session-url URL to connect to XenServer on",
"required" : "1",
"shortdesc" : "The URL of the XenServer host.",
"order" : 1},
"sudo" : {
"getopt" : "d",
"longopt" : "use-sudo",
"help" : "--use-sudo Use sudo (without password) when calling 3rd party software",
"required" : "0",
"shortdesc" : "Use sudo (without password) when calling 3rd party sotfware.",
"order" : 205},
"method" : {
"getopt" : "m:",
"longopt" : "method",
"help" : "-m, --method=[method] Method to fence (onoff|cycle) (Default: onoff)",
"required" : "0",
"shortdesc" : "Method to fence (onoff|cycle)",
"default" : "onoff",
"choices" : [ "onoff", "cycle" ],
"order" : 1}
}
# options which are added automatically if 'key' is encountered ("default" is always added)
DEPENDENCY_OPT = {
"default" : [ "help", "debug", "verbose", "version", "action", "agent", \
"power_timeout", "shell_timeout", "login_timeout", "power_wait", "retry_on", "delay" ],
"passwd" : [ "passwd_script" ],
"secure" : [ "identity_file", "ssh_options" ],
"ipaddr" : [ "ipport", "inet4_only", "inet6_only" ],
"port" : [ "separator" ],
"community" : [ "snmp_auth_prot", "snmp_sec_level", "snmp_priv_prot", \
"snmp_priv_passwd", "snmp_priv_passwd_script" ]
}
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, options, 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)
pexpect.spawn.send(self,message)
# send EOL according to what was detected in login process (telnet)
def send_eol(self, message):
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]))
syslog.syslog(syslog.LOG_ERR, "Failed to close standard output")
sys.exit(EC_GENERIC_ERROR)
def add_dependency_options(options):
## Add also options which are available for every fence agent
added_opt = []
for opt in options + ["default"]:
if DEPENDENCY_OPT.has_key(opt):
added_opt.extend([y for y in DEPENDENCY_OPT[opt] if options.count(y) == 0])
return added_opt
def fail_usage(message = ""):
if len(message) > 0:
logging.error("%s\n" % message)
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)
syslog.syslog(syslog.LOG_ERR, 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(lambda x, y: cmp(x[1]["order"], y[1]["order"]))
for key, value in sorted_list:
if len(value["help"]) != 0:
print " " + value["help"]
def metadata(avail_opt, options, docs):
# avail_opt has to be unique, if there are duplicities then they should be removed
sorted_list = [ (key, all_opt[key]) for key in list(set(avail_opt)) ]
sorted_list.sort(lambda x, y: cmp(x[1]["order"], y[1]["order"]))
print "<?xml version=\"1.0\" ?>"
print "<resource-agent name=\"" + os.path.basename(sys.argv[0]) + \
"\" shortdesc=\"" + docs["shortdesc"] + "\" >"
if "symlink" in docs:
for (symlink, desc) in docs["symlink"]:
print "<symlink name=\"" + symlink + "\" shortdesc=\"" + desc + "\"/>"
print "<longdesc>" + docs["longdesc"] + "</longdesc>"
if docs.has_key("vendorurl"):
print "<vendor-url>" + docs["vendorurl"] + "</vendor-url>"
print "<parameters>"
for option, _ in sorted_list:
if all_opt[option].has_key("shortdesc"):
print "\t<parameter name=\"" + option + "\" unique=\"0\" required=\"" + all_opt[option]["required"] + "\">"
default = ""
if all_opt[option].has_key("default"):
default = str(all_opt[option]["default"])
elif options.has_key("--" + all_opt[option]["longopt"]) and all_opt[option]["getopt"].endswith(":"):
if options["--" + all_opt[option]["longopt"]]:
try:
default = options["--" + all_opt[option]["longopt"]]
except TypeError:
## @todo/@note: Currently there is no clean way how to handle lists
## we can create a string from it but we can't set it on command line
default = str(options["--" + all_opt[option]["longopt"]])
elif options.has_key("--" + all_opt[option]["longopt"]):
default = "true"
if default:
default = default.replace("&", "&amp;" )
default = default.replace('"', "&quot;" )
default = default.replace('<', "&lt;" )
default = default.replace('>', "&gt;" )
default = default.replace("'", "&apos;" )
default = "default=\"" + default + "\" "
mixed = all_opt[option]["help"]
## split it between option and help text
res = re.compile(r"^(.*--\S+)\s+", re.IGNORECASE | re.S).search(mixed)
if (None != res):
mixed = res.group(1)
mixed = mixed.replace("<", "&lt;").replace(">", "&gt;")
print "\t\t<getopt mixed=\"" + mixed + "\" />"
if all_opt[option].has_key("choices"):
print "\t\t<content type=\"select\" "+default+" >"
for choice in all_opt[option]["choices"]:
print "\t\t\t<option value=\"%s\" />" % (choice)
print "\t\t</content>"
elif all_opt[option]["getopt"].count(":") > 0:
print "\t\t<content type=\"string\" "+default+" />"
else:
print "\t\t<content type=\"boolean\" "+default+" />"
print "\t\t<shortdesc lang=\"en\">" + all_opt[option]["shortdesc"] + "</shortdesc>"
print "\t</parameter>"
print "</parameters>"
print "<actions>"
if avail_opt.count("fabric_fencing") == 1:
## do 'unfence' at the start
print "\t<action name=\"on\" automatic=\"1\"/>"
else:
print "\t<action name=\"on\" automatic=\"0\"/>"
print "\t<action name=\"off\" />"
if avail_opt.count("fabric_fencing") == 0:
print "\t<action name=\"reboot\" />"
print "\t<action name=\"status\" />"
print "\t<action name=\"list\" />"
print "\t<action name=\"monitor\" />"
print "\t<action name=\"metadata\" />"
print "</actions>"
print "</resource-agent>"
def process_input(avail_opt):
avail_opt.extend(add_dependency_options(avail_opt))
##
## Set standard environment
#####
os.putenv("LANG", "C")
os.putenv("LC_ALL", "C")
##
## Prepare list of options for getopt
#####
getopt_string = ""
longopt_list = [ ]
for k in avail_opt:
if all_opt.has_key(k):
getopt_string += all_opt[k]["getopt"]
else:
fail_usage("Parse error: unknown option '"+k+"'")
if all_opt.has_key(k) and all_opt[k].has_key("longopt"):
if all_opt[k]["getopt"].endswith(":"):
longopt_list.append(all_opt[k]["longopt"] + "=")
else:
longopt_list.append(all_opt[k]["longopt"])
##
## Read options from command line or standard input
#####
if len(sys.argv) > 1:
try:
opt, _args = getopt.gnu_getopt(sys.argv[1:], getopt_string, longopt_list)
except getopt.GetoptError, error:
fail_usage("Parse error: " + error.msg)
## Transform short getopt to long one which are used in fencing agents
#####
old_opt = opt
opt = { }
for o in dict(old_opt).keys():
if o.startswith("--"):
for x in all_opt.keys():
if all_opt[x].has_key("longopt") and "--" + all_opt[x]["longopt"] == o:
opt["--" + all_opt[x]["longopt"]] = dict(old_opt)[o]
else:
for x in all_opt.keys():
if x in avail_opt and all_opt[x].has_key("getopt") and all_opt[x].has_key("longopt") and \
("-" + all_opt[x]["getopt"] == o or "-" + all_opt[x]["getopt"].rstrip(":") == o):
opt["--" + all_opt[x]["longopt"]] = dict(old_opt)[o]
opt[o] = dict(old_opt)[o]
## Compatibility Layer
#####
z = dict(opt)
if z.has_key("--plug") == 1:
z["-m"] = z["--plug"]
opt = z
##
#####
else:
opt = { }
name = ""
for line in sys.stdin.readlines():
line = line.strip()
if ((line.startswith("#")) or (len(line) == 0)):
continue
(name, value) = (line + "=").split("=", 1)
value = value[:-1]
if avail_opt.count(name) == 0:
logging.warning("Parse error: Ignoring unknown option '%s'\n" % line)
syslog.syslog(syslog.LOG_WARNING, "Parse error: Ignoring unknown option '"+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"
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):
device_opt.extend(add_dependency_options(device_opt))
options = dict(opt)
options["device_opt"] = device_opt
## Set requirements that should be included in metadata
#####
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("fabric_fencing"):
all_opt["action"]["default"] = "off"
all_opt["action"]["help"] = "-o, --action=[action] Action: status, off (default) or on"
## Set default values
#####
for opt in device_opt:
if all_opt[opt].has_key("default"):
getopt_long = "--" + all_opt[opt]["longopt"]
if 0 == options.has_key(getopt_long):
options[getopt_long] = all_opt[opt]["default"]
if device_opt.count("ipport"):
if options.has_key("--ipport"):
all_opt["ipport"]["help"] = "-u, --ipport=[port] " + \
"TCP/UDP port to use (default " + options["--ipport"] +")"
elif device_opt.count("snmp_version"):
all_opt["ipport"]["default"] = "161"
all_opt["ipport"]["help"] = "-u, --ipport=[port] TCP/UDP port to use (default 161)"
elif options.has_key("--ssh"):
all_opt["ipport"]["default"] = 22
all_opt["ipport"]["help"] = "-u, --ipport=[port] TCP/UDP port to use (default 22)"
elif options.has_key("--ssl"):
all_opt["ipport"]["default"] = 443
all_opt["ipport"]["help"] = "-u, --ipport=[port] TCP/UDP port to use (default 443)"
elif device_opt.count("web"):
all_opt["ipport"]["default"] = 80
if device_opt.count("ssl") == 0:
all_opt["ipport"]["help"] = "-u, --ipport=[port] TCP/UDP port to use (default 80)"
else:
all_opt["ipport"]["help"] = "-u, --ipport=[port] TCP/UDP port to use\n\
(default 80, 443 if --ssl option is used)"
else:
all_opt["ipport"]["default"] = 23
if device_opt.count("secure") == 0:
all_opt["ipport"]["help"] = "-u, --ipport=[port] TCP/UDP port to use (default 23)"
else:
all_opt["ipport"]["help"] = "-u, --ipport=[port] TCP/UDP port to use\n\
(default 23, 22 if --ssh option is used)"
## In special cases (show help, metadata or version) we don't need to check anything
#####
if options.has_key("--help") or options.has_key("--version") or \
(options.has_key("--action") and options["--action"].lower() == "metadata"):
return options
options["--action"] = options["--action"].lower()
if options.has_key("--verbose"):
logging.getLogger().setLevel(logging.DEBUG)
acceptable_actions = [ "on", "off", "status", "list", "monitor" ]
if 1 == device_opt.count("fabric_fencing"):
## Compatibility layer
#####
acceptable_actions.extend(["enable", "disable"])
else:
acceptable_actions.extend(["reboot"])
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"
## automatic detection and set of valid UUID from --plug
if (0 == options.has_key("--username")) and \
device_opt.count("login") and (device_opt.count("no_login") == 0):
fail_usage("Failed: You have to set login name")
if device_opt.count("ipaddr") and 0 == options.has_key("--ip") and 0 == options.has_key("--managed"):
fail_usage("Failed: You have to enter fence address")
if (device_opt.count("no_password") == 0):
if 0 == device_opt.count("identity_file"):
if 0 == (options.has_key("--password") or options.has_key("--password-script")):
fail_usage("Failed: You have to enter password or password script")
else:
if 0 == (options.has_key("--password") or \
options.has_key("--password-script") or options.has_key("--identity-file")):
fail_usage("Failed: You have to enter password, password script or identity file")
if 0 == options.has_key("--ssh") and 1 == options.has_key("--identity-file"):
fail_usage("Failed: You have to use identity file together with ssh connection (-x)")
if 1 == options.has_key("--identity-file"):
if 0 == os.path.isfile(options["--identity-file"]):
fail_usage("Failed: Identity file " + options["--identity-file"] + " does not exist")
if (0 == ["list", "monitor"].count(options["--action"].lower())) and \
0 == options.has_key("--plug") and device_opt.count("port") and device_opt.count("no_port") == 0:
fail_usage("Failed: You have to enter plug number or machine identification")
if options.has_key("--password-script"):
options["--password"] = os.popen(options["--password-script"]).read().rstrip()
if options.has_key("--debug-file"):
try:
fh = logging.FileHandler(options["--debug-file"])
fh.setLevel(logging.DEBUG)
logging.getLogger().addHandler(fh)
except IOError:
logging.error("Unable to create file %s" % options["--debug-file"])
fail_usage("Failed: Unable to create file " + options["--debug-file"])
if options.has_key("--snmp-priv-passwd-script"):
options["--snmp-priv-passwd"] = os.popen(options["--snmp-priv-passwd-script"]).read().rstrip()
if options.has_key("--ipport") == False:
if options.has_key("--ssh"):
options["--ipport"] = 22
elif options.has_key("--ssl"):
options["--ipport"] = 443
elif device_opt.count("web"):
options["--ipport"] = 80
else:
options["--ipport"] = 23
if options.has_key("--plug") and len(options["--plug"].split(",")) > 1 and \
options.has_key("--method") and options["--method"] == "cycle":
fail_usage("Failed: Cannot use --method cycle for more than 1 plug")
for opt in device_opt:
if all_opt[opt].has_key("choices"):
longopt = "--" + all_opt[opt]["longopt"]
possible_values_upper = map (lambda y : y.upper(), all_opt[opt]["choices"])
if options.has_key(longopt):
options[longopt] = options[longopt].upper()
if not options["--" + all_opt[opt]["longopt"]] in possible_values_upper:
fail_usage("Failed: You have to enter a valid choice " + \
"for %s from the valid values: %s" % \
("--" + all_opt[opt]["longopt"] , str(all_opt[opt]["choices"])))
return options
def wait_power_status(tn, options, get_power_fn):
for dummy in xrange(int(options["--power-timeout"])):
if get_multi_power_fn(tn, options, get_power_fn) != options["--action"]:
time.sleep(1)
else:
return 1
return 0
## 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(tn, options, get_power_fn):
status = "off"
if options.has_key("--plugs"):
for plug in options["--plugs"]:
try:
options["--uuid"] = str(uuid.UUID(plug))
except ValueError:
pass
except KeyError:
pass
options["--plug"] = plug
plug_status = get_power_fn(tn, options)
if plug_status != "off":
status = plug_status
else:
status = get_power_fn(tn, options)
return status
def set_multi_power_fn(tn, options, set_power_fn):
if options.has_key("--plugs"):
for plug in options["--plugs"]:
try:
options["--uuid"] = str(uuid.UUID(plug))
except ValueError:
pass
except KeyError:
pass
options["--plug"] = plug
set_power_fn(tn, options)
else:
set_power_fn(tn, options)
def show_docs(options, docs = None):
device_opt = options["device_opt"]
if docs == None:
docs = { }
docs["shortdesc"] = "Fence agent"
docs["longdesc"] = ""
## Process special options (and exit)
#####
if options.has_key("--help"):
usage(device_opt)
sys.exit(0)
if options.has_key("--action") and options["--action"].lower() == "metadata":
metadata(device_opt, options, docs)
sys.exit(0)
if options.has_key("--version"):
print __main__.RELEASE_VERSION, __main__.BUILD_DATE
print __main__.REDHAT_COPYRIGHT
sys.exit(0)
def fence_action(tn, options, set_power_fn, get_power_fn, get_outlet_list = None, reboot_cycle_fn = None):
result = 0
try:
if options.has_key("--plug"):
options["--plugs"] = options["--plug"].split(",")
## Process options that manipulate fencing device
#####
if (options["--action"] == "list") and 0 == options["device_opt"].count("port"):
print "N/A"
return
elif (options["--action"] == "list" and 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"
return
elif (options["--action"] == "list") or \
((options["--action"] == "monitor") and 1 == options["device_opt"].count("port")):
outlets = get_outlet_list(tn, options)
## keys can be numbers (port numbers) or strings (names of VM)
for outlet_id in outlets.keys():
(alias, status) = outlets[outlet_id]
if options["--action"] != "monitor":
- print outled_id + options["--separator"] + alias
+ print outlet_id + options["--separator"] + alias
return
status = get_multi_power_fn(tn, options, get_power_fn)
if status != "on" and status != "off":
fail(EC_STATUS)
if options["--action"] == "on":
if status == "on":
print "Success: Already ON"
else:
power_on = False
for _ in range(1, 1 + int(options["--retry-on"])):
set_multi_power_fn(tn, options, set_power_fn)
time.sleep(int(options["--power-wait"]))
if wait_power_status(tn, options, get_power_fn):
power_on = True
break
if power_on:
print "Success: Powered ON"
else:
fail(EC_WAITING_ON)
elif options["--action"] == "off":
if status == "off":
print "Success: Already OFF"
else:
set_multi_power_fn(tn, options, set_power_fn)
time.sleep(int(options["--power-wait"]))
if wait_power_status(tn, options, get_power_fn):
print "Success: Powered OFF"
else:
fail(EC_WAITING_OFF)
elif options["--action"] == "reboot":
power_on = False
if options.has_key("--method") and options["--method"].lower() == "cycle" and reboot_cycle_fn is not None:
for _ in range(1, 1 + int(options["--retry-on"])):
if reboot_cycle_fn(tn, options):
power_on = True
break
if not power_on:
fail(EC_TIMED_OUT)
else:
if status != "off":
options["--action"] = "off"
set_multi_power_fn(tn, options, set_power_fn)
time.sleep(int(options["--power-wait"]))
if wait_power_status(tn, options, get_power_fn) == 0:
fail(EC_WAITING_OFF)
options["--action"] = "on"
try:
for _ in range(1, 1 + int(options["--retry-on"])):
set_multi_power_fn(tn, options, set_power_fn)
time.sleep(int(options["--power-wait"]))
if wait_power_status(tn, options, get_power_fn) == 1:
power_on = True
break
except Exception, ex:
# an error occured during power ON phase in reboot
# fence action was completed succesfully even in that case
logging.error("%s\n", str(ex))
syslog.syslog(syslog.LOG_NOTICE, str(ex))
if power_on == False:
# this should not fail as node was fenced succesfully
logging.error('Timed out waiting to power ON\n')
syslog.syslog(syslog.LOG_NOTICE, "Timed out waiting to power ON")
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, ex:
logging.error("%s\n" % str(ex))
syslog.syslog(syslog.LOG_ERR, ex[1])
fail(EC_TIMED_OUT)
return result
def fence_login(options, re_login_string = r"(login\s*: )|(Login Name: )|(username: )|(User Name :)"):
force_ipvx = ""
if (options.has_key("--inet6-only")):
force_ipvx = "-6 "
if (options.has_key("--inet4-only")):
force_ipvx = "-4 "
if (options.has_key("eol") == False):
options["eol"] = "\r\n"
if options.has_key("--command-prompt") and type(options["--command-prompt"]) is not list:
options["--command-prompt"] = [ options["--command-prompt"] ]
## Do the delay of the fence device before logging in
## 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"]))
try:
re_login = re.compile(re_login_string, re.IGNORECASE)
re_pass = re.compile("(password)|(pass phrase)", re.IGNORECASE)
if options.has_key("--ssl"):
gnutls_opts = ""
if options.has_key("--notls"):
gnutls_opts = "--priority \"NORMAL:-VERS-TLS1.2:-VERS-TLS1.1:-VERS-TLS1.0:+VERS-SSL3.0\""
command = '%s %s --insecure --crlf -p %s %s' % \
(SSL_PATH, gnutls_opts, options["--ipport"], options["--ip"])
try:
conn = fspawn(options, command)
except pexpect.ExceptionPexpect, ex:
logging.error("%s\n" % str(ex))
syslog.syslog(syslog.LOG_ERR, str(ex))
sys.exit(EC_GENERIC_ERROR)
elif options.has_key("--ssh") and 0 == options.has_key("--identity-file"):
command = '%s %s %s@%s -p %s -o PubkeyAuthentication=no' % \
(SSH_PATH, force_ipvx, options["--username"], options["--ip"], options["--ipport"])
if options.has_key("--ssh-options"):
command += ' ' + options["--ssh-options"]
conn = fspawn(options, command)
if options.has_key("telnet_over_ssh"):
# This is for stupid ssh servers (like ALOM) which behave more like telnet
# (ignore name and display login prompt)
result = conn.log_expect(options, \
[ 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(options, re_login, int(options["--login-timeout"]))
conn.sendline(options["--username"])
conn.log_expect(options, re_pass, int(options["--login-timeout"]))
else:
result = conn.log_expect(options, \
[ "ssword:", "Are you sure you want to continue connecting (yes/no)?" ],
int(options["--login-timeout"]))
if result == 1:
conn.sendline("yes")
conn.log_expect(options, "ssword:", int(options["--login-timeout"]))
conn.sendline(options["--password"])
conn.log_expect(options, options["--command-prompt"], int(options["--login-timeout"]))
elif options.has_key("--ssh") and options.has_key("--identity-file"):
command = '%s %s %s@%s -i %s -p %s' % \
(SSH_PATH, force_ipvx, options["--username"], options["--ip"], \
options["--identity-file"], options["--ipport"])
if options.has_key("--ssh-options"):
command += ' ' + options["--ssh-options"]
conn = fspawn(options, command)
result = conn.log_expect(options, [ "Enter passphrase for key '" + options["--identity-file"] + "':", \
"Are you sure you want to continue connecting (yes/no)?" ] + \
options["--command-prompt"], int(options["--login-timeout"]))
if result == 1:
conn.sendline("yes")
result = conn.log_expect(options,
[ "Enter passphrase for key '" + options["--identity-file"]+"':"] + \
options["--command-prompt"], int(options["--login-timeout"]))
if result == 0:
if options.has_key("--password"):
conn.sendline(options["--password"])
conn.log_expect(options, options["--command-prompt"], int(options["--login-timeout"]))
else:
fail_usage("Failed: You have to enter passphrase (-p) for identity file")
else:
conn = fspawn(options, TELNET_PATH)
conn.send("set binary\n")
conn.send("open %s -%s\n"%(options["--ip"], options["--ipport"]))
result = conn.log_expect(options, 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"])
result = conn.log_expect(options, re_pass, int(options["--login-timeout"]))
elif (re_pass.search(screen) == None):
conn.log_expect(options, re_pass, int(options["--shell-timeout"]))
try:
conn.send_eol(options["--password"])
valid_password = conn.log_expect(options, [ 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(screen) != None):
conn.send_eol("")
conn.send_eol(options["--username"])
conn.log_expect(options, re_pass, int(options["--login-timeout"]))
conn.send_eol(options["--password"])
conn.log_expect(options, options["--command-prompt"], int(options["--login-timeout"]))
except KeyError:
fail(EC_PASSWORD_MISSING)
except pexpect.EOF:
fail(EC_LOGIN_DENIED)
except pexpect.TIMEOUT:
fail(EC_LOGIN_DENIED)
return conn
def is_executable(path):
if os.path.exists(path):
stats = os.stat(path)
if stat.S_ISREG(stats.st_mode) and os.access(path, os.X_OK):
return True
return False
diff --git a/fence/agents/raritan/fence_raritan.py b/fence/agents/raritan/fence_raritan.py
index c8137b03..01059ce9 100644
--- a/fence/agents/raritan/fence_raritan.py
+++ b/fence/agents/raritan/fence_raritan.py
@@ -1,98 +1,101 @@
#!/usr/bin/python
import sys, re, pexpect, exceptions
+import atexit
+import time
sys.path.append("@FENCEAGENTSLIBDIR@")
from fencing import *
+from fencing import fspawn, fail, fail_usage, TELNET_PATH, EC_LOGIN_DENIED
#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(options, 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" ]
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
if options["--action"] in ["off", "reboot"]:
time.sleep(int(options["--delay"]))
##
## Operate the fencing device
## We can not use fence_login(), username and passwd are sent on one line
####
try:
conn = fspawn(options, TELNET_PATH)
conn.send("set binary\n")
conn.send("open %s -%s\n"%(options["--ip"], options["--ipport"]))
screen = conn.read_nonblocking(size=100, timeout=int(options["--shell-timeout"]))
conn.log_expect(options, "Login.*", int(options["--shell-timeout"]))
conn.send_eol("%s" % (options["--username"]))
conn.log_expect(options, "Password.*", int(options["--shell-timeout"]))
conn.send_eol("%s" % (options["--password"]))
conn.log_expect(options, "clp.*", 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)
##
## Logout from system
##
## In some special unspecified cases it is possible that
## connection will be closed before we run close(). This is not
## a problem because everything is checked before.
######
try:
conn.send("exit\n")
conn.close()
except:
pass
sys.exit(result)
if __name__ == "__main__":
main()

File Metadata

Mime Type
text/x-diff
Expires
Wed, Feb 26, 10:55 PM (9 h, 14 m ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1465848
Default Alt Text
(68 KB)

Event Timeline