Introduce support for APC MasterSwitchPlus and Rack PDU
Provide 3 new snmp_driver values for different APC product families: - apc_masterswitch - apc_masterswitchplus - apc_rackpdu The "apc" snmp_driver is still supported and maps to the MasterSwitch driver to avoid breaking backwards compatibility. Different APC product families support different OIDs for power control. - APC MasterSwitch uses sPDUOutletCtl - APC MasterSwitchPlus uses sPDUOutletControlMSPOutletCommand - APC Rack PDU uses rPDUOutletControlOutletCommand Change-Id: I9d8724543d7da7b1c9cdc180c3396d131ed52615 Closes-Bug: #1471025
This commit is contained in:
parent
7f88443bce
commit
61f2f07569
@ -42,60 +42,10 @@ AMT
|
|||||||
SNMP
|
SNMP
|
||||||
----
|
----
|
||||||
|
|
||||||
The SNMP power driver enables control of power distribution units of the type
|
.. toctree::
|
||||||
frequently found in data centre racks. PDUs frequently have a management
|
:maxdepth: 1
|
||||||
ethernet interface and SNMP support enabling control of the power outlets.
|
|
||||||
|
|
||||||
The SNMP power driver works with the PXE driver for network deployment and
|
../drivers/snmp
|
||||||
network-configured boot.
|
|
||||||
|
|
||||||
Supported PDUs
|
|
||||||
^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
- American Power Conversion (APC)
|
|
||||||
- CyberPower (implemented according to MIB spec but not tested on hardware)
|
|
||||||
- EatonPower (implemented according to MIB spec but not tested on hardware)
|
|
||||||
- Teltronix
|
|
||||||
|
|
||||||
Software requirements
|
|
||||||
^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
- The PySNMP package must be installed, variously referred to as ``pysnmp``
|
|
||||||
or ``python-pysnmp``
|
|
||||||
|
|
||||||
Enabling the SNMP power driver
|
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
- Add ``pxe_snmp`` to the list of ``enabled_drivers`` in
|
|
||||||
``/etc/ironic/ironic.conf``
|
|
||||||
- Ironic Conductor must be restarted for the new driver to be loaded.
|
|
||||||
|
|
||||||
Ironic node configuration
|
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
Nodes are configured for SNMP control by setting the ironic node object's
|
|
||||||
``driver`` property to be ``pxe_snmp``. Further configuration values are
|
|
||||||
added to ``driver_info``:
|
|
||||||
|
|
||||||
- ``snmp_address``: the IPv4 address of the PDU controlling this node.
|
|
||||||
- ``snmp_port``: (optional) A non-standard UDP port to use for SNMP operations.
|
|
||||||
If not specified, the default port (161) is used.
|
|
||||||
- ``snmp_outlet``: The power outlet on the PDU (1-based indexing).
|
|
||||||
- ``snmp_protocol``: (optional) SNMP protocol version
|
|
||||||
(permitted values ``1``, ``2c`` or ``3``). If not specified, SNMPv1
|
|
||||||
is chosen.
|
|
||||||
- ``snmp_community``: (Required for SNMPv1 and SNMPv2c) SNMP community
|
|
||||||
parameter for reads and writes to the PDU.
|
|
||||||
- ``snmp_security``: (Required for SNMPv3) SNMP security string.
|
|
||||||
|
|
||||||
PDU configuration
|
|
||||||
^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
This version of the SNMP power driver does not support handling
|
|
||||||
PDU authentication credentials. When using SNMPv3, the PDU must be
|
|
||||||
configured for ``NoAuthentication`` and ``NoEncryption``. The
|
|
||||||
security name is used analogously to the SNMP community in early
|
|
||||||
SNMP versions.
|
|
||||||
|
|
||||||
iLO driver
|
iLO driver
|
||||||
----------
|
----------
|
||||||
|
91
doc/source/drivers/snmp.rst
Normal file
91
doc/source/drivers/snmp.rst
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
===========
|
||||||
|
SNMP driver
|
||||||
|
===========
|
||||||
|
|
||||||
|
The SNMP power driver enables control of power distribution units of the type
|
||||||
|
frequently found in data centre racks. PDUs frequently have a management
|
||||||
|
ethernet interface and SNMP support enabling control of the power outlets.
|
||||||
|
|
||||||
|
The SNMP power driver works with the PXE driver for network deployment and
|
||||||
|
network-configured boot.
|
||||||
|
|
||||||
|
List of supported devices
|
||||||
|
=========================
|
||||||
|
|
||||||
|
This is a non-exhaustive list of supported devices. Any device not listed in
|
||||||
|
this table could possibly work using a similar driver.
|
||||||
|
|
||||||
|
Please report any device status.
|
||||||
|
|
||||||
|
============== ========== ========== =====================
|
||||||
|
Manufacturer Model Supported? Driver name
|
||||||
|
============== ========== ========== =====================
|
||||||
|
APC AP7920 Yes apc_masterswitch
|
||||||
|
APC AP9606 Yes apc_masterswitch
|
||||||
|
APC AP9225 Yes apc_masterswitchplus
|
||||||
|
APC AP7155 Yes apc_rackpdu
|
||||||
|
APC AP7900 Yes apc_rackpdu
|
||||||
|
APC AP7901 Yes apc_rackpdu
|
||||||
|
APC AP7902 Yes apc_rackpdu
|
||||||
|
APC AP7911a Yes apc_rackpdu
|
||||||
|
APC AP7930 Yes apc_rackpdu
|
||||||
|
APC AP7931 Yes apc_rackpdu
|
||||||
|
APC AP7932 Yes apc_rackpdu
|
||||||
|
APC AP7940 Yes apc_rackpdu
|
||||||
|
APC AP7941 Yes apc_rackpdu
|
||||||
|
APC AP7951 Yes apc_rackpdu
|
||||||
|
APC AP7960 Yes apc_rackpdu
|
||||||
|
APC AP7990 Yes apc_rackpdu
|
||||||
|
APC AP7998 Yes apc_rackpdu
|
||||||
|
APC AP8941 Yes apc_rackpdu
|
||||||
|
APC AP8953 Yes apc_rackpdu
|
||||||
|
APC AP8959 Yes apc_rackpdu
|
||||||
|
APC AP8961 Yes apc_rackpdu
|
||||||
|
APC AP8965 Yes apc_rackpdu
|
||||||
|
Aten all? Yes aten
|
||||||
|
CyberPower all? Untested cyberpower
|
||||||
|
EatonPower all? Untested eatonpower
|
||||||
|
Teltronix all? Yes teltronix
|
||||||
|
============== ========== ========== =====================
|
||||||
|
|
||||||
|
|
||||||
|
Software Requirements
|
||||||
|
=====================
|
||||||
|
|
||||||
|
- The PySNMP package must be installed, variously referred to as ``pysnmp``
|
||||||
|
or ``python-pysnmp``
|
||||||
|
|
||||||
|
Enabling the SNMP Power Driver
|
||||||
|
==============================
|
||||||
|
|
||||||
|
- Add ``pxe_snmp`` to the list of ``enabled_drivers`` in
|
||||||
|
``/etc/ironic/ironic.conf``
|
||||||
|
- Ironic Conductor must be restarted for the new driver to be loaded.
|
||||||
|
|
||||||
|
Ironic Node Configuration
|
||||||
|
=========================
|
||||||
|
|
||||||
|
Nodes are configured for SNMP control by setting the Ironic node object's
|
||||||
|
``driver`` property to be ``pxe_snmp``. Further configuration values are
|
||||||
|
added to ``driver_info``:
|
||||||
|
|
||||||
|
- ``snmp_driver``: PDU manufacturer driver
|
||||||
|
- ``snmp_address``: the IPv4 address of the PDU controlling this node.
|
||||||
|
- ``snmp_port``: (optional) A non-standard UDP port to use for SNMP operations.
|
||||||
|
If not specified, the default port (161) is used.
|
||||||
|
- ``snmp_outlet``: The power outlet on the PDU (1-based indexing).
|
||||||
|
- ``snmp_protocol``: (optional) SNMP protocol version
|
||||||
|
(permitted values ``1``, ``2c`` or ``3``). If not specified, SNMPv1
|
||||||
|
is chosen.
|
||||||
|
- ``snmp_community``: (Required for SNMPv1 and SNMPv2c) SNMP community
|
||||||
|
parameter for reads and writes to the PDU.
|
||||||
|
- ``snmp_security``: (Required for SNMPv3) SNMP security string.
|
||||||
|
|
||||||
|
PDU Configuration
|
||||||
|
=================
|
||||||
|
|
||||||
|
This version of the SNMP power driver does not support handling
|
||||||
|
PDU authentication credentials. When using SNMPv3, the PDU must be
|
||||||
|
configured for ``NoAuthentication`` and ``NoEncryption``. The
|
||||||
|
security name is used analogously to the SNMP community in early
|
||||||
|
SNMP versions.
|
@ -398,10 +398,10 @@ class SNMPDriverAten(SNMPDriverSimple):
|
|||||||
return self.oid_enterprise + self.oid_device + (outlet, 0,)
|
return self.oid_enterprise + self.oid_device + (outlet, 0,)
|
||||||
|
|
||||||
|
|
||||||
class SNMPDriverAPC(SNMPDriverSimple):
|
class SNMPDriverAPCMasterSwitch(SNMPDriverSimple):
|
||||||
"""SNMP driver class for APC PDU devices.
|
"""SNMP driver class for APC MasterSwitch PDU devices.
|
||||||
|
|
||||||
SNMP objects for APC PDU:
|
SNMP objects for APC SNMPDriverAPCMasterSwitch PDU:
|
||||||
1.3.6.1.4.1.318.1.1.4.4.2.1.3 sPDUOutletCtl
|
1.3.6.1.4.1.318.1.1.4.4.2.1.3 sPDUOutletCtl
|
||||||
Values: 1=On, 2=Off, 3=PowerCycle, [...more options follow]
|
Values: 1=On, 2=Off, 3=PowerCycle, [...more options follow]
|
||||||
"""
|
"""
|
||||||
@ -411,6 +411,32 @@ class SNMPDriverAPC(SNMPDriverSimple):
|
|||||||
value_power_off = 2
|
value_power_off = 2
|
||||||
|
|
||||||
|
|
||||||
|
class SNMPDriverAPCMasterSwitchPlus(SNMPDriverSimple):
|
||||||
|
"""SNMP driver class for APC MasterSwitchPlus PDU devices.
|
||||||
|
|
||||||
|
SNMP objects for APC SNMPDriverAPCMasterSwitchPlus PDU:
|
||||||
|
1.3.6.1.4.1.318.1.1.6.5.1.1.5 sPDUOutletControlMSPOutletCommand
|
||||||
|
Values: 1=On, 3=Off, [...more options follow]
|
||||||
|
"""
|
||||||
|
|
||||||
|
oid_device = (318, 1, 1, 6, 5, 1, 1, 5)
|
||||||
|
value_power_on = 1
|
||||||
|
value_power_off = 3
|
||||||
|
|
||||||
|
|
||||||
|
class SNMPDriverAPCRackPDU(SNMPDriverSimple):
|
||||||
|
"""SNMP driver class for APC RackPDU devices.
|
||||||
|
|
||||||
|
SNMP objects for APC SNMPDriverAPCMasterSwitch PDU:
|
||||||
|
# 1.3.6.1.4.1.318.1.1.12.3.3.1.1.4 rPDUOutletControlOutletCommand
|
||||||
|
Values: 1=On, 2=Off, 3=PowerCycle, [...more options follow]
|
||||||
|
"""
|
||||||
|
|
||||||
|
oid_device = (318, 1, 1, 12, 3, 3, 1, 1, 4)
|
||||||
|
value_power_on = 1
|
||||||
|
value_power_off = 2
|
||||||
|
|
||||||
|
|
||||||
class SNMPDriverCyberPower(SNMPDriverSimple):
|
class SNMPDriverCyberPower(SNMPDriverSimple):
|
||||||
"""SNMP driver class for CyberPower PDU devices.
|
"""SNMP driver class for CyberPower PDU devices.
|
||||||
|
|
||||||
@ -522,7 +548,10 @@ class SNMPDriverEatonPower(SNMPDriverBase):
|
|||||||
|
|
||||||
# A dictionary of supported drivers keyed by snmp_driver attribute
|
# A dictionary of supported drivers keyed by snmp_driver attribute
|
||||||
DRIVER_CLASSES = {
|
DRIVER_CLASSES = {
|
||||||
'apc': SNMPDriverAPC,
|
'apc': SNMPDriverAPCMasterSwitch,
|
||||||
|
'apc_masterswitch': SNMPDriverAPCMasterSwitch,
|
||||||
|
'apc_masterswitchplus': SNMPDriverAPCMasterSwitchPlus,
|
||||||
|
'apc_rackpdu': SNMPDriverAPCRackPDU,
|
||||||
'aten': SNMPDriverAten,
|
'aten': SNMPDriverAten,
|
||||||
'cyberpower': SNMPDriverCyberPower,
|
'cyberpower': SNMPDriverCyberPower,
|
||||||
'eatonpower': SNMPDriverEatonPower,
|
'eatonpower': SNMPDriverEatonPower,
|
||||||
|
@ -189,6 +189,27 @@ class SNMPValidateParametersTestCase(db_base.DbTestCase):
|
|||||||
info = snmp._parse_driver_info(node)
|
info = snmp._parse_driver_info(node)
|
||||||
self.assertEqual('apc', info.get('driver'))
|
self.assertEqual('apc', info.get('driver'))
|
||||||
|
|
||||||
|
def test__parse_driver_info_apc_masterswitch(self):
|
||||||
|
# Make sure the APC driver type is parsed.
|
||||||
|
info = db_utils.get_test_snmp_info(snmp_driver='apc_masterswitch')
|
||||||
|
node = self._get_test_node(info)
|
||||||
|
info = snmp._parse_driver_info(node)
|
||||||
|
self.assertEqual('apc_masterswitch', info.get('driver'))
|
||||||
|
|
||||||
|
def test__parse_driver_info_apc_masterswitchplus(self):
|
||||||
|
# Make sure the APC driver type is parsed.
|
||||||
|
info = db_utils.get_test_snmp_info(snmp_driver='apc_masterswitchplus')
|
||||||
|
node = self._get_test_node(info)
|
||||||
|
info = snmp._parse_driver_info(node)
|
||||||
|
self.assertEqual('apc_masterswitchplus', info.get('driver'))
|
||||||
|
|
||||||
|
def test__parse_driver_info_apc_rackpdu(self):
|
||||||
|
# Make sure the APC driver type is parsed.
|
||||||
|
info = db_utils.get_test_snmp_info(snmp_driver='apc_rackpdu')
|
||||||
|
node = self._get_test_node(info)
|
||||||
|
info = snmp._parse_driver_info(node)
|
||||||
|
self.assertEqual('apc_rackpdu', info.get('driver'))
|
||||||
|
|
||||||
def test__parse_driver_info_aten(self):
|
def test__parse_driver_info_aten(self):
|
||||||
# Make sure the Aten driver type is parsed.
|
# Make sure the Aten driver type is parsed.
|
||||||
info = db_utils.get_test_snmp_info(snmp_driver='aten')
|
info = db_utils.get_test_snmp_info(snmp_driver='aten')
|
||||||
@ -834,6 +855,94 @@ class SNMPDeviceDriverTestCase(db_base.DbTestCase):
|
|||||||
def test_apc_power_reset(self, mock_get_client):
|
def test_apc_power_reset(self, mock_get_client):
|
||||||
self._test_simple_device_power_reset('apc', mock_get_client)
|
self._test_simple_device_power_reset('apc', mock_get_client)
|
||||||
|
|
||||||
|
def test_apc_masterswitch_snmp_objects(self, mock_get_client):
|
||||||
|
# Ensure the correct SNMP object OIDs and values are used by the APC
|
||||||
|
# masterswitch driver
|
||||||
|
self._update_driver_info(snmp_driver="apc_masterswitch",
|
||||||
|
snmp_outlet="6")
|
||||||
|
driver = snmp._get_driver(self.node)
|
||||||
|
oid = (1, 3, 6, 1, 4, 1, 318, 1, 1, 4, 4, 2, 1, 3, 6)
|
||||||
|
self.assertEqual(oid, driver._snmp_oid())
|
||||||
|
self.assertEqual(1, driver.value_power_on)
|
||||||
|
self.assertEqual(2, driver.value_power_off)
|
||||||
|
|
||||||
|
def test_apc_masterswitch_power_state_on(self, mock_get_client):
|
||||||
|
self._test_simple_device_power_state_on('apc_masterswitch',
|
||||||
|
mock_get_client)
|
||||||
|
|
||||||
|
def test_apc_masterswitch_power_state_off(self, mock_get_client):
|
||||||
|
self._test_simple_device_power_state_off('apc_masterswitch',
|
||||||
|
mock_get_client)
|
||||||
|
|
||||||
|
def test_apc_masterswitch_power_on(self, mock_get_client):
|
||||||
|
self._test_simple_device_power_on('apc_masterswitch', mock_get_client)
|
||||||
|
|
||||||
|
def test_apc_masterswitch_power_off(self, mock_get_client):
|
||||||
|
self._test_simple_device_power_off('apc_masterswitch', mock_get_client)
|
||||||
|
|
||||||
|
def test_apc_masterswitch_power_reset(self, mock_get_client):
|
||||||
|
self._test_simple_device_power_reset('apc_masterswitch',
|
||||||
|
mock_get_client)
|
||||||
|
|
||||||
|
def test_apc_masterswitchplus_snmp_objects(self, mock_get_client):
|
||||||
|
# Ensure the correct SNMP object OIDs and values are used by the APC
|
||||||
|
# masterswitchplus driver
|
||||||
|
self._update_driver_info(snmp_driver="apc_masterswitchplus",
|
||||||
|
snmp_outlet="6")
|
||||||
|
driver = snmp._get_driver(self.node)
|
||||||
|
oid = (1, 3, 6, 1, 4, 1, 318, 1, 1, 6, 5, 1, 1, 5, 6)
|
||||||
|
self.assertEqual(oid, driver._snmp_oid())
|
||||||
|
self.assertEqual(1, driver.value_power_on)
|
||||||
|
self.assertEqual(3, driver.value_power_off)
|
||||||
|
|
||||||
|
def test_apc_masterswitchplus_power_state_on(self, mock_get_client):
|
||||||
|
self._test_simple_device_power_state_on('apc_masterswitchplus',
|
||||||
|
mock_get_client)
|
||||||
|
|
||||||
|
def test_apc_masterswitchplus_power_state_off(self, mock_get_client):
|
||||||
|
self._test_simple_device_power_state_off('apc_masterswitchplus',
|
||||||
|
mock_get_client)
|
||||||
|
|
||||||
|
def test_apc_masterswitchplus_power_on(self, mock_get_client):
|
||||||
|
self._test_simple_device_power_on('apc_masterswitchplus',
|
||||||
|
mock_get_client)
|
||||||
|
|
||||||
|
def test_apc_masterswitchplus_power_off(self, mock_get_client):
|
||||||
|
self._test_simple_device_power_off('apc_masterswitchplus',
|
||||||
|
mock_get_client)
|
||||||
|
|
||||||
|
def test_apc_masterswitchplus_power_reset(self, mock_get_client):
|
||||||
|
self._test_simple_device_power_reset('apc_masterswitchplus',
|
||||||
|
mock_get_client)
|
||||||
|
|
||||||
|
def test_apc_rackpdu_snmp_objects(self, mock_get_client):
|
||||||
|
# Ensure the correct SNMP object OIDs and values are used by the APC
|
||||||
|
# rackpdu driver
|
||||||
|
self._update_driver_info(snmp_driver="apc_rackpdu",
|
||||||
|
snmp_outlet="6")
|
||||||
|
driver = snmp._get_driver(self.node)
|
||||||
|
oid = (1, 3, 6, 1, 4, 1, 318, 1, 1, 12, 3, 3, 1, 1, 4, 6)
|
||||||
|
|
||||||
|
self.assertEqual(oid, driver._snmp_oid())
|
||||||
|
self.assertEqual(1, driver.value_power_on)
|
||||||
|
self.assertEqual(2, driver.value_power_off)
|
||||||
|
|
||||||
|
def test_apc_rackpdu_power_state_on(self, mock_get_client):
|
||||||
|
self._test_simple_device_power_state_on('apc_rackpdu', mock_get_client)
|
||||||
|
|
||||||
|
def test_apc_rackpdu_power_state_off(self, mock_get_client):
|
||||||
|
self._test_simple_device_power_state_off('apc_rackpdu',
|
||||||
|
mock_get_client)
|
||||||
|
|
||||||
|
def test_apc_rackpdu_power_on(self, mock_get_client):
|
||||||
|
self._test_simple_device_power_on('apc_rackpdu', mock_get_client)
|
||||||
|
|
||||||
|
def test_apc_rackpdu_power_off(self, mock_get_client):
|
||||||
|
self._test_simple_device_power_off('apc_rackpdu', mock_get_client)
|
||||||
|
|
||||||
|
def test_apc_rackpdu_power_reset(self, mock_get_client):
|
||||||
|
self._test_simple_device_power_reset('apc_rackpdu', mock_get_client)
|
||||||
|
|
||||||
def test_aten_snmp_objects(self, mock_get_client):
|
def test_aten_snmp_objects(self, mock_get_client):
|
||||||
# Ensure the correct SNMP object OIDs and values are used by the
|
# Ensure the correct SNMP object OIDs and values are used by the
|
||||||
# Aten driver
|
# Aten driver
|
||||||
|
Loading…
x
Reference in New Issue
Block a user