How to add a new handler
Category path: | COREmanager |
DCImanager -> Equipment management | |
DCImanager Enterprise -> Equipment management |
Operating principles
External device handler (hereafter a handler) is an executable file, it doesn’t matter if it is a script or binary file. Data exchange between DCImanager and handler occurs through stdout and stdin. Data is transmitted in XML-file.
When DCImanager starts, it launches in turns executable files from var / dcihandlers with -info option. Each handler send XML to stdout, which describes what device this executable file processes and what functions it supports. After registration in DCImanager a new handler will be available while creating new devices.
Interface protocol
Handler registration
DCImanager launches your handler with -info option:
tresthandler -info
stdin of handler won't get anything but the handler should transfer the XML, which describes the device, through its stdout.
<doc> <type>Switch</type> - Type of device <name>First External Handler</name> - Name which will be displayed in DCImanager <requirements> - List of input data, required by handler <snmpv1/> <snmpv2c/> </requirements> <supported_funcs> - List of functions, supported by device <status/> <port_on/> <port_off/> </supported_funcs> </doc>
Contents
<type>
Type of device. It can be Switch, PDU, IPMI.
<name>
Name which will be displayed in DCImanager.
<requirements>
List of input data, required by handler. This list is responsible for data which DCImanager will offer to enter during creating a device, based on this handler. It also will specify input data, which will be received by handler during different operations with device. Can include following values:
<snmpv1/> - SNMPv1 will be available on the device creation form. Handler will get information about SNMP version and community.
<snmpv2c/> - SNMPv2c will be available on the device creation form. Handler will get information about SNMP version and community.
<snmpv3/> - SNMPv3 will be available on the device creation form. Handler will get information about SNMP version, user, password (auth phrase), private key (priv phrase) и and authentication level.
<ssh/> - On the form SSH tab will be available, handler will get user and password info for SSH connection.
<telnet/> - Telnet tab will be available on the form, handler will get user and password info for Telnet connection.
You can use any combinations of these parameters.
WARNING: DCImanager doesn't implement any protocols for external handlers (SNMP, SSH, TELNET). Parameters mentioned above just allow the user (the person who will register the device based on your handler in DCImanager) to see intelligible input fields, corresponding to the described protocols.
<supported_funcs>
List of functions supported by the device . May include the following values:
- <status/> - Handler can read the information about the device. Must be implemented.
- <statistics/> - Handler can collect traffic statistics (for switches) or power consumption (for some PDU's).
- <port_on/> - Handler can enable device's port.
- <port_off/> - Handler can disable device's port.
- <port_reset/> - Handler can reset the device port (mainly for power ports ).
- <port_speed/> - Handler can set the speed of devices' port (only for switches).
- <port_duplex/> - Handler can set the mode of devices' port (only for switches).
- <set_vlan/> - Handler can set VLAN of devices' port (only for switches)
- <mac_list/> - Handler can display the list of MAC-addresses of device's ports (only for switches).
Call of handler functions
Input data
If any handler function is called (for example if PDU's port is disabled ), executable files without parameters will be called and the xml with all necessary data will be sent to stdin. Example 1 - call of status function, which should show information about all statuses of all device's ports.
<doc> <func>status</func> <device_params> <ip>10.10.10.2</ip> <snmp_ver>SNMP v2c</snmp_ver> <snmp_community>sdffga</snmp_community> </device_params> </doc>
Example 2 - Call of function port_on, which should enable certain port.
<doc>
<func>port_on</func> <device_params> <ip>12.23.55.32</ip> <snmp_ver>SNMP v2c</snmp_ver> <snmp_community>asasda</snmp_community> </device_params> <port> <identity>1</identity> </port> </doc>
<func> - name of function to be called.
<device_params> - Device parameters,usually authentication information. Can include:
Parameter name | Description | Acceptable values |
---|---|---|
ip | IP-address of device | string |
snmp_ver | SNMP version, which will be used | SNMP v1, SNMP v2c, SNMP v3 |
snmp_community | SNMP Community | string without spaces, Latin letters |
snmp_user | SNMP user (only in case of using SNMP v3) | string |
snmp_auth_phrase | Phrase for SNMP authentication (only in case of using SNMP v3) | string |
snmp_priv_phrase | Private phrase for SNMP (only in case of using SNMP v3) | string |
snmp_auth_level | SNMP authentication level | noauth, authnopriv, authpriv |
telnet_pass | Password for Telnet connection | string |
telnet_user | Username for Telnet connection | string |
ssh_pass | Password for SSH connection | string |
ssh_user | Username for SSH connection | string |
pass | Password for IPMI | string |
user | IPMI user name | string |
<port> - port, for which the function is executed, can include:
Parameter name | Description | Acceptable value |
---|---|---|
identity | ID of the port, unique inside the device | string |
speed | The speed, which should be set on the port with ID identity | auto, auto10100, 10mbps, 100mbps, 1gbps, 10gbps |
duplex | Mode, t which should be set on the port with ID identity | auto, half, full |
vlan_id | VLAN which should be set on the port with ID identity | from 1 to 4095 |
vlan_name | Nickname of VLAN which should be set on the port with ID identity | string without spaces, Latin letters |
Output data
When handler got and processed input data, it should return a result (also in XML). Example 1 - response to function status of handler of small switch for 4 ports. Describes all ports and their state.
<doc> <hostname>comm3</hostname> <port> <identity>1</identity> <description>FastEthernet 1</description> <admin_status>on</admin_status> <oper_status>on</oper_status> </port> <port> <identity>2</identity> <description>FastEthernet 2</description> <admin_status>on</admin_status> <oper_status>off</oper_status> </port> <port> <identity>3</identity> <description>FastEthernet 3</description> <admin_status>on</admin_status> <oper_status>off</oper_status> </port> <port> <identity>4</identity> <description>FastEthernet 4</description> <admin_status>on</admin_status> <oper_status>off</oper_status> </port> </doc>
Example 2 - response to function port_off for port with ID "1".
<doc> <port> <identity>1</identity> <admin_status>off</admin_status> </port> </doc>
<hostname> - only for switches, contents switch's hostname.
<port> - contains description of port’s various parameters. Can include:
Parameter name | Descripton | Acceptable value |
---|---|---|
identity | ID of the port, unique inside the device | string |
description | Description of device port | string |
admin_status | Port's status, made by administrator. | on, off, unknown |
oper_status | Actual port's state (e.x switch port link) | on, off, unknown |
speed | Switch port speed | auto, auto10100, 10mbps, 100mbps, 1gbps, 10gbps
|
duplex | Switch port mode | auto, half, full |
rxbytes | Counter of incoming bytes, passed through the switch port | numeric value |
txbytes | Counter of outgoing bytes, passed through the switch port | numeric value |
rxpackets | Counter of incoming packets, passed through the switch port | numeric value |
txpackets | Counter of outgoing packets, passed through the switch port | numeric value |
power | Counter of power consumption in W-hr pn PDU' port | numeric value |
vlan_id | VLAN set on the switch port | from 1 to 4095 |
vlan_name | VLAN alias on the switch port | string without spaces, Latin letters |
mac | MAC-address, found on the switch port. There may be several entries for each port. | MAC-address in one of following formats: 1A2B3C4D5E6F 1A:2B:3C:4D:5E:6F 1a2b.3c4d.5e6f 1A-2B-3C-4D-5E-6F |
Also a handler can return an error, for example:
<doc> <error> <type>connection</type> <text>Failed to open connection to 12.35.56.22</text> </error> </doc>
If in output XML there is a block <error> all other content will be ignored and the operation will be terminated, also error report about an error during the work with device will be generated.
- <type> - type of an error. Can be "connection" and "unexpected_data"
- connection - device connection error
- unexpected_data - data exchange error
- <text>- text of an error, will be displayed in report.
Matching of input and output data
Switches (<type>Switch</type>)
Function | Description | Input data | Output data |
---|---|---|---|
status | should return the complete information about all the switch ports | data to access device (<device_params>) | ports descriprion |
statistics | should return the state of counters of device ports | data to access device (<device_params>) | ports counters |
port_on, port_off | should enable / disable switch port | data to access device(<device_params>) and port's ID | new port state |
port_speed | should set the speed of the switch port | data to access device(<device_params>), ID and port' speed | new port state |
port_duplex | should set the switch port mode | data to access device, ID and wanted port's mode | new port state |
set_vlan | should set the VLAN for switch port | data to access device, port ID and VLAN ID and VLAN nickname | new port state |
Power distributors
Function | Description | Input data | Output data |
---|---|---|---|
status | should return the complete information about all ports of PDU | data to access device (<device_params>) | ports description |
statistics | should return the state of all counters of device ports | data to access device(<device_params>) | ports counters |
port_on, port_off, port_reset | should turn on / off / reset port of PDU | data to access device(<device_params>)and port ID | new port status |
IPMI
Although IPMI doesn't have ports because it's integrated to the server, in DCImanager there is a special reserved port for device of this type. Its ID should be "power" (case-sensitive).
Function | Description | Input data | Output data |
---|---|---|---|
status | should return the full information about the power status of the server | data to access device(<device_params>) | port's status "power" |
port_on, port_off, port_reset | should turn on / off / reset the server's power | data to access device(<device_params>) | new port's state "power" |
Examples of handler
Switch handler
This event handler is similar to the handler SNMP common which is included in DCImanager. Switch management is carried out by using SNMPv2c library pysnmp 4v.
#!/usr/bin/python2.7
#coding=utf8
import sys
import os
import xml.etree.ElementTree as xmlET
from pysnmp.entity.rfc3413.oneliner import cmdgen
from pysnmp.proto import rfc1902
def xpath_result( root, xpath ):
res = root.findall( xpath )
if len( res ) == 1:
return res[0].text
else:
return ""
#Exceptions which can occur during the work with device.
class ConnectionProblem( Exception ):
def __init__( self ):
#Two types of problem can happen.
#connection - connection problem and...
print "<doc><error><type>connection</type><text>Unable to connect. Check address or community string.</text></error></doc>"
class UnexpectedDataProblem( Exception ):
def __init__( self, msg ):
#... unexpected_data - a problem of data exchange with device.
print "<doc><error><type>unexpected_data</type><text>" + msg + "</text></error></doc>"
#Different functions converting values from panel to devices and back.
def CiscoPortStatusToIFXStr( val ):
return "on" if val == 1 else "off"
def CiscoPortSpeedToIFXStr( val ):
if val == 1:
return "auto"
elif val == 2:
return "auto10100"
elif val == 10000000:
return "10mbps"
elif val == 100000000:
return "100mbps"
elif val == 1000000000:
return "1gbps"
elif val == 10:
return "10gbps"
else:
raise UnexpectedDataProblem( "Unexpected speed value = " + str( val ) )
def IFXPortSpeedToCisco( val ):
if val == "auto":
return 1
elif val == "auto10100":
return 2
elif val == "10mbps":
return 10000000
elif val == "100mbps":
return 100000000
elif val == "1gbps":
return 1000000000
elif val == "10gbps":
return 10
def CiscoPortDuplexToIFXStr( val ):
if val == 1:
return "half"
elif val == 2:
return "full"
elif val == 4:
return "auto"
else:
raise UnexpectedDataProblem( "Unexpected duplex value = " + str( val ) )
def IFXPortDuplexToCisco( val ):
if val == "half":
return 1
elif val == "full":
return 2
elif val == "auto":
return 4
#Handler class.
class SwitchSimpleHandler:
def __init__( self, request_from_ifx ):
#Initialization of all objects, required for SNMP query.
self.__cmdGen = cmdgen.CommandGenerator()
xmlRoot = xmlET.fromstring( request_from_ifx )
self.__Community = cmdgen.CommunityData( xpath_result( xmlRoot, "./device_params/snmp_community" ) )
self.__Target = cmdgen.UdpTransportTarget((xpath_result( xmlRoot, "./device_params/ip" ), 161))
#Define a function called by DCImanager and call corresponding method
func_name = xpath_result( xmlRoot, "./func" )
if func_name == "status":
self.__Status()
elif func_name == "port_off":
self.__PortOff( xpath_result( xmlRoot, "./port/identity" ) )
elif func_name == "port_on":
self.__PortOn( xpath_result( xmlRoot, "./port/identity" ) )
elif func_name == "port_speed":
self.__PortSpeed( xpath_result( xmlRoot, "./port/identity" ), xpath_result( xmlRoot, "./port/speed" ) )
elif func_name == "port_duplex":
self.__PortDuplex( xpath_result( xmlRoot, "./port/identity" ), xpath_result( xmlRoot, "./port/duplex" ) )
def __PortOff( self, ident ):
#Disable port
self.__SnmpSet( "1.3.6.1.2.1.2.2.1.7." + ident, rfc1902.Integer( 2 ) )
#Send to panel new port's status
output = "<doc><port>"
output += "<identity>" + ident + "</identity>"
output += "<admin_status>on</admin_status>"
output += "</port></doc>"
print output
def __PortOn( self, ident ):
#Enable port
self.__SnmpSet( "1.3.6.1.2.1.2.2.1.7." + ident, rfc1902.Integer( 1 ) )
#Send to panel new port's status
output = "<doc><port>"
output += "<identity>" + ident + "</identity>"
output += "<admin_status>on</admin_status>"
output += "</port></doc>"
print output
def __PortSpeed( self, ident, val ):
#Get a list of indexes...
indexes = self.__SnmpWalk( "1.3.6.1.4.1.9.5.1.4.1.1.11" )
#And with this list set a new speed at desirable port
#Key will be searched by value .
self.__SnmpSet( "1.3.6.1.4.1.9.5.1.4.1.1.9.1." + indexes.keys()[indexes.values().index( int( ident ) )],
rfc1902.Integer( IFXPortSpeedToCisco( val ) ) )
#Send to panel new port's speed
output = "<doc><port>"
output += "<identity>" + ident + "</identity>"
output += "<speed>" + val + "</speed>"
output += "</port></doc>"
print output
def __PortDuplex( self, ident, val ):
#Get a list of indexes...
indexes = self.__SnmpWalk( "1.3.6.1.4.1.9.5.1.4.1.1.11" )
#And with this list set a new mode at desirable port
#Key will be searched by value
self.__SnmpSet( "1.3.6.1.4.1.9.5.1.4.1.1.10.1." + indexes.keys()[indexes.values().index( int( ident ) )],
rfc1902.Integer( IFXPortDuplexToCisco( val ) ) )
#Send to panel new port's mode .
output = "<doc><port>"
output += "<identity>" + ident + "</identity>"
output += "<duplex>" + val + "</duplex>"
output += "</port></doc>"
print output
def __Status( self ):
output = "<doc>"
ports = {}#Create port dictionary where key is ID of port
#Create ports description
for ident, descr in self.__SnmpWalk( "1.3.6.1.2.1.2.2.1.2" ).iteritems():
ports[ident] = self.DevicePort( ident )
ports[ident].Description = descr
#Define ports status made by administrator
for ident, adm_status in self.__SnmpWalk( "1.3.6.1.2.1.2.2.1.7" ).iteritems():
ports[ident].AdminStatus = CiscoPortStatusToIFXStr( adm_status )
#Define real ports status
for ident, oper_status in self.__SnmpWalk( "1.3.6.1.2.1.2.2.1.8" ).iteritems():
ports[ident].OperStatus = CiscoPortStatusToIFXStr( oper_status )
#Define actual ports speed and mode.
indexes = self.__SnmpWalk( "1.3.6.1.4.1.9.5.1.4.1.1.11" )
for ind, speed in self.__SnmpWalk( "1.3.6.1.4.1.9.5.1.4.1.1.9" ).iteritems():
ports[str( indexes[ind] )].Speed = CiscoPortSpeedToIFXStr( speed )
for ind, duplex in self.__SnmpWalk( "1.3.6.1.4.1.9.5.1.4.1.1.10" ).iteritems():
ports[str( indexes[ind] )].Duplex = CiscoPortDuplexToIFXStr( duplex )
#Send a full list of ports to panel.
output = "<doc>"
for port in ports.values():
output += "<port>"
output += "<identity>" + port.Identity + "</identity>"
output += "<description>" + port.Description + "</description>"
output += "<admin_status>" + port.AdminStatus + "</admin_status>"
output += "<oper_status>" + port.OperStatus + "</oper_status>"
output += "<duplex>" + port.Duplex + "</duplex>"
output += "<speed>" + port.Speed + "</speed>"
output += "</port>"
output += "</doc>"
print output
#Set up of mib value. Value should be converted to type according to rfc1902
def __SnmpSet( self, mib, value ):
errorIndication, errorStatus, errorIndex, varBinds = self.__cmdGen.setCmd( self.__Community,
self.__Target,
( cmdgen.MibVariable( mib ), value ) )
if errorIndication:
raise ConnectionProblem
#Tree-traverse (traverse of tree, made by mib)
def __SnmpWalk( self, mib ):
errorIndication, errorStatus, errorIndex, varBindTable = self.__cmdGen.nextCmd( self.__Community,
self.__Target,
cmdgen.MibVariable( mib ) )
if errorIndication:
raise ConnectionProblem
result_map = {}
for varBindTableRow in varBindTable:
for name, val in varBindTableRow:
result_map[name.prettyPrint().rpartition( "." )[2]] = val
return result_map
class DevicePort:
def __init__( self, ident ):
self.Identity = ident
Identity = ""
Description = ""
AdminStatus = "unknown"
OperStatus = "unknown"
Duplex = "unknown"
Speed = "unknown"
@staticmethod
def Info():
output = "<doc>"
#Device type
output += "<type>Switch</type>"
output += "<name>SNMP Switch Handler</name>"
#Use SNMP v2c
output += "<requirements>"
output += "<snmpv2c/>"
output += "</requirements>"
#There are only 4 functions which DCImanager will call from switch handler:
output += "<supported_funcs>"
#get a list of ports
output += "<status/>"
#disable port
output += "<port_off/>"
#enable port
output += "<port_on/>"
#change port's mode
output += "<port_duplex/>"
#change port's speed
output += "<port_speed/>"
output += "</supported_funcs>"
output += "</doc>"
print output
__cmdGen = None
__Target = None
__Community = None
def main():
if len(sys.argv) > 1 and sys.argv[1] == "-info":
#If there is a -info key - show information about handler.
SwitchSimpleHandler.Info()
else:
#In all other cases read input stream and make handler's object,
#for processing DCImanager request
request_str = sys.stdin.read()
SwitchSimpleHandler( request_str )
#Launch of main function
main()
IPMI handler
This handler manages devices with IPMI v1.5 by ipmitool utility (written on python 2.7) Start the script by calling the main function
#!/usr/bin/python2.7
#coding=utf8
import sys
import commands
import os
import xml.etree.ElementTree as xmlET
def xpath_result( root, xpath ):
res = root.findall( xpath )
if len( res ) == 1:
return res[0].text
else:
return ""
class IPMIhandler:
def __init__( self, request_from_ifx ):
xmlRoot = xmlET.fromstring( request_from_ifx )
#Get IP-address of IPMI.
self.__IP = xpath_result( xmlRoot, "./device_params/ip" )
#Get IPMI user, who should have rights to power management.
self.__User = xpath_result( xmlRoot, "./device_params/user" ).replace( "`", "\\`" )
#Password of IPMI in ipmitool will be sent by environment variable, for security reasons
os.putenv( "IPMI_PASSWORD", xpath_result( xmlRoot, "./device_params/pass" ) )
#Defying the function, called by DCImanager and calling corresponding method.
func_name = xpath_result( xmlRoot, "./func" )
if func_name == "status":
self.__Status()
elif func_name == "port_off":
self.__PortOff()
elif func_name == "port_on":
self.__PortOn()
elif func_name == "port_reset":
self.__PortReset()
def __PortOff( self ):
#Power-off by ipmitool
cmd_res, _ = commands.getstatusoutput( self.__IPMIToolStart() + "chassis power off" )
if cmd_res == 0:
#If a command is successful, return a new status by output
#For IPMI connection port's identity should always has a value "'''power'''".
output = "<doc><port>"
output += "<identity>power</identity>"
output += "<admin_status>off</admin_status>"
output += "</port></doc>"
print output
else:
#If connection failed, report about the connection problem.
self.__ConnectionProblem( cmd_res )
def __PortOn( self ):
#Power-on by ipmitool
cmd_res, _ = commands.getstatusoutput( self.__IPMIToolStart() + "chassis power on" )
if cmd_res == 0:
#If a command is successful, return a new status by output
output = "<doc><port>"
output += "<identity>power</identity>"
output += "<admin_status>on</admin_status>"
output += "</port></doc>"
print output
else:
#If command failed, report about the connection problem.
self.__ConnectionProblem( cmd_res )
def __PortReset( self ):
#Reboot server by ipmitool
cmd_res, _ = commands.getstatusoutput( self.__IPMIToolStart() + "chassis power reset" )
if cmd_res == 0:
#If a command is successful, return a new status by output
output = "<doc><port>"
output += "<identity>power</identity>"
output += "<admin_status>on</admin_status>"
output += "</port></doc>"
print output
else:
#If connection failed, report about the connection problem.
self.__ConnectionProblem( cmd_res )
def __Status( self ):
#Check server status by ipmitool
cmd_res, cmd_out = commands.getstatusoutput( self.__IPMIToolStart() + "chassis power status" )
if cmd_res == 0:
#If a command is successful, return a new status by output
output = "<doc><port>"
output += "<identity>power</identity>"
#Description will be shown in "Device" field in server's connections list.
#This node's description is not necessary. As a description the word "Power" will be used.
output += "<description>Some IPMI</description>"
#Check ports status
if "Chassis Power is on" in cmd_out or "Chassis Power Control: Up/On" in cmd_out:
output += "<admin_status>on</admin_status>"
elif "Chassis Power is off" in cmd_out or "Chassis Power Control: Down/Off" in cmd_out:
output += "<admin_status>off</admin_status>"
else:
#If ipmitool output doesn't show port status - report about an error in data exchange and finish method executing.
self.__UnexpectedDataProblem( cmd_out )
return
output += "</port></doc>"
print output
else:
self.__ConnectionProblem( cmd_res )
def __IPMIToolStart( self ):
#Start of ipmitool. If there is -E key - password
#will be get from environment variable
return self.__IPMITool + " -H " + self.__IP + " -U " + self.__User + " -E "
def __ConnectionProblem( self, ipmi_res ):
#Return an error. Problem will be registered in DCImanager
output = "<doc><error>"
#Two types of problem can happen.
#connection - problem with connection and...
output += "<type>connection</type>"
output += "<text>ipmitool has returned " + str( ipmi_res ) + "</text>"
output += "</error></doc>"
print output
def __UnexpectedDataProblem( self, ipmi_out ):
output = "<doc><error>"
#... unexpected_data - problem of data exchange with device.
output += "<type>unexpected_data</type>"
output += "<text>Unable to parse answer from ipmitool:\n" + ipmi_out + "</text>"
output += "</error></doc>"
print output
@staticmethod
def Info():
output = "<doc>"
#Device's type
output += "<type>IPMI</type>"
#IPMI version which will be shown in drop-down menu during creation of new connection.
output += "<name>Custom IPMI v1.5 Handler</name>"
#Node "requirements" in case of IPMI is not necessary.
output += "<supported_funcs>"
#Thewre are only 3 functions DCImanager will call from IPMI handler:
#device status
output += "<status/>"
#port disable
output += "<port_off/>"
#port enable
output += "<port_on/>"
#port reset
output += "<port_reset/>"
output += "</supported_funcs>"
output += "</doc>"
print output
__IPMITool = "/usr/bin/ipmitool"
__IP = ""
__User = ""
def main():
if len(sys.argv) > 1 and sys.argv[1] == "-info":
#If there is '''-info''' key - show handler's info
IPMIhandler.Info()
else:
#In all other cases read input stream and create handler' object
#for processing DCImanager's request.
request_str = sys.stdin.read()
IPMIhandler( request_str )
#Launch of main function
main()
PDU handler
Handler for BM blades power management (IBM BladeServer) (provided by one of the clients).
#!/usr/bin/python2.7
#coding=utf8
import sys
import os
import xml.etree.ElementTree as xmlET
from pysnmp.entity.rfc3413.oneliner import cmdgen
from pysnmp.proto import rfc1902
def xpath_result( root, xpath ):
res = root.findall( xpath )
if len( res ) == 1:
return res[0].text
else:
return ""
#Exeptions. which can happen during works with device
class ConnectionProblem( Exception ):
def __init__( self ):
#Two types f problems can occurs
#connection - problem with connection and..
print "<doc><error><type>connection</type><text>Unable to connect. Check address or community string.</text></error></doc>"
class UnexpectedDataProblem( Exception ):
def __init__( self, msg ):
#... unexpected_data - problem of data exchange between device and panel
print "<doc><error><type>unexpected_data</type><text>" + msg + "</text></error></doc>"
#Different functions of converting of values from panel to devices and vice versa.
def IBMPortStatusToIFXStr( val ):
return "on" if val == 1 else "off"
#Handler type
class PowerSimpleHandler:
def __init__( self, request_from_ifx ):
#Initialization of all objects required for SNMP request
self.__cmdGen = cmdgen.CommandGenerator()
xmlRoot = xmlET.fromstring( request_from_ifx )
self.__Community = cmdgen.CommunityData( xpath_result( xmlRoot, "./device_params/snmp_community" ), mpModel=0 )
self.__Target = cmdgen.UdpTransportTarget((xpath_result( xmlRoot, "./device_params/ip" ), 161))
#Define function called by DCImanager and call corresponding method
func_name = xpath_result( xmlRoot, "./func" )
if func_name == "status":
self.__Status()
elif func_name == "port_off":
self.__PortOff( xpath_result( xmlRoot, "./port/identity" ) )
elif func_name == "port_on":
self.__PortOn( xpath_result( xmlRoot, "./port/identity" ) )
elif func_name == "port_reset":
self.__PortReset( xpath_result( xmlRoot, "./port/identity" ) )
def __PortOff( self, ident ):
#Disable port
self.__SnmpSet( "1.3.6.1.4.1.2.3.51.2.22.1.6.1.1.7." + ident, rfc1902.Integer( 0 ) )
#Send to panel new port's status
output = "<doc><port>"
output += "<identity>" + ident + "</identity>"
output += "<admin_status>off</admin_status>"
output += "</port></doc>"
print output
def __PortOn( self, ident ):
#Enable port
self.__SnmpSet( "1.3.6.1.4.1.2.3.51.2.22.1.6.1.1.7." + ident, rfc1902.Integer( 1 ) )
#Send to panel new port's status
output = "<doc><port>"
output += "<identity>" + ident + "</identity>"
output += "<admin_status>on</admin_status>"
output += "</port></doc>"
print output
def __PortReset( self, ident ):
#Reboot port
self.__SnmpSet( "1.3.6.1.4.1.2.3.51.2.22.1.6.1.1.8." + ident, rfc1902.Integer( 1 ) )
#Send to panel new port's status
output = "<doc><port>"
output += "<identity>" + ident + "</identity>"
output += "<admin_status>on</admin_status>"
output += "</port></doc>"
print output
def __Status( self ):
output = "<doc>"
ports = {}#Make a vocabulary of ports, where key is ID of port
#Define real port' status
for ident, admin_status in self.__SnmpWalk( "1.3.6.1.4.1.2.3.51.2.22.1.5.1.1.4." ).iteritems():
ports[ident] = self.DevicePort(ident)
ports[ident].AdminStatus = IBMPortStatusToIFXStr( admin_status )
#Read blades names
for ident, descr in self.__SnmpWalk( "1.3.6.1.4.1.2.3.51.2.22.1.5.1.1.6." ).iteritems():
#If there is no blade in server - change (No name) Not installed
if descr == "(No name)":
descr = "Not installed"
ports[ident].Description = descr
#Send to panel a full list of ports
output = "<doc>"
for port in ports.values():
output += "<port>"
output += "<identity>" + port.Identity + "</identity>"
output += "<description>" + port.Description + "</description>"
output += "<admin_status>" + port.AdminStatus + "</admin_status>"
output += "</port>"
output += "</doc>"
print output
#Set up of mib value. Value should be adjusted to type in accordance with rfc1902
def __SnmpSet( self, mib, value ):
errorIndication, errorStatus, errorIndex, varBinds = self.__cmdGen.setCmd( self.__Community,
self.__Target,
( cmdgen.MibVariable( mib ), value ) )
if errorIndication:
raise ConnectionProblem
#Tree-traverse (traverse of tree, made by mib)
def __SnmpWalk( self, mib ):
errorIndication, errorStatus, errorIndex, varBindTable = self.__cmdGen.nextCmd( self.__Community,
self.__Target,
cmdgen.MibVariable( mib ) )
if errorIndication:
raise ConnectionProblem
result_map = {}
for varBindTableRow in varBindTable:
for name, val in varBindTableRow:
result_map[name.prettyPrint().rpartition( "." )[2]] = val
return result_map
class DevicePort:
def __init__( self, ident ):
self.Identity = ident
Identity = ""
Description = "Blade"
AdminStatus = "unknown"
@staticmethod
def Info():
output = "<doc>"
#Type of device
output += "<type>PDU</type>"
output += "<name>Blade Power</name>"
#Use SNMP v1
output += "<requirements>"
output += "<snmpv1/>"
output += "</requirements>"
#DCImanager will call from PDU handler only 4 functions:
output += "<supported_funcs>"
#list of ports
output += "<status/>"
#disable port
output += "<port_off/>"
#enable port
output += "<port_on/>"
#port reset
output += "<port_reset/>"
output += "</supported_funcs>"
output += "</doc>"
print output
__cmdGen = None
__Target = None
__Community = None
def main():
if len(sys.argv) > 1 and sys.argv[1] == "-info":
#If there is '''-info''' key - show handler info
PowerSimpleHandler.Info()
else:
#In all other cases read input stream and create handler' object
#which execute request from DCImanager
request_str = sys.stdin.read()
PowerSimpleHandler( request_str )
#Launch of main fucntion
main()