DCImanager uses modules (service handlers) to manage equipment. A full list of handlers that the control panel supports can be found in the article Supported equipment. This article describes how to add a custom handler.
Overview
An external device handler is an executable file: a script or binary file. Data exchange between DCImanager and a handler is through stdout and stdin. The data is transmitted in an XML-file.
When DCImanager starts, it launches the executable files from var / dcihandlers with the -info key. Each handler sends an XML to stdout. The XML describes what device this executable file processes and what functions it supports. DCImanager registers a new handler that will be available when adding new devices.
How it works
Registering a new handler
DCImanager starts the handler with the -info option
testhandler -info
Nothing will be sent to the handler stdin, however, the handler must pass the XML that describes the device to its stdout. The XML example:
<doc>
<type>Switch</type>
<name>First External Handler</name>
<requirements>
<snmpv1/>
<snmpv2c/>
</requirements>
<supported_funcs>
<status/>
<port_on/>
<port_off/>
</supported_funcs>
</doc>
<type> — a device type: Switch, PDU, IPMI, UPS.
<name> — a device name that will be displayed in DCImanager.
<requirements> — a list of input data for the handler. The list defines what data DCImanager will ask to enter to add a new device, and what input data will be sent to the handler while performing operations with the device:
- <snmpv1/> — SNMPv1 will be available on the device creation form. SNMP version and Community will be sent to the handler;
- <snmpv2c/> — SNMPv2c will be available on the device creation form. SNMP version and Community will be sent to the handler;
- <snmpv3/> — SNMPv3 will be available on the device creation form. SNMP version, the username, auth phrase, priv phrase, and authentication level will be sent to the handler;
- <ssh/> — the form will contain the SSH tab. The username and password for SSH access will be sent to the handler;
- <telnet/> — the form will contain the Telnet tab. The username and password for Telnet access will be sent to the handler;
- <can_collect_power/> — must be specified only for PDU and UPS. If the control panel doesn't contain a PDU or UPS that support this option, power usage statistics information and columns in the list of servers and racks won't be displayed.
You can use any combinations of the above parameters.
<supported_funcs>
The list of device functions:
- <status/> - the handler can read the information about the device (mandatory);
- <statistics/> - the handler can collect traffic statistics (for switches) or power consumption (for some PDU).
- <port_on/> - the handler can enable device port;
- <port_off/> - the handler can disable device port;
- <port_reset/> - the handler can reset the device port (mainly for power ports);
- <port_speed/> - the handler can set the device port speed (only for switches);
- <port_duplex/> - the handler can set the device port mode (only for switches);
- <set_vlan/> - the handler can set the device port VLAN (only for switches);
- <mac_list/> - the handler can display the list of MAC-addresses of device ports (only for switches).
Device function call
Input data
When a handler function is called (e.g., to disable a PDU port), the system calls the executable file without parameters and sends the XML with necessary data through its stdin. Example 1 - call of the status function, which should show information about all statuses of all device's ports.
The following is the example of the status function call. The function returns information about device port statuses:
<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>
The port_on function call. The function enables a certain port of the device:
<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>
Device parameters:
Port parameters:
Output data
After the handler has received and processed the input data, it must return a result (also in XML).
E.g. the following is the response from the switch handler with four ports to the status function. It describes the ports and their states:
<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>
The responses to the port_off function for the port with the identifier "1".
<doc>
<port>
<identity>1</identity>
<admin_status>off</admin_status>
</port>
</doc>
Port parameters:
The handler may return an error. E.g:
<doc>
<error>
<type>connection</type>
<text>Failed to open connection to 12.35.56.22</text>
</error>
</doc>
If the output XML contains the <error> section, all other content will be ignored and the operation will be terminated. The system will generate the error report.
Matching inputs and outputs
Switches (<type>Switch</type>)
PDU (<type>PDU</type>)
IPMI (<type>IPMI</type>)
Although an IPMI doesn't have ports because it's integrated to the server, DCImanager has a reserved port for such devices. Its identifier must be "power" (case-sensitive).
UPS (<type>UPS</type>)
Only device status can be received for a UPS. The data from UPS are displayed in the UPS list.
Examples of handler
Switch
This handler is similar to the SNMP common handler in DCImanager. Switch management is performed by SNMPv2c library pysnmp 4v.
#!/usr/bin/python2.7
#coding=utf8mb4
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 that can occur during the work with device.
class ConnectionProblem( Exception ):
def __init__( self ):
#Two types of possible issues.
#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 — data exchange problem.
print "<doc><error><type>unexpected_data</type><text>" + msg + "</text></error></doc>"
#Different functions that convert values from the panel to the 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 the objects for the 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 the function that DCImanager called and call the 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 the port
self.__SnmpSet( "1.3.6.1.2.1.2.2.1.7." + ident, rfc1902.Integer( 2 ) )
#Inform the panel about a port sew status
output = "<doc><port>"
output += "<identity>" + ident + "</identity>"
output += "<admin_status>on</admin_status>"
output += "</port></doc>"
print output
def __PortOn( self, ident ):
#Enable the port
self.__SnmpSet( "1.3.6.1.2.1.2.2.1.7." + ident, rfc1902.Integer( 1 ) )
#Inform the panel about a port sew status
output = "<doc><port>"
output += "<identity>" + ident + "</identity>"
output += "<admin_status>on</admin_status>"
output += "</port></doc>"
print output
def __PortSpeed( self, ident, val ):
#Receive a list of indexes...
indexes = self.__SnmpWalk( "1.3.6.1.4.1.9.5.1.4.1.1.11" )
#To set new speed for the port.
#Find the key by the 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 ) ) )
#Inform the panel about a port sew status.
output = "<doc><port>"
output += "<identity>" + ident + "</identity>"
output += "<speed>" + val + "</speed>"
output += "</port></doc>"
print output
def __PortDuplex( self, ident, val ):
#Receive a list of indexes...
indexes = self.__SnmpWalk( "1.3.6.1.4.1.9.5.1.4.1.1.11" )
#To set a new mode for the port.
#Find the key by the 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 ) ) )
#Inform the panel about a port sew status.
output = "<doc><port>"
output += "<identity>" + ident + "</identity>"
output += "<duplex>" + val + "</duplex>"
output += "</port></doc>"
print output
def __Status( self ):
output = "<doc>"
ports = {}#Add a dictionary of ports where the keys is the port identifier.
#Define the port 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 the port statuses set by the 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 the real port statuses.
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 the current speed and mode of the ports.
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 )
#Inform the panel about 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 += "<oper_status>" + port.OperStatus + "</oper_status>"
output += "<duplex>" + port.Duplex + "</duplex>"
output += "<speed>" + port.Speed + "</speed>"
output += "</port>"
output += "</doc>"
print output
#Set the mib value. The value must correspond 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
#Traverse of the tree set 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>"
#DCImanager will call only 4 function from a switch handler:
output += "<supported_funcs>"
#Retrieve a list of ports
output += "<status/>"
#Disable a port
output += "<port_off/>"
#Enable a port
output += "<port_on/>"
#Change port mode
output += "<port_duplex/>"
#Change port mode and 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 the -info key, send the handler information
SwitchSimpleHandler.Info()
else:
#In all other cases read the input thread and create the handler object
#that will process the request from DCImanager.
request_str = sys.stdin.read()
SwitchSimpleHandler( request_str )
#Start the main function
main()
IPMI
This handler allows managing devices with IPMI v1.5 with the ipmitool utility written on python 2.7.
Start the script by calling the function main().
#!/usr/bin/python2.7
#coding=utf8mb4
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 )
#Receive the IPMI IP address
self.__IP = xpath_result( xmlRoot, "./device_params/ip" )
#Receive the IPMI user who can manage the device.
self.__User = xpath_result( xmlRoot, "./device_params/user" ).replace( "`", "\\`" )
#For security reasons we will send a password in ipmitool through the environment variable.
os.putenv( "IPMI_PASSWORD", xpath_result( xmlRoot, "./device_params/pass" ) )
#Define the function that DCImanager called and call the 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 ):
#Disable the server through ipmitool
cmd_res, _ = commands.getstatusoutput( self.__IPMIToolStart() + "chassis power off" )
if cmd_res == 0:
#If the command completed successfully, return a new status.
#For IPMI the port identity must be power.
output = "<doc><port>"
output += "<identity>power</identity>"
output += "<admin_status>off</admin_status>"
output += "</port></doc>"
print output
else:
#Should the command fail, inform about the connection problem.
self.__ConnectionProblem( cmd_res )
def __PortOn( self ):
#Enable the server through ipmitool
cmd_res, _ = commands.getstatusoutput( self.__IPMIToolStart() + "chassis power on" )
if cmd_res == 0:
#If the command completed successfully, return a new status.
output = "<doc><port>"
output += "<identity>power</identity>"
output += "<admin_status>on</admin_status>"
output += "</port></doc>"
print output
else:
##Should the command fail, inform about the connection problem.
self.__ConnectionProblem( cmd_res )
def __PortReset( self ):
#Reboot the server through ipmitool
cmd_res, _ = commands.getstatusoutput( self.__IPMIToolStart() + "chassis power reset" )
if cmd_res == 0:
#If the command completed successfully, return a new status.
output = "<doc><port>"
output += "<identity>power</identity>"
output += "<admin_status>on</admin_status>"
output += "</port></doc>"
print output
else:
##Should the command fail, inform about the connection problem.
self.__ConnectionProblem( cmd_res )
def __Status( self ):
#Define the server status through ipmitool
cmd_res, cmd_out = commands.getstatusoutput( self.__IPMIToolStart() + "chassis power status" )
if cmd_res == 0:
#If the command completed successfully, return a new status.
output = "<doc><port>"
output += "<identity>power</identity>"
#Description will be shown in the Device field of the Server connections list.
#You may not specify this node. Power will be used as its description.
output += "<description>Some IPMI</description>"
#Define a port 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 the port status cannot be defined by the ipmitool output, inform
#about the data interchange error and terminate execution of the method.
self.__UnexpectedDataProblem( cmd_out )
return
output += "</port></doc>"
print output
else:
self.__ConnectionProblem( cmd_res )
def __IPMIToolStart( self ):
#Beginning of the ipmitool command. The -E key defines that
#the password will be taken from the environment variables.
return self.__IPMITool + " -H " + self.__IP + " -U " + self.__User + " -E "
def __ConnectionProblem( self, ipmi_res ):
#Return the error message. DCImanager will register the issue.
output = "<doc><error>"
#There can be two types of issues.
#connection — connection problem 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 — data exchange problem.
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 type
output += "<type>IPMI</type>"
#IPMI version displayed in the drop-down list.
output += "<name>Custom IPMI v1.5 Handler</name>"
#You don't need to specify the requirements node for IPMI.
output += "<supported_funcs>"
#DCImanager will call only 3 functions from the IPMI handler:
#Device status
output += "<status/>"
#Disable the port
output += "<port_off/>"
#Enable
output += "<port_on/>"
#Reboot
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 the -info key, send the handler information
IPMIhandler.Info()
else:
#In all other cases read the input thread and create the handler object
#that will process the request from DCImanager.
request_str = sys.stdin.read()
IPMIhandler( request_str )
#Start the main function
main()
PDU
A handler for IBM BladeServer that allows managing blade-server power (from one of our clients).
#!/usr/bin/python2.7
#coding=utf8mb4
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 that can occur during the work with device..
class ConnectionProblem( Exception ):
def __init__( self ):
#Two types of possible issues.
#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 — data exchange problem.
print "<doc><error><type>unexpected_data</type><text>" + msg + "</text></error></doc>"
#Different functions that convert values from the panel to the devices and back.
def IBMPortStatusToIFXStr( val ):
return "on" if val == 1 else "off"
#Handler calss.
class PowerSimpleHandler:
def __init__( self, request_from_ifx ):
#Initialization of the objects for the SNMP query.
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 the function that DCImanager called and call the 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 the port
self.__SnmpSet( "1.3.6.1.4.1.2.3.51.2.22.1.6.1.1.7." + ident, rfc1902.Integer( 0 ) )
#Inform the panel about a port sew status
output = "<doc><port>"
output += "<identity>" + ident + "</identity>"
output += "<admin_status>off</admin_status>"
output += "</port></doc>"
print output
def __PortOn( self, ident ):
#Enable the port
self.__SnmpSet( "1.3.6.1.4.1.2.3.51.2.22.1.6.1.1.7." + ident, rfc1902.Integer( 1 ) )
#Inform the panel about a port sew status
output = "<doc><port>"
output += "<identity>" + ident + "</identity>"
output += "<admin_status>on</admin_status>"
output += "</port></doc>"
print output
def __PortReset( self, ident ):
#Reboot the port
self.__SnmpSet( "1.3.6.1.4.1.2.3.51.2.22.1.6.1.1.8." + ident, rfc1902.Integer( 1 ) )
#Inform the panel about a port sew 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 = {}#Add a port dictionary where the key is the port identifier..
#Define the 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 the names of blade-servers
for ident, descr in self.__SnmpWalk( "1.3.6.1.4.1.2.3.51.2.22.1.5.1.1.6." ).iteritems():
#If the blade-sever is missing, change No name into Not installed
if descr == "(No name)":
descr = "Not installed"
ports[ident].Description = descr
#Inform the panel about 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 the mib value. The value must correspond 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
#Traverse of the tree set 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>"
#Device type
output += "<type>PDU</type>"
output += "<name>Blade Power</name>"
#Use SNMP v1
output += "<requirements>"
output += "<snmpv1/>"
output += "</requirements>"
#DCImanager will call only 4 functions from a PDU:
output += "<supported_funcs>"
#Retrieve a list of ports
output += "<status/>"
#Disable the port
output += "<port_off/>"
#Enable the port
output += "<port_on/>"
#Reboot the port
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 the -info key, show the handler information
PowerSimpleHandler.Info()
else:
#In all other cases read the input thread and create the handler object
#that will process the request from DCImanager.
request_str = sys.stdin.read()
PowerSimpleHandler( request_str )
#Start the main function
main()
UPS
This handler imitates responses from a UPS.
To start the script, call the function main().
#!/usr/bin/python2.7
#coding=utf8mb4
import sys
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 ""
#Handler class.
class UPSSimpleHandler:
def __init__( self, request_from_ifx ):
#Define a function that DCImanager called and call the corresponding method
xmlRoot = xmlET.fromstring( request_from_ifx )
func_name = xpath_result( xmlRoot, "./func" )
if func_name == "status":
self.__Status()
def __Status( self ):
output = "<doc>"
#status — OK, Warning, Critical
output += " <eq_param name='device_status'>"
output += " <strvalue>OK</strvalue>"
output += " </eq_param>"
#Input voltage. Less than 100 — show the warning
output += " <eq_param name='input_voltage_line_A'>"
output += " <floatvalue>220</floatvalue>"
output += " </eq_param>"
output += " <eq_param name='input_voltage_line_B'>"
output += " <floatvalue>220</floatvalue>"
output += " </eq_param>"
#Load (%)
output += " <eq_param name='output_load_line_A'>"
output += " <floatvalue>60</floatvalue>"
output += " </eq_param>"
output += " <eq_param name='output_load_line_B'>"
output += " <floatvalue>60</floatvalue>"
output += " </eq_param>"
#Output power (kW)
output += " <eq_param name='output_power_line_A'>"
output += " <floatvalue>49.23</floatvalue>"
output += " </eq_param>"
output += " <eq_param name='output_power_line_B'>"
output += " <floatvalue>40.7</floatvalue>"
output += " </eq_param>"
#Power consumption (kW)
output += " <eq_param name='input_power_line_A'>"
output += " <floatvalue>49.23</floatvalue>"
output += " </eq_param>"
output += " <eq_param name='input_power_line_B'>"
output += " <floatvalue>40.7</floatvalue>"
output += " </eq_param>"
#Battery charge (minutes)
output += " <eq_param name='battary_time_remains'>"
output += " <floatvalue>24</floatvalue>"
output += " </eq_param>"
output += "</doc>"
print output
@staticmethod
def Info():
output = "<doc>\n"
#Device type
output += " <type>UPS</type>\n"
output += " <name>custom UPS</name>\n"
#Use SNMP v1
output += " <requirements>\n"
output += " <snmpv1/>\n"
output += " </requirements>\n"
#DCImanager will call only one function from the UPS handler:
output += " <supported_funcs>\n"
#status request
output += " <status/>\n"
output += " </supported_funcs>\n"
output += "</doc>"
print output
def main():
if len(sys.argv) > 1 and sys.argv[1] == "-info":
#If there is the -info key, show the handler information
UPSSimpleHandler.Info()
else:
#In all other cases read the input thread and create the handler object
#that will process the request from DCImanager.
request_str = sys.stdin.read()
UPSSimpleHandler( request_str )
#Start the main function
main()