This is the mail archive of the cluster-cvs@sourceware.org mailing list for the cluster.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

fence-agents: master - fence_ifmib: Brand new implementation of thisagent


Gitweb:        http://git.fedorahosted.org/git/fence-agents.git?p=fence-agents.git;a=commitdiff;h=21a0c39b079dd529c75267b2cf465305b0471c7b
Commit:        21a0c39b079dd529c75267b2cf465305b0471c7b
Parent:        01dd364e60046856b3d46d0d6c9df822d3178aff
Author:        Jan Friesse <jfriesse@redhat.com>
AuthorDate:    Wed Mar 4 15:54:09 2009 +0100
Committer:     Jan Friesse <jfriesse@redhat.com>
CommitterDate: Wed Mar 4 15:54:09 2009 +0100

fence_ifmib: Brand new implementation of this agent

Current version of agent is using unified Python library.
Main new features:
- Support for list/monitor action
- Support for metadata
- Support for SNMP v1/2c/3 (old has only 2c)
- Port can be entered not only as ifIndex, but port name
as well (ex. fc1/1).

To update, user needs change ifindex parameter to much
common port parameter.
---
 fence/agents/ifmib/README         |   10 +-
 fence/agents/ifmib/fence_ifmib.py |  350 +++++++++++++------------------------
 fence/man/fence_ifmib.8           |  123 ++++++++++---
 3 files changed, 224 insertions(+), 259 deletions(-)

diff --git a/fence/agents/ifmib/README b/fence/agents/ifmib/README
index b6e7123..cd2a3c1 100644
--- a/fence/agents/ifmib/README
+++ b/fence/agents/ifmib/README
@@ -2,9 +2,9 @@ Intro:
 ------
 This is an SNMP-based fencing agent for RHCS.  It was designed with the use-case
 of disabling ethernet ports on an iSCSI SAN, but could be used to disable any
-port on any SNMP v2c device that implementes the IF-MIB.
+port on any SNMP v1/2c/3 device that implementes the IF-MIB.
 
-The script requires PySNMP version 2 to be installed and working on all nodes
+The script requires NetSNMP to be installed and working on all nodes
 in the cluster.  There are no requirements for any MIBs to be setup --- all of
 the required OIDs are hard-coded into the script.  Since the IF-MIB is an IETF
 standard, these identifiers are very widely supported and will not change.
@@ -16,7 +16,7 @@ To use this agen with the switch used on the iSCSI network, you'll require:
    1) A managed switch running SNMP.
    2) An SNMP community with write privileges.
    3) Permission to send SNMP through any ACLs or firewalls from the nodes.
-   4) The ifIndex associated with the ports being used by the cluster nodes.
+   4) The ifIndex or ifPort associated with the ports being used by the cluster nodes.
 
 Consider a three-node cluster composed of A, B, and C.  Each node has two
 network interfaces - one used for network and cluster communication, the second
@@ -37,9 +37,9 @@ need something like this cluster.conf
 
 In a node's fencing methods, you'll include a line like this:
 
-<device name="myswitch" ifindex="43" option="off"/>
+<device name="myswitch" port="43" option="off"/>
 
 This node will be fenced by disabling the port with ifIndex 43 on the host sw1.
 In SNMP speak, we set IF-MIB::ifAdminStatus.43 = down(2).
 
-
+If you will use port name (like fc1/1), script will try to find ifIndex.
diff --git a/fence/agents/ifmib/fence_ifmib.py b/fence/agents/ifmib/fence_ifmib.py
index 42345ff..766a96d 100644
--- a/fence/agents/ifmib/fence_ifmib.py
+++ b/fence/agents/ifmib/fence_ifmib.py
@@ -1,233 +1,131 @@
 #!/usr/bin/python
-# fence_ifmib.py: fabric fencing for RHCS based on setting a network interface
-# to admin down.  Intended to be used for iSCSI connections, can be used with
-# anything that supports the IF-MIB and SNMP v2c.
-#
-# Written by Ross Vandegrift <ross@kallisti.us>
-# Copyright (C) 2008-2009 Ross Vandegrift
-#  This copyrighted material is made available to anyone wishing to use,
-#  modify, copy, or redistribute it subject to the terms and conditions
-#  of the GNU General Public License v.2.
-
-COPYRIGHT="Copyright (C) 2008-2009 Ross Vandegrift <ross@kallisti.us>"
+
+# 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, re, pexpect
+from fencing import *
+from fencing_snmp import *
 
 #BEGIN_VERSION_GENERATION
-RELEASE_VERSION="New fence_ifmib"
-BUILD_DATE="March, 2008"
+RELEASE_VERSION="IF:MIB SNMP fence agent"
+REDHAT_COPYRIGHT=""
+BUILD_DATE=""
 #END_VERSION_GENERATION
 
-import os
-os.environ['PYSNMP_API_VERSION'] = 'v2'
-import sys, getopt, random, socket
-import atexit
-from pysnmp import role, v2c, asn1
-
-ifAdminStatus = '.1.3.6.1.2.1.2.2.1.7.'
-up = 1
-down = 2
-testing = 3
-
-def usage():
-    line = '\t%s\t%s'
-    print ''
-    print 'This script fences a node by sending a command via SNMP to set'
-    print 'ifAdminStatus to down.  It is designed to kill node access'
-    print 'to the shared storage.  It only supports SNMP v2c.'
-    print ''
-    print RELEASE_VERSION, BUILD_DATE
-    print COPYRIGHT
-    print ''
-    print 'Usage: fence_ifmib [options]'
-    print line % ('-h', '\tPrint usage')
-    print line % ('-V', '\tRun verbosely')
-    print line % ('-c [private]', 'Write community string to use')
-    print line % ('-a [hostname]', 'IP/hostname of SNMP agent')
-    print line % ('-i [index]', 'ifIndex entry of the port ')
-    print line % ('-o [action]', 'One of down, up, or status')
-
-
-def vprint(v, s):
-    if v:
-        print s
-
-
-def parseargs():
-    try:
-        opt, arg = getopt.getopt (sys.argv[1:], 'hVc:v:a:i:o:')
-    except getopt.GetoptError, e:
-        print str (e)
-        usage ()
-        sys.exit (-1)
-
-    comm = ipaddr = ifindex = option = verbose = None
-
-    for o, a in opt:
-        if o == '-h':
-            usage ()
-            sys.exit (-1)
-        if o == '-V':
-            verbose = True
-        if o == '-c':
-            comm = a
-        if o == '-a':
-            ipaddr = a
-        if o == '-i':
-            try:
-                ifindex = int(a)
-            except:
-                sys.stderr.write ('fence_ifmib: ifIndex must be an integer\n')
-                usage ()
-                sys.exit (-1)
-        if o == '-o':
-            option = a
-            if option not in ('on', 'off', 'status'):
-                sys.stderr.write ('fence_ifmib: option must be one of on, off, or status\n')
-                usage ()
-                sys.exit (-1)
-
-    if comm == None or ipaddr == None or ifindex == None \
-            or option == None:
-        sts.stderr.write ('All args are madatory!\n')
-        usage ()
-        sys.exit (-1)
-
-    return (comm, ipaddr, ifindex, option, verbose)
-
-
-def parsestdin():
-    params = {}
-    for line in sys.stdin:
-        val = line.split('=')
-        if len (val) == 2:
-            params[val[0].strip ()] = val[1].strip ()
-
-    try:
-        comm = params['comm']
-    except:
-        sys.stdout.write ('fence_ifmib: Error reading community string\n')
-        sys.exit (1)
-
-    try:
-        ipaddr = params['ipaddr']
-    except:
-        sys.stdout.write ('fence_ifmib: Error reading destination IP/host\n')
-        sys.exit (1)
-
-    try:
-        ifindex = params['ifindex']
-    except:
-        sys.stdout.write ('fence_ifmib: Error reading ifindex\n')
-        sys.exit (1)
-
-    try:
-        option = params['option']
-    except:
-        option = 'off'
-
-    return (comm, ipaddr, ifindex, option)
-            
-
-def snmpget (host, comm, oid):
-    req = v2c.GETREQUEST ()
-    encoded_oids = map (asn1.OBJECTID().encode, [oid,])
-    req['community'] = comm
-    tr = role.manager ((host, 161))
-    rsp = v2c.RESPONSE ()
-    (rawrsp, src) = tr.send_and_receive (req.encode (encoded_oids=encoded_oids))
-    rsp.decode (rawrsp)
-    if rsp['error_status']:
-        raise IOError('SNMP error while reading')
-    oids = map (lambda x: x[0], map(asn1.OBJECTID ().decode, rsp['encoded_oids']))
-    vals = map (lambda x: x[0] (), map(asn1.decode, rsp['encoded_vals']))
-    return vals[0]
-
-
-def snmpset (host, comm, oid, type, value):
-    req = v2c.SETREQUEST (request_id=random.randint (1,2**16-1))
-    req['community'] = comm
-    tr = role.manager ((host, 161))
-    rsp = v2c.RESPONSE ()
-    encoded_oids = map (asn1.OBJECTID ().encode, [oid,])
-    encoded_vals = []
-    encoded_vals.append (eval ('asn1.' + type + '()').encode (value))
-    (rawrsp, src) = tr.send_and_receive (req.encode (encoded_oids=encoded_oids, encoded_vals=encoded_vals))
-    rsp.decode(rawrsp)
-    if rsp['error_status']:
-        raise IOError('SNMP error while setting')
-    oids = map (lambda x: x[0], map (asn1.OBJECTID().decode, rsp['encoded_oids']))
-    vals = map (lambda x: x[0] (), map (asn1.decode, rsp['encoded_vals']))
-    if vals[0] == value:
-        return vals[0]
-    else:
-        raise IOError('SNMP error while setting')
-
-def atexit_handler():
-	try:
-		sys.stdout.close()
-		os.close(1)
-	except IOError:
-		sys.stderr.write("%s failed to close standard output\n"%(sys.argv[0]))
-		sys.exit(1)
+### 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["-n"])
+
+	(oid,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["-n"])
+
+	conn.set("%s.%d"%(STATUSES_OID,port_num),(options["-o"]=="on" and STATUS_UP or STATUS_DOWN))
 
+# 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(ar):
+	return dict(map(lambda y:[y[0].split('.')[-1],y[1]],ar))
+
+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_num=x[0].split('.')[-1]
+
+		port_name=x[1].strip('"')
+		port_alias=(res_aliases.has_key(port_num) and res_aliases[port_num].strip('"') or "")
+		port_status=""
+		result[port_name]=(port_alias,port_status)
+
+	return result
+
+# Define new options
+def ifmib_define_defaults():
+	all_opt["snmp_version"]["default"]="2c"
+
+# Main agent method
 def main():
-    atexit.register(atexit_handler)
-
-    if len (sys.argv) > 1:
-        (comm, host, index, option, verbose) = parseargs ()
-    else:
-        verbose = False
-        (comm, host, index, option) = parsestdin ()
-
-    try:
-        switch = socket.gethostbyname (host)
-    except socket.gaierror, err:
-        vprint (verbose, 'fence_ifmib: %s' % str (err[1]))
-        sys.exit(1)
-
-    if option == 'on':
-        value = up
-    elif option == 'off':
-        value = down
-    elif option == 'status':
-        value = None
-
-    if value:
-        # For option in (on, off) - write and verify
-        try:
-            r = snmpset (switch, comm, ifAdminStatus + str (index), 'INTEGER', value)
-        except:
-            sys.stderr.write ('fence_ifmib: Error during snmp write\n')
-            sys.exit (1)
-        
-        try:
-            s = int (snmpget (switch, comm, ifAdminStatus + str (index)))
-        except:
-            sys.stderr.write ('fence_ifmib: Error during fence verification\n')
-            sys.exit (1)
-
-        if s == value:
-            vprint (verbose, 'fence_ifmib: action %s sucessful' % option)
-            sys.exit (0)
-        else:
-            vprint (verbose, 'fence_ifmib: action %s failed' % option)
-            sys.exit (1)
-    else: # status
-        try: 
-            r = int (snmpget (switch, comm, ifAdminStatus + str (index)))
-        except:
-            sys.stderr.write ('fence_ifmib: Error during snmp read\n')
-            sys.exit (1)
-
-        if r == up:
-            vprint (verbose, 'fence_ifmib: Port is admin up')
-            sys.exit (0)
-        elif r == down:
-            vprint (verbose, 'fence_ifmib: Port is admin down')
-            sys.exit (2)
-        elif r == testing:
-            vprint (verbose, 'fence_ifmib: Port is admin testing')
-            sys.exit (2)
-
-
-if __name__ == '__main__':
-    main()
+	global port_oid
+
+	device_opt = [ "help", "version", "agent", "quiet", "verbose", "debug",
+		       "action", "ipaddr", "login", "passwd", "passwd_script",
+		       "test", "port", "separator", "no_login", "no_password",
+		       "snmp_version", "community", "snmp_auth_prot", "snmp_sec_level",
+		       "snmp_priv_prot", "snmp_priv_passwd", "snmp_priv_passwd_script",
+		       "udpport"]
+
+	atexit.register(atexit_handler)
+
+	options=process_input(device_opt)
+
+	# Emulate enable/disable functionality
+	if (options.has_key("-o")):
+		options["-o"]=options["-o"].lower()
+
+		if (options["-o"]=="enable"):
+			options["-o"]="on"
+		if (options["-o"]=="disable"):
+			options["-o"]="off"
+	else:
+		options["-o"]="off"
+
+	options = check_input(device_opt, options)
+
+	# Operate the fencing device
+	fence_action(FencingSnmp(options), options, set_power_status, get_power_status, get_outlets_status)
+
+if __name__ == "__main__":
+	main()
diff --git a/fence/man/fence_ifmib.8 b/fence/man/fence_ifmib.8
index 93e8b4b..38cd223 100644
--- a/fence/man/fence_ifmib.8
+++ b/fence/man/fence_ifmib.8
@@ -1,69 +1,136 @@
-.\"  Copyright (C) 2008-2009 Ross Vandegrift.  All rights reserved.
-.\"  
-.\"  This copyrighted material is made available to anyone wishing to use,
-.\"  modify, copy, or redistribute it subject to the terms and conditions
-.\"  of the GNU General Public License v.2.
-
 .TH fence_ifmib 8
 
 .SH NAME
 fence_ifmib - I/O Fencing agent for IF-MIB capable SNMP devices
 
 .SH SYNOPSIS
-.B 
+.B
 fence_ifmib
 [\fIOPTION\fR]...
 
 .SH DESCRIPTION
-fence_ifmib is an I/O Fencing agent which can be used with any IF-MIB capable
-SNMP device.  It was written with managed ethernet switches in mind, in order
+fence_ifmib is an I/O Fencing agent which can be used with any SNMP IF-MIB capable
+device. Agent internally uses snmpget, snmpset and snmpwalk command.
+
+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.
 
-fence_ifmib accepts options on the command line as well as from stdin.  
-Fenced sends parameters through stdin when it execs the agent.  fence_ifmib 
+fence_ifmib accepts options on the command line as well as from stdin.
+Fenced sends parameters through stdin when it execs the agent.  fence_ifmib
 can be run by itself with command line options.  This is useful for testing.
 
 .SH OPTIONS
 .TP
 \fB-a\fP \fIIPaddress\fR
-IP address or hostname of the SNMP agent to be written.
+IP address or hostname of the SNMP device. Can be used any syntax supported by snmpget.
 .TP
-\fB-h\fP 
+\fB-h\fP
 Print out a help message describing available options, then exit.
 .TP
 \fB-c\fP \fIcommunity\fR
-The write community string to be used in the request.
+The read/write community string to be used in the request.
+.TP
+\fB-n\fP \fIname\fR
+Name of port to fence (fc1/1) or ifIndex (43).
+.TP
+\fB-p\fP \fIpassword\fR
+Password for login for SNMP v3 (authentication protocol pass phrase).
+.TP
+\fB-P\fP \fIpassword\fR
+Password for privacy for SNMP v3 (privacy protocol password).
+.TP
+\fB-S\fP \fIscript\fR
+Script to run to retrieve password for login for SNMP v3 (authentication protocol pass phrase).
+.TP
+\fB-R\fP \fIscript\fR
+Script to run to retrieve privacy for SNMP v3 (privacy protocol password).
 .TP
-\fB-i\fP \fIiIindex\fR
-The ifIndex of the interface to be acted upon.  This will need to be determined
-manually prior to configuration.
+\fB-l\fP \fIlogin\fR
+Login name for SNMP v3 (security name).
+.TP
+\fB-d\fP \fIversion\fR
+SNMP version (1,2c,3).
+.TP
+\fB-b\fP \fIauth_protocol\fR
+SNMP authentication protocol (MD5|SHA).
+.TP
+\fB-E\fP \fIsec_level\fR
+SNMP security level (noAuthNoPriv|authNoPriv|authPriv).
+.TP
+\fB-B\fP \fIpriv_protocol\fR
+SNMP privacy protocol (DES|AES).
+.TP
+\fB-u\fP \fIudp_port\fR
+UDP/TCP port to use.
 .TP
 \fB-o\fP \fIaction\fR
-The action required.  off (default), on, or status.  off sets ifAdminStatus
-down, on sets ifAdminStatus up, and status returns the current state.
+The action required.  off (default), on, status, list or monitor. Deprecated
+options (enable -> on and disable -> off) can be used too.
+.TP
+\fB-v\fP
+Verbose. Record session to stdout, or debug file if specified (see -D).
+.TP
+\fB-D\fP
+Specifies file, where will be written debug messages from session.
 .TP
 \fB-V\fP
-Verbose.  Print informational messages to standard out.
+Print out a version message, then exit.
 
 .SH STDIN PARAMETERS
 .TP
 \fIagent = < param >\fR
 This option is used by fence_node(8) and is ignored by fence_ifmib.
 .TP
-\fIipaddr = < hostname | ip >\fR
-IP address or hostname of the device.
+\fIipaddr = < param >\fR
+IP address or hostname of the SNMP device. Can be used any syntax supported by snmpget.
+.TP
+\fIcommunity = < param >\fR
+The read/write community string to be used in the request.
+.TP
+\fIport = < param >\fR
+Name of port to fence (fc1/1) or ifIndex (43).
+.TP
+\fIpasswd = < param >\fR
+Password for login for SNMP v3 (authentication protocol pass phrase).
+.TP
+\fIsnmp_priv_passwd\fR
+Password for privacy for SNMP v3 (privacy protocol password).
+.TP
+\fIpasswd_script = < param >\fR
+Script to run to retrieve password for login for SNMP v3 (authentication protocol pass phrase).
+.TP
+\fIsnmp_priv_passwd_script = < param>\fR
+Password for privacy for SNMP v3 (privacy protocol password).
+.TP
+\fIlogin = < param >\fR
+Login name for SNMP v3 (security name).
+.TP
+\fIsnmp_version = < param >\fR
+SNMP version (1,2c,3).
+.TP
+\fIsnmp_auth_prot = < param >\fR
+SNMP authentication protocol (MD5|SHA).
+.TP
+\fIsnmp_sec_level = < param >\fR
+SNMP security level (noAuthNoPriv|authNoPriv|authPriv).
+.TP
+\fIsnmp_priv_prot = < param >\fR
+SNMP privacy protocol (DES|AES).
 .TP
-\fIcomm = < param >\fR
-Write community string to be used in the request.
+\fIudpport = < param >\fR
+UDP/TCP port to use.
 .TP
-\fIifindex = < param >\fR
-The ifIndex of the interface to be acted upon.
+\fIaction = < param >\fR
+The action required.  off (default), on, status, list or monitor. Deprecated
+options (enable -> on and disable -> off) can be used too.
 .TP
-\fIoption = < param >\fR
-The action required.  off (default), on, or status.
+\fIverbose = < param >\fR
+Verbose.  Record session to stdout, or debug file if specified (see debug).
 .TP
+\fIdebug = < param >\fR
+Specifies file, where will be written debug messages from session.
 
 .SH SEE ALSO
 fence(8), fence_node(8)


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]